@@ -5,11 +5,10 @@ use rustc_data_structures::graph::dominators::Dominators;
5
5
use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorReported } ;
6
6
use rustc_hir as hir;
7
7
use rustc_hir:: def_id:: LocalDefId ;
8
- use rustc_hir:: { HirId , Node } ;
8
+ use rustc_hir:: Node ;
9
9
use rustc_index:: bit_set:: BitSet ;
10
10
use rustc_index:: vec:: IndexVec ;
11
11
use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
12
- use rustc_middle:: hir:: place:: PlaceBase as HirPlaceBase ;
13
12
use rustc_middle:: mir:: {
14
13
traversal, Body , ClearCrossCrate , Local , Location , Mutability , Operand , Place , PlaceElem ,
15
14
PlaceRef , VarDebugInfoContents ,
@@ -18,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind
18
17
use rustc_middle:: mir:: { Field , ProjectionElem , Promoted , Rvalue , Statement , StatementKind } ;
19
18
use rustc_middle:: mir:: { InlineAsmOperand , Terminator , TerminatorKind } ;
20
19
use rustc_middle:: ty:: query:: Providers ;
21
- use rustc_middle:: ty:: { self , ParamEnv , RegionVid , TyCtxt } ;
20
+ use rustc_middle:: ty:: { self , CapturedPlace , ParamEnv , RegionVid , TyCtxt } ;
22
21
use rustc_session:: lint:: builtin:: { MUTABLE_BORROW_RESERVATION_CONFLICT , UNUSED_MUT } ;
23
22
use rustc_span:: { Span , Symbol , DUMMY_SP } ;
24
23
@@ -73,16 +72,14 @@ crate use region_infer::RegionInferenceContext;
73
72
74
73
// FIXME(eddyb) perhaps move this somewhere more centrally.
75
74
#[ derive( Debug ) ]
76
- crate struct Upvar {
75
+ crate struct Upvar < ' tcx > {
76
+ // FIXME(project-rfc_2229#36): print capture precisely here.
77
77
name : Symbol ,
78
78
79
- // FIXME(project-rfc-2229#8): This should use Place or something similar
80
- var_hir_id : HirId ,
79
+ place : CapturedPlace < ' tcx > ,
81
80
82
81
/// If true, the capture is behind a reference.
83
82
by_ref : bool ,
84
-
85
- mutability : Mutability ,
86
83
}
87
84
88
85
const DEREF_PROJECTION : & [ PlaceElem < ' _ > ; 1 ] = & [ ProjectionElem :: Deref ] ;
@@ -161,26 +158,13 @@ fn do_mir_borrowck<'a, 'tcx>(
161
158
let upvars: Vec < _ > = tables
162
159
. closure_min_captures_flattened ( def. did . to_def_id ( ) )
163
160
. 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 ( ) ;
168
162
let capture = captured_place. info . capture_kind ;
169
163
let by_ref = match capture {
170
164
ty:: UpvarCapture :: ByValue ( _) => false ,
171
165
ty:: UpvarCapture :: ByRef ( ..) => true ,
172
166
} ;
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 }
184
168
} )
185
169
. collect ( ) ;
186
170
@@ -549,7 +533,7 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
549
533
dominators : Dominators < BasicBlock > ,
550
534
551
535
/// Information about upvars not necessarily preserved in types or MIR
552
- upvars : Vec < Upvar > ,
536
+ upvars : Vec < Upvar < ' tcx > > ,
553
537
554
538
/// Names of local (user) variables (extracted from `var_debug_info`).
555
539
local_names : IndexVec < Local , Option < Symbol > > ,
@@ -1374,13 +1358,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1374
1358
1375
1359
fn propagate_closure_used_mut_upvar ( & mut self , operand : & Operand < ' tcx > ) {
1376
1360
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) {
1379
1386
this. used_mut_upvars . push ( field) ;
1387
+ return ;
1380
1388
}
1381
- } else {
1382
- this. used_mut . insert ( place. local ) ;
1383
1389
}
1390
+
1391
+ // Handle(b)
1392
+ this. used_mut . insert ( place. local ) ;
1384
1393
} ;
1385
1394
1386
1395
// This relies on the current way that by-value
@@ -2146,6 +2155,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2146
2155
place : PlaceRef < ' tcx > ,
2147
2156
is_local_mutation_allowed : LocalMutationIsAllowed ,
2148
2157
) -> Result < RootPlace < ' tcx > , PlaceRef < ' tcx > > {
2158
+ debug ! ( "is_mutable: place={:?}, is_local...={:?}" , place, is_local_mutation_allowed) ;
2149
2159
match place. last_projection ( ) {
2150
2160
None => {
2151
2161
let local = & self . body . local_decls [ place. local ] ;
@@ -2227,11 +2237,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2227
2237
if let Some ( field) = upvar_field_projection {
2228
2238
let upvar = & self . upvars [ field. index ( ) ] ;
2229
2239
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
2233
2243
) ;
2234
- match ( upvar. mutability , is_local_mutation_allowed) {
2244
+ match ( upvar. place . mutability , is_local_mutation_allowed) {
2235
2245
(
2236
2246
Mutability :: Not ,
2237
2247
LocalMutationIsAllowed :: No
0 commit comments