From 302bb3c8717317b84f03e6c2c719d88e61a3e65c Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 29 Jun 2023 23:38:13 +0330 Subject: [PATCH] Fix data layout of reference to nested unsized structs --- crates/hir-ty/src/consteval/tests.rs | 31 ++++++++++++++++++++++++++++ crates/hir-ty/src/layout.rs | 5 ++++- crates/hir-ty/src/layout/tests.rs | 18 ++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index de3a947f358..e50dfdf965e 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -2490,6 +2490,37 @@ fn type_error() { ); } +#[test] +fn unsized_field() { + check_number( + r#" + //- minicore: coerce_unsized, index, slice, transmute + use core::mem::transmute; + + struct Slice([u8]); + struct Slice2(Slice); + + impl Slice2 { + fn as_inner(&self) -> &Slice { + &self.0 + } + + fn as_bytes(&self) -> &[u8] { + &self.as_inner().0 + } + } + + const GOAL: u8 = unsafe { + let x: &[u8] = &[1, 2, 3]; + let x: &Slice2 = transmute(x); + let x = x.as_bytes(); + x[0] + x[1] + x[2] + }; + "#, + 6, + ); +} + #[test] fn unsized_local() { check_fail( diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 35d3407c16c..a566c06a540 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -315,7 +315,10 @@ fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { let data = db.struct_data(*i); let mut it = data.variant_data.fields().iter().rev(); match it.next() { - Some((f, _)) => field_ty(db, (*i).into(), f, subst), + Some((f, _)) => { + let last_field_ty = field_ty(db, (*i).into(), f, subst); + struct_tail_erasing_lifetimes(db, last_field_ty) + } None => pointee, } } diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index b75f213df2d..0257aef7a4c 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -343,6 +343,24 @@ fn return_position_impl_trait() { } } +#[test] +fn unsized_ref() { + size_and_align! { + struct S1([u8]); + struct S2(S1); + struct S3(i32, str); + struct S4(u64, S3); + #[allow(dead_code)] + struct S5 { + field1: u8, + field2: i16, + field_last: S4, + } + + struct Goal(&'static S1, &'static S2, &'static S3, &'static S4, &'static S5); + } +} + #[test] fn enums() { size_and_align! {