Skip to content

Commit 3e313d9

Browse files
committed
rustc_trans: don't round up the DST prefix size to its alignment.
1 parent 1987131 commit 3e313d9

File tree

5 files changed

+70
-48
lines changed

5 files changed

+70
-48
lines changed

src/librustc_trans/common.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,7 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
124124
/// Returns true if the type is represented as a pair of immediates.
125125
pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
126126
-> bool {
127-
let tcx = ccx.tcx();
128-
let layout = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
129-
match ty.layout(&infcx) {
130-
Ok(layout) => layout,
131-
Err(err) => {
132-
bug!("type_is_imm_pair: layout for `{:?}` failed: {}",
133-
ty, err);
134-
}
135-
}
136-
});
137-
138-
match *layout {
127+
match *ccx.layout_of(ty) {
139128
Layout::FatPointer { .. } => true,
140129
Layout::Univariant { ref variant, .. } => {
141130
// There must be only 2 fields.

src/librustc_trans/context.rs

+8
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,14 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
947947
TypeOfDepthLock(self.local())
948948
}
949949

950+
pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
951+
self.tcx().normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| {
952+
ty.layout(&infcx).unwrap_or_else(|e| {
953+
bug!("failed to get layout for `{}`: {}", ty, e);
954+
})
955+
})
956+
}
957+
950958
pub fn check_overflow(&self) -> bool {
951959
self.shared.check_overflow
952960
}

src/librustc_trans/glue.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -338,13 +338,22 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
338338
ty::TyStruct(def, substs) => {
339339
let ccx = bcx.ccx();
340340
// First get the size of all statically known fields.
341-
// Don't use type_of::sizing_type_of because that expects t to be sized.
341+
// Don't use type_of::sizing_type_of because that expects t to be sized,
342+
// and it also rounds up to alignment, which we want to avoid,
343+
// as the unsized field's alignment could be smaller.
342344
assert!(!t.is_simd());
343-
let repr = adt::represent_type(ccx, t);
344-
let sizing_type = adt::sizing_type_of(ccx, &repr, true);
345-
debug!("DST {} sizing_type: {:?}", t, sizing_type);
346-
let sized_size = llsize_of_alloc(ccx, sizing_type);
347-
let sized_align = llalign_of_min(ccx, sizing_type);
345+
let layout = ccx.layout_of(t);
346+
debug!("DST {} layout: {:?}", t, layout);
347+
348+
let (sized_size, sized_align) = match *layout {
349+
ty::layout::Layout::Univariant { ref variant, .. } => {
350+
(variant.min_size().bytes(), variant.align.abi())
351+
}
352+
_ => {
353+
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
354+
t, layout);
355+
}
356+
};
348357
debug!("DST {} statically sized prefix size: {} align: {}",
349358
t, sized_size, sized_align);
350359
let sized_size = C_uint(ccx, sized_size);

src/librustc_trans/type_of.rs

+23-30
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use abi::FnType;
1515
use adt;
1616
use common::*;
1717
use machine;
18-
use rustc::traits::Reveal;
1918
use rustc::ty::{self, Ty, TypeFoldable};
2019

2120
use type_::Type;
@@ -124,37 +123,31 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
124123
cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
125124

126125
// FIXME(eddyb) Temporary sanity check for ty::layout.
127-
let layout = cx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
128-
t.layout(&infcx)
129-
});
130-
match layout {
131-
Ok(layout) => {
132-
if !type_is_sized(cx.tcx(), t) {
133-
if !layout.is_unsized() {
134-
bug!("layout should be unsized for type `{}` / {:#?}",
135-
t, layout);
136-
}
137-
138-
// Unsized types get turned into a fat pointer for LLVM.
139-
return llsizingty;
140-
}
141-
let r = layout.size(&cx.tcx().data_layout).bytes();
142-
let l = machine::llsize_of_alloc(cx, llsizingty);
143-
if r != l {
144-
bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
145-
r, l, t, layout);
146-
}
147-
let r = layout.align(&cx.tcx().data_layout).abi();
148-
let l = machine::llalign_of_min(cx, llsizingty) as u64;
149-
if r != l {
150-
bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
151-
r, l, t, layout);
152-
}
153-
}
154-
Err(e) => {
155-
bug!("failed to get layout for `{}`: {}", t, e);
126+
let layout = cx.layout_of(t);
127+
if !type_is_sized(cx.tcx(), t) {
128+
if !layout.is_unsized() {
129+
bug!("layout should be unsized for type `{}` / {:#?}",
130+
t, layout);
156131
}
132+
133+
// Unsized types get turned into a fat pointer for LLVM.
134+
return llsizingty;
135+
}
136+
137+
let r = layout.size(&cx.tcx().data_layout).bytes();
138+
let l = machine::llsize_of_alloc(cx, llsizingty);
139+
if r != l {
140+
bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
141+
r, l, t, layout);
157142
}
143+
144+
let r = layout.align(&cx.tcx().data_layout).abi();
145+
let l = machine::llalign_of_min(cx, llsizingty) as u64;
146+
if r != l {
147+
bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
148+
r, l, t, layout);
149+
}
150+
158151
llsizingty
159152
}
160153

src/test/run-pass/issue-35815.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2016 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+
struct Foo<T: ?Sized> {
14+
a: i64,
15+
b: bool,
16+
c: T,
17+
}
18+
19+
fn main() {
20+
let foo: &Foo<i32> = &Foo { a: 1, b: false, c: 2i32 };
21+
let foo_unsized: &Foo<Send> = foo;
22+
assert_eq!(mem::size_of_val(foo), mem::size_of_val(foo_unsized));
23+
}

0 commit comments

Comments
 (0)