Skip to content

Commit b796696

Browse files
committed
support revealing-uses in closures
1 parent 116e0e6 commit b796696

File tree

12 files changed

+439
-140
lines changed

12 files changed

+439
-140
lines changed

compiler/rustc_borrowck/src/consumers.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub use super::polonius::legacy::{
1515
RichLocation, RustcFacts,
1616
};
1717
pub use super::region_infer::RegionInferenceContext;
18-
use crate::{BorrowCheckRootCtxt, do_mir_borrowck};
18+
use crate::BorrowCheckRootCtxt;
1919

2020
/// Options determining the output behavior of [`get_body_with_borrowck_facts`].
2121
///
@@ -101,6 +101,6 @@ pub fn get_body_with_borrowck_facts(
101101
def_id: LocalDefId,
102102
options: ConsumerOptions,
103103
) -> BodyWithBorrowckFacts<'_> {
104-
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
105-
*do_mir_borrowck(&mut root_cx, def_id, Some(options)).1.unwrap()
104+
let root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
105+
*root_cx.borrowck_root(Some(options)).1.unwrap()
106106
}

compiler/rustc_borrowck/src/lib.rs

+94-41
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::cell::RefCell;
2222
use std::marker::PhantomData;
2323
use std::ops::{ControlFlow, Deref};
2424

25+
use nll::YieldComputeRegions;
2526
use root_cx::BorrowCheckRootCtxt;
2627
use rustc_abi::FieldIdx;
2728
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -52,6 +53,7 @@ use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
5253
use rustc_span::{ErrorGuaranteed, Span, Symbol};
5354
use smallvec::SmallVec;
5455
use tracing::{debug, instrument};
56+
use type_check::Locations;
5557

5658
use crate::borrow_set::{BorrowData, BorrowSet};
5759
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
@@ -125,12 +127,8 @@ fn mir_borrowck(
125127
let opaque_types = ConcreteOpaqueTypes(Default::default());
126128
Ok(tcx.arena.alloc(opaque_types))
127129
} else {
128-
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
129-
let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
130-
do_mir_borrowck(&mut root_cx, def, None).0;
131-
debug_assert!(closure_requirements.is_none());
132-
debug_assert!(used_mut_upvars.is_empty());
133-
root_cx.finalize()
130+
let root_cx = BorrowCheckRootCtxt::new(tcx, def);
131+
root_cx.borrowck_root(None).0
134132
}
135133
}
136134

@@ -142,6 +140,8 @@ struct PropagatedBorrowCheckResults<'tcx> {
142140
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
143141
}
144142

143+
type DeferredClosureRequirements<'tcx> = Vec<(LocalDefId, ty::GenericArgsRef<'tcx>, Locations)>;
144+
145145
/// After we borrow check a closure, we are left with various
146146
/// requirements that we have inferred between the free regions that
147147
/// appear in the closure's signature or on its field types. These
@@ -280,6 +280,17 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
280280
}
281281
}
282282

283+
struct YieldDoMirBorrowck<'tcx> {
284+
infcx: BorrowckInferCtxt<'tcx>,
285+
body_owned: Body<'tcx>,
286+
promoted: IndexVec<Promoted, Body<'tcx>>,
287+
move_data: MoveData<'tcx>,
288+
locals_are_invalidated_at_exit: bool,
289+
borrow_set: BorrowSet<'tcx>,
290+
location_table: PoloniusLocationTable,
291+
yield_compute_regions: YieldComputeRegions<'tcx>,
292+
}
293+
283294
/// Perform the actual borrow checking.
284295
///
285296
/// Use `consumer_options: None` for the default behavior of returning
@@ -288,11 +299,11 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
288299
///
289300
/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`.
290301
#[instrument(skip(root_cx), level = "debug")]
291-
fn do_mir_borrowck<'tcx>(
302+
fn start_do_mir_borrowck<'tcx>(
292303
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
293304
def: LocalDefId,
294305
consumer_options: Option<ConsumerOptions>,
295-
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
306+
) -> YieldDoMirBorrowck<'tcx> {
296307
let tcx = root_cx.tcx;
297308
let infcx = BorrowckInferCtxt::new(tcx, def);
298309
let (input_body, promoted) = tcx.mir_promoted(def);
@@ -303,33 +314,13 @@ fn do_mir_borrowck<'tcx>(
303314
root_cx.set_tainted_by_errors(e);
304315
}
305316

306-
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
307-
for var_debug_info in &input_body.var_debug_info {
308-
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
309-
if let Some(local) = place.as_local() {
310-
if let Some(prev_name) = local_names[local]
311-
&& var_debug_info.name != prev_name
312-
{
313-
span_bug!(
314-
var_debug_info.source_info.span,
315-
"local {:?} has many names (`{}` vs `{}`)",
316-
local,
317-
prev_name,
318-
var_debug_info.name
319-
);
320-
}
321-
local_names[local] = Some(var_debug_info.name);
322-
}
323-
}
324-
}
325-
326317
// Replace all regions with fresh inference variables. This
327318
// requires first making our own copy of the MIR. This copy will
328319
// be modified (in place) to contain non-lexical lifetimes. It
329320
// will have a lifetime tied to the inference context.
330321
let mut body_owned = input_body.clone();
331322
let mut promoted = input_promoted.to_owned();
332-
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
323+
let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
333324
let body = &body_owned; // no further changes
334325

335326
let location_table = PoloniusLocationTable::new(body);
@@ -343,6 +334,50 @@ fn do_mir_borrowck<'tcx>(
343334
let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
344335
let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
345336

337+
let yield_compute_regions = nll::compute_regions(
338+
root_cx,
339+
&infcx,
340+
universal_regions,
341+
body,
342+
&promoted,
343+
&location_table,
344+
flow_inits,
345+
&move_data,
346+
&borrow_set,
347+
consumer_options,
348+
);
349+
350+
YieldDoMirBorrowck {
351+
infcx,
352+
body_owned,
353+
promoted,
354+
move_data,
355+
locals_are_invalidated_at_exit,
356+
borrow_set,
357+
location_table,
358+
yield_compute_regions,
359+
}
360+
}
361+
362+
fn resume_do_mir_borrowck<'tcx>(
363+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
364+
def: LocalDefId,
365+
consumer_options: Option<ConsumerOptions>,
366+
YieldDoMirBorrowck {
367+
infcx,
368+
body_owned,
369+
promoted,
370+
move_data,
371+
locals_are_invalidated_at_exit,
372+
borrow_set,
373+
location_table,
374+
yield_compute_regions,
375+
}: YieldDoMirBorrowck<'tcx>,
376+
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
377+
assert!(!infcx.has_opaque_types_in_storage());
378+
let tcx = infcx.tcx;
379+
let body = &body_owned;
380+
346381
// Compute non-lexical lifetimes.
347382
let nll::NllOutput {
348383
regioncx,
@@ -351,17 +386,15 @@ fn do_mir_borrowck<'tcx>(
351386
opt_closure_req,
352387
nll_errors,
353388
polonius_diagnostics,
354-
} = nll::compute_regions(
389+
} = nll::resume_compute_regions(
355390
root_cx,
356391
&infcx,
357-
free_regions,
358392
body,
359-
&promoted,
360393
&location_table,
361-
flow_inits,
362394
&move_data,
363395
&borrow_set,
364396
consumer_options,
397+
yield_compute_regions,
365398
);
366399

367400
// Dump MIR results into a file, if that is enabled. This lets us
@@ -376,14 +409,14 @@ fn do_mir_borrowck<'tcx>(
376409
let movable_coroutine =
377410
// The first argument is the coroutine type passed by value
378411
if let Some(local) = body.local_decls.raw.get(1)
379-
// Get the interior types and args which typeck computed
380-
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
381-
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
382-
{
383-
true
384-
} else {
385-
false
386-
};
412+
// Get the interior types and args which typeck computed
413+
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
414+
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
415+
{
416+
true
417+
} else {
418+
false
419+
};
387420

388421
// While promoteds should mostly be correct by construction, we need to check them for
389422
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
@@ -434,6 +467,26 @@ fn do_mir_borrowck<'tcx>(
434467
promoted_mbcx.report_move_errors();
435468
}
436469

470+
let mut local_names = IndexVec::from_elem(None, &body.local_decls);
471+
for var_debug_info in &body.var_debug_info {
472+
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
473+
if let Some(local) = place.as_local() {
474+
if let Some(prev_name) = local_names[local]
475+
&& var_debug_info.name != prev_name
476+
{
477+
span_bug!(
478+
var_debug_info.source_info.span,
479+
"local {:?} has many names (`{}` vs `{}`)",
480+
local,
481+
prev_name,
482+
var_debug_info.name
483+
);
484+
}
485+
local_names[local] = Some(var_debug_info.name);
486+
}
487+
}
488+
}
489+
437490
let mut mbcx = MirBorrowckCtxt {
438491
root_cx,
439492
infcx: &infcx,

0 commit comments

Comments
 (0)