Skip to content

Commit aa05a15

Browse files
authored
Auto merge of #36027 - eddyb:unsized-prefix, r=nagisa
rustc_trans: don't round up the DST prefix size to its alignment. Fixes #35815 by using `ty::layout` and `min_size` to compute the size of the DST prefix. `ty::layout::Struct::min_size` is not rounded up to alignment, which could be smaller for the DST field.
2 parents e17d6db + 3e313d9 commit aa05a15

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
@@ -949,6 +949,14 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
949949
TypeOfDepthLock(self.local())
950950
}
951951

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

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
use rustc::ty::subst::Substs;
2120

@@ -125,37 +124,31 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
125124
cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
126125

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

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)