about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-11-18 22:19:53 +0000
committerbors <bors@rust-lang.org>2018-11-18 22:19:53 +0000
commita9b791b3c0543120ed03e70600e6cf4f451b4124 (patch)
treeb55a44dde3f1298849e77c43d1f45edccde7ecf6
parent13c9439925797cd7a65c917d047c07a500d9bfe6 (diff)
parentba0bab39e04a13ad996e41a2ef2ca9b83fbb2cf4 (diff)
downloadrust-a9b791b3c0543120ed03e70600e6cf4f451b4124.tar.gz
rust-a9b791b3c0543120ed03e70600e6cf4f451b4124.zip
Auto merge of #55672 - RalfJung:miri-extern-types, r=eddyb
miri: accept extern types in structs if they are the only field

Fixes https://github.com/rust-lang/rust/issues/55541

Cc @oli-obk @eddyb https://github.com/rust-lang/rust/issues/43467
-rw-r--r--src/librustc_mir/interpret/eval_context.rs17
-rw-r--r--src/librustc_mir/interpret/place.rs13
-rw-r--r--src/test/ui/consts/const-eval/issue-55541.rs27
3 files changed, 53 insertions, 4 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index e6267012dc2..ca09857bbd5 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -341,8 +341,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/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() {}