1
Fork 0

Introduce new fake reads

This commit is contained in:
Roxane 2021-02-02 21:07:52 -05:00
parent 9320b121b5
commit ec10b71d42
11 changed files with 195 additions and 21 deletions

View file

@ -17,7 +17,7 @@ use rustc_target::abi::VariantIdx;
use rustc_index::vec::Idx;
/// The "outermost" place that holds this value.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
crate enum PlaceBase {
/// Denotes the start of a `Place`.
Local(Local),
@ -67,7 +67,7 @@ crate enum PlaceBase {
///
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
#[derive(Clone)]
#[derive(Clone, Debug)]
crate struct PlaceBuilder<'tcx> {
base: PlaceBase,
projection: Vec<PlaceElem<'tcx>>,
@ -199,7 +199,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
from_builder: PlaceBuilder<'tcx>,
tcx: TyCtxt<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
) -> Result<PlaceBuilder<'tcx>, HirId> {
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
match from_builder.base {
PlaceBase::Local(_) => Ok(from_builder),
PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
@ -236,7 +236,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
var_hir_id, from_builder.projection,
);
}
return Err(var_hir_id);
return Err(upvar_resolved_place_builder);
};
let closure_ty = typeck_results
@ -288,7 +288,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
if let PlaceBase::Local(local) = self.base {
Place { local, projection: tcx.intern_place_elems(&self.projection) }
} else {
self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
self.try_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
}
}
@ -300,6 +300,17 @@ impl<'tcx> PlaceBuilder<'tcx> {
to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
}
fn try_upvars_resolved<'a>(
self,
tcx: TyCtxt<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
) -> PlaceBuilder<'tcx> {
match to_upvars_resolved_place_builder(self, tcx, typeck_results) {
Ok(upvars_resolved) => upvars_resolved,
Err(upvars_unresolved) => upvars_unresolved,
}
}
crate fn base(&self) -> PlaceBase {
self.base
}

View file

@ -8,6 +8,7 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::Place;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
@ -164,7 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
}
ExprKind::Closure { closure_id, substs, upvars, movability } => {
ExprKind::Closure { closure_id, substs, upvars, movability, fake_reads } => {
// see (*) above
let operands: Vec<_> = upvars
.into_iter()
@ -203,6 +204,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
})
.collect();
if let Some(fake_reads) = fake_reads {
for thir_place in fake_reads.into_iter() {
// = this.hir.mirror(thir_place);
let mir_place = unpack!(block = this.as_place(block, thir_place));
// [FIXME] RFC2229 FakeReadCause can be ForLet or ForMatch, need to use the correct one
this.cfg.push_fake_read(
block,
source_info,
FakeReadCause::ForMatchedPlace,
mir_place,
);
}
}
let result = match substs {
UpvarSubsts::Generator(substs) => {
// We implicitly set the discriminant to 0. See

View file

@ -420,7 +420,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => {
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
let place = unpack!(block = this.as_place(block, expr));
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
this.cfg.push_assign(block, source_info, destination, rvalue);
@ -437,7 +436,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
let place = unpack!(block = this.as_place(block, expr));
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
this.cfg.push_assign(block, source_info, destination, rvalue);

View file

@ -5,6 +5,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_index::vec::Idx;
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::mir::interpret::Scalar;
@ -452,7 +453,39 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
.zip(substs.upvar_tys())
.map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty)),
);
ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
let fake_reads = match self.typeck_results().closure_fake_reads.get(&def_id) {
Some(vals) => Some(self.arena.alloc_from_iter(vals
.iter()
.filter(|val| match val.base {
HirPlaceBase::Upvar(_) => true,
_ => false,
})
.map(|val| {
let var_hir_id = match val.base {
HirPlaceBase::Upvar(upvar_id) => {
debug!("upvar");
upvar_id.var_path.hir_id
}
_ => {
bug!(
"Do not know how to get HirId out of Rvalue and StaticItem"
);
}
};
self.fake_read_capture_upvar(expr, val.clone(), var_hir_id)
})
)),
None => None,
};
ExprKind::Closure {
closure_id: def_id,
substs,
upvars,
movability,
fake_reads: fake_reads,
}
}
hir::ExprKind::Path(ref qpath) => {
@ -1012,6 +1045,49 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
ExprKind::Deref { arg: ref_expr }
}
fn fake_read_capture_upvar(
&mut self,
closure_expr: &'tcx hir::Expr<'tcx>,
place: HirPlace<'tcx>,
hir_id: hir::HirId,
) -> Expr<'thir, 'tcx> {
let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
let var_ty = place.base_ty;
let mut captured_place_expr = Expr {
temp_lifetime,
ty: var_ty,
span: closure_expr.span,
kind: self.convert_var(hir_id),
};
// [FIXME] RFC2229 Maybe we should introduce an immutable borrow of the fake capture so that we don't
// end up moving this place
for proj in place.projections.iter() {
let kind = match proj.kind {
HirProjectionKind::Deref => {
ExprKind::Deref { arg: self.arena.alloc(captured_place_expr) }
}
HirProjectionKind::Field(field, ..) => {
// Variant index will always be 0, because for multi-variant
// enums, we capture the enum entirely.
ExprKind::Field {
lhs: self.arena.alloc(captured_place_expr),
name: Field::new(field as usize),
}
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
// We don't capture these projections, so we can ignore them here
continue;
}
};
captured_place_expr =
Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
}
captured_place_expr
}
fn capture_upvar(
&mut self,
closure_expr: &'tcx hir::Expr<'tcx>,

View file

@ -281,6 +281,7 @@ pub enum ExprKind<'thir, 'tcx> {
substs: UpvarSubsts<'tcx>,
upvars: &'thir [Expr<'thir, 'tcx>],
movability: Option<hir::Movability>,
fake_reads: Option<&'thir mut [Expr<'thir, 'tcx>]>,
},
Literal {
literal: &'tcx Const<'tcx>,