about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2017-08-02 15:29:13 -0700
committerRalf Jung <post@ralfj.de>2017-08-02 15:29:13 -0700
commitc533cf84969e7c04cc2616525e64bae2092884bd (patch)
treed8296a89052c9ae18ef1466e241dc2ce42c02dea
parent8deb9387e96256f29f6b335e8d38c467ccc26961 (diff)
downloadrust-c533cf84969e7c04cc2616525e64bae2092884bd.tar.gz
rust-c533cf84969e7c04cc2616525e64bae2092884bd.zip
fix size_of_val on unsized tuples
-rw-r--r--src/librustc_mir/interpret/eval_context.rs20
-rw-r--r--tests/run-pass-fullmir/unsized-tuple-impls.rs2
2 files changed, 17 insertions, 5 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 86e5d855f44..30a305a7b60 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -280,13 +280,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     pub fn size_and_align_of_dst(
         &mut self,
         ty: ty::Ty<'tcx>,
-        value: Value,
+        value: Value, // This has to be a fat ptr; we only care about the "extra" data in it.
     ) -> EvalResult<'tcx, (u64, u64)> {
         if let Some(size) = self.type_size(ty)? {
             Ok((size as u64, self.type_align(ty)? as u64))
         } else {
             match ty.sty {
-                ty::TyAdt(def, substs) => {
+                ty::TyAdt(..) | ty::TyTuple(..) => {
                     // First get the size of all statically known fields.
                     // 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,
@@ -309,9 +309,19 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
                     // Recurse to get the size of the dynamically sized field (must be
                     // the last field).
-                    let last_field = def.struct_variant().fields.last().unwrap();
-                    let field_ty = self.field_ty(substs, last_field);
-                    let (unsized_size, unsized_align) = self.size_and_align_of_dst(field_ty, value)?;
+                    let (unsized_size, unsized_align) = match ty.sty {
+                        ty::TyAdt(def, substs) => {
+                            let last_field = def.struct_variant().fields.last().unwrap();
+                            let field_ty = self.field_ty(substs, last_field);
+                            self.size_and_align_of_dst(field_ty, value)?
+                        }
+                        ty::TyTuple(ref types, _) => {
+                            let field_ty = types.last().unwrap();
+                            let field_ty = self.tcx.normalize_associated_type(field_ty);
+                            self.size_and_align_of_dst(field_ty, value)?
+                        }
+                        _ => bug!("We already checked that we know this type"),
+                    };
 
                     // FIXME (#26403, #27023): We should be adding padding
                     // to `sized_size` (to accommodate the `unsized_align`
diff --git a/tests/run-pass-fullmir/unsized-tuple-impls.rs b/tests/run-pass-fullmir/unsized-tuple-impls.rs
index d332f7be833..ccb6883e873 100644
--- a/tests/run-pass-fullmir/unsized-tuple-impls.rs
+++ b/tests/run-pass-fullmir/unsized-tuple-impls.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(unsized_tuple_coercion)]
+use std::mem;
 
 fn main() {
     let x : &(i32, i32, [i32]) = &(0, 1, [2, 3]);
@@ -18,4 +19,5 @@ fn main() {
     assert_eq!(a, [x, y]);
 
     assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]");
+    assert_eq!(mem::size_of_val(x), 16);
 }