Skip to content

Commit

Permalink
rustc_trans: don't round up the DST prefix size to its alignment.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Aug 27, 2016
1 parent 1987131 commit 3e313d9
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 48 deletions.
13 changes: 1 addition & 12 deletions src/librustc_trans/common.rs
Expand Up @@ -124,18 +124,7 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
/// Returns true if the type is represented as a pair of immediates.
pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
-> bool {
let tcx = ccx.tcx();
let layout = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
match ty.layout(&infcx) {
Ok(layout) => layout,
Err(err) => {
bug!("type_is_imm_pair: layout for `{:?}` failed: {}",
ty, err);
}
}
});

match *layout {
match *ccx.layout_of(ty) {
Layout::FatPointer { .. } => true,
Layout::Univariant { ref variant, .. } => {
// There must be only 2 fields.
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_trans/context.rs
Expand Up @@ -947,6 +947,14 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
TypeOfDepthLock(self.local())
}

pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
self.tcx().normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| {
ty.layout(&infcx).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", ty, e);
})
})
}

pub fn check_overflow(&self) -> bool {
self.shared.check_overflow
}
Expand Down
21 changes: 15 additions & 6 deletions src/librustc_trans/glue.rs
Expand Up @@ -338,13 +338,22 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
ty::TyStruct(def, substs) => {
let ccx = bcx.ccx();
// First get the size of all statically known fields.
// Don't use type_of::sizing_type_of because that expects t to be sized.
// Don't use type_of::sizing_type_of because that expects t to be sized,
// and it also rounds up to alignment, which we want to avoid,
// as the unsized field's alignment could be smaller.
assert!(!t.is_simd());
let repr = adt::represent_type(ccx, t);
let sizing_type = adt::sizing_type_of(ccx, &repr, true);
debug!("DST {} sizing_type: {:?}", t, sizing_type);
let sized_size = llsize_of_alloc(ccx, sizing_type);
let sized_align = llalign_of_min(ccx, sizing_type);
let layout = ccx.layout_of(t);
debug!("DST {} layout: {:?}", t, layout);

let (sized_size, sized_align) = match *layout {
ty::layout::Layout::Univariant { ref variant, .. } => {
(variant.min_size().bytes(), variant.align.abi())
}
_ => {
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
t, layout);
}
};
debug!("DST {} statically sized prefix size: {} align: {}",
t, sized_size, sized_align);
let sized_size = C_uint(ccx, sized_size);
Expand Down
53 changes: 23 additions & 30 deletions src/librustc_trans/type_of.rs
Expand Up @@ -15,7 +15,6 @@ use abi::FnType;
use adt;
use common::*;
use machine;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TypeFoldable};

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

// FIXME(eddyb) Temporary sanity check for ty::layout.
let layout = cx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
t.layout(&infcx)
});
match layout {
Ok(layout) => {
if !type_is_sized(cx.tcx(), t) {
if !layout.is_unsized() {
bug!("layout should be unsized for type `{}` / {:#?}",
t, layout);
}

// Unsized types get turned into a fat pointer for LLVM.
return llsizingty;
}
let r = layout.size(&cx.tcx().data_layout).bytes();
let l = machine::llsize_of_alloc(cx, llsizingty);
if r != l {
bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
r, l, t, layout);
}
let r = layout.align(&cx.tcx().data_layout).abi();
let l = machine::llalign_of_min(cx, llsizingty) as u64;
if r != l {
bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
r, l, t, layout);
}
}
Err(e) => {
bug!("failed to get layout for `{}`: {}", t, e);
let layout = cx.layout_of(t);
if !type_is_sized(cx.tcx(), t) {
if !layout.is_unsized() {
bug!("layout should be unsized for type `{}` / {:#?}",
t, layout);
}

// Unsized types get turned into a fat pointer for LLVM.
return llsizingty;
}

let r = layout.size(&cx.tcx().data_layout).bytes();
let l = machine::llsize_of_alloc(cx, llsizingty);
if r != l {
bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
r, l, t, layout);
}

let r = layout.align(&cx.tcx().data_layout).abi();
let l = machine::llalign_of_min(cx, llsizingty) as u64;
if r != l {
bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
r, l, t, layout);
}

llsizingty
}

Expand Down
23 changes: 23 additions & 0 deletions src/test/run-pass/issue-35815.rs
@@ -0,0 +1,23 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem;

struct Foo<T: ?Sized> {
a: i64,
b: bool,
c: T,
}

fn main() {
let foo: &Foo<i32> = &Foo { a: 1, b: false, c: 2i32 };
let foo_unsized: &Foo<Send> = foo;
assert_eq!(mem::size_of_val(foo), mem::size_of_val(foo_unsized));
}

0 comments on commit 3e313d9

Please sign in to comment.