Skip to content

Commit 48662d7

Browse files
committed
rustc_trans: correctly round up the largest variant to the enum's alignment.
1 parent f4473a4 commit 48662d7

File tree

2 files changed

+36
-12
lines changed

2 files changed

+36
-12
lines changed

src/librustc_trans/trans/adt.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
323323
mk_struct(cx, &ftys[], false, t)
324324
}).collect();
325325

326-
ensure_enum_fits_in_address_space(cx, ity, &fields[], t);
326+
ensure_enum_fits_in_address_space(cx, &fields[], t);
327327

328328
General(ity, fields, dtor)
329329
}
@@ -582,20 +582,14 @@ fn ensure_struct_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
582582

583583
fn union_size_and_align(sts: &[Struct]) -> (machine::llsize, machine::llalign) {
584584
let size = sts.iter().map(|st| st.size).max().unwrap();
585-
let most_aligned = sts.iter().max_by(|st| st.align).unwrap();
586-
(size, most_aligned.align)
585+
let align = sts.iter().map(|st| st.align).max().unwrap();
586+
(roundup(size, align), align)
587587
}
588588

589589
fn ensure_enum_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
590-
discr: IntType,
591590
fields: &[Struct],
592591
scapegoat: Ty<'tcx>) {
593-
let discr_size = machine::llsize_of_alloc(ccx, ll_inttype(ccx, discr));
594-
let (field_size, field_align) = union_size_and_align(fields);
595-
596-
// field_align < 1<<32, discr_size <= 8, field_size < OBJ_SIZE_BOUND <= 1<<61
597-
// so the sum is less than 1<<62 (and can't overflow).
598-
let total_size = roundup(discr_size, field_align) + field_size;
592+
let (total_size, _) = union_size_and_align(fields);
599593

600594
if total_size >= ccx.obj_size_bound() {
601595
ccx.report_overbig_object(scapegoat);
@@ -667,9 +661,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
667661
// FIXME #10604: this breaks when vector types are present.
668662
let (size, align) = union_size_and_align(&sts[]);
669663
let align_s = align as u64;
664+
assert_eq!(size % align_s, 0);
665+
let align_units = size / align_s - 1;
666+
670667
let discr_ty = ll_inttype(cx, ity);
671668
let discr_size = machine::llsize_of_alloc(cx, discr_ty);
672-
let align_units = (size + align_s - 1) / align_s - 1;
673669
let fill_ty = match align_s {
674670
1 => Type::array(&Type::i8(cx), align_units),
675671
2 => Type::array(&Type::i16(cx), align_units),
@@ -1049,7 +1045,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
10491045
}
10501046
General(ity, ref cases, _) => {
10511047
let case = &cases[discr as uint];
1052-
let max_sz = cases.iter().map(|x| x.size).max().unwrap();
1048+
let (max_sz, _) = union_size_and_align(&cases[]);
10531049
let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true);
10541050
let mut f = vec![lldiscr];
10551051
f.push_all(vals);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::mem;
12+
13+
#[derive(PartialEq, Show)]
14+
enum Foo {
15+
A(u32),
16+
Bar([u16; 4]),
17+
C
18+
}
19+
20+
// NOTE(eddyb) Don't make this a const, needs to be a static
21+
// so it is always instantiated as a LLVM constant value.
22+
static FOO: Foo = Foo::C;
23+
24+
fn main() {
25+
assert_eq!(FOO, Foo::C);
26+
assert_eq!(mem::size_of::<Foo>(), 12);
27+
assert_eq!(mem::min_align_of::<Foo>(), 4);
28+
}

0 commit comments

Comments
 (0)