]> git.lizzy.rs Git - rust.git/commitdiff
miri: accept extern types in structs if they are the only field
authorRalf Jung <post@ralfj.de>
Sun, 4 Nov 2018 10:23:34 +0000 (11:23 +0100)
committerRalf Jung <post@ralfj.de>
Sun, 4 Nov 2018 10:23:34 +0000 (11:23 +0100)
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/place.rs
src/test/ui/consts/const-eval/issue-55541.rs [new file with mode: 0644]

index bc7ad16dc97bc7b59caee2cd1b65736c9652f362..48a8d0bbe56d645b67d4de12786716f8dbdcf43a 100644 (file)
@@ -371,8 +371,19 @@ pub(super) fn size_and_align_of(
                 // 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`
index 3b104e2284fe2d51459f1c168209359ffc6f76c0..8bd29aff841cfa1843a4651da289e2e8923b2f56 100644 (file)
@@ -354,7 +354,8 @@ pub fn mplace_field(
         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 (file)
index 0000000..bf8965e
--- /dev/null
@@ -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() {}