about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-08-27 08:51:55 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-08-27 08:51:55 +0300
commit3e313d9528adc64042012a19cc9a700bff11f19d (patch)
tree3b317966d2d4d91a9390dab238851f7018c19e91
parent1987131063f08afc54d57cdba56c2acddcff191d (diff)
downloadrust-3e313d9528adc64042012a19cc9a700bff11f19d.tar.gz
rust-3e313d9528adc64042012a19cc9a700bff11f19d.zip
rustc_trans: don't round up the DST prefix size to its alignment.
-rw-r--r--src/librustc_trans/common.rs13
-rw-r--r--src/librustc_trans/context.rs8
-rw-r--r--src/librustc_trans/glue.rs21
-rw-r--r--src/librustc_trans/type_of.rs53
-rw-r--r--src/test/run-pass/issue-35815.rs23
5 files changed, 70 insertions, 48 deletions
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index c5053e4feee..94e8aed7cb7 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 0a295b251b3..77be9964f68 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 6a072c84dd9..823c23b2e66 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 6862002ed83..153df13e048 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 00000000000..61954292650
--- /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 <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));
+}