diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 8aee019e99494..6ce10672a6145 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -757,14 +757,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } - StatementKind::PlaceMention(..) => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`PlaceMention` should have been removed after drop lowering phase", - ); - } - } StatementKind::AscribeUserType(..) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( @@ -874,6 +866,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { StatementKind::StorageDead(_) | StatementKind::Coverage(_) | StatementKind::ConstEvalCounter + | StatementKind::PlaceMention(..) | StatementKind::Nop => {} } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index f5d44d239e034..7b0b5102c2db6 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -768,6 +768,7 @@ fn test_unstable_options_tracking_hash() { tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(mir_emit_retag, true); tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]); + tracked!(mir_keep_place_mention, true); tracked!(mir_opt_level, Some(4)); tracked!(move_size_limit, Some(4096)); tracked!(mutable_noalias, false); diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 303c120f795cf..306cb4fa5ed0d 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -333,8 +333,6 @@ pub enum StatementKind<'tcx> { /// /// When executed at runtime, this computes the given place, but then discards /// it without doing a load. It is UB if the place is not pointing to live memory. - /// - /// Disallowed after drop elaboration. PlaceMention(Box>), /// Encodes a user's type ascription. These need to be preserved diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 0923824db4888..d435d3ee69b76 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -24,7 +24,6 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck { for statement in basic_block.statements.iter_mut() { match statement.kind { StatementKind::AscribeUserType(..) - | StatementKind::PlaceMention(..) | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _))) | StatementKind::FakeRead(..) => statement.make_nop(), _ => (), diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 18c407b42d373..7bc5183a00a82 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -54,11 +54,10 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS | StatementKind::Coverage(_) | StatementKind::Intrinsic(_) | StatementKind::ConstEvalCounter + | StatementKind::PlaceMention(_) | StatementKind::Nop => (), - StatementKind::FakeRead(_) - | StatementKind::PlaceMention(_) - | StatementKind::AscribeUserType(_, _) => { + StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { bug!("{:?} not found in this MIR phase!", &statement.kind) } } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 5a842714e5dad..78758e2db28ab 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -582,10 +582,9 @@ impl WriteInfo { | StatementKind::Nop | StatementKind::Coverage(_) | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) => (), - StatementKind::FakeRead(_) - | StatementKind::AscribeUserType(_, _) - | StatementKind::PlaceMention(_) => { + | StatementKind::StorageDead(_) + | StatementKind::PlaceMention(_) => (), + StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { bug!("{:?} not found in this MIR phase", statement) } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 7a2420a6d940d..03e9fdef56ee5 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -48,6 +48,7 @@ mod add_retag; mod check_const_item_mutation; mod check_packed_ref; pub mod check_unsafety; +mod remove_place_mention; // This pass is public to allow external drivers to perform MIR cleanup pub mod cleanup_post_borrowck; mod const_debuginfo; @@ -460,8 +461,11 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { /// Returns the sequence of passes that do the initial cleanup of runtime MIR. fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let passes: &[&dyn MirPass<'tcx>] = - &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::ElaborateDrops]; + let passes: &[&dyn MirPass<'tcx>] = &[ + &lower_intrinsics::LowerIntrinsics, + &remove_place_mention::RemovePlaceMention, + &simplify::SimplifyCfg::ElaborateDrops, + ]; pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup))); diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs new file mode 100644 index 0000000000000..8be1c37572d14 --- /dev/null +++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs @@ -0,0 +1,23 @@ +//! This pass removes `PlaceMention` statement, which has no effect at codegen. + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct RemovePlaceMention; + +impl<'tcx> MirPass<'tcx> for RemovePlaceMention { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + !sess.opts.unstable_opts.mir_keep_place_mention + } + + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("Running RemovePlaceMention on {:?}", body.source); + for data in body.basic_blocks.as_mut_preserves_cfg() { + data.statements.retain(|statement| match statement.kind { + StatementKind::PlaceMention(..) | StatementKind::Nop => false, + _ => true, + }) + } + } +} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8e8ad72ec8a3f..d9f03fe14072e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1558,6 +1558,9 @@ options! { "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \ enabled, overriding all other checks. Passes that are not specified are enabled or \ disabled by other flags as usual."), + mir_keep_place_mention: bool = (false, parse_bool, [TRACKED], + "keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ + (default: no)"), #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")] mir_opt_level: Option = (None, parse_opt_number, [TRACKED], "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index f67a718ba73a9..fc938080a0efd 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -130,6 +130,7 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[ "-Zalways-encode-mir", "-Zextra-const-ub-checks", "-Zmir-emit-retag", + "-Zmir-keep-place-mention", "-Zmir-opt-level=0", "-Zmir-enable-passes=-CheckAlignment", ]; diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.rs index 3b2aba67a686c..7c5f440b774f2 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.rs @@ -6,6 +6,8 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let _ = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed + unsafe { + let _ = *p; //~ ERROR: dereferenced after this allocation got freed + } panic!("this should never print"); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.stderr index e047c3287b558..7b76389c75359 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_underscore.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dangling_pointer_deref_underscore.rs:LL:CC | -LL | let _ = unsafe { *p }; - | ^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | let _ = *p; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information