about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-06-29 23:38:13 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-06-29 23:38:13 +0330
commit302bb3c8717317b84f03e6c2c719d88e61a3e65c (patch)
tree2af3c3a121ac6becf7924eac4fc5f991098ecfb4
parentf53f9230f06190a3682a8c9a1b958e5ecc5cf8d3 (diff)
downloadrust-302bb3c8717317b84f03e6c2c719d88e61a3e65c.tar.gz
rust-302bb3c8717317b84f03e6c2c719d88e61a3e65c.zip
Fix data layout of reference to nested unsized structs
-rw-r--r--crates/hir-ty/src/consteval/tests.rs31
-rw-r--r--crates/hir-ty/src/layout.rs5
-rw-r--r--crates/hir-ty/src/layout/tests.rs18
3 files changed, 53 insertions, 1 deletions
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
@@ -2491,6 +2491,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(
         r#"
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
@@ -344,6 +344,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! {
         enum Goal {