@@ -5,11 +5,10 @@ use rustc_data_structures::graph::dominators::Dominators;
55use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorReported } ;
66use rustc_hir as hir;
77use rustc_hir:: def_id:: LocalDefId ;
8- use rustc_hir:: { HirId , Node } ;
8+ use rustc_hir:: Node ;
99use rustc_index:: bit_set:: BitSet ;
1010use rustc_index:: vec:: IndexVec ;
1111use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
12- use rustc_middle:: hir:: place:: PlaceBase as HirPlaceBase ;
1312use rustc_middle:: mir:: {
1413 traversal, Body , ClearCrossCrate , Local , Location , Mutability , Operand , Place , PlaceElem ,
1514 PlaceRef , VarDebugInfoContents ,
@@ -18,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind
1817use rustc_middle:: mir:: { Field , ProjectionElem , Promoted , Rvalue , Statement , StatementKind } ;
1918use rustc_middle:: mir:: { InlineAsmOperand , Terminator , TerminatorKind } ;
2019use rustc_middle:: ty:: query:: Providers ;
21- use rustc_middle:: ty:: { self , ParamEnv , RegionVid , TyCtxt } ;
20+ use rustc_middle:: ty:: { self , CapturedPlace , ParamEnv , RegionVid , TyCtxt } ;
2221use rustc_session:: lint:: builtin:: { MUTABLE_BORROW_RESERVATION_CONFLICT , UNUSED_MUT } ;
2322use rustc_span:: { Span , Symbol , DUMMY_SP } ;
2423
@@ -73,16 +72,14 @@ crate use region_infer::RegionInferenceContext;
7372
7473// FIXME(eddyb) perhaps move this somewhere more centrally.
7574#[ derive( Debug ) ]
76- crate struct Upvar {
75+ crate struct Upvar < ' tcx > {
76+ // FIXME(project-rfc_2229#36): print capture precisely here.
7777 name : Symbol ,
7878
79- // FIXME(project-rfc-2229#8): This should use Place or something similar
80- var_hir_id : HirId ,
79+ place : CapturedPlace < ' tcx > ,
8180
8281 /// If true, the capture is behind a reference.
8382 by_ref : bool ,
84-
85- mutability : Mutability ,
8683}
8784
8885const DEREF_PROJECTION : & [ PlaceElem < ' _ > ; 1 ] = & [ ProjectionElem :: Deref ] ;
@@ -161,26 +158,13 @@ fn do_mir_borrowck<'a, 'tcx>(
161158 let upvars: Vec < _ > = tables
162159 . closure_min_captures_flattened ( def. did . to_def_id ( ) )
163160 . map ( |captured_place| {
164- let var_hir_id = match captured_place. place . base {
165- HirPlaceBase :: Upvar ( upvar_id) => upvar_id. var_path . hir_id ,
166- _ => bug ! ( "Expected upvar" ) ,
167- } ;
161+ let var_hir_id = captured_place. get_root_variable ( ) ;
168162 let capture = captured_place. info . capture_kind ;
169163 let by_ref = match capture {
170164 ty:: UpvarCapture :: ByValue ( _) => false ,
171165 ty:: UpvarCapture :: ByRef ( ..) => true ,
172166 } ;
173- let mut upvar = Upvar {
174- name : tcx. hir ( ) . name ( var_hir_id) ,
175- var_hir_id,
176- by_ref,
177- mutability : Mutability :: Not ,
178- } ;
179- let bm = * tables. pat_binding_modes ( ) . get ( var_hir_id) . expect ( "missing binding mode" ) ;
180- if bm == ty:: BindByValue ( hir:: Mutability :: Mut ) {
181- upvar. mutability = Mutability :: Mut ;
182- }
183- upvar
167+ Upvar { name : tcx. hir ( ) . name ( var_hir_id) , place : captured_place. clone ( ) , by_ref }
184168 } )
185169 . collect ( ) ;
186170
@@ -549,7 +533,7 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
549533 dominators : Dominators < BasicBlock > ,
550534
551535 /// Information about upvars not necessarily preserved in types or MIR
552- upvars : Vec < Upvar > ,
536+ upvars : Vec < Upvar < ' tcx > > ,
553537
554538 /// Names of local (user) variables (extracted from `var_debug_info`).
555539 local_names : IndexVec < Local , Option < Symbol > > ,
@@ -1374,13 +1358,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
13741358
13751359 fn propagate_closure_used_mut_upvar ( & mut self , operand : & Operand < ' tcx > ) {
13761360 let propagate_closure_used_mut_place = |this : & mut Self , place : Place < ' tcx > | {
1377- if !place. projection . is_empty ( ) {
1378- if let Some ( field) = this. is_upvar_field_projection ( place. as_ref ( ) ) {
1361+ // We have three possibilities here:
1362+ // a. We are modifying something through a mut-ref
1363+ // b. We are modifying something that is local to our parent
1364+ // c. Current body is a nested closure, and we are modifying path starting from
1365+ // a Place captured by our parent closure.
1366+
1367+ // Handle (c), the path being modified is exactly the path captured by our parent
1368+ if let Some ( field) = this. is_upvar_field_projection ( place. as_ref ( ) ) {
1369+ this. used_mut_upvars . push ( field) ;
1370+ return ;
1371+ }
1372+
1373+ for ( place_ref, proj) in place. iter_projections ( ) . rev ( ) {
1374+ // Handle (a)
1375+ if proj == ProjectionElem :: Deref {
1376+ match place_ref. ty ( this. body ( ) , this. infcx . tcx ) . ty . kind ( ) {
1377+ // We aren't modifying a variable directly
1378+ ty:: Ref ( _, _, hir:: Mutability :: Mut ) => return ,
1379+
1380+ _ => { }
1381+ }
1382+ }
1383+
1384+ // Handle (c)
1385+ if let Some ( field) = this. is_upvar_field_projection ( place_ref) {
13791386 this. used_mut_upvars . push ( field) ;
1387+ return ;
13801388 }
1381- } else {
1382- this. used_mut . insert ( place. local ) ;
13831389 }
1390+
1391+ // Handle(b)
1392+ this. used_mut . insert ( place. local ) ;
13841393 } ;
13851394
13861395 // This relies on the current way that by-value
@@ -2146,6 +2155,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21462155 place : PlaceRef < ' tcx > ,
21472156 is_local_mutation_allowed : LocalMutationIsAllowed ,
21482157 ) -> Result < RootPlace < ' tcx > , PlaceRef < ' tcx > > {
2158+ debug ! ( "is_mutable: place={:?}, is_local...={:?}" , place, is_local_mutation_allowed) ;
21492159 match place. last_projection ( ) {
21502160 None => {
21512161 let local = & self . body . local_decls [ place. local ] ;
@@ -2227,11 +2237,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
22272237 if let Some ( field) = upvar_field_projection {
22282238 let upvar = & self . upvars [ field. index ( ) ] ;
22292239 debug ! (
2230- "upvar.mutability={:?} local_mutation_is_allowed={:?} \
2231- place={:?}",
2232- upvar, is_local_mutation_allowed, place
2240+ "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2241+ place={:?}, place_base={:?} ",
2242+ upvar, is_local_mutation_allowed, place, place_base
22332243 ) ;
2234- match ( upvar. mutability , is_local_mutation_allowed) {
2244+ match ( upvar. place . mutability , is_local_mutation_allowed) {
22352245 (
22362246 Mutability :: Not ,
22372247 LocalMutationIsAllowed :: No
0 commit comments