@@ -18,15 +18,16 @@ use rustc::infer::InferCtxt;
18
18
use rustc:: ty:: { self , ParamEnv , TyCtxt } ;
19
19
use rustc:: ty:: maps:: Providers ;
20
20
use rustc:: lint:: builtin:: UNUSED_MUT ;
21
- use rustc:: mir:: { AssertMessage , BasicBlock , BorrowKind , ClearCrossCrate , Local } ;
22
- use rustc:: mir:: { Location , Place , Mir , Mutability , Operand , Projection , ProjectionElem } ;
23
- use rustc:: mir:: { Rvalue , Field , Statement , StatementKind , Terminator , TerminatorKind } ;
24
- use rustc:: mir:: ClosureRegionRequirements ;
21
+ use rustc:: mir:: { AssertMessage , AggregateKind , BasicBlock , BorrowCheckResult , BorrowKind } ;
22
+ use rustc:: mir:: { ClearCrossCrate , Local , Location , Place , Mir , Mutability , Operand } ;
23
+ use rustc:: mir:: { Projection , ProjectionElem , Rvalue , Field , Statement , StatementKind } ;
24
+ use rustc:: mir:: { Terminator , TerminatorKind } ;
25
25
26
26
use rustc_data_structures:: control_flow_graph:: dominators:: Dominators ;
27
27
use rustc_data_structures:: fx:: FxHashSet ;
28
28
use rustc_data_structures:: indexed_set:: IdxSetBuf ;
29
29
use rustc_data_structures:: indexed_vec:: Idx ;
30
+ use rustc_data_structures:: small_vec:: SmallVec ;
30
31
31
32
use std:: rc:: Rc ;
32
33
@@ -70,12 +71,15 @@ pub fn provide(providers: &mut Providers) {
70
71
fn mir_borrowck < ' a , ' tcx > (
71
72
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
72
73
def_id : DefId ,
73
- ) -> Option < ClosureRegionRequirements < ' tcx > > {
74
+ ) -> BorrowCheckResult < ' tcx > {
74
75
let input_mir = tcx. mir_validated ( def_id) ;
75
76
debug ! ( "run query mir_borrowck: {}" , tcx. item_path_str( def_id) ) ;
76
77
77
78
if !tcx. has_attr ( def_id, "rustc_mir_borrowck" ) && !tcx. use_mir_borrowck ( ) {
78
- return None ;
79
+ return BorrowCheckResult {
80
+ closure_requirements : None ,
81
+ used_mut_upvars : SmallVec :: new ( ) ,
82
+ } ;
79
83
}
80
84
81
85
let opt_closure_req = tcx. infer_ctxt ( ) . enter ( |infcx| {
@@ -91,7 +95,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
91
95
infcx : & InferCtxt < ' a , ' gcx , ' tcx > ,
92
96
input_mir : & Mir < ' gcx > ,
93
97
def_id : DefId ,
94
- ) -> Option < ClosureRegionRequirements < ' gcx > > {
98
+ ) -> BorrowCheckResult < ' gcx > {
95
99
let tcx = infcx. tcx ;
96
100
let attributes = tcx. get_attrs ( def_id) ;
97
101
let param_env = tcx. param_env ( def_id) ;
@@ -239,6 +243,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
239
243
moved_error_reported : FxHashSet ( ) ,
240
244
nonlexical_regioncx : opt_regioncx,
241
245
used_mut : FxHashSet ( ) ,
246
+ used_mut_upvars : SmallVec :: new ( ) ,
242
247
nonlexical_cause_info : None ,
243
248
borrow_set,
244
249
dominators,
@@ -254,7 +259,28 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
254
259
255
260
mbcx. analyze_results ( & mut state) ; // entry point for DataflowResultsConsumer
256
261
257
- opt_closure_req
262
+ debug ! ( "mbcx.used_mut: {:?}" , mbcx. used_mut) ;
263
+
264
+ for local in mbcx. mir . mut_vars_iter ( ) . filter ( |local| !mbcx. used_mut . contains ( local) ) {
265
+ if let ClearCrossCrate :: Set ( ref vsi) = mbcx. mir . visibility_scope_info {
266
+ let source_info = mbcx. mir . local_decls [ local] . source_info ;
267
+ let mut_span = tcx. sess . codemap ( ) . span_until_non_whitespace ( source_info. span ) ;
268
+
269
+ tcx. struct_span_lint_node (
270
+ UNUSED_MUT ,
271
+ vsi[ source_info. scope ] . lint_root ,
272
+ source_info. span ,
273
+ "variable does not need to be mutable"
274
+ )
275
+ . span_suggestion_short ( mut_span, "remove this `mut`" , "" . to_owned ( ) )
276
+ . emit ( ) ;
277
+ }
278
+ }
279
+
280
+ BorrowCheckResult {
281
+ closure_requirements : opt_closure_req,
282
+ used_mut_upvars : mbcx. used_mut_upvars ,
283
+ }
258
284
}
259
285
260
286
#[ allow( dead_code) ]
@@ -292,6 +318,9 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
292
318
/// This field keeps track of all the local variables that are declared mut and are mutated.
293
319
/// Used for the warning issued by an unused mutable local variable.
294
320
used_mut : FxHashSet < Local > ,
321
+ /// If the function we're checking is a closure, then we'll need to report back the list of
322
+ /// mutable upvars that have been used. This field keeps track of them.
323
+ used_mut_upvars : SmallVec < [ Field ; 8 ] > ,
295
324
/// Non-lexical region inference context, if NLL is enabled. This
296
325
/// contains the results from region inference and lets us e.g.
297
326
/// find out which CFG points are contained in each borrow region.
@@ -439,22 +468,6 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
439
468
440
469
self . check_activations ( location, span, flow_state) ;
441
470
442
- for local in self . mir . mut_vars_iter ( ) . filter ( |local| !self . used_mut . contains ( local) ) {
443
- if let ClearCrossCrate :: Set ( ref vsi) = self . mir . visibility_scope_info {
444
- let source_info = self . mir . local_decls [ local] . source_info ;
445
- let mut_span = self . tcx . sess . codemap ( ) . span_until_non_whitespace ( source_info. span ) ;
446
-
447
- self . tcx . struct_span_lint_node (
448
- UNUSED_MUT ,
449
- vsi[ source_info. scope ] . lint_root ,
450
- source_info. span ,
451
- "variable does not need to be mutable"
452
- )
453
- . span_suggestion_short ( mut_span, "remove this `mut`" , "" . to_owned ( ) )
454
- . emit ( ) ;
455
- }
456
- }
457
-
458
471
match term. kind {
459
472
TerminatorKind :: SwitchInt {
460
473
ref discr,
@@ -1118,9 +1131,33 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1118
1131
// `NullOp::Box`?
1119
1132
}
1120
1133
1121
- Rvalue :: Aggregate ( ref _aggregate_kind, ref operands) => for operand in operands {
1122
- self . consume_operand ( context, ( operand, span) , flow_state) ;
1123
- } ,
1134
+ Rvalue :: Aggregate ( ref aggregate_kind, ref operands) => {
1135
+ // We need to report back the list of mutable upvars that were
1136
+ // moved into the closure and subsequently used by the closure,
1137
+ // in order to populate our used_mut set.
1138
+ if let AggregateKind :: Closure ( def_id, _) = & * * aggregate_kind {
1139
+ let BorrowCheckResult { used_mut_upvars, .. } = self . tcx . mir_borrowck ( * def_id) ;
1140
+ for field in used_mut_upvars {
1141
+ match operands[ field. index ( ) ] {
1142
+ Operand :: Move ( Place :: Local ( local) ) => {
1143
+ self . used_mut . insert ( local) ;
1144
+ }
1145
+ Operand :: Move ( Place :: Projection ( ref proj) ) => {
1146
+ if let Some ( field) = self . is_upvar_field_projection ( & proj. base ) {
1147
+ self . used_mut_upvars . push ( field) ;
1148
+ }
1149
+ }
1150
+ Operand :: Move ( Place :: Static ( ..) ) |
1151
+ Operand :: Copy ( ..) |
1152
+ Operand :: Constant ( ..) => { }
1153
+ }
1154
+ }
1155
+ }
1156
+
1157
+ for operand in operands {
1158
+ self . consume_operand ( context, ( operand, span) , flow_state) ;
1159
+ }
1160
+ }
1124
1161
}
1125
1162
}
1126
1163
@@ -1652,8 +1689,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1652
1689
err. emit ( ) ;
1653
1690
} ,
1654
1691
Reservation ( WriteKind :: Mutate ) | Write ( WriteKind :: Mutate ) => {
1655
- if let Place :: Local ( local) = * place {
1656
- self . used_mut . insert ( local) ;
1692
+ match place {
1693
+ Place :: Local ( local) => {
1694
+ self . used_mut . insert ( * local) ;
1695
+ }
1696
+ Place :: Projection ( ref proj) => {
1697
+ if let Some ( field) = self . is_upvar_field_projection ( & proj. base ) {
1698
+ self . used_mut_upvars . push ( field) ;
1699
+ }
1700
+ }
1701
+ Place :: Static ( ..) => { }
1657
1702
}
1658
1703
if let Err ( place_err) = self . is_mutable ( place, is_local_mutation_allowed) {
1659
1704
error_reported = true ;
0 commit comments