@@ -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 ;
@@ -35,7 +36,7 @@ use rustc_infer::infer::{
35
36
} ;
36
37
use rustc_middle:: mir:: * ;
37
38
use rustc_middle:: query:: Providers ;
38
- use rustc_middle:: ty:: { self , ParamEnv , RegionVid , TyCtxt , TypingMode , fold_regions} ;
39
+ use rustc_middle:: ty:: { self , ParamEnv , RegionVid , Ty , TyCtxt , TypingMode , fold_regions} ;
39
40
use rustc_middle:: { bug, span_bug} ;
40
41
use rustc_mir_dataflow:: impls:: {
41
42
EverInitializedPlaces , MaybeInitializedPlaces , MaybeUninitializedPlaces ,
@@ -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,194 @@ 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
+ fn mir_borrowck (
107
+ tcx : TyCtxt < ' _ > ,
108
+ def : LocalDefId ,
109
+ ) -> Result < & ConcreteOpaqueTypes < ' _ > , ErrorGuaranteed > {
110
+ assert ! ( !tcx. is_typeck_child( def. to_def_id( ) ) ) ;
106
111
let ( input_body, _) = tcx. mir_promoted ( def) ;
112
+ debug ! ( "run query mir_borrowck: {}" , tcx. def_path_str( def) ) ;
113
+
107
114
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) ;
115
+ if let Some ( guar) = input_body. tainted_by_errors {
116
+ debug ! ( "Skipping borrowck because of tainted body" ) ;
117
+ Err ( guar)
118
+ } else if input_body. should_skip ( ) {
119
+ debug ! ( "Skipping borrowck because of injected body" ) ;
120
+ let opaque_types = ConcreteOpaqueTypes ( Default :: default ( ) ) ;
121
+ Ok ( tcx. arena . alloc ( opaque_types) )
122
+ } else {
123
+ let mut root_cx = BorrowCheckRootCtxt :: new ( tcx, def) ;
124
+ let BorrowCheckResult { closure_requirements, used_mut_upvars } =
125
+ do_mir_borrowck ( & mut root_cx, def, None ) . 0 ;
126
+ debug_assert ! ( closure_requirements. is_none( ) ) ;
127
+ debug_assert ! ( used_mut_upvars. is_empty( ) ) ;
128
+ root_cx. finalize ( )
118
129
}
130
+ }
131
+
132
+ #[ derive( Debug ) ]
133
+ struct BorrowCheckResult < ' tcx > {
134
+ closure_requirements : Option < ClosureRegionRequirements < ' tcx > > ,
135
+ used_mut_upvars : SmallVec < [ FieldIdx ; 8 ] > ,
136
+ }
137
+
138
+ /// After we borrow check a closure, we are left with various
139
+ /// requirements that we have inferred between the free regions that
140
+ /// appear in the closure's signature or on its field types. These
141
+ /// requirements are then verified and proved by the closure's
142
+ /// creating function. This struct encodes those requirements.
143
+ ///
144
+ /// The requirements are listed as being between various `RegionVid`. The 0th
145
+ /// region refers to `'static`; subsequent region vids refer to the free
146
+ /// regions that appear in the closure (or coroutine's) type, in order of
147
+ /// appearance. (This numbering is actually defined by the `UniversalRegions`
148
+ /// struct in the NLL region checker. See for example
149
+ /// `UniversalRegions::closure_mapping`.) Note the free regions in the
150
+ /// closure's signature and captures are erased.
151
+ ///
152
+ /// Example: If type check produces a closure with the closure args:
153
+ ///
154
+ /// ```text
155
+ /// ClosureArgs = [
156
+ /// 'a, // From the parent.
157
+ /// 'b,
158
+ /// i8, // the "closure kind"
159
+ /// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
160
+ /// &'<erased> String, // some upvar
161
+ /// ]
162
+ /// ```
163
+ ///
164
+ /// We would "renumber" each free region to a unique vid, as follows:
165
+ ///
166
+ /// ```text
167
+ /// ClosureArgs = [
168
+ /// '1, // From the parent.
169
+ /// '2,
170
+ /// i8, // the "closure kind"
171
+ /// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
172
+ /// &'4 String, // some upvar
173
+ /// ]
174
+ /// ```
175
+ ///
176
+ /// Now the code might impose a requirement like `'1: '2`. When an
177
+ /// instance of the closure is created, the corresponding free regions
178
+ /// can be extracted from its type and constrained to have the given
179
+ /// outlives relationship.
180
+ #[ derive( Clone , Debug ) ]
181
+ pub struct ClosureRegionRequirements < ' tcx > {
182
+ /// The number of external regions defined on the closure. In our
183
+ /// example above, it would be 3 -- one for `'static`, then `'1`
184
+ /// and `'2`. This is just used for a sanity check later on, to
185
+ /// make sure that the number of regions we see at the callsite
186
+ /// matches.
187
+ pub num_external_vids : usize ,
188
+
189
+ /// Requirements between the various free regions defined in
190
+ /// indices.
191
+ pub outlives_requirements : Vec < ClosureOutlivesRequirement < ' tcx > > ,
192
+ }
193
+
194
+ /// Indicates an outlives-constraint between a type or between two
195
+ /// free regions declared on the closure.
196
+ #[ derive( Copy , Clone , Debug ) ]
197
+ pub struct ClosureOutlivesRequirement < ' tcx > {
198
+ // This region or type ...
199
+ pub subject : ClosureOutlivesSubject < ' tcx > ,
119
200
120
- let borrowck_result = do_mir_borrowck ( tcx , def , None ) . 0 ;
121
- debug ! ( "mir_borrowck done" ) ;
201
+ // ... must outlive this one.
202
+ pub outlived_free_region : ty :: RegionVid ,
122
203
123
- tcx. arena . alloc ( borrowck_result)
204
+ // If not, report an error here ...
205
+ pub blame_span : Span ,
206
+
207
+ // ... due to this reason.
208
+ pub category : ConstraintCategory < ' tcx > ,
209
+ }
210
+
211
+ // Make sure this enum doesn't unintentionally grow
212
+ #[ cfg( target_pointer_width = "64" ) ]
213
+ rustc_data_structures:: static_assert_size!( ConstraintCategory <' _>, 16 ) ;
214
+
215
+ /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
216
+ /// that must outlive some region.
217
+ #[ derive( Copy , Clone , Debug ) ]
218
+ pub enum ClosureOutlivesSubject < ' tcx > {
219
+ /// Subject is a type, typically a type parameter, but could also
220
+ /// be a projection. Indicates a requirement like `T: 'a` being
221
+ /// passed to the caller, where the type here is `T`.
222
+ Ty ( ClosureOutlivesSubjectTy < ' tcx > ) ,
223
+
224
+ /// Subject is a free region from the closure. Indicates a requirement
225
+ /// like `'a: 'b` being passed to the caller; the region here is `'a`.
226
+ Region ( ty:: RegionVid ) ,
227
+ }
228
+
229
+ /// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
230
+ ///
231
+ /// This abstraction is necessary because the type may include `ReVar` regions,
232
+ /// which is what we use internally within NLL code, and they can't be used in
233
+ /// a query response.
234
+ ///
235
+ /// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
236
+ /// type is not recognized as a binder for late-bound region.
237
+ #[ derive( Copy , Clone , Debug ) ]
238
+ pub struct ClosureOutlivesSubjectTy < ' tcx > {
239
+ inner : Ty < ' tcx > ,
240
+ }
241
+
242
+ impl < ' tcx > ClosureOutlivesSubjectTy < ' tcx > {
243
+ /// All regions of `ty` must be of kind `ReVar` and must represent
244
+ /// universal regions *external* to the closure.
245
+ pub fn bind ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> Self {
246
+ let inner = fold_regions ( tcx, ty, |r, depth| match r. kind ( ) {
247
+ ty:: ReVar ( vid) => {
248
+ let br = ty:: BoundRegion {
249
+ var : ty:: BoundVar :: from_usize ( vid. index ( ) ) ,
250
+ kind : ty:: BoundRegionKind :: Anon ,
251
+ } ;
252
+ ty:: Region :: new_bound ( tcx, depth, br)
253
+ }
254
+ _ => bug ! ( "unexpected region in ClosureOutlivesSubjectTy: {r:?}" ) ,
255
+ } ) ;
256
+
257
+ Self { inner }
258
+ }
259
+
260
+ pub fn instantiate (
261
+ self ,
262
+ tcx : TyCtxt < ' tcx > ,
263
+ mut map : impl FnMut ( ty:: RegionVid ) -> ty:: Region < ' tcx > ,
264
+ ) -> Ty < ' tcx > {
265
+ fold_regions ( tcx, self . inner , |r, depth| match r. kind ( ) {
266
+ ty:: ReBound ( debruijn, br) => {
267
+ debug_assert_eq ! ( debruijn, depth) ;
268
+ map ( ty:: RegionVid :: from_usize ( br. var . index ( ) ) )
269
+ }
270
+ _ => bug ! ( "unexpected region {r:?}" ) ,
271
+ } )
272
+ }
124
273
}
125
274
126
275
/// Perform the actual borrow checking.
127
276
///
128
277
/// Use `consumer_options: None` for the default behavior of returning
129
278
/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according
130
279
/// to the given [`ConsumerOptions`].
131
- #[ instrument( skip( tcx ) , level = "debug" ) ]
280
+ #[ instrument( skip( root_cx ) , level = "debug" ) ]
132
281
fn do_mir_borrowck < ' tcx > (
133
- tcx : TyCtxt < ' tcx > ,
282
+ root_cx : & mut BorrowCheckRootCtxt < ' tcx > ,
134
283
def : LocalDefId ,
135
284
consumer_options : Option < ConsumerOptions > ,
136
285
) -> ( BorrowCheckResult < ' tcx > , Option < Box < BodyWithBorrowckFacts < ' tcx > > > ) {
286
+ let tcx = root_cx. tcx ;
137
287
let infcx = BorrowckInferCtxt :: new ( tcx, def) ;
138
288
let ( input_body, promoted) = tcx. mir_promoted ( def) ;
139
289
let input_body: & Body < ' _ > = & input_body. borrow ( ) ;
140
290
let input_promoted: & IndexSlice < _ , _ > = & promoted. borrow ( ) ;
141
291
if let Some ( e) = input_body. tainted_by_errors {
142
292
infcx. set_tainted_by_errors ( e) ;
293
+ root_cx. set_tainted_by_errors ( e) ;
143
294
}
144
295
145
296
let mut local_names = IndexVec :: from_elem ( None , & input_body. local_decls ) ;
@@ -191,13 +342,13 @@ fn do_mir_borrowck<'tcx>(
191
342
// Compute non-lexical lifetimes.
192
343
let nll:: NllOutput {
193
344
regioncx,
194
- concrete_opaque_types,
195
345
polonius_input,
196
346
polonius_output,
197
347
opt_closure_req,
198
348
nll_errors,
199
349
polonius_diagnostics,
200
350
} = nll:: compute_regions (
351
+ root_cx,
201
352
& infcx,
202
353
free_regions,
203
354
body,
@@ -216,26 +367,19 @@ fn do_mir_borrowck<'tcx>(
216
367
// We also have a `#[rustc_regions]` annotation that causes us to dump
217
368
// information.
218
369
let diags_buffer = & mut BorrowckDiagnosticsBuffer :: default ( ) ;
219
- nll:: dump_annotation (
220
- & infcx,
221
- body,
222
- & regioncx,
223
- & opt_closure_req,
224
- & concrete_opaque_types,
225
- diags_buffer,
226
- ) ;
370
+ nll:: dump_annotation ( & infcx, body, & regioncx, & opt_closure_req, diags_buffer) ;
227
371
228
372
let movable_coroutine =
229
- // The first argument is the coroutine type passed by value
230
- if let Some ( local) = body. local_decls . raw . get ( 1 )
231
- // Get the interior types and args which typeck computed
232
- && let ty:: Coroutine ( def_id, _) = * local. ty . kind ( )
233
- && tcx. coroutine_movability ( def_id) == hir:: Movability :: Movable
234
- {
235
- true
236
- } else {
237
- false
238
- } ;
373
+ // The first argument is the coroutine type passed by value
374
+ if let Some ( local) = body. local_decls . raw . get ( 1 )
375
+ // Get the interior types and args which typeck computed
376
+ && let ty:: Coroutine ( def_id, _) = * local. ty . kind ( )
377
+ && tcx. coroutine_movability ( def_id) == hir:: Movability :: Movable
378
+ {
379
+ true
380
+ } else {
381
+ false
382
+ } ;
239
383
240
384
// While promoteds should mostly be correct by construction, we need to check them for
241
385
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
@@ -246,6 +390,7 @@ fn do_mir_borrowck<'tcx>(
246
390
// this check out of `MirBorrowckCtxt`, actually doing so is far from trivial.
247
391
let move_data = MoveData :: gather_moves ( promoted_body, tcx, |_| true ) ;
248
392
let mut promoted_mbcx = MirBorrowckCtxt {
393
+ root_cx,
249
394
infcx : & infcx,
250
395
body : promoted_body,
251
396
move_data : & move_data,
@@ -286,6 +431,7 @@ fn do_mir_borrowck<'tcx>(
286
431
}
287
432
288
433
let mut mbcx = MirBorrowckCtxt {
434
+ root_cx,
289
435
infcx : & infcx,
290
436
body,
291
437
move_data : & move_data,
@@ -353,13 +499,13 @@ fn do_mir_borrowck<'tcx>(
353
499
354
500
debug ! ( "mbcx.used_mut: {:?}" , mbcx. used_mut) ;
355
501
mbcx. lint_unused_mut ( ) ;
356
- let tainted_by_errors = mbcx. emit_errors ( ) ;
502
+ if let Some ( guar) = mbcx. emit_errors ( ) {
503
+ mbcx. root_cx . set_tainted_by_errors ( guar) ;
504
+ }
357
505
358
506
let result = BorrowCheckResult {
359
- concrete_opaque_types : concrete_opaque_types. into_inner ( ) ,
360
507
closure_requirements : opt_closure_req,
361
508
used_mut_upvars : mbcx. used_mut_upvars ,
362
- tainted_by_errors,
363
509
} ;
364
510
365
511
let body_with_facts = if consumer_options. is_some ( ) {
@@ -512,6 +658,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
512
658
}
513
659
514
660
struct MirBorrowckCtxt < ' a , ' infcx , ' tcx > {
661
+ root_cx : & ' a mut BorrowCheckRootCtxt < ' tcx > ,
515
662
infcx : & ' infcx BorrowckInferCtxt < ' tcx > ,
516
663
body : & ' a Body < ' tcx > ,
517
664
move_data : & ' a MoveData < ' tcx > ,
@@ -1385,11 +1532,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1385
1532
| AggregateKind :: CoroutineClosure ( def_id, _)
1386
1533
| AggregateKind :: Coroutine ( def_id, _) => {
1387
1534
let def_id = def_id. expect_local ( ) ;
1388
- let BorrowCheckResult { used_mut_upvars, .. } =
1389
- self . infcx . tcx . mir_borrowck ( def_id) ;
1535
+ let used_mut_upvars = self . root_cx . used_mut_upvars ( def_id) ;
1390
1536
debug ! ( "{:?} used_mut_upvars={:?}" , def_id, used_mut_upvars) ;
1391
- for field in used_mut_upvars {
1392
- self . propagate_closure_used_mut_upvar ( & operands[ * field] ) ;
1537
+ // FIXME: We're cloning the `SmallVec` here to avoid borrowing `root_cx`
1538
+ // when calling `propagate_closure_used_mut_upvar`. This should ideally
1539
+ // be unnecessary.
1540
+ for field in used_mut_upvars. clone ( ) {
1541
+ self . propagate_closure_used_mut_upvar ( & operands[ field] ) ;
1393
1542
}
1394
1543
}
1395
1544
AggregateKind :: Adt ( ..)
0 commit comments