From 4672cb7bde348a3096bf1e6125d3cff98bf52b4d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Jul 2017 23:43:13 -0700 Subject: [PATCH 1/4] make force_allocation handle packed ByValPair --- src/librustc_mir/interpret/eval_context.rs | 75 +++++++++++++------- src/librustc_mir/interpret/lvalue.rs | 2 + src/librustc_mir/interpret/memory.rs | 12 ++-- src/librustc_mir/interpret/step.rs | 10 +-- src/librustc_mir/interpret/terminator/mod.rs | 13 ++-- tests/run-pass/packed_struct.rs | 3 +- 6 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 331ae7e248b1..5913ff168fc7 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -609,7 +609,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let operand_ty = self.operand_ty(operand); assert_eq!(self.type_size(operand_ty)?, Some(0)); } - let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; + let (offset, ty, _packed) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; + // TODO: The packed flag is ignored // FIXME(solson) let dest = self.force_allocation(dest)?.to_ptr()?; @@ -702,7 +703,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { LvalueExtra::DowncastVariant(..) => bug!("attempted to take a reference to an enum downcast lvalue"), }; - self.write_value(val, dest, dest_ty)?; } @@ -826,7 +826,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32], - ) -> EvalResult<'tcx, (Size, Ty<'tcx>)> { + ) -> EvalResult<'tcx, (Size, Ty<'tcx>, bool)> { // Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant let path = discrfield.iter().skip(2).map(|&i| i as usize); @@ -849,16 +849,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { mut offset: Size, mut ty: Ty<'tcx>, path: I, - ) -> EvalResult<'tcx, (Size, Ty<'tcx>)> { + ) -> EvalResult<'tcx, (Size, Ty<'tcx>, bool)> { // Skip the initial 0 intended for LLVM GEP. + let mut packed = false; for field_index in path { let field_offset = self.get_field_offset(ty, field_index)?; trace!("field_path_offset_and_ty: {}, {}, {:?}, {:?}", field_index, ty, field_offset, offset); - ty = self.get_field_ty(ty, field_index)?; + let field_ty = self.get_field_ty(ty, field_index)?; + ty = field_ty.0; + packed = packed || field_ty.1; offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap(); } - Ok((offset, ty)) + Ok((offset, ty, packed)) } fn get_fat_field(&self, pointee_ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> { match (field_index, &self.tcx.struct_tail(pointee_ty).sty) { @@ -870,33 +873,46 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } - pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> { + /// Returns the field type and whether the field is packed + pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, (Ty<'tcx>, bool)> { match ty.sty { - ty::TyAdt(adt_def, _) if adt_def.is_box() => self.get_fat_field(ty.boxed_ty(), field_index), + ty::TyAdt(adt_def, _) if adt_def.is_box() => + Ok((self.get_fat_field(ty.boxed_ty(), field_index)?, false)), ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { use rustc::ty::layout::Layout::*; match *self.type_layout(ty)? { - RawNullablePointer { nndiscr, .. } | - StructWrappedNullablePointer { nndiscr, .. } => Ok(adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs)), + RawNullablePointer { nndiscr, .. } => + Ok((adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs), false)), + StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => { + let ty = adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs); + Ok((ty, nonnull.packed)) + }, _ => Err(EvalError::Unimplemented(format!("get_field_ty can't handle enum type: {:?}, {:?}", ty, ty.sty))), } } ty::TyAdt(adt_def, substs) => { - Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs)) + let variant_def = adt_def.struct_variant(); + use rustc::ty::layout::Layout::*; + match *self.type_layout(ty)? { + Univariant { ref variant, .. } => + Ok((variant_def.fields[field_index].ty(self.tcx, substs), variant.packed)), + _ => Err(EvalError::Unimplemented(format!("get_field_ty can't handle struct type: {:?}, {:?}", ty, ty.sty))), + } } - ty::TyTuple(fields, _) => Ok(fields[field_index]), + ty::TyTuple(fields, _) => Ok((fields[field_index], false)), ty::TyRef(_, ref tam) | - ty::TyRawPtr(ref tam) => self.get_fat_field(tam.ty, field_index), + ty::TyRawPtr(ref tam) => Ok((self.get_fat_field(tam.ty, field_index)?, false)), - ty::TyArray(ref inner, _) => Ok(inner), + ty::TyArray(ref inner, _) => Ok((inner, false)), _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))), } } fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> { + // Also see lvalue_field in lvalue.rs, which handles more cases but needs an actual value at the given type let layout = self.type_layout(ty)?; use rustc::ty::layout::Layout::*; @@ -1236,20 +1252,28 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ptr: MemoryPointer, mut ty: Ty<'tcx> ) -> EvalResult<'tcx> { + let mut packed = false; while self.get_field_count(ty)? == 1 { - ty = self.get_field_ty(ty, 0)?; + let field = self.get_field_ty(ty, 0)?; + ty = field.0; + packed = packed || field.1; } assert_eq!(self.get_field_count(ty)?, 2); - let field_0 = self.get_field_offset(ty, 0)?.bytes(); - let field_1 = self.get_field_offset(ty, 1)?.bytes(); + let field_0 = self.get_field_offset(ty, 0)?; + let field_1 = self.get_field_offset(ty, 1)?; let field_0_ty = self.get_field_ty(ty, 0)?; let field_1_ty = self.get_field_ty(ty, 1)?; - let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized"); - let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized"); - let field_0_ptr = ptr.offset(field_0, &self)?.into(); - let field_1_ptr = ptr.offset(field_1, &self)?.into(); - self.memory.write_primval(field_0_ptr, a, field_0_size)?; - self.memory.write_primval(field_1_ptr, b, field_1_size)?; + // The .1 components say whether the field is packed + assert_eq!(field_0_ty.1, field_1_ty.1, "the two fields must agree on being packed"); + packed = packed || field_0_ty.1; + let field_0_size = self.type_size(field_0_ty.0)?.expect("pair element type must be sized"); + let field_1_size = self.type_size(field_1_ty.0)?.expect("pair element type must be sized"); + let field_0_ptr = ptr.offset(field_0.bytes(), &self)?.into(); + let field_1_ptr = ptr.offset(field_1.bytes(), &self)?.into(); + self.write_maybe_aligned(!packed, + |ectx| ectx.memory.write_primval(field_0_ptr, a, field_0_size))?; + self.write_maybe_aligned(!packed, + |ectx| ectx.memory.write_primval(field_1_ptr, b, field_1_size))?; Ok(()) } @@ -1529,8 +1553,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { return self.unsize_into_ptr(src, src_ty, dest, dest_ty, src_ty.boxed_ty(), dest_ty.boxed_ty()); } if self.ty_to_primval_kind(src_ty).is_ok() { - let sty = self.get_field_ty(src_ty, 0)?; - let dty = self.get_field_ty(dest_ty, 0)?; + // TODO: We ignore the packed flag here + let sty = self.get_field_ty(src_ty, 0)?.0; + let dty = self.get_field_ty(dest_ty, 0)?.0; return self.unsize_into(src, sty, dest, dty); } // unsizing of generic struct with pointer fields diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs index e4ab3d90a5c1..da357a6d1e71 100644 --- a/src/librustc_mir/interpret/lvalue.rs +++ b/src/librustc_mir/interpret/lvalue.rs @@ -295,6 +295,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { _ => bug!("field access on non-product type: {:?}", base_layout), }; + //trace!("Field {} of {:?} is at offset {}{}", field_index, base_ty, offset.bytes(), + // if packed { " (packed)" } else { "" }); // Do not allocate in trivial cases let (base_ptr, base_extra, aligned) = match base { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 461fced3c609..591f5dc7fe80 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -1402,20 +1402,20 @@ pub(crate) trait HasMemory<'a, 'tcx> { fn read_maybe_aligned(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> where F: FnOnce(&mut Self) -> EvalResult<'tcx, T> { - assert!(self.memory_mut().reads_are_aligned, "Unaligned reads must not be nested"); - self.memory_mut().reads_are_aligned = aligned; + let old = self.memory_mut().reads_are_aligned; + self.memory_mut().reads_are_aligned = old && aligned; let t = f(self); - self.memory_mut().reads_are_aligned = true; + self.memory_mut().reads_are_aligned = old; t } fn write_maybe_aligned(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> where F: FnOnce(&mut Self) -> EvalResult<'tcx, T> { - assert!(self.memory_mut().writes_are_aligned, "Unaligned writes must not be nested"); - self.memory_mut().writes_are_aligned = aligned; + let old = self.memory_mut().writes_are_aligned; + self.memory_mut().writes_are_aligned = old && aligned; let t = f(self); - self.memory_mut().writes_are_aligned = true; + self.memory_mut().writes_are_aligned = old; t } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 86e123233061..075fab36f64f 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -11,12 +11,14 @@ use rustc::ty; use rustc::ty::layout::Layout; use rustc::ty::subst::Substs; +use syntax::codemap::Span; +use syntax::ast::Mutability; + use error::{EvalResult, EvalError}; use eval_context::{EvalContext, StackPopCleanup}; use lvalue::{Global, GlobalId, Lvalue}; use value::{Value, PrimVal}; -use syntax::codemap::Span; -use syntax::ast::Mutability; +use memory::HasMemory; impl<'a, 'tcx> EvalContext<'a, 'tcx> { pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> { @@ -101,12 +103,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { if variant_index as u64 != nndiscr { - let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; + let (offset, ty, packed) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; let nonnull = self.force_allocation(dest)?.to_ptr()?.offset(offset.bytes(), &self)?; trace!("struct wrapped nullable pointer type: {}", ty); // only the pointer part of a fat pointer is used for this space optimization let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield"); - self.memory.write_uint(nonnull, 0, discr_size)?; + self.write_maybe_aligned(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?; } }, diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 3ee6bab77e05..e5b6d3713812 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -9,7 +9,7 @@ use syntax::abi::Abi; use error::{EvalError, EvalResult}; use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited, self}; use lvalue::Lvalue; -use memory::{MemoryPointer, TlsKey, Kind}; +use memory::{MemoryPointer, TlsKey, Kind, HasMemory}; use value::{PrimVal, Value}; use rustc_data_structures::indexed_vec::Idx; use const_eval; @@ -402,7 +402,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?; let mut arg_operands = arg_operands.to_vec(); let ty = self.operand_ty(&arg_operands[0]); - let ty = self.get_field_ty(ty, 0)?; + let ty = self.get_field_ty(ty, 0)?.0; // TODO: packed flag is ignored match arg_operands[0] { mir::Operand::Consume(ref mut lval) => *lval = lval.clone().field(mir::Field::new(0), ty), _ => bug!("virtual call first arg cannot be a constant"), @@ -464,7 +464,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(false) } - pub fn read_discriminant_value(&self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { + pub fn read_discriminant_value(&mut self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { use rustc::ty::layout::Layout::*; let adt_layout = self.type_layout(adt_ty)?; //trace!("read_discriminant_value {:#?}", adt_layout); @@ -487,12 +487,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { - let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?; - let nonnull = adt_ptr.offset(offset.bytes(), self)?; + let (offset, ty, packed) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?; + let nonnull = adt_ptr.offset(offset.bytes(), &*self)?; trace!("struct wrapped nullable pointer type: {}", ty); // only the pointer part of a fat pointer is used for this space optimization let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield"); - self.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size)? + self.read_maybe_aligned(!packed, + |ectx| ectx.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size))? } // The discriminant_value intrinsic returns 0 for non-sum types. diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 7219649e728c..0c4781198282 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -40,7 +40,8 @@ fn test_unsizing() { let arr = [1, 2, 3]; let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr }; - let _uns: UnalignedPtr<[i32]> = arr_unaligned; + let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned; + let _unused = &arr_unaligned; // forcing an allocation, which could also yield "unaligned write"-errors } fn main() { From 14c8e834b99ca3d422828b44ed0b2d4a76335be6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 27 Jul 2017 09:14:04 -0700 Subject: [PATCH 2/4] use Cell for memory's aligned flag to avoid infecting interfaces with 'fake' mutability --- src/librustc_mir/interpret/eval_context.rs | 20 +++---- src/librustc_mir/interpret/lvalue.rs | 8 +-- src/librustc_mir/interpret/memory.rs | 54 ++++++++++++------- src/librustc_mir/interpret/step.rs | 2 +- .../interpret/terminator/intrinsic.rs | 30 +++++------ src/librustc_mir/interpret/terminator/mod.rs | 44 +++++++-------- src/librustc_mir/interpret/validation.rs | 4 +- src/librustc_mir/interpret/value.rs | 8 +-- 8 files changed, 92 insertions(+), 78 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 5913ff168fc7..c1ddfb9ffeaf 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1161,7 +1161,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Lvalue::Ptr { ptr, extra, aligned } => { assert_eq!(extra, LvalueExtra::None); - self.write_maybe_aligned(aligned, + self.write_maybe_aligned_mut(aligned, |ectx| ectx.write_value_to_ptr(src_val, ptr, dest_ty)) } @@ -1193,7 +1193,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we // knew for certain that there were no outstanding pointers to this allocation. - self.write_maybe_aligned(aligned, + self.write_maybe_aligned_mut(aligned, |ectx| ectx.write_value_to_ptr(src_val, dest_ptr, dest_ty))?; } else if let Value::ByRef(src_ptr, aligned) = src_val { @@ -1208,7 +1208,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // It is a valid optimization to attempt reading a primitive value out of the // source and write that into the destination without making an allocation, so // we do so here. - self.read_maybe_aligned(aligned, |ectx| { + self.read_maybe_aligned_mut(aligned, |ectx| { if let Ok(Some(src_val)) = ectx.try_read_value(src_ptr, dest_ty) { write_dest(ectx, src_val)?; } else { @@ -1235,7 +1235,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ) -> EvalResult<'tcx> { match value { Value::ByRef(ptr, aligned) => { - self.read_maybe_aligned(aligned, |ectx| ectx.copy(ptr, dest, dest_ty)) + self.read_maybe_aligned_mut(aligned, |ectx| ectx.copy(ptr, dest, dest_ty)) }, Value::ByVal(primval) => { let size = self.type_size(dest_ty)?.expect("dest type must be sized"); @@ -1270,9 +1270,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let field_1_size = self.type_size(field_1_ty.0)?.expect("pair element type must be sized"); let field_0_ptr = ptr.offset(field_0.bytes(), &self)?.into(); let field_1_ptr = ptr.offset(field_1.bytes(), &self)?.into(); - self.write_maybe_aligned(!packed, + self.write_maybe_aligned_mut(!packed, |ectx| ectx.memory.write_primval(field_0_ptr, a, field_0_size))?; - self.write_maybe_aligned(!packed, + self.write_maybe_aligned_mut(!packed, |ectx| ectx.memory.write_primval(field_1_ptr, b, field_1_size))?; Ok(()) } @@ -1376,7 +1376,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } - pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { + pub(super) fn read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { if let Some(val) = self.try_read_value(ptr, ty)? { Ok(val) } else { @@ -1400,7 +1400,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } - fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { + fn try_read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { use syntax::ast::FloatTy; let val = match ty.sty { @@ -1512,7 +1512,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match (&src_pointee_ty.sty, &dest_pointee_ty.sty) { (&ty::TyArray(_, length), &ty::TySlice(_)) => { - let ptr = src.into_ptr(&mut self.memory)?; + let ptr = src.into_ptr(&self.memory)?; // u64 cast is from usize to u64, which is always good self.write_value(ptr.to_value_with_len(length as u64), dest, dest_ty) } @@ -1526,7 +1526,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let trait_ref = data.principal().unwrap().with_self_ty(self.tcx, src_pointee_ty); let trait_ref = self.tcx.erase_regions(&trait_ref); let vtable = self.get_vtable(src_pointee_ty, trait_ref)?; - let ptr = src.into_ptr(&mut self.memory)?; + let ptr = src.into_ptr(&self.memory)?; self.write_value(ptr.to_value_with_vtable(vtable), dest, dest_ty) }, diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs index da357a6d1e71..4d4db267ecf8 100644 --- a/src/librustc_mir/interpret/lvalue.rs +++ b/src/librustc_mir/interpret/lvalue.rs @@ -351,17 +351,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(Lvalue::Ptr { ptr, extra, aligned: aligned && !packed }) } - pub(super) fn val_to_lvalue(&mut self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> { + pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> { Ok(match self.tcx.struct_tail(ty).sty { ty::TyDynamic(..) => { - let (ptr, vtable) = val.into_ptr_vtable_pair(&mut self.memory)?; + let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?; Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable), aligned: true } }, ty::TyStr | ty::TySlice(_) => { - let (ptr, len) = val.into_slice(&mut self.memory)?; + let (ptr, len) = val.into_slice(&self.memory)?; Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len), aligned: true } }, - _ => Lvalue::Ptr { ptr: val.into_ptr(&mut self.memory)?, extra: LvalueExtra::None, aligned: true }, + _ => Lvalue::Ptr { ptr: val.into_ptr(&self.memory)?, extra: LvalueExtra::None, aligned: true }, }) } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 591f5dc7fe80..2226744c6ab4 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -1,6 +1,7 @@ use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; use std::{fmt, iter, ptr, mem, io, ops}; +use std::cell::Cell; use rustc::ty; use rustc::ty::layout::{self, TargetDataLayout, HasDataLayout}; @@ -266,8 +267,8 @@ pub struct Memory<'a, 'tcx> { /// To avoid having to pass flags to every single memory access, we have some global state saying whether /// alignment checking is currently enforced for read and/or write accesses. - reads_are_aligned: bool, - writes_are_aligned: bool, + reads_are_aligned: Cell, + writes_are_aligned: Cell, /// The current stack frame. Used to check accesses against locks. cur_frame: usize, @@ -287,8 +288,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { literal_alloc_cache: HashMap::new(), thread_local: BTreeMap::new(), next_thread_local: 0, - reads_are_aligned: true, - writes_are_aligned: true, + reads_are_aligned: Cell::new(true), + writes_are_aligned: Cell::new(true), cur_frame: usize::max_value(), } } @@ -796,7 +797,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { impl<'a, 'tcx> Memory<'a, 'tcx> { fn get_bytes_unchecked(&self, ptr: MemoryPointer, size: u64, align: u64) -> EvalResult<'tcx, &[u8]> { // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL - if self.reads_are_aligned { + if self.reads_are_aligned.get() { self.check_align(ptr.into(), align)?; } if size == 0 { @@ -813,7 +814,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { fn get_bytes_unchecked_mut(&mut self, ptr: MemoryPointer, size: u64, align: u64) -> EvalResult<'tcx, &mut [u8]> { // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL - if self.writes_are_aligned { + if self.writes_are_aligned.get() { self.check_align(ptr.into(), align)?; } if size == 0 { @@ -909,10 +910,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { pub fn copy(&mut self, src: Pointer, dest: Pointer, size: u64, align: u64, nonoverlapping: bool) -> EvalResult<'tcx> { if size == 0 { // Empty accesses don't need to be valid pointers, but they should still be aligned - if self.reads_are_aligned { + if self.reads_are_aligned.get() { self.check_align(src, align)?; } - if self.writes_are_aligned { + if self.writes_are_aligned.get() { self.check_align(dest, align)?; } return Ok(()); @@ -968,7 +969,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> { if size == 0 { // Empty accesses don't need to be valid pointers, but they should still be non-NULL - if self.reads_are_aligned { + if self.reads_are_aligned.get() { self.check_align(ptr, 1)?; } return Ok(&[]); @@ -979,7 +980,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx> { if src.is_empty() { // Empty accesses don't need to be valid pointers, but they should still be non-NULL - if self.writes_are_aligned { + if self.writes_are_aligned.get() { self.check_align(ptr, 1)?; } return Ok(()); @@ -992,7 +993,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<'tcx> { if count == 0 { // Empty accesses don't need to be valid pointers, but they should still be non-NULL - if self.writes_are_aligned { + if self.writes_are_aligned.get() { self.check_align(ptr, 1)?; } return Ok(()); @@ -1399,23 +1400,36 @@ pub(crate) trait HasMemory<'a, 'tcx> { fn memory(&self) -> &Memory<'a, 'tcx>; // These are not supposed to be overriden. - fn read_maybe_aligned(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> - where F: FnOnce(&mut Self) -> EvalResult<'tcx, T> + fn read_maybe_aligned(&self, aligned: bool, f: F) -> EvalResult<'tcx, T> + where F: FnOnce(&Self) -> EvalResult<'tcx, T> { - let old = self.memory_mut().reads_are_aligned; - self.memory_mut().reads_are_aligned = old && aligned; + let old = self.memory().reads_are_aligned.get(); + // Do alignment checking if *all* nested calls say it has to be aligned. + self.memory().reads_are_aligned.set(old && aligned); let t = f(self); - self.memory_mut().reads_are_aligned = old; + self.memory().reads_are_aligned.set(old); t } - fn write_maybe_aligned(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> + fn read_maybe_aligned_mut(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> where F: FnOnce(&mut Self) -> EvalResult<'tcx, T> { - let old = self.memory_mut().writes_are_aligned; - self.memory_mut().writes_are_aligned = old && aligned; + let old = self.memory().reads_are_aligned.get(); + // Do alignment checking if *all* nested calls say it has to be aligned. + self.memory().reads_are_aligned.set(old && aligned); let t = f(self); - self.memory_mut().writes_are_aligned = old; + self.memory().reads_are_aligned.set(old); + t + } + + fn write_maybe_aligned_mut(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> + where F: FnOnce(&mut Self) -> EvalResult<'tcx, T> + { + let old = self.memory().writes_are_aligned.get(); + // Do alignment checking if *all* nested calls say it has to be aligned. + self.memory().writes_are_aligned.set(old && aligned); + let t = f(self); + self.memory().writes_are_aligned.set(old); t } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 075fab36f64f..b78945155f1a 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -108,7 +108,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { trace!("struct wrapped nullable pointer type: {}", ty); // only the pointer part of a fat pointer is used for this space optimization let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield"); - self.write_maybe_aligned(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?; + self.write_maybe_aligned_mut(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?; } }, diff --git a/src/librustc_mir/interpret/terminator/intrinsic.rs b/src/librustc_mir/interpret/terminator/intrinsic.rs index 2be5b7666f05..69dd41c82aac 100644 --- a/src/librustc_mir/interpret/terminator/intrinsic.rs +++ b/src/librustc_mir/interpret/terminator/intrinsic.rs @@ -45,7 +45,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "arith_offset" => { let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64; - let ptr = arg_vals[0].into_ptr(&mut self.memory)?; + let ptr = arg_vals[0].into_ptr(&self.memory)?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_ty)?; } @@ -61,7 +61,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "atomic_load_acq" | "volatile_load" => { let ty = substs.type_at(0); - let ptr = arg_vals[0].into_ptr(&mut self.memory)?; + let ptr = arg_vals[0].into_ptr(&self.memory)?; self.write_value(Value::by_ref(ptr), dest, ty)?; } @@ -70,7 +70,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "atomic_store_rel" | "volatile_store" => { let ty = substs.type_at(0); - let dest = arg_vals[0].into_ptr(&mut self.memory)?; + let dest = arg_vals[0].into_ptr(&self.memory)?; self.write_value_to_ptr(arg_vals[1], dest, ty)?; } @@ -80,7 +80,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { _ if intrinsic_name.starts_with("atomic_xchg") => { let ty = substs.type_at(0); - let ptr = arg_vals[0].into_ptr(&mut self.memory)?; + let ptr = arg_vals[0].into_ptr(&self.memory)?; let change = self.value_to_primval(arg_vals[1], ty)?; let old = self.read_value(ptr, ty)?; let old = match old { @@ -94,7 +94,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { _ if intrinsic_name.starts_with("atomic_cxchg") => { let ty = substs.type_at(0); - let ptr = arg_vals[0].into_ptr(&mut self.memory)?; + let ptr = arg_vals[0].into_ptr(&self.memory)?; let expect_old = self.value_to_primval(arg_vals[1], ty)?; let change = self.value_to_primval(arg_vals[2], ty)?; let old = self.read_value(ptr, ty)?; @@ -115,7 +115,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | "atomic_xadd_acqrel" | "atomic_xadd_relaxed" | "atomic_xsub" | "atomic_xsub_acq" | "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { let ty = substs.type_at(0); - let ptr = arg_vals[0].into_ptr(&mut self.memory)?; + let ptr = arg_vals[0].into_ptr(&self.memory)?; let change = self.value_to_primval(arg_vals[1], ty)?; let old = self.read_value(ptr, ty)?; let old = match old { @@ -148,8 +148,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. let elem_align = self.type_align(elem_ty)?; - let src = arg_vals[0].into_ptr(&mut self.memory)?; - let dest = arg_vals[1].into_ptr(&mut self.memory)?; + let src = arg_vals[0].into_ptr(&self.memory)?; + let dest = arg_vals[1].into_ptr(&self.memory)?; self.memory.copy(src, dest, count * elem_size, elem_align, intrinsic_name.ends_with("_nonoverlapping"))?; } } @@ -176,7 +176,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "discriminant_value" => { let ty = substs.type_at(0); - let adt_ptr = arg_vals[0].into_ptr(&mut self.memory)?.to_ptr()?; + let adt_ptr = arg_vals[0].into_ptr(&self.memory)?.to_ptr()?; let discr_val = self.read_discriminant_value(adt_ptr, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?; } @@ -297,7 +297,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "move_val_init" => { let ty = substs.type_at(0); - let ptr = arg_vals[0].into_ptr(&mut self.memory)?; + let ptr = arg_vals[0].into_ptr(&self.memory)?; self.write_value_to_ptr(arg_vals[1], ptr, ty)?; } @@ -310,7 +310,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "offset" => { let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64; - let ptr = arg_vals[0].into_ptr(&mut self.memory)?; + let ptr = arg_vals[0].into_ptr(&self.memory)?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_ty)?; } @@ -399,7 +399,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "transmute" => { let src_ty = substs.type_at(0); let ptr = self.force_allocation(dest)?.to_ptr()?; - self.write_maybe_aligned(/*aligned*/false, |ectx| { + self.write_maybe_aligned_mut(/*aligned*/false, |ectx| { ectx.write_value_to_ptr(arg_vals[0], ptr.into(), src_ty) })?; } @@ -464,7 +464,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let ty_align = self.type_align(ty)?; let val_byte = self.value_to_primval(arg_vals[1], u8)?.to_u128()? as u8; let size = self.type_size(ty)?.expect("write_bytes() type must be sized"); - let ptr = arg_vals[0].into_ptr(&mut self.memory)?; + let ptr = arg_vals[0].into_ptr(&self.memory)?; let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?; if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work @@ -550,7 +550,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok((size, align.abi())) } ty::TyDynamic(..) => { - let (_, vtable) = value.into_ptr_vtable_pair(&mut self.memory)?; + let (_, vtable) = value.into_ptr_vtable_pair(&self.memory)?; // the second entry in the vtable is the dynamic size of the object. self.read_size_and_align_from_vtable(vtable) } @@ -558,7 +558,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty::TySlice(_) | ty::TyStr => { let elem_ty = ty.sequence_element_type(self.tcx); let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized") as u64; - let (_, len) = value.into_slice(&mut self.memory)?; + let (_, len) = value.into_slice(&self.memory)?; let align = self.type_align(elem_ty)?; Ok((len * elem_size, align as u64)) } diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index e5b6d3713812..b9b72ca34ac2 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -397,7 +397,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }, ty::InstanceDef::Virtual(_, idx) => { let ptr_size = self.memory.pointer_size(); - let (_, vtable) = self.eval_operand(&arg_operands[0])?.into_ptr_vtable_pair(&mut self.memory)?; + let (_, vtable) = self.eval_operand(&arg_operands[0])?.into_ptr_vtable_pair(&self.memory)?; let fn_ptr = self.memory.read_ptr(vtable.offset(ptr_size * (idx as u64 + 3), &self)?)?; let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?; let mut arg_operands = arg_operands.to_vec(); @@ -464,7 +464,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(false) } - pub fn read_discriminant_value(&mut self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { + pub fn read_discriminant_value(&self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { use rustc::ty::layout::Layout::*; let adt_layout = self.type_layout(adt_ty)?; //trace!("read_discriminant_value {:#?}", adt_layout); @@ -577,7 +577,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::heap::::__rust_dealloc" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?; let old_size = self.value_to_primval(args[1], usize)?.to_u64()?; let align = self.value_to_primval(args[2], usize)?.to_u64()?; if old_size == 0 { @@ -589,7 +589,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust)?; } "alloc::heap::::__rust_realloc" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?; let old_size = self.value_to_primval(args[1], usize)?.to_u64()?; let old_align = self.value_to_primval(args[2], usize)?.to_u64()?; let new_size = self.value_to_primval(args[3], usize)?.to_u64()?; @@ -665,7 +665,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "free" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = args[0].into_ptr(&self.memory)?; if !ptr.is_null()? { self.memory.deallocate(ptr.to_ptr()?, None, Kind::C)?; } @@ -679,8 +679,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "dlsym" => { - let _handle = args[0].into_ptr(&mut self.memory)?; - let symbol = args[1].into_ptr(&mut self.memory)?.to_ptr()?; + let _handle = args[0].into_ptr(&self.memory)?; + let symbol = args[1].into_ptr(&self.memory)?.to_ptr()?; let symbol_name = self.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); @@ -691,8 +691,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32 // We abort on panic, so not much is going on here, but we still have to call the closure let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); - let f = args[0].into_ptr(&mut self.memory)?.to_ptr()?; - let data = args[1].into_ptr(&mut self.memory)?; + let f = args[0].into_ptr(&self.memory)?.to_ptr()?; + let data = args[1].into_ptr(&self.memory)?; let f_instance = self.memory.get_fn(f)?; self.write_null(dest, dest_ty)?; @@ -723,8 +723,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "memcmp" => { - let left = args[0].into_ptr(&mut self.memory)?; - let right = args[1].into_ptr(&mut self.memory)?; + let left = args[0].into_ptr(&self.memory)?; + let right = args[1].into_ptr(&self.memory)?; let n = self.value_to_primval(args[2], usize)?.to_u64()?; let result = { @@ -743,7 +743,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "memrchr" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = args[0].into_ptr(&self.memory)?; let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8; let num = self.value_to_primval(args[2], usize)?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) { @@ -755,7 +755,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "memchr" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = args[0].into_ptr(&self.memory)?; let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8; let num = self.value_to_primval(args[2], usize)?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) { @@ -768,7 +768,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "getenv" => { let result = { - let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let name_ptr = args[0].into_ptr(&self.memory)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.env_vars.get(name) { Some(&var) => PrimVal::Ptr(var), @@ -781,7 +781,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "unsetenv" => { let mut success = None; { - let name_ptr = args[0].into_ptr(&mut self.memory)?; + let name_ptr = args[0].into_ptr(&self.memory)?; if !name_ptr.is_null()? { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { @@ -802,8 +802,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "setenv" => { let mut new = None; { - let name_ptr = args[0].into_ptr(&mut self.memory)?; - let value_ptr = args[1].into_ptr(&mut self.memory)?.to_ptr()?; + let name_ptr = args[0].into_ptr(&self.memory)?; + let value_ptr = args[1].into_ptr(&self.memory)?.to_ptr()?; let value = self.memory.read_c_str(value_ptr)?; if !name_ptr.is_null()? { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; @@ -829,7 +829,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "write" => { let fd = self.value_to_primval(args[0], usize)?.to_u64()?; - let buf = args[1].into_ptr(&mut self.memory)?; + let buf = args[1].into_ptr(&self.memory)?; let n = self.value_to_primval(args[2], usize)?.to_u64()?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -846,7 +846,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "strlen" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; } @@ -889,10 +889,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = args[0].into_ptr(&mut self.memory)?; + let key_ptr = args[0].into_ptr(&self.memory)?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match args[1].into_ptr(&mut self.memory)?.into_inner_primval() { + let dtor = match args[1].into_ptr(&self.memory)?.into_inner_primval() { PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), PrimVal::Bytes(0) => None, PrimVal::Bytes(_) => return Err(EvalError::ReadBytesAsPointer), @@ -934,7 +934,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "pthread_setspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t let key = self.value_to_primval(args[0], usize)?.to_u64()? as TlsKey; - let new_ptr = args[1].into_ptr(&mut self.memory)?; + let new_ptr = args[1].into_ptr(&self.memory)?; self.memory.store_tls(key, new_ptr)?; // Return success (0) diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs index 4c9e239299dc..8c3cc1852507 100644 --- a/src/librustc_mir/interpret/validation.rs +++ b/src/librustc_mir/interpret/validation.rs @@ -151,7 +151,7 @@ std::sync::atomic::AtomicBool::get_mut$|\ fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, re: Option, mutbl: Mutability, mode: ValidationMode) -> EvalResult<'tcx> { // Check alignment and non-NULLness let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; - let ptr = val.into_ptr(&mut self.memory)?; + let ptr = val.into_ptr(&self.memory)?; self.memory.check_align(ptr, align)?; // Recurse @@ -309,7 +309,7 @@ std::sync::atomic::AtomicBool::get_mut$|\ self.validate_ptr(val, query.ty.boxed_ty(), query.re, query.mutbl, mode) } TyFnPtr(_sig) => { - let ptr = self.read_lvalue(query.lval)?.into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = self.read_lvalue(query.lval)?.into_ptr(&self.memory)?.to_ptr()?; self.memory.get_fn(ptr)?; // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). Ok(()) diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs index a4115ddb5ccf..302ea0abec3c 100644 --- a/src/librustc_mir/interpret/value.rs +++ b/src/librustc_mir/interpret/value.rs @@ -167,7 +167,7 @@ impl<'a, 'tcx: 'a> Value { /// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef, /// this may have to perform a load. - pub(super) fn into_ptr(&self, mem: &mut Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> { + pub(super) fn into_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> { use self::Value::*; match *self { ByRef(ptr, aligned) => { @@ -179,7 +179,7 @@ impl<'a, 'tcx: 'a> Value { pub(super) fn into_ptr_vtable_pair( &self, - mem: &mut Memory<'a, 'tcx> + mem: &Memory<'a, 'tcx> ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> { use self::Value::*; match *self { @@ -197,11 +197,11 @@ impl<'a, 'tcx: 'a> Value { } } - pub(super) fn into_slice(&self, mem: &mut Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> { + pub(super) fn into_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> { use self::Value::*; match *self { ByRef(ref_ptr, aligned) => { - mem.write_maybe_aligned(aligned, |mem| { + mem.read_maybe_aligned(aligned, |mem| { let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?; let len = mem.read_usize(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?; Ok((ptr, len)) From eb6c743e424ec9ebe80ad7026175d506e6b6da65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jul 2017 19:43:05 -0700 Subject: [PATCH 3/4] avoid anonymous bool --- src/librustc_mir/interpret/eval_context.rs | 75 ++++++++++--------- src/librustc_mir/interpret/lvalue.rs | 6 +- src/librustc_mir/interpret/step.rs | 4 +- .../interpret/terminator/intrinsic.rs | 14 ++-- src/librustc_mir/interpret/terminator/mod.rs | 10 +-- src/librustc_mir/interpret/value.rs | 10 +-- 6 files changed, 62 insertions(+), 57 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c1ddfb9ffeaf..bbaaba08a14d 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -142,6 +142,12 @@ impl Default for ResourceLimits { } } +#[derive(Copy, Clone, Debug)] +pub struct TyAndPacked<'tcx> { + pub ty: Ty<'tcx>, + pub packed: bool, +} + impl<'a, 'tcx> EvalContext<'a, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, limits: ResourceLimits) -> Self { EvalContext { @@ -381,7 +387,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { .expect("global should have been cached (static)"); match global_value.value { // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions - Value::ByRef(ptr, _aligned) => + Value::ByRef { ptr, aligned: _aligned } => // Alignment does not matter for this call self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)?, Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val { @@ -439,7 +445,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } pub fn deallocate_local(&mut self, local: Option) -> EvalResult<'tcx> { - if let Some(Value::ByRef(ptr, _aligned)) = local { + if let Some(Value::ByRef { ptr, aligned: _ }) = local { trace!("deallocating local"); let ptr = ptr.to_ptr()?; self.memory.dump_alloc(ptr.alloc_id); @@ -609,7 +615,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let operand_ty = self.operand_ty(operand); assert_eq!(self.type_size(operand_ty)?, Some(0)); } - let (offset, ty, _packed) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; + let (offset, TyAndPacked { ty, packed: _}) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; // TODO: The packed flag is ignored // FIXME(solson) @@ -745,7 +751,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let src_ty = self.operand_ty(operand); if self.type_is_fat_ptr(src_ty) { match (src, self.type_is_fat_ptr(dest_ty)) { - (Value::ByRef(..), _) | + (Value::ByRef{..}, _) | (Value::ByValPair(..), true) => { self.write_value(src, dest, dest_ty)?; }, @@ -826,7 +832,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32], - ) -> EvalResult<'tcx, (Size, Ty<'tcx>, bool)> { + ) -> EvalResult<'tcx, (Size, TyAndPacked<'tcx>)> { // Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant let path = discrfield.iter().skip(2).map(|&i| i as usize); @@ -849,19 +855,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { mut offset: Size, mut ty: Ty<'tcx>, path: I, - ) -> EvalResult<'tcx, (Size, Ty<'tcx>, bool)> { + ) -> EvalResult<'tcx, (Size, TyAndPacked<'tcx>)> { // Skip the initial 0 intended for LLVM GEP. let mut packed = false; for field_index in path { let field_offset = self.get_field_offset(ty, field_index)?; trace!("field_path_offset_and_ty: {}, {}, {:?}, {:?}", field_index, ty, field_offset, offset); let field_ty = self.get_field_ty(ty, field_index)?; - ty = field_ty.0; - packed = packed || field_ty.1; + ty = field_ty.ty; + packed = packed || field_ty.packed; offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap(); } - Ok((offset, ty, packed)) + Ok((offset, TyAndPacked { ty, packed })) } fn get_fat_field(&self, pointee_ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> { match (field_index, &self.tcx.struct_tail(pointee_ty).sty) { @@ -874,18 +880,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } /// Returns the field type and whether the field is packed - pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, (Ty<'tcx>, bool)> { + pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, TyAndPacked<'tcx>> { match ty.sty { ty::TyAdt(adt_def, _) if adt_def.is_box() => - Ok((self.get_fat_field(ty.boxed_ty(), field_index)?, false)), + Ok(TyAndPacked { ty: self.get_fat_field(ty.boxed_ty(), field_index)?, packed: false }), ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { use rustc::ty::layout::Layout::*; match *self.type_layout(ty)? { RawNullablePointer { nndiscr, .. } => - Ok((adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs), false)), + Ok(TyAndPacked { ty: adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs), packed: false }), StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => { let ty = adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs); - Ok((ty, nonnull.packed)) + Ok(TyAndPacked { ty, packed: nonnull.packed }) }, _ => Err(EvalError::Unimplemented(format!("get_field_ty can't handle enum type: {:?}, {:?}", ty, ty.sty))), } @@ -895,17 +901,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { use rustc::ty::layout::Layout::*; match *self.type_layout(ty)? { Univariant { ref variant, .. } => - Ok((variant_def.fields[field_index].ty(self.tcx, substs), variant.packed)), + Ok(TyAndPacked { ty: variant_def.fields[field_index].ty(self.tcx, substs), packed: variant.packed }), _ => Err(EvalError::Unimplemented(format!("get_field_ty can't handle struct type: {:?}, {:?}", ty, ty.sty))), } } - ty::TyTuple(fields, _) => Ok((fields[field_index], false)), + ty::TyTuple(fields, _) => Ok(TyAndPacked { ty: fields[field_index], packed: false }), ty::TyRef(_, ref tam) | - ty::TyRawPtr(ref tam) => Ok((self.get_fat_field(tam.ty, field_index)?, false)), + ty::TyRawPtr(ref tam) => Ok(TyAndPacked { ty: self.get_fat_field(tam.ty, field_index)?, packed: false }), - ty::TyArray(ref inner, _) => Ok((inner, false)), + ty::TyArray(ref inner, _) => Ok(TyAndPacked { ty: inner, packed: false }), _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))), } @@ -1042,7 +1048,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // -1 since we don't store the return value match self.stack[frame].locals[local.index() - 1] { None => return Err(EvalError::DeadLocal), - Some(Value::ByRef(ptr, aligned)) => { + Some(Value::ByRef { ptr, aligned }) => { Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None } }, Some(val) => { @@ -1060,7 +1066,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Lvalue::Global(cid) => { let global_val = self.globals.get(&cid).expect("global not cached").clone(); match global_val.value { - Value::ByRef(ptr, aligned) => + Value::ByRef { ptr, aligned } => Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None }, _ => { let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.instance.substs)?; @@ -1086,7 +1092,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { /// ensures this Value is not a ByRef pub(super) fn follow_by_ref_value(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { match value { - Value::ByRef(ptr, aligned) => { + Value::ByRef { ptr, aligned } => { self.read_maybe_aligned(aligned, |ectx| ectx.read_value(ptr, ty)) } other => Ok(other), @@ -1095,7 +1101,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { pub(super) fn value_to_primval(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { match self.follow_by_ref_value(value, ty)? { - Value::ByRef(..) => bug!("follow_by_ref_value can't result in `ByRef`"), + Value::ByRef{..} => bug!("follow_by_ref_value can't result in `ByRef`"), Value::ByVal(primval) => { self.ensure_valid_value(primval, ty)?; @@ -1185,7 +1191,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { old_dest_val: Value, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { - if let Value::ByRef(dest_ptr, aligned) = old_dest_val { + if let Value::ByRef { ptr: dest_ptr, aligned } = old_dest_val { // If the value is already `ByRef` (that is, backed by an `Allocation`), // then we must write the new value into this allocation, because there may be // other pointers into the allocation. These other pointers are logically @@ -1196,7 +1202,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.write_maybe_aligned_mut(aligned, |ectx| ectx.write_value_to_ptr(src_val, dest_ptr, dest_ty))?; - } else if let Value::ByRef(src_ptr, aligned) = src_val { + } else if let Value::ByRef { ptr: src_ptr, aligned } = src_val { // If the value is not `ByRef`, then we know there are no pointers to it // and we can simply overwrite the `Value` in the locals array directly. // @@ -1234,7 +1240,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { match value { - Value::ByRef(ptr, aligned) => { + Value::ByRef { ptr, aligned } => { self.read_maybe_aligned_mut(aligned, |ectx| ectx.copy(ptr, dest, dest_ty)) }, Value::ByVal(primval) => { @@ -1255,19 +1261,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let mut packed = false; while self.get_field_count(ty)? == 1 { let field = self.get_field_ty(ty, 0)?; - ty = field.0; - packed = packed || field.1; + ty = field.ty; + packed = packed || field.packed; } assert_eq!(self.get_field_count(ty)?, 2); let field_0 = self.get_field_offset(ty, 0)?; let field_1 = self.get_field_offset(ty, 1)?; let field_0_ty = self.get_field_ty(ty, 0)?; let field_1_ty = self.get_field_ty(ty, 1)?; - // The .1 components say whether the field is packed - assert_eq!(field_0_ty.1, field_1_ty.1, "the two fields must agree on being packed"); - packed = packed || field_0_ty.1; - let field_0_size = self.type_size(field_0_ty.0)?.expect("pair element type must be sized"); - let field_1_size = self.type_size(field_1_ty.0)?.expect("pair element type must be sized"); + assert_eq!(field_0_ty.packed, field_1_ty.packed, "the two fields must agree on being packed"); + packed = packed || field_0_ty.packed; + let field_0_size = self.type_size(field_0_ty.ty)?.expect("pair element type must be sized"); + let field_1_size = self.type_size(field_1_ty.ty)?.expect("pair element type must be sized"); let field_0_ptr = ptr.offset(field_0.bytes(), &self)?.into(); let field_1_ptr = ptr.offset(field_1.bytes(), &self)?.into(); self.write_maybe_aligned_mut(!packed, @@ -1554,8 +1559,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } if self.ty_to_primval_kind(src_ty).is_ok() { // TODO: We ignore the packed flag here - let sty = self.get_field_ty(src_ty, 0)?.0; - let dty = self.get_field_ty(dest_ty, 0)?.0; + let sty = self.get_field_ty(src_ty, 0)?.ty; + let dty = self.get_field_ty(dest_ty, 0)?.ty; return self.unsize_into(src, sty, dest, dty); } // unsizing of generic struct with pointer fields @@ -1570,7 +1575,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { //let src = adt::MaybeSizedValue::sized(src); //let dst = adt::MaybeSizedValue::sized(dst); let src_ptr = match src { - Value::ByRef(ptr, true) => ptr, + Value::ByRef { ptr, aligned: true } => ptr, // TODO: Is it possible for unaligned pointers to occur here? _ => bug!("expected aligned pointer, got {:?}", src), }; @@ -1617,7 +1622,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Err(err) => { panic!("Failed to access local: {:?}", err); } - Ok(Value::ByRef(ptr, aligned)) => match ptr.into_inner_primval() { + Ok(Value::ByRef { ptr, aligned }) => match ptr.into_inner_primval() { PrimVal::Ptr(ptr) => { write!(msg, " by {}ref:", if aligned { "" } else { "unaligned " }).unwrap(); allocs.push(ptr.alloc_id); diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs index 4d4db267ecf8..f1d1ba70b4f5 100644 --- a/src/librustc_mir/interpret/lvalue.rs +++ b/src/librustc_mir/interpret/lvalue.rs @@ -196,7 +196,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match lvalue { Lvalue::Ptr { ptr, extra, aligned } => { assert_eq!(extra, LvalueExtra::None); - Ok(Value::ByRef(ptr, aligned)) + Ok(Value::ByRef { ptr, aligned }) } Lvalue::Local { frame, local } => { self.stack[frame].get_local(local) @@ -307,7 +307,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0"); return Ok(base); }, - Value::ByRef(..) | + Value::ByRef{..} | Value::ByValPair(..) | Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(), }, @@ -317,7 +317,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0"); return Ok(base); }, - Value::ByRef(..) | + Value::ByRef{..} | Value::ByValPair(..) | Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(), }, diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index b78945155f1a..1679688625dc 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -15,7 +15,7 @@ use syntax::codemap::Span; use syntax::ast::Mutability; use error::{EvalResult, EvalError}; -use eval_context::{EvalContext, StackPopCleanup}; +use eval_context::{EvalContext, StackPopCleanup, TyAndPacked}; use lvalue::{Global, GlobalId, Lvalue}; use value::{Value, PrimVal}; use memory::HasMemory; @@ -103,7 +103,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { if variant_index as u64 != nndiscr { - let (offset, ty, packed) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; + let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; let nonnull = self.force_allocation(dest)?.to_ptr()?.offset(offset.bytes(), &self)?; trace!("struct wrapped nullable pointer type: {}", ty); // only the pointer part of a fat pointer is used for this space optimization diff --git a/src/librustc_mir/interpret/terminator/intrinsic.rs b/src/librustc_mir/interpret/terminator/intrinsic.rs index 69dd41c82aac..5c608bc16300 100644 --- a/src/librustc_mir/interpret/terminator/intrinsic.rs +++ b/src/librustc_mir/interpret/terminator/intrinsic.rs @@ -85,7 +85,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let old = self.read_value(ptr, ty)?; let old = match old { Value::ByVal(val) => val, - Value::ByRef(..) => bug!("just read the value, can't be byref"), + Value::ByRef { .. } => bug!("just read the value, can't be byref"), Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), }; self.write_primval(dest, old, ty)?; @@ -100,7 +100,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let old = self.read_value(ptr, ty)?; let old = match old { Value::ByVal(val) => val, - Value::ByRef(..) => bug!("just read the value, can't be byref"), + Value::ByRef { .. } => bug!("just read the value, can't be byref"), Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; @@ -120,7 +120,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let old = self.read_value(ptr, ty)?; let old = match old { Value::ByVal(val) => val, - Value::ByRef(..) => bug!("just read the value, can't be byref"), + Value::ByRef { .. } => bug!("just read the value, can't be byref"), Value::ByValPair(..) => bug!("atomic_xadd_relaxed doesn't work with nonprimitives"), }; self.write_primval(dest, old, ty)?; @@ -251,10 +251,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let size = self.type_size(dest_ty)?.expect("cannot zero unsized value"); let init = |this: &mut Self, val: Value| { let zero_val = match val { - Value::ByRef(ptr, aligned) => { + Value::ByRef { ptr, aligned } => { // These writes have no alignment restriction anyway. this.memory.write_repeat(ptr, 0, size)?; - Value::ByRef(ptr, aligned) + Value::ByRef { ptr, aligned } }, // TODO(solson): Revisit this, it's fishy to check for Undef here. Value::ByVal(PrimVal::Undef) => match this.ty_to_primval_kind(dest_ty) { @@ -442,9 +442,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let size = dest_layout.size(&self.tcx.data_layout).bytes(); let uninit = |this: &mut Self, val: Value| { match val { - Value::ByRef(ptr, aligned) => { + Value::ByRef { ptr, aligned } => { this.memory.mark_definedness(ptr, size, false)?; - Ok(Value::ByRef(ptr, aligned)) + Ok(Value::ByRef { ptr, aligned }) }, _ => Ok(Value::ByVal(PrimVal::Undef)), } diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index b9b72ca34ac2..288409783db8 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -7,7 +7,7 @@ use syntax::attr; use syntax::abi::Abi; use error::{EvalError, EvalResult}; -use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited, self}; +use eval_context::{EvalContext, IntegerExt, StackPopCleanup, TyAndPacked, is_inhabited, self}; use lvalue::Lvalue; use memory::{MemoryPointer, TlsKey, Kind, HasMemory}; use value::{PrimVal, Value}; @@ -313,10 +313,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { if self.frame().mir.args_iter().count() == fields.len() + 1 { let offsets = variant.offsets.iter().map(|s| s.bytes()); match arg_val { - Value::ByRef(ptr, aligned) => { + Value::ByRef { ptr, aligned } => { assert!(aligned, "Unaligned ByRef-values cannot occur as function arguments"); for ((offset, ty), arg_local) in offsets.zip(fields).zip(arg_locals) { - let arg = Value::ByRef(ptr.offset(offset, &self)?, true); + let arg = Value::ByRef { ptr: ptr.offset(offset, &self)?, aligned: true}; let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; trace!("writing arg {:?} to {:?} (type: {})", arg, dest, ty); self.write_value(arg, dest, ty)?; @@ -402,7 +402,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?; let mut arg_operands = arg_operands.to_vec(); let ty = self.operand_ty(&arg_operands[0]); - let ty = self.get_field_ty(ty, 0)?.0; // TODO: packed flag is ignored + let ty = self.get_field_ty(ty, 0)?.ty; // TODO: packed flag is ignored match arg_operands[0] { mir::Operand::Consume(ref mut lval) => *lval = lval.clone().field(mir::Field::new(0), ty), _ => bug!("virtual call first arg cannot be a constant"), @@ -487,7 +487,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { - let (offset, ty, packed) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?; + let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?; let nonnull = adt_ptr.offset(offset.bytes(), &*self)?; trace!("struct wrapped nullable pointer type: {}", ty); // only the pointer part of a fat pointer is used for this space optimization diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs index 302ea0abec3c..87b3d9f383c4 100644 --- a/src/librustc_mir/interpret/value.rs +++ b/src/librustc_mir/interpret/value.rs @@ -32,7 +32,7 @@ pub(super) fn f64_to_bytes(f: f64) -> u128 { /// operations and fat pointers. This idea was taken from rustc's trans. #[derive(Clone, Copy, Debug)] pub enum Value { - ByRef(Pointer, bool), + ByRef { ptr: Pointer, aligned: bool}, ByVal(PrimVal), ByValPair(PrimVal, PrimVal), } @@ -162,7 +162,7 @@ pub enum PrimValKind { impl<'a, 'tcx: 'a> Value { #[inline] pub(super) fn by_ref(ptr: Pointer) -> Self { - Value::ByRef(ptr, true) + Value::ByRef { ptr, aligned: true } } /// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef, @@ -170,7 +170,7 @@ impl<'a, 'tcx: 'a> Value { pub(super) fn into_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> { use self::Value::*; match *self { - ByRef(ptr, aligned) => { + ByRef { ptr, aligned } => { mem.read_maybe_aligned(aligned, |mem| mem.read_ptr(ptr.to_ptr()?) ) }, ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr.into()), @@ -183,7 +183,7 @@ impl<'a, 'tcx: 'a> Value { ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> { use self::Value::*; match *self { - ByRef(ref_ptr, aligned) => { + ByRef { ptr: ref_ptr, aligned } => { mem.read_maybe_aligned(aligned, |mem| { let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?; let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?; @@ -200,7 +200,7 @@ impl<'a, 'tcx: 'a> Value { pub(super) fn into_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> { use self::Value::*; match *self { - ByRef(ref_ptr, aligned) => { + ByRef { ptr: ref_ptr, aligned } => { mem.read_maybe_aligned(aligned, |mem| { let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?; let len = mem.read_usize(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?; From 4458001644d084f9741ccc0227ed1afb96ca0dbf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jul 2017 19:44:03 -0700 Subject: [PATCH 4/4] remove some commented-out tracing --- src/librustc_mir/interpret/lvalue.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs index f1d1ba70b4f5..a3927e2637a3 100644 --- a/src/librustc_mir/interpret/lvalue.rs +++ b/src/librustc_mir/interpret/lvalue.rs @@ -295,8 +295,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { _ => bug!("field access on non-product type: {:?}", base_layout), }; - //trace!("Field {} of {:?} is at offset {}{}", field_index, base_ty, offset.bytes(), - // if packed { " (packed)" } else { "" }); // Do not allocate in trivial cases let (base_ptr, base_extra, aligned) = match base {