about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2018-08-15 20:22:28 +0200
committerRalf Jung <post@ralfj.de>2018-08-22 09:06:28 +0200
commit0807ad19ef0b7e1d56b040f79a3192c4229c2224 (patch)
treefd296db6deabbf48ffd90b056549ee9e4b57b759
parent689c71193ac2bac0366c917f38f3a553f12ff895 (diff)
downloadrust-0807ad19ef0b7e1d56b040f79a3192c4229c2224.tar.gz
rust-0807ad19ef0b7e1d56b040f79a3192c4229c2224.zip
fix union field access and DST computations and dumping of places
-rw-r--r--src/librustc_mir/interpret/eval_context.rs33
-rw-r--r--src/librustc_mir/interpret/place.rs27
2 files changed, 33 insertions, 27 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 3a1f0db227f..06e015cc4e6 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -465,36 +465,38 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
     /// Return the size and alignment 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(
+    pub fn size_and_align_of_val(
         &self,
         val: ValTy<'tcx>,
     ) -> EvalResult<'tcx, (Size, Align)> {
-        if !val.layout.is_unsized() {
-            Ok(val.layout.size_and_align())
+        let pointee_ty = val.layout.ty.builtin_deref(true).unwrap().ty;
+        let layout = self.layout_of(pointee_ty)?;
+        if !layout.is_unsized() {
+            Ok(layout.size_and_align())
         } else {
-            match val.layout.ty.sty {
+            match layout.ty.sty {
                 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,
                     // as the unsized field's alignment could be smaller.
-                    assert!(!val.layout.ty.is_simd());
-                    debug!("DST layout: {:?}", val.layout);
+                    assert!(!layout.ty.is_simd());
+                    debug!("DST layout: {:?}", layout);
 
-                    let sized_size = val.layout.fields.offset(val.layout.fields.count() - 1);
-                    let sized_align = val.layout.align;
+                    let sized_size = layout.fields.offset(layout.fields.count() - 1);
+                    let sized_align = layout.align;
                     debug!(
                         "DST {} statically sized prefix size: {:?} align: {:?}",
-                        val.layout.ty,
+                        layout.ty,
                         sized_size,
                         sized_align
                     );
 
                     // Recurse to get the size of the dynamically sized field (must be
                     // the last field).
-                    let field_layout = val.layout.field(self, val.layout.fields.count() - 1)?;
+                    let field_layout = layout.field(self, layout.fields.count() - 1)?;
                     let (unsized_size, unsized_align) =
-                        self.size_and_align_of_dst(ValTy {
+                        self.size_and_align_of_val(ValTy {
                             value: val.value,
                             layout: field_layout
                         })?;
@@ -533,12 +535,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 }
 
                 ty::TySlice(_) | ty::TyStr => {
-                    let (elem_size, align) = val.layout.field(self, 0)?.size_and_align();
+                    let (elem_size, align) = layout.field(self, 0)?.size_and_align();
                     let (_, len) = val.to_scalar_slice(self)?;
                     Ok((elem_size * len, align))
                 }
 
-                _ => bug!("size_of_val::<{:?}>", val.layout.ty),
+                _ => bug!("size_of_val::<{:?}>", layout.ty),
             }
         }
     }
@@ -963,10 +965,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 self.memory.dump_allocs(allocs);
             }
             Place::Ptr(mplace) => {
-                let (ptr, align) = mplace.to_scalar_ptr_align();
-                match ptr {
+                match mplace.ptr {
                     Scalar::Ptr(ptr) => {
-                        trace!("by align({}) ref:", align.abi());
+                        trace!("by align({}) ref:", mplace.align.abi());
                         self.memory.dump_alloc(ptr.alloc_id);
                     }
                     ptr => trace!(" integral by ref: {:?}", ptr),
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index c3ae78dbecf..a9b85f318dc 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -7,7 +7,7 @@ use std::convert::TryFrom;
 
 use rustc::mir;
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, HasDataLayout};
+use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
 use rustc_data_structures::indexed_vec::Idx;
 
 use rustc::mir::interpret::{
@@ -275,22 +275,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 assert!(field < len, "Tried to access element {} of array/slice with length {}", field, len);
                 stride * field
             }
-            _ => bug!("Unexpected layout for field access: {:#?}", base.layout),
+            layout::FieldPlacement::Union(count) => {
+                assert!(field < count as u64, "Tried to access field {} of union with {} fields", field, count);
+                // Offset is always 0
+                Size::from_bytes(0)
+            }
         };
         // the only way conversion can fail if is this is an array (otherwise we already panicked
         // above). In that case, all fields are equal.
         let field = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
 
         // Adjust offset
-        let offset = match base.extra {
-            PlaceExtra::Vtable(tab) => {
-                let (_, align) = self.size_and_align_of_dst(ValTy {
-                    layout: base.layout,
-                    value: Value::new_dyn_trait(base.ptr, tab),
-                })?;
-                offset.abi_align(align)
-            }
-            _ => offset,
+        let offset = if field.is_unsized() {
+            let vtable = match base.extra {
+                PlaceExtra::Vtable(tab) => tab,
+                _ => bug!("Unsized place with unsized field must come with vtable"),
+            };
+            let (_, align) = self.read_size_and_align_from_vtable(vtable)?;
+            offset.abi_align(align)
+        } else {
+            // No adjustment needed
+            offset
         };
 
         let ptr = base.ptr.ptr_offset(offset, self)?;