diff --git a/src/helpers.rs b/src/helpers.rs index 52d3db8ac46f..880b18c7d542 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc::ty; +use rustc::ty::{self, layout}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; @@ -124,8 +124,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let (unsafe_cell_size, _) = self.size_and_align_of_mplace(place)? // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size_and_align()); - // Now handle this `UnsafeCell`. - unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + // Now handle this `UnsafeCell`, unless it is empty. + if unsafe_cell_size != Size::ZERO { + unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + } else { + Ok(()) + } }, }; visitor.visit_value(place)?; @@ -152,8 +156,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: { type V = MPlaceTy<'tcx, Borrow>; - const WANT_FIELDS_SORTED: bool = true; // sorted? yes please! - #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { &self.ecx @@ -179,6 +181,31 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } } + // Make sure we visit aggregrates in increasing offset order + fn visit_aggregate( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + fields: impl Iterator>>, + ) -> EvalResult<'tcx> { + match place.layout.fields { + layout::FieldPlacement::Array { .. } => { + // For the array layout, we know the iterator will yield sorted elements so + // we can avoid the allocation. + self.walk_aggregate(place, fields) + } + layout::FieldPlacement::Arbitrary { .. } => { + // Gather the subplaces and sort them before visiting. + let mut places = fields.collect::>>>()?; + places[..].sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); + self.walk_aggregate(place, places.into_iter().map(Ok)) + } + layout::FieldPlacement::Union { .. } => { + // Uh, what? + bug!("A union is not an aggregate we should ever visit") + } + } + } + // We have to do *something* for unions fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> {