about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs19
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs11
-rw-r--r--tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs32
-rw-r--r--tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr9
-rw-r--r--tests/ui/consts/const-eval/issue-91827-extern-types.rs59
-rw-r--r--tests/ui/extern/extern-types-field-offset.rs26
-rw-r--r--tests/ui/extern/extern-types-field-offset.run.stderr4
7 files changed, 85 insertions, 75 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index a3fb3b9d783..c0bb3ac5661 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -99,6 +99,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         let offset = self.layout.fields.offset(ix);
         let effective_field_align = self.align.restrict_for_offset(offset);
 
+        // `simple` is called when we don't need to adjust the offset to
+        // the dynamic alignment of the field.
         let mut simple = || {
             let llval = match self.layout.abi {
                 _ if offset.bytes() == 0 => {
@@ -141,28 +143,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         };
 
         // Simple cases, which don't need DST adjustment:
-        //   * no metadata available - just log the case
-        //   * known alignment - sized types, `[T]`, `str` or a foreign type
+        //   * known alignment - sized types, `[T]`, `str`
+        //   * offset 0 -- rounding up to alignment cannot change the offset
         // Note that looking at `field.align` is incorrect since that is not necessarily equal
         // to the dynamic alignment of the type.
         match field.ty.kind() {
-            _ if self.llextra.is_none() => {
-                debug!(
-                    "unsized field `{}`, of `{:?}` has no metadata for adjustment",
-                    ix, self.llval
-                );
-                return simple();
-            }
             _ if field.is_sized() => return simple(),
-            ty::Slice(..) | ty::Str | ty::Foreign(..) => return simple(),
+            ty::Slice(..) | ty::Str => return simple(),
+            _ if offset.bytes() == 0 => return simple(),
             _ => {}
         }
 
         // We need to get the pointer manually now.
         // We do this by casting to a `*i8`, then offsetting it by the appropriate amount.
         // We do this instead of, say, simply adjusting the pointer from the result of a GEP
-        // because the field may have an arbitrary alignment in the LLVM representation
-        // anyway.
+        // because the field may have an arbitrary alignment in the LLVM representation.
         //
         // To demonstrate:
         //
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 4d9e296d544..0f3b6b25c61 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -174,12 +174,15 @@ where
                     };
                     (base_meta, offset.align_to(align))
                 }
-                None => {
-                    // For unsized types with an extern type tail we perform no adjustments.
-                    // NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
-                    assert!(matches!(base_meta, MemPlaceMeta::None));
+                None if offset == Size::ZERO => {
+                    // If the offset is 0, then rounding it up to alignment wouldn't change anything,
+                    // so we can do this even for types where we cannot determine the alignment.
                     (base_meta, offset)
                 }
+                None => {
+                    // We don't know the alignment of this field, so we cannot adjust.
+                    throw_unsup_format!("`extern type` does not have a known offset")
+                }
             }
         } else {
             // base_meta could be present; we might be accessing a sized field of an unsized
diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs
new file mode 100644
index 00000000000..7384e71db3a
--- /dev/null
+++ b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.rs
@@ -0,0 +1,32 @@
+// Test that we can handle unsized types with an extern type tail part.
+// Regression test for issue #91827.
+
+#![feature(extern_types)]
+
+use std::ptr::addr_of;
+
+extern "C" {
+    type Opaque;
+}
+
+struct Newtype(Opaque);
+
+struct S {
+    i: i32,
+    a: Opaque,
+}
+
+const NEWTYPE: () = unsafe {
+    // Projecting to the newtype works, because it is always at offset 0.
+    let x: &Newtype = unsafe { &*(1usize as *const Newtype) };
+    let field = &x.0;
+};
+
+const OFFSET: () = unsafe {
+    // This needs to compute the field offset, but we don't know the type's alignment, so this fail.
+    let x: &S = unsafe { &*(1usize as *const S) };
+    let field = &x.a; //~ERROR: evaluation of constant value failed
+    //~| does not have a known offset
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr
new file mode 100644
index 00000000000..645ad8121bc
--- /dev/null
+++ b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-91827-extern-types-field-offset.rs:28:17
+   |
+LL |     let field = &x.a;
+   |                 ^^^^ `extern type` does not have a known offset
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types.rs b/tests/ui/consts/const-eval/issue-91827-extern-types.rs
deleted file mode 100644
index c9aaa6e5587..00000000000
--- a/tests/ui/consts/const-eval/issue-91827-extern-types.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-// run-pass
-//
-// Test that we can handle unsized types with an extern type tail part.
-// Regression test for issue #91827.
-
-#![feature(extern_types)]
-
-use std::ptr::addr_of;
-
-extern "C" {
-    type Opaque;
-}
-
-unsafe impl Sync for Opaque {}
-
-#[repr(C)]
-pub struct List<T> {
-    len: usize,
-    data: [T; 0],
-    tail: Opaque,
-}
-
-#[repr(C)]
-pub struct ListImpl<T, const N: usize> {
-    len: usize,
-    data: [T; N],
-}
-
-impl<T> List<T> {
-    const fn as_slice(&self) -> &[T] {
-        unsafe {
-            let ptr = addr_of!(self.tail) as *const T;
-            std::slice::from_raw_parts(ptr, self.len)
-        }
-    }
-}
-
-impl<T, const N: usize> ListImpl<T, N> {
-    const fn as_list(&self) -> &List<T> {
-        unsafe { std::mem::transmute(self) }
-    }
-}
-
-pub static A: ListImpl<u128, 3> = ListImpl {
-    len: 3,
-    data: [5, 6, 7],
-};
-pub static A_REF: &'static List<u128> = A.as_list();
-pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list());
-
-const fn tail_offset<T>(list: &List<T>) -> isize {
-    unsafe { (addr_of!(list.tail) as *const u8).offset_from(list as *const List<T> as *const u8) }
-}
-
-fn main() {
-    assert_eq!(A_REF.as_slice(), &[5, 6, 7]);
-    // Check that interpreter and code generation agree about the position of the tail field.
-    assert_eq!(A_TAIL_OFFSET, tail_offset(A_REF));
-}
diff --git a/tests/ui/extern/extern-types-field-offset.rs b/tests/ui/extern/extern-types-field-offset.rs
new file mode 100644
index 00000000000..f2682293dcf
--- /dev/null
+++ b/tests/ui/extern/extern-types-field-offset.rs
@@ -0,0 +1,26 @@
+// run-fail
+// check-run-results
+// normalize-stderr-test "panicking\.rs:\d+:\d+:" -> "panicking.rs:"
+#![feature(extern_types)]
+
+extern "C" {
+    type Opaque;
+}
+
+struct Newtype(Opaque);
+
+struct S {
+    i: i32,
+    a: Opaque,
+}
+
+fn main() {
+    // Projecting to the newtype works, because it is always at offset 0.
+    let x: &Newtype = unsafe { &*(1usize as *const Newtype) };
+    let field = &x.0;
+
+    // This needs to compute the field offset, but we don't know the type's alignment,
+    // so this panics.
+    let x: &S = unsafe { &*(1usize as *const S) };
+    let field = &x.a;
+}
diff --git a/tests/ui/extern/extern-types-field-offset.run.stderr b/tests/ui/extern/extern-types-field-offset.run.stderr
new file mode 100644
index 00000000000..d6ebf3e391d
--- /dev/null
+++ b/tests/ui/extern/extern-types-field-offset.run.stderr
@@ -0,0 +1,4 @@
+thread 'main' panicked at library/core/src/panicking.rs:
+attempted to compute the size or alignment of extern type `Opaque`
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+thread caused non-unwinding panic. aborting.