about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-03-20 12:49:46 -0700
committerbors <bors@rust-lang.org>2016-03-20 12:49:46 -0700
commit2af3dd73dbc71e0f345746e123df4ac71d3f392c (patch)
tree6fd6e286356b6cfcd3dece5681b80a04467a46bf
parent978bc070a66f7f4f82dc0f2c4a4e4e35478851b6 (diff)
parentb5be09564188b39aa2fbc73b057c1e35e99ee99f (diff)
downloadrust-2af3dd73dbc71e0f345746e123df4ac71d3f392c.tar.gz
rust-2af3dd73dbc71e0f345746e123df4ac71d3f392c.zip
Auto merge of #32010 - devonhollowood:non-c-like-enum-repr, r=Aatch
Add tests for #26114

First step in fixing #26114
-rw-r--r--src/librustc_trans/trans/adt.rs19
-rw-r--r--src/test/run-pass/enum-discrim-manual-sizing.rs33
2 files changed, 46 insertions, 6 deletions
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index 45a1236647e..db0fa2a64bd 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -396,6 +396,15 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     }
                 }
             }
+
+            // If the alignment is smaller than the chosen discriminant size, don't use the
+            // alignment as the final size.
+            let min_ty = ll_inttype(&cx, min_ity);
+            let min_size = machine::llsize_of_real(cx, min_ty);
+            if (align as u64) < min_size {
+                use_align = false;
+            }
+
             let ity = if use_align {
                 // Use the overall alignment
                 match align {
@@ -813,11 +822,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             // FIXME #10604: this breaks when vector types are present.
             let (size, align) = union_size_and_align(&sts[..]);
             let align_s = align as u64;
-            assert_eq!(size % align_s, 0);
-            let align_units = size / align_s - 1;
-
             let discr_ty = ll_inttype(cx, ity);
             let discr_size = machine::llsize_of_alloc(cx, discr_ty);
+            let padded_discr_size = roundup(discr_size, align);
+            assert_eq!(size % align_s, 0); // Ensure division in align_units comes out evenly
+            let align_units = (size - padded_discr_size) / align_s;
             let fill_ty = match align_s {
                 1 => Type::array(&Type::i8(cx), align_units),
                 2 => Type::array(&Type::i16(cx), align_units),
@@ -829,10 +838,10 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 _ => panic!("unsupported enum alignment: {}", align)
             };
             assert_eq!(machine::llalign_of_min(cx, fill_ty), align);
-            assert_eq!(align_s % discr_size, 0);
+            assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly
             let mut fields: Vec<Type> =
                 [discr_ty,
-                 Type::array(&discr_ty, align_s / discr_size - 1),
+                 Type::array(&discr_ty, (padded_discr_size - discr_size)/discr_size),
                  fill_ty].iter().cloned().collect();
             if delay_drop_flag && dtor_needed {
                 fields.pop();
diff --git a/src/test/run-pass/enum-discrim-manual-sizing.rs b/src/test/run-pass/enum-discrim-manual-sizing.rs
index edad5cc1652..3bbc107e0b9 100644
--- a/src/test/run-pass/enum-discrim-manual-sizing.rs
+++ b/src/test/run-pass/enum-discrim-manual-sizing.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 
-use std::mem::size_of;
+use std::mem::{size_of, align_of};
 
 #[repr(i8)]
 enum Ei8 {
@@ -71,6 +71,24 @@ enum Euint {
     Buint = 1
 }
 
+#[repr(u8)]
+enum Eu8NonCLike<T> {
+    _None,
+    _Some(T),
+}
+
+#[repr(i64)]
+enum Ei64NonCLike<T> {
+    _None,
+    _Some(T),
+}
+
+#[repr(u64)]
+enum Eu64NonCLike<T> {
+    _None,
+    _Some(T),
+}
+
 pub fn main() {
     assert_eq!(size_of::<Ei8>(), 1);
     assert_eq!(size_of::<Eu8>(), 1);
@@ -82,4 +100,17 @@ pub fn main() {
     assert_eq!(size_of::<Eu64>(), 8);
     assert_eq!(size_of::<Eint>(), size_of::<isize>());
     assert_eq!(size_of::<Euint>(), size_of::<usize>());
+    assert_eq!(size_of::<Eu8NonCLike<()>>(), 1);
+    assert_eq!(size_of::<Ei64NonCLike<()>>(), 8);
+    assert_eq!(size_of::<Eu64NonCLike<()>>(), 8);
+    let u8_expected_size = round_up(9, align_of::<Eu64NonCLike<u8>>());
+    assert_eq!(size_of::<Eu64NonCLike<u8>>(), u8_expected_size);
+    let array_expected_size = round_up(28, align_of::<Eu64NonCLike<[u32; 5]>>());
+    assert_eq!(size_of::<Eu64NonCLike<[u32; 5]>>(), array_expected_size);
+    assert_eq!(size_of::<Eu64NonCLike<[u32; 6]>>(), 32);
+}
+
+// Rounds x up to the next multiple of a
+fn round_up(x: usize, a: usize) -> usize {
+    ((x + (a - 1)) / a) * a
 }