about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2017-08-03 11:39:30 -0700
committerGitHub <noreply@github.com>2017-08-03 11:39:30 -0700
commit5aed31812eb8e46fbf1ef8fc13b068ac6bcbb3f9 (patch)
tree1d0fc69af693d05c245379c9ddb2d3ea73945a56
parent8deb9387e96256f29f6b335e8d38c467ccc26961 (diff)
parent5d27b94b04b87f6ca65c770e8e788c17f7af7a13 (diff)
downloadrust-5aed31812eb8e46fbf1ef8fc13b068ac6bcbb3f9.tar.gz
rust-5aed31812eb8e46fbf1ef8fc13b068ac6bcbb3f9.zip
Merge pull request #281 from RalfJung/unsized
fix size_of_val on unsized tuples
-rw-r--r--src/librustc_mir/interpret/eval_context.rs21
-rw-r--r--tests/run-pass-fullmir/unsized-tuple-impls.rs2
2 files changed, 19 insertions, 4 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 86e5d855f44..16015c4bf3a 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -277,6 +277,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         self.tcx.erase_regions(&value)
     }
 
+    /// Return the size and aligment of the value at the given type.
+    /// Note that the value does not matter if the type is sized. For unsized types,
+    /// the value has to be a fat pointer, and we only care about the "extra" data in it.
     pub fn size_and_align_of_dst(
         &mut self,
         ty: ty::Ty<'tcx>,
@@ -286,7 +289,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             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 +312,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);
 }