diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_middle/src/ty/context.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/block.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_place.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_rvalue.rs | 33 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/expr/into.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/mod.rs | 90 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/simplify.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/test.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/cx/expr.rs | 103 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/mod.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/upvar.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/writeback.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/expr_use_visitor.rs | 37 |
13 files changed, 177 insertions, 179 deletions
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2d1231d819d..425e62d6f61 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -47,6 +47,7 @@ use rustc_hir::{ }; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; +use rustc_middle::mir::FakeReadCause; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; @@ -430,8 +431,7 @@ pub struct TypeckResults<'tcx> { /// see `MinCaptureInformationMap` for more details. pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>, - /// [FIXME] RFC2229 Change to use HashSet instead of Vec - pub closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>>, + pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause)>>, /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index ae4d6b56152..808c6e3ff64 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -94,14 +94,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) ); } - // ROX: - // - // Where the handling of destructure patterns start - // - // let (a, b, c, _ ) = something - // - // (a, b, c, _) is the pattern - // something is the initializer StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => { let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); @@ -133,8 +125,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ArmHasGuard(false), Some((None, initializer_span)), ); - // This is where we get into pattern handling of the let - // statement this.expr_into_pattern(block, pattern.clone(), init) }) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index f819a638c7a..6519d5fae1c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -84,6 +84,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( mir_projections: &[PlaceElem<'tcx>], ) -> Vec<HirProjectionKind> { let mut hir_projections = Vec::new(); + let mut variant = None; for mir_projection in mir_projections { let hir_projection = match mir_projection { @@ -91,13 +92,17 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( ProjectionElem::Field(field, _) => { // We will never encouter this for multivariant enums, // read the comment for `Downcast`. - HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0)) + let variant = variant.unwrap_or(VariantIdx::new(0)); + HirProjectionKind::Field(field.index() as u32, variant) } - ProjectionElem::Downcast(..) => { - // This projections exist only for enums that have - // multiple variants. Since such enums that are captured - // completely, we can stop here. - break; + ProjectionElem::Downcast(.., idx) => { + // This projections exist for enums that have + // single and multiple variants. + // For single variants, enums are not captured completely. + // We keep track of VariantIdx so we can use this information + // if the next ProjectionElem is a Field + variant = Some(*idx); + continue; } ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } @@ -107,7 +112,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( break; } }; - + variant = None; hir_projections.push(hir_projection); } @@ -231,13 +236,12 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( from_builder.projection ) } else { - // FIXME(project-rfc-2229#24): Handle this case properly debug!( "No associated capture found for {:?}[{:#?}]", var_hir_id, from_builder.projection, ); } - return Err(upvar_resolved_place_builder); + return Err(from_builder); }; let closure_ty = typeck_results @@ -289,11 +293,10 @@ impl<'tcx> PlaceBuilder<'tcx> { if let PlaceBase::Local(local) = self.base { Place { local, projection: tcx.intern_place_elems(&self.projection) } } else { - self.try_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) + self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) } } - /// ROX: Function that will be called when we really do need a place fn expect_upvars_resolved<'a>( self, tcx: TyCtxt<'tcx>, @@ -302,14 +305,14 @@ impl<'tcx> PlaceBuilder<'tcx> { to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() } - fn try_upvars_resolved<'a>( + crate fn try_upvars_resolved<'a>( self, tcx: TyCtxt<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> PlaceBuilder<'tcx> { + ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { match to_upvars_resolved_place_builder(self, tcx, typeck_results) { - Ok(upvars_resolved) => upvars_resolved, - Err(upvars_unresolved) => upvars_unresolved, + Ok(upvars_resolved) => Ok(upvars_resolved), + Err(upvars_unresolved) => Err(upvars_unresolved), } } @@ -376,7 +379,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(place_builder.into_place(self.tcx, self.typeck_results)) } - // ROX: As place builder /// This is used when constructing a compound `Place`, so that we can avoid creating /// intermediate `Place` values until we know the full set of projections. crate fn as_place_builder( diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 3a8665777b7..c7f16fd4e40 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -165,7 +165,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } - ExprKind::Closure { closure_id, substs, upvars, movability, fake_reads } => { + ExprKind::Closure { + closure_id, + substs, + upvars, + movability, + fake_reads: opt_fake_reads, + } => { // see (*) above let operands: Vec<_> = upvars .into_iter() @@ -204,18 +210,19 @@ 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, - ); + if let Some(fake_reads) = opt_fake_reads { + for (thir_place, cause) in fake_reads.into_iter() { + let place_builder = + unpack!(block = this.as_place_builder(block, thir_place)); + + if let Ok(place_builder_resolved) = + place_builder.clone().try_upvars_resolved(this.tcx, this.typeck_results) + { + let mir_place = place_builder_resolved + .clone() + .into_place(this.tcx, this.typeck_results); + this.cfg.push_fake_read(block, source_info, cause, mir_place); + } } } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index e0ad34e08ef..b2e8b2de1bc 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -280,7 +280,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let field_names: Vec<_> = (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect(); - // ROX: This is probably here the function record/struct update pattern is done. let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { let place_builder = unpack!(block = this.as_place_builder(block, base)); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7285cf75623..59b3fd86478 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1,6 +1,3 @@ -// ROX: this folder contains all code for handling patterns, including exhaustiveness checking etc. -// We want to be careful ^^' - //! Code related to match expressions. These are sufficiently complex to //! warrant their own module and submodules. :) This main module includes the //! high-level algorithm, the submodules contain the details. @@ -100,7 +97,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,)); - let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms); + let mut arm_candidates = + self.create_match_candidates(scrutinee_place.clone(), &arms.clone()); let match_has_guard = arms.iter().any(|arm| arm.guard.is_some()); let mut candidates = @@ -127,8 +125,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, ) -> BlockAnd<PlaceBuilder<'tcx>> { let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee)); - let scrutinee_place = - scrutinee_place_builder.clone().into_place(self.tcx, self.typeck_results); // Matching on a `scrutinee_place` with an uninhabited type doesn't // generate any memory reads by itself, and so if the place "expression" // contains unsafe operations like raw pointer dereferences or union @@ -146,7 +142,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // check safety. let cause_matched_place = FakeReadCause::ForMatchedPlace; let source_info = self.source_info(scrutinee_span); - self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); + + if let Ok(scrutinee_builder) = + scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { + let scrutinee_place = + scrutinee_builder.clone().into_place(self.tcx, self.typeck_results); + self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); + } block.and(scrutinee_place_builder) } @@ -228,7 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn lower_match_arms( &mut self, destination: Place<'tcx>, - scrutinee_place: PlaceBuilder<'tcx>, + scrutinee_place_builder: PlaceBuilder<'tcx>, scrutinee_span: Span, arm_candidates: Vec<(&'_ Arm<'_, 'tcx>, Candidate<'_, 'tcx>)>, outer_source_info: SourceInfo, @@ -242,17 +245,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_source_info = self.source_info(arm.span); let arm_scope = (arm.scope, arm_source_info); self.in_scope(arm_scope, arm.lint_level, |this| { + let body = arm.body.clone(); + let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None; + let scrutinee_place: Place<'tcx>; + if let Ok(scrutinee_builder) = scrutinee_place_builder + .clone() + .try_upvars_resolved(this.tcx, this.typeck_results) + { + scrutinee_place = + scrutinee_builder.clone().into_place(this.tcx, this.typeck_results); + opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span)); + } let scope = this.declare_bindings( None, arm.span, &arm.pattern, ArmHasGuard(arm.guard.is_some()), - Some(( - Some( - &scrutinee_place.clone().into_place(this.tcx, this.typeck_results), - ), - scrutinee_span, - )), + opt_scrutinee_place, ); let arm_block = this.bind_pattern( @@ -457,15 +466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } _ => { - // Converts the destruct pattern into a place - // - // We don't want to convert to a place right away - // because in case of such pattern inside a closure, the projections matching a - // captured place might have not been applied. - // [FIXME] Need to find where this is happening and make the necessary changes there once - // Candidate is modified - // - // We want to use a place builder; Maybe use `as_place_builder` let place_builder = unpack!(block = self.as_place_builder(block, initializer)); self.place_into_pattern(block, irrefutable_pat, place_builder, true) } @@ -479,12 +479,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer: PlaceBuilder<'tcx>, set_match_place: bool, ) -> BlockAnd<()> { - let place = initializer.clone().into_place(self.tcx, self.typeck_results); - let mut candidate = Candidate::new(initializer, &irrefutable_pat, false); - + let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false); let fake_borrow_temps = self.lower_match_tree(block, irrefutable_pat.span, false, &mut [&mut candidate]); - // For matches and function arguments, the place that is being matched // can be set when creating the variables. But the place for // let PATTERN = ... might not even exist until we do the assignment. @@ -499,7 +496,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, )))) = self.local_decls[local].local_info { - *match_place = Some(place); + if let Ok(match_pair_resolved) = + initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { + let place = match_pair_resolved + .clone() + .into_place(self.tcx, self.typeck_results); + *match_place = Some(place); + } } else { bug!("Let binding to non-user variable.") } @@ -1461,7 +1465,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of any places that is switched on. if let Some(fb) = fake_borrows { - fb.insert(match_place.clone().into_place(self.tcx, self.typeck_results)); + if let Ok(match_place_resolved) = + match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { + let resolved_place = + match_place_resolved.clone().into_place(self.tcx, self.typeck_results); + fb.insert(resolved_place); + } } // perform the test, branching to one of N blocks. For each of @@ -1776,28 +1786,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Guard::IfLet(pat, scrutinee) => { let scrutinee_span = scrutinee.span; - let scrutinee_place = unpack!( + let scrutinee_place_builder = unpack!( block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span) ); - let mut guard_candidate = Candidate::new(scrutinee_place.clone(), &pat, false); + let mut guard_candidate = + Candidate::new(scrutinee_place_builder.clone(), &pat, false); let wildcard = Pat::wildcard_from_ty(pat.ty); let mut otherwise_candidate = - Candidate::new(scrutinee_place.clone(), &wildcard, false); + Candidate::new(scrutinee_place_builder.clone(), &wildcard, false); let fake_borrow_temps = self.lower_match_tree( block, pat.span, false, &mut [&mut guard_candidate, &mut otherwise_candidate], ); + let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None; + let scrutinee_place: Place<'tcx>; + if let Ok(scrutinee_builder) = scrutinee_place_builder + .clone() + .try_upvars_resolved(self.tcx, self.typeck_results) + { + scrutinee_place = + scrutinee_builder.clone().into_place(self.tcx, self.typeck_results); + opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span)); + } self.declare_bindings( None, pat.span.to(arm_span.unwrap()), pat, ArmHasGuard(false), - Some(( - Some(&scrutinee_place.clone().into_place(tcx, self.typeck_results)), - scrutinee.span, - )), + opt_scrutinee_place, ); let post_guard_block = self.bind_pattern( self.source_info(pat.span), diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index d9c1d4abf07..dc4f2886456 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -149,9 +149,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate: &mut Candidate<'pat, 'tcx>, ) -> Result<(), MatchPair<'pat, 'tcx>> { let tcx = self.tcx; - // Generate place to be used in Ascription - // Generate place to be used in Binding - let place = match_pair.place.clone().into_place(tcx, self.typeck_results); match *match_pair.pattern.kind { PatKind::AscribeUserType { ref subpattern, @@ -159,6 +156,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { // Apply the type ascription to the value at `match_pair.place`, which is the // value being matched, taking the variance field into account. + let place = match_pair.place.clone().into_place(self.tcx, self.typeck_results); candidate.ascriptions.push(Ascription { span: user_ty_span, user_ty, @@ -177,6 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => { + let place = match_pair.place.clone().into_place(self.tcx, self.typeck_results); candidate.bindings.push(Binding { name, mutability, diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index b804cd4574f..02f1998f496 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -156,7 +156,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { test: &Test<'tcx>, make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>, ) { - let place = place_builder.clone().into_place(self.tcx, self.typeck_results); + let place: Place<'tcx>; + if let Ok(test_place_builder) = + place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results) + { + place = test_place_builder.clone().into_place(self.tcx, self.typeck_results); + } else { + return; + } debug!( "perform_test({:?}, {:?}: {:?}, {:?})", block, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 25e08efb2e3..6b7bd2e9dcc 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -455,27 +455,32 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { ); 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) - }) - )), + Some(vals) => { + Some( + vals.iter() + .map(|(place, cause)| { + ( + self.arena.alloc( + self.convert_captured_hir_place(expr, place.clone()), + ), + *cause, + ) + // 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) + }) + .collect(), + ) + } None => None, }; @@ -1045,23 +1050,26 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { ExprKind::Deref { arg: ref_expr } } - fn fake_read_capture_upvar( + fn convert_captured_hir_place( &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 var_hir_id = match place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + base => bug!("Expected an upvar, found {:?}", base), + }; + let mut captured_place_expr = Expr { temp_lifetime, ty: var_ty, span: closure_expr.span, - kind: self.convert_var(hir_id), + kind: self.convert_var(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 => { @@ -1095,48 +1103,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { upvar_ty: Ty<'tcx>, ) -> Expr<'thir, 'tcx> { let upvar_capture = captured_place.info.capture_kind; + let captured_place_expr = + self.convert_captured_hir_place(closure_expr, captured_place.place.clone()); let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); - let var_ty = captured_place.place.base_ty; - - // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path - // as it's seen for use within the closure and not at the time of closure creation. - // - // That is we see expect to see it start from a captured upvar and not something that is local - // to the closure's parent. - let var_hir_id = match captured_place.place.base { - HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, - base => bug!("Expected an upvar, found {:?}", base), - }; - - let mut captured_place_expr = Expr { - temp_lifetime, - ty: var_ty, - span: closure_expr.span, - kind: self.convert_var(var_hir_id), - }; - - for proj in captured_place.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 }; - } match upvar_capture { ty::UpvarCapture::ByValue(_) => captured_place_expr, diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index 730c0f4a3df..a6ec3b7bdd2 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -9,7 +9,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::infer::canonical::Canonical; use rustc_middle::middle::region; -use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp}; +use rustc_middle::mir::{BinOp, BorrowKind, FakeReadCause, Field, UnOp}; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType}; @@ -281,7 +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>]>, + fake_reads: Option<Vec<(&'thir mut Expr<'thir, 'tcx>, FakeReadCause)>>, }, Literal { literal: &'tcx Const<'tcx>, diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 932f07ff1bd..9a43eaa3f5d 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -34,7 +34,6 @@ use super::writeback::Resolver; use super::FnCtxt; use crate::expr_use_visitor as euv; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -42,6 +41,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind}; +use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts}; use rustc_session::lint; @@ -248,7 +248,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter()); self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type); - let fake_reads = delegate.fake_reads.into_iter().map(|fake_read| fake_read).collect(); + let fake_reads = + delegate.fake_reads.into_iter().map(|(place, cause)| (place, cause)).collect(); self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads); // If we are also inferred the closure kind here, @@ -1153,7 +1154,7 @@ struct InferBorrowKind<'a, 'tcx> { /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow } /// ``` capture_information: InferredCaptureInformation<'tcx>, - fake_reads: FxHashSet<Place<'tcx>>, // these need to be fake read. + fake_reads: Vec<(Place<'tcx>, FakeReadCause)>, } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { @@ -1415,9 +1416,9 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { - fn fake_read(&mut self, place: Place<'tcx>) { + fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause) { if let PlaceBase::Upvar(_) = place.base { - self.fake_reads.insert(place); + self.fake_reads.push((place, cause)); } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 9cccda7768c..1be629ce9dc 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -12,6 +12,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::Place as HirPlace; +use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -368,18 +369,20 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } fn visit_fake_reads_map(&mut self) { - let mut resolved_closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>> = - Default::default(); + let mut resolved_closure_fake_reads: FxHashMap< + DefId, + Vec<(HirPlace<'tcx>, FakeReadCause)>, + > = Default::default(); for (closure_def_id, fake_reads) in self.fcx.typeck_results.borrow().closure_fake_reads.iter() { - let mut resolved_fake_reads = Vec::<HirPlace<'tcx>>::new(); - for fake_read in fake_reads.iter() { + let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause)>::new(); + for (place, cause) in fake_reads.iter() { let locatable = self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()); - let resolved_fake_read = self.resolve(fake_read.clone(), &locatable); - resolved_fake_reads.push(resolved_fake_read); + let resolved_fake_read = self.resolve(place.clone(), &locatable); + resolved_fake_reads.push((resolved_fake_read, *cause)); } resolved_closure_fake_reads.insert(*closure_def_id, resolved_fake_reads); } diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index ad39b93c067..6dbf8094548 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -8,13 +8,14 @@ pub use self::ConsumeMode::*; pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; use rustc_hir as hir; -use rustc_hir::def::Res; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; -// use rustc_hir::Pat; use rustc_hir::PatKind; +use rustc_hir::QPath; use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::ProjectionKind; +use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, adjustment, TyCtxt}; use rustc_target::abi::VariantIdx; @@ -54,7 +55,7 @@ pub trait Delegate<'tcx> { fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId); // [FIXME] RFC2229 This should also affect clippy ref: https://github.com/sexxi-goose/rust/pull/27 - fn fake_read(&mut self, place: Place<'tcx>); + fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause); } #[derive(Copy, Clone, PartialEq, Debug)] @@ -237,18 +238,26 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // We only want to borrow discr if the pattern contain something other // than wildcards let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; - let mut res = false; + let mut needs_to_be_read = false; for arm in arms.iter() { return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |_place, pat| { if let PatKind::Binding(_, _, _, opt_sub_pat) = pat.kind { if let None = opt_sub_pat { - res = true; + needs_to_be_read = true; + } + } else if let PatKind::TupleStruct(qpath, _, _) = &pat.kind { + // If a TupleStruct has a Some PathSegment, we should read the discr_place + // regardless if it contains a Wild pattern later + if let QPath::Resolved(_, path) = qpath { + if let Res::Def(DefKind::Ctor(_, _), _) = path.res { + needs_to_be_read = true; + } } } })); } - if res { + if needs_to_be_read { self.borrow_expr(&discr, ty::ImmBorrow); } @@ -539,6 +548,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) { + self.delegate.fake_read(discr_place.place.clone(), FakeReadCause::ForMatchedPlace); self.walk_pat(discr_place, &arm.pat); if let Some(hir::Guard::If(ref e)) = arm.guard { @@ -551,6 +561,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or /// let binding, and *not* a match arm or nested pat.) fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { + self.delegate.fake_read(discr_place.place.clone(), FakeReadCause::ForLet); self.walk_pat(discr_place, pat); } @@ -558,8 +569,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat); - self.delegate.fake_read(discr_place.place.clone()); - let tcx = self.tcx(); let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { @@ -620,10 +629,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing /// closure as the DefId. fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) { - // Over here we walk a closure that is nested inside the current body - // If the current body is a closure, then we also want to report back any fake reads, - // starting off of variables that are captured by our parent as well. - let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); let upvars = self.tcx().upvars_mentioned(self.body_owner); @@ -633,15 +638,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ty::Closure(..) | ty::Generator(..) ); - // [FIXME] RFC2229 Closures within closures don't work if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) { - for fake_read in fake_reads.iter() { - // Use this as a reference for if we should promote the fake read + for (fake_read, cause) in fake_reads.iter() { match fake_read.base { PlaceBase::Upvar(upvar_id) => { if upvars.map_or(body_owner_is_closure, |upvars| { !upvars.contains_key(&upvar_id.var_path.hir_id) }) { + // [FIXME] RFC2229 Update this comment // The nested closure might be capturing the current (enclosing) closure's local variables. // We check if the root variable is ever mentioned within the enclosing closure, if not // then for the current body (if it's a closure) these aren't captures, we will ignore them. @@ -655,14 +659,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ); } }; - self.delegate.fake_read(fake_read.clone()); + self.delegate.fake_read(fake_read.clone(), *cause); } } if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id) { for (var_hir_id, min_list) in min_captures.iter() { - // Use this as a reference for if we should promote the fake read if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) { // The nested closure might be capturing the current (enclosing) closure's local variables. // We check if the root variable is ever mentioned within the enclosing closure, if not |
