From f27cd60ae1819b3b23fc8c3cb21d5f7d457014a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Nov 2018 11:04:10 +0100 Subject: [PATCH 1/6] no more action on ref or cast, but add new MIR statement for escaping a ptr to raw --- src/librustc/ich/impls_mir.rs | 3 + src/librustc/mir/mod.rs | 9 ++ src/librustc/mir/visit.rs | 5 +- src/librustc_codegen_llvm/mir/statement.rs | 3 +- src/librustc_mir/borrow_check/mod.rs | 1 + .../borrow_check/nll/invalidation.rs | 1 + .../borrow_check/nll/type_check/mod.rs | 5 +- src/librustc_mir/dataflow/impls/borrows.rs | 1 + .../dataflow/move_paths/builder.rs | 3 +- src/librustc_mir/interpret/cast.rs | 27 ++---- src/librustc_mir/interpret/machine.rs | 23 ++--- src/librustc_mir/interpret/place.rs | 30 +++--- src/librustc_mir/interpret/step.rs | 22 ++--- src/librustc_mir/interpret/terminator.rs | 5 +- src/librustc_mir/transform/add_retag.rs | 92 +++++++++++++------ src/librustc_mir/transform/check_unsafety.rs | 1 + src/librustc_mir/transform/qualify_consts.rs | 1 + .../transform/qualify_min_const_fn.rs | 1 + .../transform/remove_noop_landing_pads.rs | 5 +- src/librustc_mir/transform/rustc_peek.rs | 1 + src/librustc_passes/mir_stats.rs | 1 + src/test/mir-opt/inline-retag.rs | 2 + src/test/mir-opt/retag.rs | 27 +++++- 23 files changed, 159 insertions(+), 110 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index a73fe2b8a1a..1bd02dfeaca 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -257,6 +257,9 @@ fn hash_stable(&self, mir::StatementKind::EndRegion(ref region_scope) => { region_scope.hash_stable(hcx, hasher); } + mir::StatementKind::EscapeToRaw(ref place) => { + place.hash_stable(hcx, hasher); + } mir::StatementKind::Retag { fn_entry, ref place } => { fn_entry.hash_stable(hcx, hasher); place.hash_stable(hcx, hasher); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 36bc2edcf58..0817c2e8bf2 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1766,6 +1766,13 @@ pub enum StatementKind<'tcx> { place: Place<'tcx>, }, + /// Escape the given reference to a raw pointer, so that it can be accessed + /// without precise provenance tracking. These statements are currently only interpreted + /// by miri and only generated when "-Z mir-emit-retag" is passed. + /// See + /// for more details. + EscapeToRaw(Operand<'tcx>), + /// Mark one terminating point of a region scope (i.e. static region). /// (The starting point(s) arise implicitly from borrows.) EndRegion(region::Scope), @@ -1827,6 +1834,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)), Retag { fn_entry, ref place } => write!(fmt, "Retag({}{:?})", if fn_entry { "[fn entry] " } else { "" }, place), + EscapeToRaw(ref place) => write!(fmt, "EscapeToRaw({:?})", place), StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place), StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place), SetDiscriminant { @@ -2968,6 +2976,7 @@ impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> { (StatementKind::StorageDead)(a), (StatementKind::InlineAsm) { asm, outputs, inputs }, (StatementKind::Retag) { fn_entry, place }, + (StatementKind::EscapeToRaw)(place), (StatementKind::EndRegion)(a), (StatementKind::AscribeUserType)(a, v, b), (StatementKind::Nop), diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index c130e047e47..2a994ee0509 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -385,6 +385,9 @@ fn super_statement(&mut self, location ); } + StatementKind::EscapeToRaw(ref $($mutability)* op) => { + self.visit_operand(op, location); + } StatementKind::StorageLive(ref $($mutability)* local) => { self.visit_local( local, @@ -1022,7 +1025,7 @@ pub enum MutatingUseContext<'tcx> { /// f(&mut x.y); /// Projection, - /// Retagging (updating the "Stacked Borrows" tag) + /// Retagging, a "Stacked Borrows" shadow state operation Retag, } diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs index c8c8e02bf05..8bda2c98594 100644 --- a/src/librustc_codegen_llvm/mir/statement.rs +++ b/src/librustc_codegen_llvm/mir/statement.rs @@ -105,8 +105,9 @@ pub fn codegen_statement(&mut self, bx } mir::StatementKind::FakeRead(..) | - mir::StatementKind::EndRegion(_) | + mir::StatementKind::EndRegion(..) | mir::StatementKind::Retag { .. } | + mir::StatementKind::EscapeToRaw { .. } | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Nop => bx, } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index d4f00ab3bb9..533b777d67d 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -601,6 +601,7 @@ fn visit_statement_entry( StatementKind::Nop | StatementKind::AscribeUserType(..) | StatementKind::Retag { .. } + | StatementKind::EscapeToRaw { .. } | StatementKind::StorageLive(..) => { // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant // to borrow check. diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index cfe03c2d1c7..576509c0fdd 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -137,6 +137,7 @@ fn visit_statement(&mut self, StatementKind::Nop | StatementKind::AscribeUserType(..) | StatementKind::Retag { .. } | + StatementKind::EscapeToRaw { .. } | StatementKind::StorageLive(..) => { // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant // to borrow check. diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 734ddbc3ab9..3c2301ba4a7 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1290,11 +1290,12 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca } } StatementKind::FakeRead(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) | StatementKind::InlineAsm { .. } | StatementKind::EndRegion(_) | StatementKind::Retag { .. } + | StatementKind::EscapeToRaw { .. } | StatementKind::Nop => {} } } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 69d2a89b5f2..811da9e1acc 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -339,6 +339,7 @@ fn statement_effect(&self, sets: &mut BlockSets, location: Location mir::StatementKind::SetDiscriminant { .. } | mir::StatementKind::StorageLive(..) | mir::StatementKind::Retag { .. } | + mir::StatementKind::EscapeToRaw { .. } | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Nop => {} diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 874e862de23..e6e165ef3de 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -301,8 +301,9 @@ fn gather_statement(&mut self, stmt: &Statement<'tcx>) { span_bug!(stmt.source_info.span, "SetDiscriminant should not exist during borrowck"); } - StatementKind::EndRegion(_) | + StatementKind::EndRegion(..) | StatementKind::Retag { .. } | + StatementKind::EscapeToRaw { .. } | StatementKind::AscribeUserType(..) | StatementKind::Nop => {} } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 06748d60e45..118539fc58e 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -44,28 +44,16 @@ pub fn cast( } Misc => { - let src_layout = src.layout; let src = self.read_immediate(src)?; - let src = if M::ENABLE_PTR_TRACKING_HOOKS && src_layout.ty.is_region_ptr() { - // The only `Misc` casts on references are those creating raw pointers. - assert!(dest.layout.ty.is_unsafe_ptr()); - // For the purpose of the "ptr tag hooks", treat this as creating - // a new, raw reference. - let place = self.ref_to_mplace(src)?; - self.create_ref(place, None)? - } else { - *src - }; - - if self.type_is_fat_ptr(src_layout.ty) { - match (src, self.type_is_fat_ptr(dest.layout.ty)) { + if self.type_is_fat_ptr(src.layout.ty) { + match (*src, self.type_is_fat_ptr(dest.layout.ty)) { // pointers to extern types (Immediate::Scalar(_),_) | // slices and trait objects to other slices/trait objects (Immediate::ScalarPair(..), true) => { // No change to immediate - self.write_immediate(src, dest)?; + self.write_immediate(*src, dest)?; } // slices and trait objects to thin pointers (dropping the metadata) (Immediate::ScalarPair(data, _), false) => { @@ -73,11 +61,11 @@ pub fn cast( } } } else { - match src_layout.variants { + match src.layout.variants { layout::Variants::Single { index } => { - if let Some(def) = src_layout.ty.ty_adt_def() { + if let Some(def) = src.layout.ty.ty_adt_def() { // Cast from a univariant enum - assert!(src_layout.is_zst()); + assert!(src.layout.is_zst()); let discr_val = def .discriminant_for_variant(*self.tcx, index) .val; @@ -90,8 +78,7 @@ pub fn cast( layout::Variants::NicheFilling { .. } => {}, } - let src = src.to_scalar()?; - let dest_val = self.cast_scalar(src, src_layout, dest.layout)?; + let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?; self.write_scalar(dest_val, dest)?; } } diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 27cf28ef41e..214ffd071cc 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -211,18 +211,6 @@ fn tag_new_allocation( kind: MemoryKind, ) -> EvalResult<'tcx, Pointer>; - /// Executed when evaluating the `&` operator: Creating a new reference. - /// This has the chance to adjust the tag. It should not change anything else! - /// `mutability` can be `None` in case a raw ptr is being created. - #[inline] - fn tag_reference( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - place: MPlaceTy<'tcx, Self::PointerTag>, - _mutability: Option, - ) -> EvalResult<'tcx, Scalar> { - Ok(place.ptr) - } - /// Executed when evaluating the `*` operator: Following a reference. /// This has the chance to adjust the tag. It should not change anything else! /// `mutability` can be `None` in case a raw ptr is being dereferenced. @@ -235,7 +223,7 @@ fn tag_dereference( Ok(place.ptr) } - /// Execute a validation operation + /// Execute a retagging operation #[inline] fn retag( _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, @@ -244,4 +232,13 @@ fn retag( ) -> EvalResult<'tcx> { Ok(()) } + + /// Execute an escape-to-raw operation + #[inline] + fn escape_to_raw( + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _ptr: OpTy<'tcx, Self::PointerTag>, + ) -> EvalResult<'tcx> { + Ok(()) + } } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 19430c85cf7..da62594cb22 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -151,6 +151,16 @@ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> { // it now must be aligned. self.to_scalar_ptr_align().0.to_ptr() } + + /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space. + /// This is the inverse of `ref_to_mplace`. + #[inline(always)] + pub fn to_ref(self) -> Immediate { + match self.meta { + None => Immediate::Scalar(self.ptr.into()), + Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), + } + } } impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { @@ -266,7 +276,7 @@ impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M> M::MemoryMap: AllocMap, Allocation)>, { /// Take a value, which represents a (thin or fat) reference, and make it a place. - /// Alignment is just based on the type. This is the inverse of `create_ref`. + /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. pub fn ref_to_mplace( &self, val: ImmTy<'tcx, M::PointerTag>, @@ -294,24 +304,6 @@ pub fn ref_to_mplace( Ok(mplace) } - /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space. - /// This is the inverse of `ref_to_mplace`. - /// `mutbl` indicates whether we are create a shared or mutable ref, or a raw pointer (`None`). - pub fn create_ref( - &mut self, - mut place: MPlaceTy<'tcx, M::PointerTag>, - mutbl: Option, - ) -> EvalResult<'tcx, Immediate> { - // Pointer tag tracking might want to adjust the tag - if M::ENABLE_PTR_TRACKING_HOOKS { - place.mplace.ptr = M::tag_reference(self, place, mutbl)? - } - Ok(match place.meta { - None => Immediate::Scalar(place.ptr.into()), - Some(meta) => Immediate::ScalarPair(place.ptr.into(), meta.into()), - }) - } - /// Offset a pointer to project to a field. Unlike place_field, this is always /// possible without allocating, so it can take &self. Also return the field's layout. /// This supports both struct and array fields. diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index db055204c0a..ac13e5982da 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -12,7 +12,7 @@ //! //! The main entry point is the `step` method. -use rustc::{hir, mir}; +use rustc::mir; use rustc::ty::layout::LayoutOf; use rustc::mir::interpret::{EvalResult, Scalar, PointerArithmetic}; @@ -118,12 +118,17 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> { // interpreter is solely intended for borrowck'ed code. FakeRead(..) => {} - // Retagging. + // Stacked Borrows. Retag { fn_entry, ref place } => { let dest = self.eval_place(place)?; M::retag(self, fn_entry, dest)?; } + EscapeToRaw(ref op) => { + let op = self.eval_operand(op, None)?; + M::escape_to_raw(self, op)?; + } + // Statements we do not track. EndRegion(..) => {} AscribeUserType(..) => {} @@ -247,19 +252,10 @@ fn eval_rvalue_into_place( )?; } - Ref(_, borrow_kind, ref place) => { + Ref(_, _, ref place) => { let src = self.eval_place(place)?; let val = self.force_allocation(src)?; - let mutbl = match borrow_kind { - mir::BorrowKind::Mut { .. } | - mir::BorrowKind::Unique => - hir::MutMutable, - mir::BorrowKind::Shared | - mir::BorrowKind::Shallow => - hir::MutImmutable, - }; - let val = self.create_ref(val, Some(mutbl))?; - self.write_immediate(val, dest)?; + self.write_immediate(val.to_ref(), dest)?; } NullaryOp(mir::NullOp::Box, _) => { diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index b5df625b302..4cd7ca8182e 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -447,10 +447,7 @@ fn drop_in_place( }; let arg = OpTy { - op: Operand::Immediate(self.create_ref( - place, - None // this is a "raw reference" - )?), + op: Operand::Immediate(place.to_ref()), layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?, }; diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index a50011cf5a1..0be91c3c339 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -20,20 +20,22 @@ pub struct AddRetag; -/// Determines whether this place is local: If it is part of a local variable. -/// We do not consider writes to pointers local, only writes that immediately assign -/// to a local variable. -/// One important property here is that evaluating the place immediately after -/// the assignment must produce the same place as what was used during the assignment. -fn is_local<'tcx>( +/// Determines whether this place is "stable": Whether, if we evaluate it again +/// after the assignment, we can be sure to obtain the same place value. +/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic +/// copies. Data races are UB.) +fn is_stable<'tcx>( place: &Place<'tcx>, ) -> bool { use rustc::mir::Place::*; match *place { - Local { .. } => true, - Promoted(_) | - Static(_) => false, + // Locals and statics have stable addresses, for sure + Local { .. } | + Promoted { .. } | + Static { .. } => + true, + // Recurse for projections Projection(ref proj) => { match proj.elem { ProjectionElem::Deref | @@ -47,15 +49,15 @@ fn is_local<'tcx>( ProjectionElem::Subslice { .. } | ProjectionElem::Downcast { .. } => // These just offset by a constant, entirely independent of everything else. - is_local(&proj.base), + is_stable(&proj.base), } } } } -/// Determine whether this type has a reference in it, recursing below compound types but +/// Determine whether this type may have a reference in it, recursing below compound types but /// not below references. -fn has_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { +fn may_have_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { match ty.sty { // Primitive types that are not references ty::Bool | ty::Char | @@ -68,12 +70,12 @@ fn has_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> b ty::Adt(..) if ty.is_box() => true, // Compound types ty::Array(ty, ..) | ty::Slice(ty) => - has_reference(ty, tcx), + may_have_reference(ty, tcx), ty::Tuple(tys) => - tys.iter().any(|ty| has_reference(ty, tcx)), + tys.iter().any(|ty| may_have_reference(ty, tcx)), ty::Adt(adt, substs) => adt.variants.iter().any(|v| v.fields.iter().any(|f| - has_reference(f.ty(tcx, substs), tcx) + may_have_reference(f.ty(tcx, substs), tcx) )), // Conservative fallback _ => true, @@ -92,7 +94,9 @@ fn run_pass<'a, 'tcx>(&self, let (span, arg_count) = (mir.span, mir.arg_count); let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut(); let needs_retag = |place: &Place<'tcx>| { - is_local(place) && has_reference(place.ty(&*local_decls, tcx).to_ty(tcx), tcx) + // FIXME: Instead of giving up for unstable places, we should introduce + // a temporary and retag on that. + is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).to_ty(tcx), tcx) }; // PART 1 @@ -118,23 +122,29 @@ fn run_pass<'a, 'tcx>(&self, } // PART 2 - // Retag return values of functions. + // Retag return values of functions. Also escape-to-raw the argument of `drop`. // We collect the return destinations because we cannot mutate while iterating. let mut returns: Vec<(SourceInfo, Place<'tcx>, BasicBlock)> = Vec::new(); for block_data in basic_blocks.iter_mut() { - match block_data.terminator { - Some(Terminator { kind: TerminatorKind::Call { ref destination, .. }, - source_info }) => { + match block_data.terminator().kind { + TerminatorKind::Call { ref destination, .. } => { // Remember the return destination for later if let Some(ref destination) = destination { if needs_retag(&destination.0) { - returns.push((source_info, destination.0.clone(), destination.1)); + returns.push(( + block_data.terminator().source_info, + destination.0.clone(), + destination.1, + )); } } } + TerminatorKind::Drop { .. } | + TerminatorKind::DropAndReplace { .. } => { + // `Drop` is also a call, but it doesn't return anything so we are good. + } _ => { // Not a block ending in a Call -> ignore. - // `Drop` is also a call, but it doesn't return anything so we are good. } } } @@ -153,21 +163,43 @@ fn run_pass<'a, 'tcx>(&self, // iterate backwards using indices. for i in (0..block_data.statements.len()).rev() { match block_data.statements[i].kind { - // Assignments can make values obtained elsewhere "local". - // We could try to be smart here and e.g. only retag if the assignment - // loaded from memory, but that seems risky: We might miss a subtle corner - // case. - StatementKind::Assign(ref place, box Rvalue::Use(..)) - if needs_retag(place) => { + // If we are casting *from* a reference, we may have to escape-to-raw. + StatementKind::Assign(_, box Rvalue::Cast( + CastKind::Misc, + ref src, + dest_ty, + )) => { + let src_ty = src.ty(&*local_decls, tcx); + if src_ty.is_region_ptr() { + // The only `Misc` casts on references are those creating raw pointers. + assert!(dest_ty.is_unsafe_ptr()); + // Insert escape-to-raw before the cast. We are not concerned + // with stability here: Our EscapeToRaw will not change the value + // that the cast will then use. + // `src` might be a "move", but we rely on this not actually moving + // but just doing a memcpy. It is crucial that we do EscapeToRaw + // on the src because we need it with its original type. + let source_info = block_data.statements[i].source_info; + block_data.statements.insert(i, Statement { + source_info, + kind: StatementKind::EscapeToRaw(src.clone()), + }); + } + } + // Assignments of reference or ptr type are the ones where we may have + // to update tags. This includes `x = &[mut] ...` and hence + // we also retag after taking a reference! + StatementKind::Assign(ref place, _) if needs_retag(place) => { // Insert a retag after the assignment. let source_info = block_data.statements[i].source_info; - block_data.statements.insert(i+1,Statement { + block_data.statements.insert(i+1, Statement { source_info, kind: StatementKind::Retag { fn_entry: false, place: place.clone() }, }); } + // Do nothing for the rest _ => {}, - } + }; } } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index c28bb0ca357..4ebeebca227 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -114,6 +114,7 @@ fn visit_statement(&mut self, StatementKind::StorageDead(..) | StatementKind::EndRegion(..) | StatementKind::Retag { .. } | + StatementKind::EscapeToRaw { .. } | StatementKind::AscribeUserType(..) | StatementKind::Nop => { // safe (at least as emitted during MIR construction) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ca9c4eb9b8b..5fd83321296 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1168,6 +1168,7 @@ fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, locat StatementKind::InlineAsm {..} | StatementKind::EndRegion(_) | StatementKind::Retag { .. } | + StatementKind::EscapeToRaw { .. } | StatementKind::AscribeUserType(..) | StatementKind::Nop => {} } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 1e193485950..ed13063cfdf 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -242,6 +242,7 @@ fn check_statement( | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Retag { .. } + | StatementKind::EscapeToRaw { .. } | StatementKind::EndRegion(_) | StatementKind::AscribeUserType(..) | StatementKind::Nop => Ok(()), diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index c1c127fa8d6..445ffbbcf34 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -65,10 +65,11 @@ fn is_nop_landing_pad( // turn a landing pad to a non-nop } - StatementKind::Assign(_, _) | + StatementKind::Assign { .. } | StatementKind::SetDiscriminant { .. } | StatementKind::InlineAsm { .. } | - StatementKind::Retag { .. } => { + StatementKind::Retag { .. } | + StatementKind::EscapeToRaw { .. } => { return false; } } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index a5a19f04b7e..8f026c706fd 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -163,6 +163,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir::StatementKind::InlineAsm { .. } | mir::StatementKind::EndRegion(_) | mir::StatementKind::Retag { .. } | + mir::StatementKind::EscapeToRaw { .. } | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Nop => continue, mir::StatementKind::SetDiscriminant{ .. } => diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index ecfe7d13782..68840ed4a48 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -85,6 +85,7 @@ fn visit_statement(&mut self, StatementKind::FakeRead(..) => "StatementKind::FakeRead", StatementKind::EndRegion(..) => "StatementKind::EndRegion", StatementKind::Retag { .. } => "StatementKind::Retag", + StatementKind::EscapeToRaw { .. } => "StatementKind::EscapeToRaw", StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant", StatementKind::StorageLive(..) => "StatementKind::StorageLive", StatementKind::StorageDead(..) => "StatementKind::StorageDead", diff --git a/src/test/mir-opt/inline-retag.rs b/src/test/mir-opt/inline-retag.rs index 4b3280ee561..1e5e1ad5ed1 100644 --- a/src/test/mir-opt/inline-retag.rs +++ b/src/test/mir-opt/inline-retag.rs @@ -32,6 +32,8 @@ fn bar() -> bool { // bb0: { // ... // Retag(_3); +// ... +// Retag(_3); // Retag(_6); // StorageLive(_9); // _9 = (*_3); diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 9c013008ab2..7da55c0868c 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -26,7 +26,9 @@ fn main() { { let v = Test(0).foo(&mut x); // just making sure we do not panic when there is a tuple struct ctor let w = { v }; // assignment - let _w = w; // reborrow + let w = w; // reborrow + // escape-to-raw (mut) + let _w = w as *mut _; } // Also test closures @@ -35,6 +37,9 @@ fn main() { // need to call `foo_shr` or it doesn't even get generated Test(0).foo_shr(&0); + + // escape-to-raw (shr) + let _w = _w as *const _; } // END RUST SOURCE @@ -44,6 +49,7 @@ fn main() { // Retag([fn entry] _2); // ... // _0 = &mut (*_3); +// Retag(_0); // ... // return; // } @@ -73,23 +79,36 @@ fn main() { // _9 = move _3; // Retag(_9); // _8 = &mut (*_9); +// Retag(_8); // StorageDead(_9); // StorageLive(_10); // _10 = move _8; // Retag(_10); // ... -// _13 = move _14(move _15) -> bb2; +// _14 = &mut (*_10); +// Retag(_14); +// EscapeToRaw(move _14); +// _13 = move _14 as *mut i32 (Misc); +// ... +// _17 = move _18(move _19) -> bb2; // } // // bb2: { -// Retag(_13); +// Retag(_17); // ... +// _21 = const Test::foo_shr(move _22, move _24) -> bb3; // } +// +// bb3: { +// ... +// return; +// } +// // ... // } // END rustc.main.EraseRegions.after.mir // START rustc.main-{{closure}}.EraseRegions.after.mir -// fn main::{{closure}}(_1: &[closure@NodeId(117)], _2: &i32) -> &i32 { +// fn main::{{closure}}(_1: &[closure@NodeId(124)], _2: &i32) -> &i32 { // ... // bb0: { // Retag([fn entry] _1); From b9a35dcb49dbc69b484bc97f807715c218a9ecbf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Nov 2018 11:10:03 +0100 Subject: [PATCH 2/6] calling the ptr hooks no longer needs expensive preparation, remove the opt-out --- src/librustc_mir/const_eval.rs | 1 - src/librustc_mir/interpret/machine.rs | 5 ----- src/librustc_mir/interpret/place.rs | 18 ++++++++---------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 011887090ee..cbcc6709c01 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -351,7 +351,6 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> type MemoryMap = FxHashMap, Allocation)>; const STATIC_KIND: Option = None; // no copying of statics allowed - const ENABLE_PTR_TRACKING_HOOKS: bool = false; // we don't have no provenance #[inline(always)] fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 214ffd071cc..55da12a68e3 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -95,11 +95,6 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// that is added to the memory so that the work is not done twice. const STATIC_KIND: Option; - /// As an optimization, you can prevent the pointer tracking hooks from ever being - /// called. You should only do this if you do not care about provenance tracking. - /// This controls the `tag_reference` and `tag_dereference` hooks. - const ENABLE_PTR_TRACKING_HOOKS: bool; - /// Whether to enforce the validity invariant fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index da62594cb22..d52250a43ac 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -290,16 +290,14 @@ pub fn ref_to_mplace( let mplace = MemPlace { ptr, align, meta }; let mut mplace = MPlaceTy { mplace, layout }; // Pointer tag tracking might want to adjust the tag. - if M::ENABLE_PTR_TRACKING_HOOKS { - let mutbl = match val.layout.ty.sty { - // `builtin_deref` considers boxes immutable, that's useless for our purposes - ty::Ref(_, _, mutbl) => Some(mutbl), - ty::Adt(def, _) if def.is_box() => Some(hir::MutMutable), - ty::RawPtr(_) => None, - _ => bug!("Unexpected pointer type {}", val.layout.ty.sty), - }; - mplace.mplace.ptr = M::tag_dereference(self, mplace, mutbl)?; - } + let mutbl = match val.layout.ty.sty { + // `builtin_deref` considers boxes immutable, that's useless for our purposes + ty::Ref(_, _, mutbl) => Some(mutbl), + ty::Adt(def, _) if def.is_box() => Some(hir::MutMutable), + ty::RawPtr(_) => None, + _ => bug!("Unexpected pointer type {}", val.layout.ty.sty), + }; + mplace.mplace.ptr = M::tag_dereference(self, mplace, mutbl)?; // Done Ok(mplace) } From f174099885fed58c8053cf02bf353b6822897b75 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Nov 2018 18:10:15 +0100 Subject: [PATCH 3/6] array index accesses are stable places --- src/librustc_mir/build/expr/as_place.rs | 3 ++ src/librustc_mir/transform/add_retag.rs | 14 ++++--- src/test/mir-opt/array-index-is-temporary.rs | 43 ++++++++++++++++++++ 3 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/test/mir-opt/array-index-is-temporary.rs diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 77746e5538d..cb3c88876a3 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -86,6 +86,9 @@ fn expr_as_place( // region_scope=None so place indexes live forever. They are scalars so they // do not need storage annotations, and they are often copied between // places. + // Making this a *fresh* temporary also means we do not have to worry about + // the index changing later: Nothing will ever change this temporary. + // The "retagging" transformation (for Stacked Borrows) relies on this. let idx = unpack!(block = this.as_temp(block, None, index, Mutability::Mut)); // bounds check: diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index 0be91c3c339..be7e34e2dcb 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -38,17 +38,19 @@ fn is_stable<'tcx>( // Recurse for projections Projection(ref proj) => { match proj.elem { - ProjectionElem::Deref | - ProjectionElem::Index(_) => - // Which place these point to depends on external circumstances - // (a local storing the array index, the current value of - // the projection base), so we stop tracking here. + // Which place this evaluates to can change with any memory write, + // so cannot assume this to be stable. + ProjectionElem::Deref => false, + // Array indices are intersting, but MIR building generates a *fresh* + // temporary for every array access, so the index cannot be changed as + // a side-effect. + ProjectionElem::Index { .. } | + // The rest is completely boring, they just offset by a constant. ProjectionElem::Field { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast { .. } => - // These just offset by a constant, entirely independent of everything else. is_stable(&proj.base), } } diff --git a/src/test/mir-opt/array-index-is-temporary.rs b/src/test/mir-opt/array-index-is-temporary.rs new file mode 100644 index 00000000000..856e1063f60 --- /dev/null +++ b/src/test/mir-opt/array-index-is-temporary.rs @@ -0,0 +1,43 @@ +// Retagging (from Stacked Borrows) relies on the array index being a fresh +// temporary, so that side-effects cannot change it. +// Test that this is indeed the case. + +unsafe fn foo(z: *mut usize) -> u32 { + *z = 2; + 99 +} + +fn main() { + let mut x = [42, 43, 44]; + let mut y = 1; + let z: *mut usize = &mut y; + x[y] = unsafe { foo(z) }; +} + +// END RUST SOURCE +// START rustc.main.EraseRegions.after.mir +// bb0: { +// ... +// _6 = &mut _2; +// _5 = &mut (*_6); +// _4 = move _5 as *mut usize (Misc); +// _3 = move _4; +// ... +// _8 = _3; +// _7 = const foo(move _8) -> bb1; +// } +// +// bb1: { +// ... +// _9 = _2; +// _10 = Len(_1); +// _11 = Lt(_9, _10); +// assert(move _11, "index out of bounds: the len is move _10 but the index is _9") -> bb2; +// } +// +// bb2: { +// _1[_9] = move _7; +// ... +// return; +// } +// END rustc.main.EraseRegions.after.mir From 154835e5e70ff4e735c8a344a9c13c63433eb670 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 10:07:50 +0100 Subject: [PATCH 4/6] only count deref_operand as actual deref, but not all ref-to-place conversions --- src/librustc_mir/interpret/intrinsics.rs | 14 +++++------ src/librustc_mir/interpret/operand.rs | 11 --------- src/librustc_mir/interpret/place.rs | 31 ++++++++++++++++++------ src/librustc_mir/interpret/terminator.rs | 2 +- src/librustc_mir/interpret/validity.rs | 5 +--- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index cb2a750f4e3..7c704e97911 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -183,8 +183,7 @@ pub fn hook_fn( } else if Some(def_id) == self.tcx.lang_items().panic_fn() { assert!(args.len() == 1); // &(&'static str, &'static str, u32, u32) - let ptr = self.read_immediate(args[0])?; - let place = self.ref_to_mplace(ptr)?; + let place = self.deref_operand(args[0])?; let (msg, file, line, col) = ( self.mplace_field(place, 0)?, self.mplace_field(place, 1)?, @@ -192,9 +191,9 @@ pub fn hook_fn( self.mplace_field(place, 3)?, ); - let msg_place = self.ref_to_mplace(self.read_immediate(msg.into())?)?; + let msg_place = self.deref_operand(msg.into())?; let msg = Symbol::intern(self.read_str(msg_place)?); - let file_place = self.ref_to_mplace(self.read_immediate(file.into())?)?; + let file_place = self.deref_operand(file.into())?; let file = Symbol::intern(self.read_str(file_place)?); let line = self.read_scalar(line.into())?.to_u32()?; let col = self.read_scalar(col.into())?.to_u32()?; @@ -203,17 +202,16 @@ pub fn hook_fn( assert!(args.len() == 2); // &'static str, &(&'static str, u32, u32) let msg = args[0]; - let ptr = self.read_immediate(args[1])?; - let place = self.ref_to_mplace(ptr)?; + let place = self.deref_operand(args[1])?; let (file, line, col) = ( self.mplace_field(place, 0)?, self.mplace_field(place, 1)?, self.mplace_field(place, 2)?, ); - let msg_place = self.ref_to_mplace(self.read_immediate(msg.into())?)?; + let msg_place = self.deref_operand(msg.into())?; let msg = Symbol::intern(self.read_str(msg_place)?); - let file_place = self.ref_to_mplace(self.read_immediate(file.into())?)?; + let file_place = self.deref_operand(file.into())?; let file = Symbol::intern(self.read_str(file_place)?); let line = self.read_scalar(line.into())?.to_u32()?; let col = self.read_scalar(col.into())?.to_u32()?; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 83a2d14b7ca..a97bf95e734 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -555,17 +555,6 @@ pub fn operand_downcast( }) } - // Take an operand, representing a pointer, and dereference it to a place -- that - // will always be a MemPlace. - pub(super) fn deref_operand( - &self, - src: OpTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let val = self.read_immediate(src)?; - trace!("deref to {} on {:?}", val.layout.ty, *val); - Ok(self.ref_to_mplace(val)?) - } - pub fn operand_projection( &self, base: OpTy<'tcx, M::PointerTag>, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index d52250a43ac..510b5826e48 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -277,6 +277,8 @@ impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M> { /// Take a value, which represents a (thin or fat) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. + /// This does NOT call the "deref" machine hook, so it does NOT count as a + /// deref as far as Stacked Borrows is concerned. Use `deref_operand` for that! pub fn ref_to_mplace( &self, val: ImmTy<'tcx, M::PointerTag>, @@ -284,11 +286,25 @@ pub fn ref_to_mplace( let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty; let layout = self.layout_of(pointee_type)?; - let align = layout.align; - let meta = val.to_meta()?; - let ptr = val.to_scalar_ptr()?; - let mplace = MemPlace { ptr, align, meta }; - let mut mplace = MPlaceTy { mplace, layout }; + let mplace = MemPlace { + ptr: val.to_scalar_ptr()?, + align: layout.align, + meta: val.to_meta()?, + }; + Ok(MPlaceTy { mplace, layout }) + } + + // Take an operand, representing a pointer, and dereference it to a place -- that + // will always be a MemPlace. Lives in `place.rs` because it creates a place. + // This calls the "deref" machine hook, and counts as a deref as far as + // Stacked Borrows is concerned. + pub fn deref_operand( + &self, + src: OpTy<'tcx, M::PointerTag>, + ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let val = self.read_immediate(src)?; + trace!("deref to {} on {:?}", val.layout.ty, *val); + let mut place = self.ref_to_mplace(val)?; // Pointer tag tracking might want to adjust the tag. let mutbl = match val.layout.ty.sty { // `builtin_deref` considers boxes immutable, that's useless for our purposes @@ -297,9 +313,8 @@ pub fn ref_to_mplace( ty::RawPtr(_) => None, _ => bug!("Unexpected pointer type {}", val.layout.ty.sty), }; - mplace.mplace.ptr = M::tag_dereference(self, mplace, mutbl)?; - // Done - Ok(mplace) + place.mplace.ptr = M::tag_dereference(self, place, mutbl)?; + Ok(place) } /// Offset a pointer to project to a field. Unlike place_field, this is always diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 4cd7ca8182e..6070b31d3e7 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -402,7 +402,7 @@ fn eval_fn_call( ty::InstanceDef::Virtual(_, idx) => { let ptr_size = self.pointer_size(); let ptr_align = self.tcx.data_layout.pointer_align; - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; let vtable = ptr.vtable()?; let fn_ptr = self.memory.read_ptr_sized( vtable.offset(ptr_size * (idx as u64 + 3), self)?, diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 8c8b3e2ca77..97bce651c05 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -322,13 +322,10 @@ fn visit_primitive(&mut self, value: ImmTy<'tcx, M::PointerTag>) -> EvalResult<' } } } - // Turn ptr into place. - // `ref_to_mplace` also calls the machine hook for (re)activating the tag, - // which in turn will (in full miri) check if the pointer is dereferencable. - let place = self.ecx.ref_to_mplace(value)?; // Recursive checking if let Some(ref mut ref_tracking) = self.ref_tracking { assert!(self.const_mode, "We should only do recursie checking in const mode"); + let place = self.ecx.ref_to_mplace(value)?; if size != Size::ZERO { // Non-ZST also have to be dereferencable let ptr = try_validation!(place.ptr.to_ptr(), From 9e3f571cc348e8d2004bb9ffc215bf27133e3552 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 12:21:28 +0100 Subject: [PATCH 5/6] drop glue works with raw ptrs, it must EscapeToRaw --- src/librustc_mir/shim.rs | 10 +++++++++- src/librustc_mir/transform/generator.rs | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 76a8501fb17..7705396b383 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -222,6 +222,14 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ); if let Some(..) = ty { + let dropee_ptr = Place::Local(Local::new(1+0)); + if tcx.sess.opts.debugging_opts.mir_emit_retag { + // We use raw ptr operations, better prepare the alias tracking for that + mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { + source_info, + kind: StatementKind::EscapeToRaw(Operand::Copy(dropee_ptr.clone())), + }) + } let patch = { let param_env = tcx.param_env(def_id).with_reveal_all(); let mut elaborator = DropShimElaborator { @@ -230,7 +238,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx, param_env }; - let dropee = Place::Local(Local::new(1+0)).deref(); + let dropee = dropee_ptr.deref(); let resume_block = elaborator.patch.resume_block(); elaborate_drops::elaborate_drop( &mut elaborator, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 5889fabee9d..a292887b17e 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -684,6 +684,13 @@ fn create_generator_drop_shim<'a, 'tcx>( is_block_tail: None, is_user_variable: None, }; + if tcx.sess.opts.debugging_opts.mir_emit_retag { + // Alias tracking must know we changed the type + mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { + source_info, + kind: StatementKind::EscapeToRaw(Operand::Copy(Place::Local(self_arg()))), + }) + } no_landing_pads(tcx, &mut mir); From b891a81164e86fa21f55607bc56b0b8e04083936 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 15:36:36 +0100 Subject: [PATCH 6/6] comment --- src/librustc_mir/shim.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 7705396b383..2d548dd8cf1 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -222,6 +222,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ); if let Some(..) = ty { + // The first argument (index 0), but add 1 for the return value. let dropee_ptr = Place::Local(Local::new(1+0)); if tcx.sess.opts.debugging_opts.mir_emit_retag { // We use raw ptr operations, better prepare the alias tracking for that