about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/interpret/eval_context.rs17
-rw-r--r--src/librustc_mir/interpret/place.rs13
-rw-r--r--src/libstd/time.rs2
-rw-r--r--src/test/ui/consts/const-eval/issue-55541.rs27
4 files changed, 54 insertions, 5 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index dbda506d115..ce7269d1e78 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -340,8 +340,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
                 // the last field).  Can't have foreign types here, how would we
                 // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1)?;
-                let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)?
-                    .expect("Fields cannot be extern types");
+                let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? {
+                    Some(size_and_align) => size_and_align,
+                    None => {
+                        // A field with extern type.  If this field is at offset 0, we behave
+                        // like the underlying extern type.
+                        // FIXME: Once we have made decisions for how to handle size and alignment
+                        // of `extern type`, this should be adapted.  It is just a temporary hack
+                        // to get some code to work that probably ought to work.
+                        if sized_size == Size::ZERO {
+                            return Ok(None)
+                        } else {
+                            bug!("Fields cannot be extern types, unless they are at offset 0")
+                        }
+                    }
+                };
 
                 // FIXME (#26403, #27023): We should be adding padding
                 // to `sized_size` (to accommodate the `unsized_align`
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 201d320dcd8..fa76eeb2fed 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -351,8 +351,17 @@ where
         // Offset may need adjustment for unsized fields
         let (meta, offset) = if field_layout.is_unsized() {
             // re-use parent metadata to determine dynamic field layout
-            let (_, align) = self.size_and_align_of(base.meta, field_layout)?
-                .expect("Fields cannot be extern types");
+            let align = match self.size_and_align_of(base.meta, field_layout)? {
+                Some((_, align)) => align,
+                None if offset == Size::ZERO =>
+                    // An extern type at offset 0, we fall back to its static alignment.
+                    // FIXME: Once we have made decisions for how to handle size and alignment
+                    // of `extern type`, this should be adapted.  It is just a temporary hack
+                    // to get some code to work that probably ought to work.
+                    field_layout.align,
+                None =>
+                    bug!("Cannot compute offset for extern type field at non-0 offset"),
+            };
             (base.meta, offset.abi_align(align))
         } else {
             // base.meta could be present; we might be accessing a sized field of an unsized
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index d124cf53dda..58be1972a81 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -481,7 +481,7 @@ mod tests {
             let (a, b) = ($a, $b);
             if a != b {
                 let (a, b) = if a > b {(a, b)} else {(b, a)};
-                assert!(a - Duration::new(0, 100) <= b,
+                assert!(a - Duration::new(0, 1000) <= b,
                         "{:?} is not almost equal to {:?}", a, b);
             }
         })
diff --git a/src/test/ui/consts/const-eval/issue-55541.rs b/src/test/ui/consts/const-eval/issue-55541.rs
new file mode 100644
index 00000000000..611fb89341d
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-55541.rs
@@ -0,0 +1,27 @@
+// compile-pass
+
+// Test that we can handle newtypes wrapping extern types
+
+#![feature(extern_types, const_transmute)]
+
+use std::marker::PhantomData;
+
+extern "C" {
+  pub type ExternType;
+}
+unsafe impl Sync for ExternType {}
+static MAGIC_FFI_STATIC: u8 = 42;
+
+#[repr(transparent)]
+pub struct Wrapper(ExternType);
+pub static MAGIC_FFI_REF: &'static Wrapper = unsafe {
+  std::mem::transmute(&MAGIC_FFI_STATIC)
+};
+
+#[repr(transparent)]
+pub struct Wrapper2(PhantomData<Vec<i32>>, ExternType);
+pub static MAGIC_FFI_REF2: &'static Wrapper2 = unsafe {
+  std::mem::transmute(&MAGIC_FFI_STATIC)
+};
+
+fn main() {}