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 = [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 { + _None, + _Some(T), +} + +#[repr(i64)] +enum Ei64NonCLike { + _None, + _Some(T), +} + +#[repr(u64)] +enum Eu64NonCLike { + _None, + _Some(T), +} + pub fn main() { assert_eq!(size_of::(), 1); assert_eq!(size_of::(), 1); @@ -82,4 +100,17 @@ pub fn main() { assert_eq!(size_of::(), 8); assert_eq!(size_of::(), size_of::()); assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::>(), 1); + assert_eq!(size_of::>(), 8); + assert_eq!(size_of::>(), 8); + let u8_expected_size = round_up(9, align_of::>()); + assert_eq!(size_of::>(), u8_expected_size); + let array_expected_size = round_up(28, align_of::>()); + assert_eq!(size_of::>(), array_expected_size); + assert_eq!(size_of::>(), 32); +} + +// Rounds x up to the next multiple of a +fn round_up(x: usize, a: usize) -> usize { + ((x + (a - 1)) / a) * a }