Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit ec10b71

Browse files
committed
Introduce new fake reads
1 parent 9320b12 commit ec10b71

File tree

11 files changed

+195
-21
lines changed

11 files changed

+195
-21
lines changed

compiler/rustc_middle/src/ty/context.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ pub struct TypeckResults<'tcx> {
430430
/// see `MinCaptureInformationMap` for more details.
431431
pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
432432

433+
/// [FIXME] RFC2229 Change to use HashSet instead of Vec
434+
pub closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>>,
435+
433436
/// Stores the type, expression, span and optional scope span of all types
434437
/// that are live across the yield of this generator (if a generator).
435438
pub generator_interior_types: ty::Binder<Vec<GeneratorInteriorTypeCause<'tcx>>>,
@@ -464,6 +467,7 @@ impl<'tcx> TypeckResults<'tcx> {
464467
concrete_opaque_types: Default::default(),
465468
closure_captures: Default::default(),
466469
closure_min_captures: Default::default(),
470+
closure_fake_reads: Default::default(),
467471
generator_interior_types: ty::Binder::dummy(Default::default()),
468472
treat_byte_string_as_slice: Default::default(),
469473
}
@@ -715,6 +719,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
715719
ref concrete_opaque_types,
716720
ref closure_captures,
717721
ref closure_min_captures,
722+
ref closure_fake_reads,
718723
ref generator_interior_types,
719724
ref treat_byte_string_as_slice,
720725
} = *self;
@@ -750,6 +755,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
750755
concrete_opaque_types.hash_stable(hcx, hasher);
751756
closure_captures.hash_stable(hcx, hasher);
752757
closure_min_captures.hash_stable(hcx, hasher);
758+
closure_fake_reads.hash_stable(hcx, hasher);
753759
generator_interior_types.hash_stable(hcx, hasher);
754760
treat_byte_string_as_slice.hash_stable(hcx, hasher);
755761
})

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_target::abi::VariantIdx;
1717
use rustc_index::vec::Idx;
1818

1919
/// The "outermost" place that holds this value.
20-
#[derive(Copy, Clone)]
20+
#[derive(Copy, Clone, Debug)]
2121
crate enum PlaceBase {
2222
/// Denotes the start of a `Place`.
2323
Local(Local),
@@ -67,7 +67,7 @@ crate enum PlaceBase {
6767
///
6868
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
6969
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
70-
#[derive(Clone)]
70+
#[derive(Clone, Debug)]
7171
crate struct PlaceBuilder<'tcx> {
7272
base: PlaceBase,
7373
projection: Vec<PlaceElem<'tcx>>,
@@ -199,7 +199,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
199199
from_builder: PlaceBuilder<'tcx>,
200200
tcx: TyCtxt<'tcx>,
201201
typeck_results: &'a ty::TypeckResults<'tcx>,
202-
) -> Result<PlaceBuilder<'tcx>, HirId> {
202+
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
203203
match from_builder.base {
204204
PlaceBase::Local(_) => Ok(from_builder),
205205
PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
@@ -236,7 +236,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
236236
var_hir_id, from_builder.projection,
237237
);
238238
}
239-
return Err(var_hir_id);
239+
return Err(upvar_resolved_place_builder);
240240
};
241241

242242
let closure_ty = typeck_results
@@ -288,7 +288,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
288288
if let PlaceBase::Local(local) = self.base {
289289
Place { local, projection: tcx.intern_place_elems(&self.projection) }
290290
} else {
291-
self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
291+
self.try_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
292292
}
293293
}
294294

@@ -300,6 +300,17 @@ impl<'tcx> PlaceBuilder<'tcx> {
300300
to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
301301
}
302302

303+
fn try_upvars_resolved<'a>(
304+
self,
305+
tcx: TyCtxt<'tcx>,
306+
typeck_results: &'a ty::TypeckResults<'tcx>,
307+
) -> PlaceBuilder<'tcx> {
308+
match to_upvars_resolved_place_builder(self, tcx, typeck_results) {
309+
Ok(upvars_resolved) => upvars_resolved,
310+
Err(upvars_unresolved) => upvars_unresolved,
311+
}
312+
}
313+
303314
crate fn base(&self) -> PlaceBase {
304315
self.base
305316
}

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
88
use crate::thir::*;
99
use rustc_middle::middle::region;
1010
use rustc_middle::mir::AssertKind;
11+
use rustc_middle::mir::Place;
1112
use rustc_middle::mir::*;
1213
use rustc_middle::ty::{self, Ty, UpvarSubsts};
1314
use rustc_span::Span;
@@ -164,7 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
164165

165166
block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
166167
}
167-
ExprKind::Closure { closure_id, substs, upvars, movability } => {
168+
ExprKind::Closure { closure_id, substs, upvars, movability, fake_reads } => {
168169
// see (*) above
169170
let operands: Vec<_> = upvars
170171
.into_iter()
@@ -203,6 +204,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
203204
}
204205
})
205206
.collect();
207+
208+
if let Some(fake_reads) = fake_reads {
209+
for thir_place in fake_reads.into_iter() {
210+
// = this.hir.mirror(thir_place);
211+
let mir_place = unpack!(block = this.as_place(block, thir_place));
212+
// [FIXME] RFC2229 FakeReadCause can be ForLet or ForMatch, need to use the correct one
213+
this.cfg.push_fake_read(
214+
block,
215+
source_info,
216+
FakeReadCause::ForMatchedPlace,
217+
mir_place,
218+
);
219+
}
220+
}
221+
206222
let result = match substs {
207223
UpvarSubsts::Generator(substs) => {
208224
// We implicitly set the discriminant to 0. See

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
420420
| ExprKind::PlaceTypeAscription { .. }
421421
| ExprKind::ValueTypeAscription { .. } => {
422422
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
423-
424423
let place = unpack!(block = this.as_place(block, expr));
425424
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
426425
this.cfg.push_assign(block, source_info, destination, rvalue);
@@ -437,7 +436,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
437436
}
438437

439438
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
440-
441439
let place = unpack!(block = this.as_place(block, expr));
442440
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
443441
this.cfg.push_assign(block, source_info, destination, rvalue);

compiler/rustc_mir_build/src/thir/cx/expr.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
55
use rustc_hir as hir;
66
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
77
use rustc_index::vec::Idx;
8+
use rustc_middle::hir::place::Place as HirPlace;
89
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
910
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
1011
use rustc_middle::mir::interpret::Scalar;
@@ -452,7 +453,39 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
452453
.zip(substs.upvar_tys())
453454
.map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty)),
454455
);
455-
ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
456+
457+
let fake_reads = match self.typeck_results().closure_fake_reads.get(&def_id) {
458+
Some(vals) => Some(self.arena.alloc_from_iter(vals
459+
.iter()
460+
.filter(|val| match val.base {
461+
HirPlaceBase::Upvar(_) => true,
462+
_ => false,
463+
})
464+
.map(|val| {
465+
let var_hir_id = match val.base {
466+
HirPlaceBase::Upvar(upvar_id) => {
467+
debug!("upvar");
468+
upvar_id.var_path.hir_id
469+
}
470+
_ => {
471+
bug!(
472+
"Do not know how to get HirId out of Rvalue and StaticItem"
473+
);
474+
}
475+
};
476+
self.fake_read_capture_upvar(expr, val.clone(), var_hir_id)
477+
})
478+
)),
479+
None => None,
480+
};
481+
482+
ExprKind::Closure {
483+
closure_id: def_id,
484+
substs,
485+
upvars,
486+
movability,
487+
fake_reads: fake_reads,
488+
}
456489
}
457490

458491
hir::ExprKind::Path(ref qpath) => {
@@ -1012,6 +1045,49 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
10121045
ExprKind::Deref { arg: ref_expr }
10131046
}
10141047

1048+
fn fake_read_capture_upvar(
1049+
&mut self,
1050+
closure_expr: &'tcx hir::Expr<'tcx>,
1051+
place: HirPlace<'tcx>,
1052+
hir_id: hir::HirId,
1053+
) -> Expr<'thir, 'tcx> {
1054+
let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
1055+
let var_ty = place.base_ty;
1056+
1057+
let mut captured_place_expr = Expr {
1058+
temp_lifetime,
1059+
ty: var_ty,
1060+
span: closure_expr.span,
1061+
kind: self.convert_var(hir_id),
1062+
};
1063+
// [FIXME] RFC2229 Maybe we should introduce an immutable borrow of the fake capture so that we don't
1064+
// end up moving this place
1065+
for proj in place.projections.iter() {
1066+
let kind = match proj.kind {
1067+
HirProjectionKind::Deref => {
1068+
ExprKind::Deref { arg: self.arena.alloc(captured_place_expr) }
1069+
}
1070+
HirProjectionKind::Field(field, ..) => {
1071+
// Variant index will always be 0, because for multi-variant
1072+
// enums, we capture the enum entirely.
1073+
ExprKind::Field {
1074+
lhs: self.arena.alloc(captured_place_expr),
1075+
name: Field::new(field as usize),
1076+
}
1077+
}
1078+
HirProjectionKind::Index | HirProjectionKind::Subslice => {
1079+
// We don't capture these projections, so we can ignore them here
1080+
continue;
1081+
}
1082+
};
1083+
1084+
captured_place_expr =
1085+
Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
1086+
}
1087+
1088+
captured_place_expr
1089+
}
1090+
10151091
fn capture_upvar(
10161092
&mut self,
10171093
closure_expr: &'tcx hir::Expr<'tcx>,

compiler/rustc_mir_build/src/thir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ pub enum ExprKind<'thir, 'tcx> {
281281
substs: UpvarSubsts<'tcx>,
282282
upvars: &'thir [Expr<'thir, 'tcx>],
283283
movability: Option<hir::Movability>,
284+
fake_reads: Option<&'thir mut [Expr<'thir, 'tcx>]>,
284285
},
285286
Literal {
286287
literal: &'tcx Const<'tcx>,

compiler/rustc_typeck/src/check/upvar.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use super::writeback::Resolver;
3434
use super::FnCtxt;
3535

3636
use crate::expr_use_visitor as euv;
37+
use rustc_data_structures::fx::FxHashSet;
3738
use rustc_data_structures::fx::FxIndexMap;
3839
use rustc_hir as hir;
3940
use rustc_hir::def_id::DefId;
@@ -145,6 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
145146
current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
146147
current_origin: None,
147148
capture_information: Default::default(),
149+
fake_reads: Default::default(),
148150
};
149151
euv::ExprUseVisitor::new(
150152
&mut delegate,
@@ -246,6 +248,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
246248
let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
247249
self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
248250

251+
let fake_reads = delegate.fake_reads.into_iter().map(|fake_read| fake_read).collect();
252+
self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads);
253+
249254
// If we are also inferred the closure kind here,
250255
// process any deferred resolutions.
251256
let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
@@ -1148,6 +1153,8 @@ struct InferBorrowKind<'a, 'tcx> {
11481153
/// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
11491154
/// ```
11501155
capture_information: InferredCaptureInformation<'tcx>,
1156+
// [FIXME] RFC2229 Change Vec to FxHashSet
1157+
fake_reads: FxHashSet<Place<'tcx>>, // these need to be fake read.
11511158
}
11521159

11531160
impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
@@ -1409,6 +1416,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
14091416
}
14101417

14111418
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1419+
fn fake_read(&mut self, place: PlaceWithHirId<'tcx>) {
1420+
if let PlaceBase::Upvar(_) = place.place.base {
1421+
self.fake_reads.insert(place.place);
1422+
}
1423+
}
1424+
14121425
fn consume(
14131426
&mut self,
14141427
place_with_id: &PlaceWithHirId<'tcx>,

compiler/rustc_typeck/src/check/writeback.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44

55
use crate::check::FnCtxt;
66

7+
use rustc_data_structures::stable_map::FxHashMap;
78
use rustc_errors::ErrorReported;
89
use rustc_hir as hir;
10+
use rustc_hir::def_id::DefId;
911
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
1012
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
1113
use rustc_infer::infer::InferCtxt;
14+
use rustc_middle::hir::place::Place as HirPlace;
1215
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
1316
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
1417
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -56,6 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5659
}
5760
wbcx.visit_body(body);
5861
wbcx.visit_min_capture_map();
62+
wbcx.visit_fake_reads_map();
5963
wbcx.visit_upvar_capture_map();
6064
wbcx.visit_closures();
6165
wbcx.visit_liberated_fn_sigs();
@@ -363,6 +367,25 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
363367
self.typeck_results.closure_min_captures = min_captures_wb;
364368
}
365369

370+
fn visit_fake_reads_map(&mut self) {
371+
let mut resolved_closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>> =
372+
Default::default();
373+
for (closure_def_id, fake_reads) in
374+
self.fcx.typeck_results.borrow().closure_fake_reads.iter()
375+
{
376+
let mut resolved_fake_reads = Vec::<HirPlace<'tcx>>::new();
377+
for fake_read in fake_reads.iter() {
378+
let locatable =
379+
self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local());
380+
381+
let resolved_fake_read = self.resolve(fake_read.clone(), &locatable);
382+
resolved_fake_reads.push(resolved_fake_read);
383+
}
384+
resolved_closure_fake_reads.insert(*closure_def_id, resolved_fake_reads);
385+
}
386+
self.typeck_results.closure_fake_reads = resolved_closure_fake_reads;
387+
}
388+
366389
fn visit_upvar_capture_map(&mut self) {
367390
for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() {
368391
let new_upvar_capture = match *upvar_capture {

0 commit comments

Comments
 (0)