Skip to content

Commit 21fab43

Browse files
committed
Auto merge of #104844 - cjgillot:mention-eval-place, r=jackh726,RalfJung
Evaluate place expression in `PlaceMention` #102256 introduces a `PlaceMention(place)` MIR statement which keep trace of `let _ = place` statements from surface rust, but without semantics. This PR proposes to change the behaviour of `let _ =` patterns with respect to the borrow-checker to verify that the bound place is live. Specifically, consider this code: ```rust let _ = { let a = 5; &a }; ``` This passes borrowck without error on stable. Meanwhile, replacing `_` by `_: _` or `_p` errors with "error[E0597]: `a` does not live long enough", [see playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c448d25a7c205dc95a0967fe96bccce8). This PR *does not* change how `_` patterns behave with respect to initializedness: it remains ok to bind a moved-from place to `_`. The relevant test is `tests/ui/borrowck/let_underscore_temporary.rs`. Crater check found no regression. For consistency, this PR changes miri to evaluate the place found in `PlaceMention`, and report eventual dangling pointers found within it. r? `@RalfJung`
2 parents ccb6290 + 2870d26 commit 21fab43

File tree

22 files changed

+201
-39
lines changed

22 files changed

+201
-39
lines changed

compiler/rustc_borrowck/src/def_use.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,16 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
5252
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
5353
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
5454

55+
// `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
56+
// contain dangling references.
57+
PlaceContext::NonUse(NonUseContext::PlaceMention) |
58+
PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
59+
5560
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
5661
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
5762
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
5863
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
5964
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
60-
PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
6165
PlaceContext::MutatingUse(MutatingUseContext::Retag) =>
6266
Some(DefUse::Use),
6367

@@ -72,8 +76,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
7276
PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
7377
Some(DefUse::Drop),
7478

75-
// This statement exists to help unsafeck. It does not require the place to be live.
76-
PlaceContext::NonUse(NonUseContext::PlaceMention) => None,
7779
// Debug info is neither def nor use.
7880
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
7981

compiler/rustc_borrowck/src/invalidation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
7979
}
8080
// Only relevant for mir typeck
8181
StatementKind::AscribeUserType(..)
82-
// Only relevant for unsafeck
82+
// Only relevant for liveness and unsafeck
8383
| StatementKind::PlaceMention(..)
8484
// Doesn't have any language semantics
8585
| StatementKind::Coverage(..)

compiler/rustc_borrowck/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
665665
}
666666
// Only relevant for mir typeck
667667
StatementKind::AscribeUserType(..)
668-
// Only relevant for unsafeck
668+
// Only relevant for liveness and unsafeck
669669
| StatementKind::PlaceMention(..)
670670
// Doesn't have any language semantics
671671
| StatementKind::Coverage(..)

compiler/rustc_const_eval/src/interpret/step.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
113113

114114
Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
115115

116-
// Statements we do not track.
117-
PlaceMention(..) | AscribeUserType(..) => {}
116+
// Evaluate the place expression, without reading from it.
117+
PlaceMention(box place) => {
118+
let _ = self.eval_place(*place)?;
119+
}
120+
121+
// This exists purely to guide borrowck lifetime inference, and does not have
122+
// an operational effect.
123+
AscribeUserType(..) => {}
118124

119125
// Currently, Miri discards Coverage statements. Coverage statements are only injected
120126
// via an optional compile time MIR pass and have no side effects. Since Coverage

compiler/rustc_const_eval/src/transform/validate.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -802,14 +802,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
802802
}
803803
}
804804
}
805-
StatementKind::PlaceMention(..) => {
806-
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
807-
self.fail(
808-
location,
809-
"`PlaceMention` should have been removed after drop lowering phase",
810-
);
811-
}
812-
}
813805
StatementKind::AscribeUserType(..) => {
814806
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
815807
self.fail(
@@ -919,6 +911,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
919911
StatementKind::StorageDead(_)
920912
| StatementKind::Coverage(_)
921913
| StatementKind::ConstEvalCounter
914+
| StatementKind::PlaceMention(..)
922915
| StatementKind::Nop => {}
923916
}
924917

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,7 @@ fn test_unstable_options_tracking_hash() {
768768
tracked!(merge_functions, Some(MergeFunctions::Disabled));
769769
tracked!(mir_emit_retag, true);
770770
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
771+
tracked!(mir_keep_place_mention, true);
771772
tracked!(mir_opt_level, Some(4));
772773
tracked!(move_size_limit, Some(4096));
773774
tracked!(mutable_noalias, false);

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,8 @@ pub enum StatementKind<'tcx> {
331331
/// This is especially useful for `let _ = PLACE;` bindings that desugar to a single
332332
/// `PlaceMention(PLACE)`.
333333
///
334-
/// When executed at runtime this is a nop.
335-
///
336-
/// Disallowed after drop elaboration.
334+
/// When executed at runtime, this computes the given place, but then discards
335+
/// it without doing a load. It is UB if the place is not pointing to live memory.
337336
PlaceMention(Box<Place<'tcx>>),
338337

339338
/// Encodes a user's type ascription. These need to be preserved

compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
2424
for statement in basic_block.statements.iter_mut() {
2525
match statement.kind {
2626
StatementKind::AscribeUserType(..)
27-
| StatementKind::PlaceMention(..)
2827
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
2928
| StatementKind::FakeRead(..) => statement.make_nop(),
3029
_ => (),

compiler/rustc_mir_transform/src/dead_store_elimination.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,10 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
5454
| StatementKind::Coverage(_)
5555
| StatementKind::Intrinsic(_)
5656
| StatementKind::ConstEvalCounter
57+
| StatementKind::PlaceMention(_)
5758
| StatementKind::Nop => (),
5859

59-
StatementKind::FakeRead(_)
60-
| StatementKind::PlaceMention(_)
61-
| StatementKind::AscribeUserType(_, _) => {
60+
StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
6261
bug!("{:?} not found in this MIR phase!", &statement.kind)
6362
}
6463
}

compiler/rustc_mir_transform/src/dest_prop.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,10 +582,9 @@ impl WriteInfo {
582582
| StatementKind::Nop
583583
| StatementKind::Coverage(_)
584584
| StatementKind::StorageLive(_)
585-
| StatementKind::StorageDead(_) => (),
586-
StatementKind::FakeRead(_)
587-
| StatementKind::AscribeUserType(_, _)
588-
| StatementKind::PlaceMention(_) => {
585+
| StatementKind::StorageDead(_)
586+
| StatementKind::PlaceMention(_) => (),
587+
StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
589588
bug!("{:?} not found in this MIR phase", statement)
590589
}
591590
}

0 commit comments

Comments
 (0)