From 3e313d9528adc64042012a19cc9a700bff11f19d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 27 Aug 2016 08:51:55 +0300 Subject: [PATCH] rustc_trans: don't round up the DST prefix size to its alignment. --- src/librustc_trans/common.rs | 13 +------- src/librustc_trans/context.rs | 8 +++++ src/librustc_trans/glue.rs | 21 +++++++++---- src/librustc_trans/type_of.rs | 53 ++++++++++++++------------------ src/test/run-pass/issue-35815.rs | 23 ++++++++++++++ 5 files changed, 70 insertions(+), 48 deletions(-) create mode 100644 src/test/run-pass/issue-35815.rs diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index c5053e4feee62..94e8aed7cb73b 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -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. diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 0a295b251b31e..77be9964f68b9 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -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 } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 6a072c84dd9b3..823c23b2e66b3 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -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); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 6862002ed83b2..153df13e048db 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -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; @@ -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 } diff --git a/src/test/run-pass/issue-35815.rs b/src/test/run-pass/issue-35815.rs new file mode 100644 index 0000000000000..619542926500b --- /dev/null +++ b/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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +struct Foo { + a: i64, + b: bool, + c: T, +} + +fn main() { + let foo: &Foo = &Foo { a: 1, b: false, c: 2i32 }; + let foo_unsized: &Foo = foo; + assert_eq!(mem::size_of_val(foo), mem::size_of_val(foo_unsized)); +}