Skip to content

Commit c3cf93a

Browse files
committed
Fix diagnostic issue when using FakeReads in closures
1 parent cb473c2 commit c3cf93a

31 files changed

+120
-81
lines changed

compiler/rustc_middle/src/mir/mod.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -1470,7 +1470,7 @@ pub struct Statement<'tcx> {
14701470

14711471
// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
14721472
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
1473-
static_assert_size!(Statement<'_>, 32);
1473+
static_assert_size!(Statement<'_>, 40);
14741474

14751475
impl Statement<'_> {
14761476
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -1593,7 +1593,12 @@ pub enum FakeReadCause {
15931593

15941594
/// `let x: !; match x {}` doesn't generate any read of x so we need to
15951595
/// generate a read of x to check that it is initialized and safe.
1596-
ForMatchedPlace,
1596+
///
1597+
/// If a closure pattern matches a Place starting with an Upvar, then we introduce a
1598+
/// FakeRead for that Place outside the closure, in such a case this option would be
1599+
/// Some(closure_def_id).
1600+
/// Otherwise, the value of the optional DefId will be None.
1601+
ForMatchedPlace(Option<DefId>),
15971602

15981603
/// A fake read of the RefWithinGuard version of a bind-by-value variable
15991604
/// in a match guard to ensure that it's value hasn't change by the time
@@ -1612,7 +1617,12 @@ pub enum FakeReadCause {
16121617
/// but in some cases it can affect the borrow checker, as in #53695.
16131618
/// Therefore, we insert a "fake read" here to ensure that we get
16141619
/// appropriate errors.
1615-
ForLet,
1620+
///
1621+
/// If a closure pattern matches a Place starting with an Upvar, then we introduce a
1622+
/// FakeRead for that Place outside the closure, in such a case this option would be
1623+
/// Some(closure_def_id).
1624+
/// Otherwise, the value of the optional DefId will be None.
1625+
ForLet(Option<DefId>),
16161626

16171627
/// If we have an index expression like
16181628
///

compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
515515
let block = &self.body.basic_blocks()[location.block];
516516

517517
let kind = if let Some(&Statement {
518-
kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
518+
kind: StatementKind::FakeRead(FakeReadCause::ForLet(_), _),
519519
..
520520
}) = block.statements.get(location.statement_index)
521521
{

compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId;
77
use rustc_hir::lang_items::LangItemGroup;
88
use rustc_hir::GeneratorKind;
99
use rustc_middle::mir::{
10-
AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
11-
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
10+
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
11+
Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
1212
};
1313
use rustc_middle::ty::print::Print;
1414
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
@@ -794,6 +794,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
794794
}
795795
}
796796

797+
// StatementKind::FakeRead only contains a def_id if they are introduced as a result
798+
// of pattern matching within a closure.
799+
if let StatementKind::FakeRead(cause, box ref place) = stmt.kind {
800+
match cause {
801+
FakeReadCause::ForMatchedPlace(Some(closure_def_id))
802+
| FakeReadCause::ForLet(Some(closure_def_id)) => {
803+
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
804+
let places = &[Operand::Move(*place)];
805+
if let Some((args_span, generator_kind, var_span)) =
806+
self.closure_span(closure_def_id, moved_place, places)
807+
{
808+
return ClosureUse { generator_kind, args_span, var_span };
809+
}
810+
}
811+
_ => {}
812+
}
813+
}
814+
797815
let normal_ret =
798816
if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
799817
PatUse(stmt.source_info.span)

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+14-18
Original file line numberDiff line numberDiff line change
@@ -179,24 +179,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
179179
// match x { _ => () } // fake read of `x`
180180
// };
181181
// ```
182-
// FIXME(RFC2229): Remove feature gate once diagnostics are improved
183-
if this.tcx.features().capture_disjoint_fields {
184-
for (thir_place, cause, hir_id) in fake_reads.into_iter() {
185-
let place_builder =
186-
unpack!(block = this.as_place_builder(block, thir_place));
187-
188-
if let Ok(place_builder_resolved) =
189-
place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
190-
{
191-
let mir_place =
192-
place_builder_resolved.into_place(this.tcx, this.typeck_results);
193-
this.cfg.push_fake_read(
194-
block,
195-
this.source_info(this.tcx.hir().span(*hir_id)),
196-
*cause,
197-
mir_place,
198-
);
199-
}
182+
for (thir_place, cause, hir_id) in fake_reads.into_iter() {
183+
let place_builder = unpack!(block = this.as_place_builder(block, thir_place));
184+
185+
if let Ok(place_builder_resolved) =
186+
place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
187+
{
188+
let mir_place =
189+
place_builder_resolved.into_place(this.tcx, this.typeck_results);
190+
this.cfg.push_fake_read(
191+
block,
192+
this.source_info(this.tcx.hir().span(*hir_id)),
193+
*cause,
194+
mir_place,
195+
);
200196
}
201197
}
202198

compiler/rustc_mir_build/src/build/matches/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
139139
// uninhabited value. If we get never patterns, those will check that
140140
// the place is initialized, and so this read would only be used to
141141
// check safety.
142-
let cause_matched_place = FakeReadCause::ForMatchedPlace;
142+
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
143143
let source_info = self.source_info(scrutinee_span);
144144

145145
if let Ok(scrutinee_builder) =
@@ -400,7 +400,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
400400

401401
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
402402
let source_info = self.source_info(irrefutable_pat.span);
403-
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place);
403+
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place);
404404

405405
self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
406406
block.unit()
@@ -435,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
435435

436436
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
437437
let pattern_source_info = self.source_info(irrefutable_pat.span);
438-
let cause_let = FakeReadCause::ForLet;
438+
let cause_let = FakeReadCause::ForLet(None);
439439
self.cfg.push_fake_read(block, pattern_source_info, cause_let, place);
440440

441441
let ty_source_info = self.source_info(user_ty_span);

compiler/rustc_typeck/src/expr_use_visitor.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -279,9 +279,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
279279
if needs_to_be_read {
280280
self.borrow_expr(&discr, ty::ImmBorrow);
281281
} else {
282+
let closure_def_id = match discr_place.place.base {
283+
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
284+
_ => None,
285+
};
286+
282287
self.delegate.fake_read(
283288
discr_place.place.clone(),
284-
FakeReadCause::ForMatchedPlace,
289+
FakeReadCause::ForMatchedPlace(closure_def_id),
285290
discr_place.hir_id,
286291
);
287292

@@ -577,9 +582,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
577582
}
578583

579584
fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
585+
let closure_def_id = match discr_place.place.base {
586+
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
587+
_ => None,
588+
};
589+
580590
self.delegate.fake_read(
581591
discr_place.place.clone(),
582-
FakeReadCause::ForMatchedPlace,
592+
FakeReadCause::ForMatchedPlace(closure_def_id),
583593
discr_place.hir_id,
584594
);
585595
self.walk_pat(discr_place, &arm.pat);
@@ -594,9 +604,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
594604
/// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
595605
/// let binding, and *not* a match arm or nested pat.)
596606
fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
607+
let closure_def_id = match discr_place.place.base {
608+
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
609+
_ => None,
610+
};
611+
597612
self.delegate.fake_read(
598613
discr_place.place.clone(),
599-
FakeReadCause::ForLet,
614+
FakeReadCause::ForLet(closure_def_id),
600615
discr_place.hir_id,
601616
);
602617
self.walk_pat(discr_place, pat);

src/test/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir

+14-14
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,12 @@ fn address_of_reborrow() -> () {
130130
StorageLive(_2); // scope 0 at $DIR/address-of.rs:4:14: 4:21
131131
_2 = [const 0_i32; 10]; // scope 0 at $DIR/address-of.rs:4:14: 4:21
132132
_1 = &_2; // scope 0 at $DIR/address-of.rs:4:13: 4:21
133-
FakeRead(ForLet, _1); // scope 0 at $DIR/address-of.rs:4:9: 4:10
133+
FakeRead(ForLet(None), _1); // scope 0 at $DIR/address-of.rs:4:9: 4:10
134134
StorageLive(_3); // scope 1 at $DIR/address-of.rs:5:9: 5:14
135135
StorageLive(_4); // scope 1 at $DIR/address-of.rs:5:22: 5:29
136136
_4 = [const 0_i32; 10]; // scope 1 at $DIR/address-of.rs:5:22: 5:29
137137
_3 = &mut _4; // scope 1 at $DIR/address-of.rs:5:17: 5:29
138-
FakeRead(ForLet, _3); // scope 1 at $DIR/address-of.rs:5:9: 5:14
138+
FakeRead(ForLet(None), _3); // scope 1 at $DIR/address-of.rs:5:9: 5:14
139139
StorageLive(_5); // scope 2 at $DIR/address-of.rs:7:5: 7:18
140140
StorageLive(_6); // scope 2 at $DIR/address-of.rs:7:5: 7:18
141141
_6 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:7:5: 7:6
@@ -170,25 +170,25 @@ fn address_of_reborrow() -> () {
170170
StorageDead(_13); // scope 2 at $DIR/address-of.rs:11:20: 11:21
171171
StorageLive(_15); // scope 2 at $DIR/address-of.rs:13:9: 13:10
172172
_15 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:13:23: 13:24
173-
FakeRead(ForLet, _15); // scope 2 at $DIR/address-of.rs:13:9: 13:10
173+
FakeRead(ForLet(None), _15); // scope 2 at $DIR/address-of.rs:13:9: 13:10
174174
AscribeUserType(_15, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 2 at $DIR/address-of.rs:13:12: 13:20
175175
StorageLive(_16); // scope 3 at $DIR/address-of.rs:14:9: 14:10
176176
_16 = &raw const (*_1); // scope 3 at $DIR/address-of.rs:14:31: 14:32
177-
FakeRead(ForLet, _16); // scope 3 at $DIR/address-of.rs:14:9: 14:10
177+
FakeRead(ForLet(None), _16); // scope 3 at $DIR/address-of.rs:14:9: 14:10
178178
AscribeUserType(_16, o, UserTypeProjection { base: UserType(5), projs: [] }); // scope 3 at $DIR/address-of.rs:14:12: 14:28
179179
StorageLive(_17); // scope 4 at $DIR/address-of.rs:15:9: 15:10
180180
StorageLive(_18); // scope 4 at $DIR/address-of.rs:15:30: 15:31
181181
_18 = &raw const (*_1); // scope 4 at $DIR/address-of.rs:15:30: 15:31
182182
_17 = move _18 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 4 at $DIR/address-of.rs:15:30: 15:31
183183
StorageDead(_18); // scope 4 at $DIR/address-of.rs:15:30: 15:31
184-
FakeRead(ForLet, _17); // scope 4 at $DIR/address-of.rs:15:9: 15:10
184+
FakeRead(ForLet(None), _17); // scope 4 at $DIR/address-of.rs:15:9: 15:10
185185
AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] }); // scope 4 at $DIR/address-of.rs:15:12: 15:27
186186
StorageLive(_19); // scope 5 at $DIR/address-of.rs:16:9: 16:10
187187
StorageLive(_20); // scope 5 at $DIR/address-of.rs:16:27: 16:28
188188
_20 = &raw const (*_1); // scope 5 at $DIR/address-of.rs:16:27: 16:28
189189
_19 = move _20 as *const [i32] (Pointer(Unsize)); // scope 5 at $DIR/address-of.rs:16:27: 16:28
190190
StorageDead(_20); // scope 5 at $DIR/address-of.rs:16:27: 16:28
191-
FakeRead(ForLet, _19); // scope 5 at $DIR/address-of.rs:16:9: 16:10
191+
FakeRead(ForLet(None), _19); // scope 5 at $DIR/address-of.rs:16:9: 16:10
192192
AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] }); // scope 5 at $DIR/address-of.rs:16:12: 16:24
193193
StorageLive(_21); // scope 6 at $DIR/address-of.rs:18:5: 18:18
194194
StorageLive(_22); // scope 6 at $DIR/address-of.rs:18:5: 18:18
@@ -218,25 +218,25 @@ fn address_of_reborrow() -> () {
218218
StorageDead(_27); // scope 6 at $DIR/address-of.rs:21:22: 21:23
219219
StorageLive(_29); // scope 6 at $DIR/address-of.rs:23:9: 23:10
220220
_29 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:23:23: 23:24
221-
FakeRead(ForLet, _29); // scope 6 at $DIR/address-of.rs:23:9: 23:10
221+
FakeRead(ForLet(None), _29); // scope 6 at $DIR/address-of.rs:23:9: 23:10
222222
AscribeUserType(_29, o, UserTypeProjection { base: UserType(13), projs: [] }); // scope 6 at $DIR/address-of.rs:23:12: 23:20
223223
StorageLive(_30); // scope 7 at $DIR/address-of.rs:24:9: 24:10
224224
_30 = &raw const (*_3); // scope 7 at $DIR/address-of.rs:24:31: 24:32
225-
FakeRead(ForLet, _30); // scope 7 at $DIR/address-of.rs:24:9: 24:10
225+
FakeRead(ForLet(None), _30); // scope 7 at $DIR/address-of.rs:24:9: 24:10
226226
AscribeUserType(_30, o, UserTypeProjection { base: UserType(15), projs: [] }); // scope 7 at $DIR/address-of.rs:24:12: 24:28
227227
StorageLive(_31); // scope 8 at $DIR/address-of.rs:25:9: 25:10
228228
StorageLive(_32); // scope 8 at $DIR/address-of.rs:25:30: 25:31
229229
_32 = &raw const (*_3); // scope 8 at $DIR/address-of.rs:25:30: 25:31
230230
_31 = move _32 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 8 at $DIR/address-of.rs:25:30: 25:31
231231
StorageDead(_32); // scope 8 at $DIR/address-of.rs:25:30: 25:31
232-
FakeRead(ForLet, _31); // scope 8 at $DIR/address-of.rs:25:9: 25:10
232+
FakeRead(ForLet(None), _31); // scope 8 at $DIR/address-of.rs:25:9: 25:10
233233
AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] }); // scope 8 at $DIR/address-of.rs:25:12: 25:27
234234
StorageLive(_33); // scope 9 at $DIR/address-of.rs:26:9: 26:10
235235
StorageLive(_34); // scope 9 at $DIR/address-of.rs:26:27: 26:28
236236
_34 = &raw const (*_3); // scope 9 at $DIR/address-of.rs:26:27: 26:28
237237
_33 = move _34 as *const [i32] (Pointer(Unsize)); // scope 9 at $DIR/address-of.rs:26:27: 26:28
238238
StorageDead(_34); // scope 9 at $DIR/address-of.rs:26:27: 26:28
239-
FakeRead(ForLet, _33); // scope 9 at $DIR/address-of.rs:26:9: 26:10
239+
FakeRead(ForLet(None), _33); // scope 9 at $DIR/address-of.rs:26:9: 26:10
240240
AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] }); // scope 9 at $DIR/address-of.rs:26:12: 26:24
241241
StorageLive(_35); // scope 10 at $DIR/address-of.rs:28:5: 28:16
242242
StorageLive(_36); // scope 10 at $DIR/address-of.rs:28:5: 28:16
@@ -266,25 +266,25 @@ fn address_of_reborrow() -> () {
266266
StorageDead(_41); // scope 10 at $DIR/address-of.rs:31:20: 31:21
267267
StorageLive(_43); // scope 10 at $DIR/address-of.rs:33:9: 33:10
268268
_43 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:33:21: 33:22
269-
FakeRead(ForLet, _43); // scope 10 at $DIR/address-of.rs:33:9: 33:10
269+
FakeRead(ForLet(None), _43); // scope 10 at $DIR/address-of.rs:33:9: 33:10
270270
AscribeUserType(_43, o, UserTypeProjection { base: UserType(23), projs: [] }); // scope 10 at $DIR/address-of.rs:33:12: 33:18
271271
StorageLive(_44); // scope 11 at $DIR/address-of.rs:34:9: 34:10
272272
_44 = &raw mut (*_3); // scope 11 at $DIR/address-of.rs:34:29: 34:30
273-
FakeRead(ForLet, _44); // scope 11 at $DIR/address-of.rs:34:9: 34:10
273+
FakeRead(ForLet(None), _44); // scope 11 at $DIR/address-of.rs:34:9: 34:10
274274
AscribeUserType(_44, o, UserTypeProjection { base: UserType(25), projs: [] }); // scope 11 at $DIR/address-of.rs:34:12: 34:26
275275
StorageLive(_45); // scope 12 at $DIR/address-of.rs:35:9: 35:10
276276
StorageLive(_46); // scope 12 at $DIR/address-of.rs:35:28: 35:29
277277
_46 = &raw mut (*_3); // scope 12 at $DIR/address-of.rs:35:28: 35:29
278278
_45 = move _46 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 12 at $DIR/address-of.rs:35:28: 35:29
279279
StorageDead(_46); // scope 12 at $DIR/address-of.rs:35:28: 35:29
280-
FakeRead(ForLet, _45); // scope 12 at $DIR/address-of.rs:35:9: 35:10
280+
FakeRead(ForLet(None), _45); // scope 12 at $DIR/address-of.rs:35:9: 35:10
281281
AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] }); // scope 12 at $DIR/address-of.rs:35:12: 35:25
282282
StorageLive(_47); // scope 13 at $DIR/address-of.rs:36:9: 36:10
283283
StorageLive(_48); // scope 13 at $DIR/address-of.rs:36:25: 36:26
284284
_48 = &raw mut (*_3); // scope 13 at $DIR/address-of.rs:36:25: 36:26
285285
_47 = move _48 as *mut [i32] (Pointer(Unsize)); // scope 13 at $DIR/address-of.rs:36:25: 36:26
286286
StorageDead(_48); // scope 13 at $DIR/address-of.rs:36:25: 36:26
287-
FakeRead(ForLet, _47); // scope 13 at $DIR/address-of.rs:36:9: 36:10
287+
FakeRead(ForLet(None), _47); // scope 13 at $DIR/address-of.rs:36:9: 36:10
288288
AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); // scope 13 at $DIR/address-of.rs:36:12: 36:22
289289
_0 = const (); // scope 0 at $DIR/address-of.rs:3:26: 37:2
290290
StorageDead(_47); // scope 13 at $DIR/address-of.rs:37:1: 37:2

0 commit comments

Comments
 (0)