about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlexis Beingessner <a.beingessner@gmail.com>2017-11-20 12:26:13 -0500
committerAlexis Beingessner <a.beingessner@gmail.com>2017-11-20 15:18:48 -0500
commit8293fe9fdf2d3398176297b82a72cd32d13538d8 (patch)
tree26bf0d323a22ccde1d11f3cf562e1b6742268dcc
parentf50fd075c2555d8511ccee8a7fe7aee3f2c45e14 (diff)
downloadrust-8293fe9fdf2d3398176297b82a72cd32d13538d8.tar.gz
rust-8293fe9fdf2d3398176297b82a72cd32d13538d8.zip
Implement the special repr(C)-non-clike-enum layout
-rw-r--r--src/librustc/ty/layout.rs42
1 files changed, 26 insertions, 16 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 71bf333a8c6..7d262adffdb 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -942,8 +942,8 @@ impl<'a, 'tcx> LayoutDetails {
             AlwaysSized,
             /// A univariant, the last field of which may be coerced to unsized.
             MaybeUnsized,
-            /// A univariant, but part of an enum.
-            EnumVariant(Integer),
+            /// A univariant, but with a prefix of an arbitrary size & alignment (e.g. enum tag).
+            Prefixed(Size, Align),
         }
         let univariant_uninterned = |fields: &[TyLayout], repr: &ReprOptions, kind| {
             let packed = repr.packed();
@@ -962,14 +962,11 @@ impl<'a, 'tcx> LayoutDetails {
             let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
 
             // Anything with repr(C) or repr(packed) doesn't optimize.
-            let optimize = match kind {
-                StructKind::AlwaysSized |
-                StructKind::MaybeUnsized |
-                StructKind::EnumVariant(I8) => {
-                    (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty()
-                }
-                StructKind::EnumVariant(_) => false
-            };
+            let mut optimize = (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty();
+            if let StructKind::Prefixed(_, align) = kind {
+                optimize &= align.abi() == 1;
+            }
+
             if optimize {
                 let end = if let StructKind::MaybeUnsized = kind {
                     fields.len() - 1
@@ -987,7 +984,7 @@ impl<'a, 'tcx> LayoutDetails {
                             (!f.is_zst(), cmp::Reverse(f.align.abi()))
                         })
                     }
-                    StructKind::EnumVariant(_) => {
+                    StructKind::Prefixed(..) => {
                         optimizing.sort_by_key(|&x| fields[x as usize].align.abi());
                     }
                 }
@@ -1001,12 +998,11 @@ impl<'a, 'tcx> LayoutDetails {
 
             let mut offset = Size::from_bytes(0);
 
-            if let StructKind::EnumVariant(discr) = kind {
-                offset = discr.size();
+            if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
                 if !packed {
-                    let discr_align = discr.align(dl);
-                    align = align.max(discr_align);
+                    align = align.max(prefix_align);
                 }
+                offset = prefix_size.abi_align(prefix_align);
             }
 
             for &i in &inverse_memory_index {
@@ -1558,10 +1554,24 @@ impl<'a, 'tcx> LayoutDetails {
                 let mut start_align = Align::from_bytes(256, 256).unwrap();
                 assert_eq!(Integer::for_abi_align(dl, start_align), None);
 
+                // repr(C) on an enum tells us to make a (tag, union) layout,
+                // so we need to grow the prefix alignment to be at least
+                // the alignment of the union. (This value is used both for
+                // determining the alignment of the overall enum, and the
+                // determining the alignment of the payload after the tag.)
+                let mut prefix_align = min_ity.align(dl);
+                if def.repr.c() {
+                    for fields in &variants {
+                        for field in fields {
+                            prefix_align = prefix_align.max(field.align);
+                        }
+                    }
+                }
+
                 // Create the set of structs that represent each variant.
                 let mut variants = variants.into_iter().enumerate().map(|(i, field_layouts)| {
                     let mut st = univariant_uninterned(&field_layouts,
-                        &def.repr, StructKind::EnumVariant(min_ity))?;
+                        &def.repr, StructKind::Prefixed(min_ity.size(), prefix_align))?;
                     st.variants = Variants::Single { index: i };
                     // Find the first field we can't move later
                     // to make room for a larger discriminant.