Skip to content

Commit 3b64fe9

Browse files
committedMay 21, 2022
Auto merge of rust-lang#96923 - eholk:fix-fake-read, r=nikomatsakis
Drop Tracking: Implement `fake_read` callback This PR updates drop tracking's use of `ExprUseVisitor` so that we treat `fake_read` events as borrows. Without doing this, we were not handling match expressions correctly, which showed up as a breakage in the `addassign-yield.rs` test. We did not previously notice this because we still had rather large temporary scopes that we held borrows for, which changed in rust-lang#94309. This PR also includes a variant of the `addassign-yield.rs` test case to make sure we continue to have correct behavior here with drop tracking. r? `@nikomatsakis`
2 parents 4a86c79 + bf21a81 commit 3b64fe9

File tree

9 files changed

+115
-47
lines changed

9 files changed

+115
-47
lines changed
 

‎compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs

+47-34
Original file line numberDiff line numberDiff line change
@@ -77,38 +77,8 @@ impl<'tcx> ExprUseDelegate<'tcx> {
7777
}
7878
self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
7979
}
80-
}
81-
82-
impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
83-
fn consume(
84-
&mut self,
85-
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
86-
diag_expr_id: HirId,
87-
) {
88-
let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) {
89-
Some(parent) => parent,
90-
None => place_with_id.hir_id,
91-
};
92-
debug!(
93-
"consume {:?}; diag_expr_id={:?}, using parent {:?}",
94-
place_with_id, diag_expr_id, parent
95-
);
96-
place_with_id
97-
.try_into()
98-
.map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
99-
}
100-
101-
fn borrow(
102-
&mut self,
103-
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
104-
diag_expr_id: HirId,
105-
bk: rustc_middle::ty::BorrowKind,
106-
) {
107-
debug!(
108-
"borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}, \
109-
borrow_kind={bk:?}"
110-
);
11180

81+
fn borrow_place(&mut self, place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>) {
11282
self.places
11383
.borrowed
11484
.insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
@@ -158,6 +128,40 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
158128
self.places.borrowed_temporaries.insert(place_with_id.hir_id);
159129
}
160130
}
131+
}
132+
133+
impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
134+
fn consume(
135+
&mut self,
136+
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
137+
diag_expr_id: HirId,
138+
) {
139+
let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) {
140+
Some(parent) => parent,
141+
None => place_with_id.hir_id,
142+
};
143+
debug!(
144+
"consume {:?}; diag_expr_id={:?}, using parent {:?}",
145+
place_with_id, diag_expr_id, parent
146+
);
147+
place_with_id
148+
.try_into()
149+
.map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
150+
}
151+
152+
fn borrow(
153+
&mut self,
154+
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
155+
diag_expr_id: HirId,
156+
bk: rustc_middle::ty::BorrowKind,
157+
) {
158+
debug!(
159+
"borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}, \
160+
borrow_kind={bk:?}"
161+
);
162+
163+
self.borrow_place(place_with_id);
164+
}
161165

162166
fn copy(
163167
&mut self,
@@ -208,9 +212,18 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
208212

209213
fn fake_read(
210214
&mut self,
211-
_place: expr_use_visitor::Place<'tcx>,
212-
_cause: rustc_middle::mir::FakeReadCause,
213-
_diag_expr_id: HirId,
215+
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
216+
cause: rustc_middle::mir::FakeReadCause,
217+
diag_expr_id: HirId,
214218
) {
219+
debug!(
220+
"fake_read place_with_id={place_with_id:?}; cause={cause:?}; diag_expr_id={diag_expr_id:?}"
221+
);
222+
223+
// fake reads happen in places like the scrutinee of a match expression.
224+
// we treat those as a borrow, much like a copy: the idea is that we are
225+
// transiently creating a `&T` ref that we can read from to observe the current
226+
// value (this `&T` is immediately dropped afterwards).
227+
self.borrow_place(place_with_id);
215228
}
216229
}

‎compiler/rustc_typeck/src/check/upvar.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1755,14 +1755,19 @@ struct InferBorrowKind<'a, 'tcx> {
17551755
}
17561756

17571757
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1758-
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
1759-
let PlaceBase::Upvar(_) = place.base else { return };
1758+
fn fake_read(
1759+
&mut self,
1760+
place: &PlaceWithHirId<'tcx>,
1761+
cause: FakeReadCause,
1762+
diag_expr_id: hir::HirId,
1763+
) {
1764+
let PlaceBase::Upvar(_) = place.place.base else { return };
17601765

17611766
// We need to restrict Fake Read precision to avoid fake reading unsafe code,
17621767
// such as deref of a raw pointer.
17631768
let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
17641769

1765-
let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
1770+
let (place, _) = restrict_capture_precision(place.place.clone(), dummy_capture_kind);
17661771

17671772
let (place, _) = restrict_repr_packed_field_ref_capture(
17681773
self.fcx.tcx,

‎compiler/rustc_typeck/src/expr_use_visitor.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ pub trait Delegate<'tcx> {
7070
}
7171

7272
/// The `place` should be a fake read because of specified `cause`.
73-
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
73+
fn fake_read(
74+
&mut self,
75+
place_with_id: &PlaceWithHirId<'tcx>,
76+
cause: FakeReadCause,
77+
diag_expr_id: hir::HirId,
78+
);
7479
}
7580

7681
#[derive(Copy, Clone, PartialEq, Debug)]
@@ -328,7 +333,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
328333
};
329334

330335
self.delegate.fake_read(
331-
discr_place.place.clone(),
336+
&discr_place,
332337
FakeReadCause::ForMatchedPlace(closure_def_id),
333338
discr_place.hir_id,
334339
);
@@ -618,7 +623,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
618623
};
619624

620625
self.delegate.fake_read(
621-
discr_place.place.clone(),
626+
discr_place,
622627
FakeReadCause::ForMatchedPlace(closure_def_id),
623628
discr_place.hir_id,
624629
);
@@ -642,7 +647,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
642647
};
643648

644649
self.delegate.fake_read(
645-
discr_place.place.clone(),
650+
discr_place,
646651
FakeReadCause::ForLet(closure_def_id),
647652
discr_place.hir_id,
648653
);
@@ -777,7 +782,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
777782
);
778783
}
779784
};
780-
self.delegate.fake_read(fake_read.clone(), *cause, *hir_id);
785+
self.delegate.fake_read(
786+
&PlaceWithHirId { place: fake_read.clone(), hir_id: *hir_id },
787+
*cause,
788+
*hir_id,
789+
);
781790
}
782791
}
783792

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// run-pass
2+
// compile-flags: -Zdrop-tracking
3+
4+
// Based on addassign-yield.rs, but with drop tracking enabled. Originally we did not implement
5+
// the fake_read callback on ExprUseVisitor which caused this case to break.
6+
7+
#![feature(generators)]
8+
9+
fn foo() {
10+
let _y = static || {
11+
let x = &mut 0;
12+
*{
13+
yield;
14+
x
15+
} += match String::new() {
16+
_ => 0,
17+
};
18+
};
19+
20+
// Please don't ever actually write something like this
21+
let _z = static || {
22+
let x = &mut 0;
23+
*{
24+
let inner = &mut 1;
25+
*{
26+
yield ();
27+
inner
28+
} += match String::new() {
29+
_ => 1,
30+
};
31+
yield;
32+
x
33+
} += match String::new() {
34+
_ => 2,
35+
};
36+
};
37+
}
38+
39+
fn main() {
40+
foo()
41+
}

‎src/tools/clippy/clippy_lints/src/escape.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
187187
}
188188
}
189189

190-
fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
190+
fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
191191
}
192192

193193
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {

‎src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
114114
}
115115
}
116116

117-
fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
117+
fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
118118
}
119119

120120
impl MutatePairDelegate<'_, '_> {

‎src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,5 +343,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
343343

344344
fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
345345

346-
fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
346+
fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
347347
}

‎src/tools/clippy/clippy_utils/src/sugg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
10331033

10341034
fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
10351035

1036-
fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
1036+
fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
10371037
}
10381038

10391039
#[cfg(test)]

‎src/tools/clippy/clippy_utils/src/usage.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
7474
self.update(cmt);
7575
}
7676

77-
fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
77+
fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
7878
}
7979

8080
pub struct ParamBindingIdCollector {

0 commit comments

Comments
 (0)
Please sign in to comment.