@@ -21,6 +21,7 @@ use std::cell::RefCell;
21
21
use std:: marker:: PhantomData ;
22
22
use std:: ops:: { ControlFlow , Deref } ;
23
23
24
+ use root_cx:: BorrowCheckRootCtxt ;
24
25
use rustc_abi:: FieldIdx ;
25
26
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
26
27
use rustc_data_structures:: graph:: dominators:: Dominators ;
@@ -45,7 +46,7 @@ use rustc_mir_dataflow::move_paths::{
45
46
} ;
46
47
use rustc_mir_dataflow:: { Analysis , EntryStates , Results , ResultsVisitor , visit_results} ;
47
48
use rustc_session:: lint:: builtin:: { TAIL_EXPR_DROP_ORDER , UNUSED_MUT } ;
48
- use rustc_span:: { Span , Symbol } ;
49
+ use rustc_span:: { ErrorGuaranteed , Span , Symbol } ;
49
50
use smallvec:: SmallVec ;
50
51
use tracing:: { debug, instrument} ;
51
52
@@ -73,14 +74,14 @@ mod def_use;
73
74
mod diagnostics;
74
75
mod member_constraints;
75
76
mod nll;
76
- mod opaque_types;
77
77
mod path_utils;
78
78
mod place_ext;
79
79
mod places_conflict;
80
80
mod polonius;
81
81
mod prefixes;
82
82
mod region_infer;
83
83
mod renumber;
84
+ mod root_cx;
84
85
mod session_diagnostics;
85
86
mod type_check;
86
87
mod universal_regions;
@@ -102,44 +103,64 @@ pub fn provide(providers: &mut Providers) {
102
103
* providers = Providers { mir_borrowck, ..* providers } ;
103
104
}
104
105
105
- fn mir_borrowck ( tcx : TyCtxt < ' _ > , def : LocalDefId ) -> & BorrowCheckResult < ' _ > {
106
+ /// Provider for `query mir_borrowck`. Similar to `typeck`, this must
107
+ /// only be called for typeck roots which will then borrowck all
108
+ /// nested bodies as well.
109
+ fn mir_borrowck (
110
+ tcx : TyCtxt < ' _ > ,
111
+ def : LocalDefId ,
112
+ ) -> Result < & ConcreteOpaqueTypes < ' _ > , ErrorGuaranteed > {
113
+ assert ! ( !tcx. is_typeck_child( def. to_def_id( ) ) ) ;
106
114
let ( input_body, _) = tcx. mir_promoted ( def) ;
115
+ debug ! ( "run query mir_borrowck: {}" , tcx. def_path_str( def) ) ;
116
+
107
117
let input_body: & Body < ' _ > = & input_body. borrow ( ) ;
108
- if input_body. should_skip ( ) || input_body. tainted_by_errors . is_some ( ) {
109
- debug ! ( "Skipping borrowck because of injected body or tainted body" ) ;
110
- // Let's make up a borrowck result! Fun times!
111
- let result = BorrowCheckResult {
112
- concrete_opaque_types : FxIndexMap :: default ( ) ,
113
- closure_requirements : None ,
114
- used_mut_upvars : SmallVec :: new ( ) ,
115
- tainted_by_errors : input_body. tainted_by_errors ,
116
- } ;
117
- return tcx. arena . alloc ( result) ;
118
+ if let Some ( guar) = input_body. tainted_by_errors {
119
+ debug ! ( "Skipping borrowck because of tainted body" ) ;
120
+ Err ( guar)
121
+ } else if input_body. should_skip ( ) {
122
+ debug ! ( "Skipping borrowck because of injected body" ) ;
123
+ let opaque_types = ConcreteOpaqueTypes ( Default :: default ( ) ) ;
124
+ Ok ( tcx. arena . alloc ( opaque_types) )
125
+ } else {
126
+ let mut root_cx = BorrowCheckRootCtxt :: new ( tcx, def) ;
127
+ let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
128
+ do_mir_borrowck ( & mut root_cx, def, None ) . 0 ;
129
+ debug_assert ! ( closure_requirements. is_none( ) ) ;
130
+ debug_assert ! ( used_mut_upvars. is_empty( ) ) ;
131
+ root_cx. finalize ( )
118
132
}
133
+ }
119
134
120
- let borrowck_result = do_mir_borrowck ( tcx, def, None ) . 0 ;
121
- debug ! ( "mir_borrowck done" ) ;
122
-
123
- tcx. arena . alloc ( borrowck_result)
135
+ /// Data propagated to the typeck parent by nested items.
136
+ /// This should always be empty for the typeck root.
137
+ #[ derive( Debug ) ]
138
+ struct PropagatedBorrowCheckResults < ' tcx > {
139
+ closure_requirements : Option < ClosureRegionRequirements < ' tcx > > ,
140
+ used_mut_upvars : SmallVec < [ FieldIdx ; 8 ] > ,
124
141
}
125
142
126
143
/// Perform the actual borrow checking.
127
144
///
128
145
/// Use `consumer_options: None` for the default behavior of returning
129
- /// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according
130
- /// to the given [`ConsumerOptions`].
131
- #[ instrument( skip( tcx) , level = "debug" ) ]
146
+ /// [`PropagatedBorrowCheckResults`] only. Otherwise, return [`BodyWithBorrowckFacts`]
147
+ /// according to the given [`ConsumerOptions`].
148
+ ///
149
+ /// For nested bodies this should only be called through `root_cx.get_or_insert_nested`.
150
+ #[ instrument( skip( root_cx) , level = "debug" ) ]
132
151
fn do_mir_borrowck < ' tcx > (
133
- tcx : TyCtxt < ' tcx > ,
152
+ root_cx : & mut BorrowCheckRootCtxt < ' tcx > ,
134
153
def : LocalDefId ,
135
154
consumer_options : Option < ConsumerOptions > ,
136
- ) -> ( BorrowCheckResult < ' tcx > , Option < Box < BodyWithBorrowckFacts < ' tcx > > > ) {
155
+ ) -> ( PropagatedBorrowCheckResults < ' tcx > , Option < Box < BodyWithBorrowckFacts < ' tcx > > > ) {
156
+ let tcx = root_cx. tcx ;
137
157
let infcx = BorrowckInferCtxt :: new ( tcx, def) ;
138
158
let ( input_body, promoted) = tcx. mir_promoted ( def) ;
139
159
let input_body: & Body < ' _ > = & input_body. borrow ( ) ;
140
160
let input_promoted: & IndexSlice < _ , _ > = & promoted. borrow ( ) ;
141
161
if let Some ( e) = input_body. tainted_by_errors {
142
162
infcx. set_tainted_by_errors ( e) ;
163
+ root_cx. set_tainted_by_errors ( e) ;
143
164
}
144
165
145
166
let mut local_names = IndexVec :: from_elem ( None , & input_body. local_decls ) ;
@@ -185,13 +206,13 @@ fn do_mir_borrowck<'tcx>(
185
206
// Compute non-lexical lifetimes.
186
207
let nll:: NllOutput {
187
208
regioncx,
188
- concrete_opaque_types,
189
209
polonius_input,
190
210
polonius_output,
191
211
opt_closure_req,
192
212
nll_errors,
193
213
polonius_diagnostics,
194
214
} = nll:: compute_regions (
215
+ root_cx,
195
216
& infcx,
196
217
free_regions,
197
218
body,
@@ -210,26 +231,19 @@ fn do_mir_borrowck<'tcx>(
210
231
// We also have a `#[rustc_regions]` annotation that causes us to dump
211
232
// information.
212
233
let diags_buffer = & mut BorrowckDiagnosticsBuffer :: default ( ) ;
213
- nll:: dump_annotation (
214
- & infcx,
215
- body,
216
- & regioncx,
217
- & opt_closure_req,
218
- & concrete_opaque_types,
219
- diags_buffer,
220
- ) ;
234
+ nll:: dump_annotation ( & infcx, body, & regioncx, & opt_closure_req, diags_buffer) ;
221
235
222
236
let movable_coroutine =
223
- // The first argument is the coroutine type passed by value
224
- if let Some ( local) = body. local_decls . raw . get ( 1 )
225
- // Get the interior types and args which typeck computed
226
- && let ty:: Coroutine ( def_id, _) = * local. ty . kind ( )
227
- && tcx. coroutine_movability ( def_id) == hir:: Movability :: Movable
228
- {
229
- true
230
- } else {
231
- false
232
- } ;
237
+ // The first argument is the coroutine type passed by value
238
+ if let Some ( local) = body. local_decls . raw . get ( 1 )
239
+ // Get the interior types and args which typeck computed
240
+ && let ty:: Coroutine ( def_id, _) = * local. ty . kind ( )
241
+ && tcx. coroutine_movability ( def_id) == hir:: Movability :: Movable
242
+ {
243
+ true
244
+ } else {
245
+ false
246
+ } ;
233
247
234
248
// While promoteds should mostly be correct by construction, we need to check them for
235
249
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
@@ -240,6 +254,7 @@ fn do_mir_borrowck<'tcx>(
240
254
// this check out of `MirBorrowckCtxt`, actually doing so is far from trivial.
241
255
let move_data = MoveData :: gather_moves ( promoted_body, tcx, |_| true ) ;
242
256
let mut promoted_mbcx = MirBorrowckCtxt {
257
+ root_cx,
243
258
infcx : & infcx,
244
259
body : promoted_body,
245
260
move_data : & move_data,
@@ -280,6 +295,7 @@ fn do_mir_borrowck<'tcx>(
280
295
}
281
296
282
297
let mut mbcx = MirBorrowckCtxt {
298
+ root_cx,
283
299
infcx : & infcx,
284
300
body,
285
301
move_data : & move_data,
@@ -347,13 +363,13 @@ fn do_mir_borrowck<'tcx>(
347
363
348
364
debug ! ( "mbcx.used_mut: {:?}" , mbcx. used_mut) ;
349
365
mbcx. lint_unused_mut ( ) ;
350
- let tainted_by_errors = mbcx. emit_errors ( ) ;
366
+ if let Some ( guar) = mbcx. emit_errors ( ) {
367
+ mbcx. root_cx . set_tainted_by_errors ( guar) ;
368
+ }
351
369
352
- let result = BorrowCheckResult {
353
- concrete_opaque_types : concrete_opaque_types. into_inner ( ) ,
370
+ let result = PropagatedBorrowCheckResults {
354
371
closure_requirements : opt_closure_req,
355
372
used_mut_upvars : mbcx. used_mut_upvars ,
356
- tainted_by_errors,
357
373
} ;
358
374
359
375
let body_with_facts = if consumer_options. is_some ( ) {
@@ -488,6 +504,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
488
504
}
489
505
490
506
struct MirBorrowckCtxt < ' a , ' infcx , ' tcx > {
507
+ root_cx : & ' a mut BorrowCheckRootCtxt < ' tcx > ,
491
508
infcx : & ' infcx BorrowckInferCtxt < ' tcx > ,
492
509
body : & ' a Body < ' tcx > ,
493
510
move_data : & ' a MoveData < ' tcx > ,
@@ -1361,11 +1378,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1361
1378
| AggregateKind :: CoroutineClosure ( def_id, _)
1362
1379
| AggregateKind :: Coroutine ( def_id, _) => {
1363
1380
let def_id = def_id. expect_local ( ) ;
1364
- let BorrowCheckResult { used_mut_upvars, .. } =
1365
- self . infcx . tcx . mir_borrowck ( def_id) ;
1381
+ let used_mut_upvars = self . root_cx . used_mut_upvars ( def_id) ;
1366
1382
debug ! ( "{:?} used_mut_upvars={:?}" , def_id, used_mut_upvars) ;
1367
- for field in used_mut_upvars {
1368
- self . propagate_closure_used_mut_upvar ( & operands[ * field] ) ;
1383
+ // FIXME: We're cloning the `SmallVec` here to avoid borrowing `root_cx`
1384
+ // when calling `propagate_closure_used_mut_upvar`. This should ideally
1385
+ // be unnecessary.
1386
+ for field in used_mut_upvars. clone ( ) {
1387
+ self . propagate_closure_used_mut_upvar ( & operands[ field] ) ;
1369
1388
}
1370
1389
}
1371
1390
AggregateKind :: Adt ( ..)
0 commit comments