about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2018-11-04 11:23:34 +0100
committerRalf Jung <post@ralfj.de>2018-11-04 11:23:34 +0100
commite753d2105159397eff162aa3f1f7715f96b5772d (patch)
treeea9e25100dd93fc13f2065472731929298ffc038
parent6d69fe7a2fa31108ee7d23515cec7dd151d08331 (diff)
downloadrust-e753d2105159397eff162aa3f1f7715f96b5772d.tar.gz
rust-e753d2105159397eff162aa3f1f7715f96b5772d.zip
miri: accept extern types in structs if they are the only field
-rw-r--r--src/librustc_mir/interpret/eval_context.rs15
-rw-r--r--src/librustc_mir/interpret/place.rs3
-rw-r--r--src/test/ui/consts/const-eval/issue-55541.rs21
3 files changed, 36 insertions, 3 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index bc7ad16dc97..48a8d0bbe56 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -371,8 +371,19 @@ 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 is the only field,
+                        // we treat this struct just the same.  Else, this is an error
+                        // (for now).
+                        if layout.fields.count() == 1 {
+                            return Ok(None)
+                        } else {
+                            bug!("Fields cannot be extern types, unless they are the only field")
+                        }
+                    }
+                };
 
                 // 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 3b104e2284f..8bd29aff841 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -354,7 +354,8 @@ where
         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");
+                // If this is an extern type, we fall back to its static size and alignment.
+                .unwrap_or_else(|| base.layout.size_and_align());
             (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..bf8965e8361
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-55541.rs
@@ -0,0 +1,21 @@
+// compile-pass
+
+// Test that we can handle newtypes wrapping extern types
+
+#![feature(extern_types, const_transmute)]
+
+extern "C" {
+  pub type ExternType;
+}
+unsafe impl Sync for ExternType {}
+
+#[repr(transparent)]
+pub struct Wrapper(ExternType);
+
+static MAGIC_FFI_STATIC: u8 = 42;
+
+pub static MAGIC_FFI_REF: &'static Wrapper = unsafe {
+  std::mem::transmute(&MAGIC_FFI_STATIC)
+};
+
+fn main() {}