Skip to content

Commit d85f8b0

Browse files
committed
support revealing-uses in closures
1 parent 1bce98f commit d85f8b0

File tree

11 files changed

+377
-115
lines changed

11 files changed

+377
-115
lines changed

compiler/rustc_borrowck/src/consumers.rs

Lines changed: 3 additions & 3 deletions
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

Lines changed: 121 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@ use std::borrow::Cow;
2121
use std::cell::RefCell;
2222
use std::marker::PhantomData;
2323
use std::ops::{ControlFlow, Deref};
24+
use std::rc::Rc;
2425

2526
use borrow_set::LocalsStateAtExit;
27+
use polonius_engine::AllFacts;
28+
use region_infer::opaque_types::DeferredOpaqueTypeError;
2629
use root_cx::BorrowCheckRootCtxt;
2730
use rustc_abi::FieldIdx;
31+
use rustc_data_structures::frozen::Frozen;
2832
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
2933
use rustc_data_structures::graph::dominators::Dominators;
3034
use rustc_errors::LintDiagnostic;
@@ -33,6 +37,7 @@ use rustc_hir::CRATE_HIR_ID;
3337
use rustc_hir::def_id::LocalDefId;
3438
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
3539
use rustc_index::{IndexSlice, IndexVec};
40+
use rustc_infer::infer::outlives::env::RegionBoundPairs;
3641
use rustc_infer::infer::{
3742
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
3843
};
@@ -48,23 +53,28 @@ use rustc_mir_dataflow::impls::{
4853
use rustc_mir_dataflow::move_paths::{
4954
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
5055
};
56+
use rustc_mir_dataflow::points::DenseLocationMap;
5157
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
5258
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
5359
use rustc_span::{ErrorGuaranteed, Span, Symbol};
5460
use smallvec::SmallVec;
5561
use tracing::{debug, instrument};
62+
use type_check::free_region_relations::UniversalRegionRelations;
63+
use type_check::{Locations, MirTypeckRegionConstraints, MirTypeckResults};
5664

5765
use crate::borrow_set::{BorrowData, BorrowSet};
58-
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
66+
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions, RustcFacts};
5967
use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
6068
use crate::diagnostics::{
6169
AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName,
6270
};
6371
use crate::path_utils::*;
6472
use crate::place_ext::PlaceExt;
6573
use crate::places_conflict::{PlaceConflictBias, places_conflict};
66-
use crate::polonius::PoloniusDiagnosticsContext;
67-
use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
74+
use crate::polonius::legacy::{
75+
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
76+
};
77+
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
6878
use crate::prefixes::PrefixSet;
6979
use crate::region_infer::RegionInferenceContext;
7080
use crate::renumber::RegionCtxt;
@@ -126,12 +136,8 @@ fn mir_borrowck(
126136
let opaque_types = ConcreteOpaqueTypes(Default::default());
127137
Ok(tcx.arena.alloc(opaque_types))
128138
} else {
129-
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
130-
let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
131-
do_mir_borrowck(&mut root_cx, def, None).0;
132-
debug_assert!(closure_requirements.is_none());
133-
debug_assert!(used_mut_upvars.is_empty());
134-
root_cx.finalize()
139+
let root_cx = BorrowCheckRootCtxt::new(tcx, def);
140+
root_cx.borrowck_root(None).0
135141
}
136142
}
137143

@@ -143,6 +149,8 @@ struct PropagatedBorrowCheckResults<'tcx> {
143149
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
144150
}
145151

152+
type DeferredClosureRequirements<'tcx> = Vec<(LocalDefId, ty::GenericArgsRef<'tcx>, Locations)>;
153+
146154
/// After we borrow check a closure, we are left with various
147155
/// requirements that we have inferred between the free regions that
148156
/// appear in the closure's signature or on its field types. These
@@ -281,6 +289,24 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
281289
}
282290
}
283291

292+
struct BorrowckState<'tcx> {
293+
infcx: BorrowckInferCtxt<'tcx>,
294+
body_owned: Body<'tcx>,
295+
promoted: IndexVec<Promoted, Body<'tcx>>,
296+
move_data: MoveData<'tcx>,
297+
borrow_set: BorrowSet<'tcx>,
298+
location_table: PoloniusLocationTable,
299+
location_map: Rc<DenseLocationMap>,
300+
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
301+
region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>,
302+
known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>,
303+
constraints: MirTypeckRegionConstraints<'tcx>,
304+
deferred_closure_requirements: DeferredClosureRequirements<'tcx>,
305+
deferred_opaque_type_errors: Vec<DeferredOpaqueTypeError<'tcx>>,
306+
polonius_facts: Option<AllFacts<RustcFacts>>,
307+
polonius_context: Option<PoloniusContext>,
308+
}
309+
284310
/// Perform the actual borrow checking.
285311
///
286312
/// Use `consumer_options: None` for the default behavior of returning
@@ -289,11 +315,11 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
289315
///
290316
/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`.
291317
#[instrument(skip(root_cx), level = "debug")]
292-
fn do_mir_borrowck<'tcx>(
318+
fn start_do_mir_borrowck<'tcx>(
293319
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
294320
def: LocalDefId,
295321
consumer_options: Option<ConsumerOptions>,
296-
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
322+
) -> BorrowckState<'tcx> {
297323
let tcx = root_cx.tcx;
298324
let infcx = BorrowckInferCtxt::new(tcx, def);
299325
let (input_body, promoted) = tcx.mir_promoted(def);
@@ -314,6 +340,7 @@ fn do_mir_borrowck<'tcx>(
314340
let body = &body_owned; // no further changes
315341

316342
let location_table = PoloniusLocationTable::new(body);
343+
let location_map = Rc::new(DenseLocationMap::new(body));
317344

318345
let move_data = MoveData::gather_moves(body, tcx, |_| true);
319346

@@ -324,6 +351,80 @@ fn do_mir_borrowck<'tcx>(
324351
let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
325352
let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
326353

354+
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
355+
let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default()
356+
|| is_polonius_legacy_enabled;
357+
let mut polonius_facts =
358+
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
359+
360+
// Run the MIR type-checker.
361+
let MirTypeckResults {
362+
constraints,
363+
universal_region_relations,
364+
region_bound_pairs,
365+
known_type_outlives_obligations,
366+
deferred_closure_requirements,
367+
polonius_context,
368+
} = type_check::type_check(
369+
root_cx,
370+
&infcx,
371+
&body,
372+
&promoted,
373+
universal_regions,
374+
&location_table,
375+
&borrow_set,
376+
&mut polonius_facts,
377+
flow_inits,
378+
&move_data,
379+
Rc::clone(&location_map),
380+
);
381+
382+
BorrowckState {
383+
infcx,
384+
body_owned,
385+
promoted,
386+
move_data,
387+
borrow_set,
388+
location_table,
389+
location_map,
390+
universal_region_relations,
391+
region_bound_pairs,
392+
known_type_outlives_obligations,
393+
constraints,
394+
deferred_closure_requirements,
395+
deferred_opaque_type_errors: Default::default(),
396+
polonius_facts,
397+
polonius_context,
398+
}
399+
}
400+
401+
fn resume_do_mir_borrowck<'tcx>(
402+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
403+
consumer_options: Option<ConsumerOptions>,
404+
BorrowckState {
405+
infcx,
406+
body_owned,
407+
promoted,
408+
move_data,
409+
borrow_set,
410+
location_table,
411+
location_map,
412+
universal_region_relations,
413+
region_bound_pairs: _,
414+
known_type_outlives_obligations: _,
415+
constraints,
416+
deferred_closure_requirements,
417+
deferred_opaque_type_errors,
418+
polonius_facts,
419+
polonius_context,
420+
}: BorrowckState<'tcx>,
421+
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
422+
assert!(!infcx.has_opaque_types_in_storage());
423+
assert!(deferred_closure_requirements.is_empty());
424+
let tcx = root_cx.tcx;
425+
let body = &body_owned;
426+
let def = body.source.def_id().expect_local();
427+
327428
// Compute non-lexical lifetimes.
328429
let nll::NllOutput {
329430
regioncx,
@@ -333,18 +434,23 @@ fn do_mir_borrowck<'tcx>(
333434
nll_errors,
334435
polonius_diagnostics,
335436
} = nll::compute_regions(
336-
root_cx,
337437
&infcx,
338-
universal_regions,
339438
body,
340-
&promoted,
341439
&location_table,
342-
flow_inits,
343440
&move_data,
344441
&borrow_set,
442+
location_map,
345443
consumer_options,
444+
universal_region_relations,
445+
constraints,
446+
polonius_facts,
447+
polonius_context,
346448
);
347449

450+
if nll_errors.has_errors().is_none() && !deferred_opaque_type_errors.is_empty() {
451+
regioncx.emit_deferred_opaque_type_errors(root_cx, &infcx, deferred_opaque_type_errors);
452+
}
453+
348454
// Dump MIR results into a file, if that is enabled. This lets us
349455
// write unit-tests, as well as helping with debugging.
350456
nll::dump_nll_mir(&infcx, body, &regioncx, &opt_closure_req, &borrow_set);

compiler/rustc_borrowck/src/nll.rs

Lines changed: 37 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,33 @@ use std::path::PathBuf;
55
use std::rc::Rc;
66
use std::str::FromStr;
77

8-
use polonius_engine::{Algorithm, Output};
8+
use polonius_engine::{Algorithm, AllFacts, Output};
9+
use rustc_data_structures::frozen::Frozen;
910
use rustc_index::IndexSlice;
1011
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
1112
use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir};
1213
use rustc_middle::ty::print::with_no_trimmed_paths;
1314
use rustc_middle::ty::{self, TyCtxt};
14-
use rustc_mir_dataflow::ResultsCursor;
15-
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
1615
use rustc_mir_dataflow::move_paths::MoveData;
1716
use rustc_mir_dataflow::points::DenseLocationMap;
1817
use rustc_session::config::MirIncludeSpans;
1918
use rustc_span::sym;
2019
use tracing::{debug, instrument};
2120

2221
use crate::borrow_set::BorrowSet;
23-
use crate::consumers::ConsumerOptions;
22+
use crate::consumers::{ConsumerOptions, RustcFacts};
2423
use crate::diagnostics::RegionErrors;
25-
use crate::polonius::PoloniusDiagnosticsContext;
2624
use crate::polonius::legacy::{
2725
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
2826
};
27+
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
2928
use crate::region_infer::RegionInferenceContext;
30-
use crate::region_infer::opaque_types::handle_opaque_type_uses;
31-
use crate::type_check::{self, MirTypeckResults};
29+
use crate::type_check::MirTypeckRegionConstraints;
30+
use crate::type_check::free_region_relations::UniversalRegionRelations;
3231
use crate::universal_regions::UniversalRegions;
3332
use crate::{
34-
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
35-
polonius, renumber,
33+
BorrowckInferCtxt, BorrowckState, ClosureOutlivesSubject, ClosureRegionRequirements, polonius,
34+
renumber,
3635
};
3736

3837
/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
@@ -73,55 +72,47 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
7372
universal_regions
7473
}
7574

76-
/// Computes the (non-lexical) regions from the input MIR.
75+
pub(crate) fn compute_closure_requirements_modulo_opaques<'tcx>(
76+
partial_result: &BorrowckState<'tcx>,
77+
) -> Option<ClosureRegionRequirements<'tcx>> {
78+
let BorrowckState {
79+
infcx,
80+
body_owned,
81+
location_map,
82+
universal_region_relations,
83+
constraints,
84+
..
85+
} = partial_result;
86+
87+
let mut regioncx = RegionInferenceContext::new(
88+
&infcx,
89+
constraints.clone(),
90+
universal_region_relations.clone(),
91+
location_map.clone(),
92+
);
93+
let (closure_region_requirements, _nll_errors) = regioncx.solve(infcx, &body_owned, None);
94+
closure_region_requirements
95+
}
96+
97+
/// Computes and checks the region graph for the given constraints.
7798
///
7899
/// This may result in errors being reported.
79-
pub(crate) fn compute_regions<'a, 'tcx>(
80-
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
100+
pub(crate) fn compute_regions<'tcx>(
81101
infcx: &BorrowckInferCtxt<'tcx>,
82-
universal_regions: UniversalRegions<'tcx>,
83102
body: &Body<'tcx>,
84-
promoted: &IndexSlice<Promoted, Body<'tcx>>,
85103
location_table: &PoloniusLocationTable,
86-
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
87104
move_data: &MoveData<'tcx>,
88105
borrow_set: &BorrowSet<'tcx>,
106+
location_map: Rc<DenseLocationMap>,
89107
consumer_options: Option<ConsumerOptions>,
108+
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
109+
constraints: MirTypeckRegionConstraints<'tcx>,
110+
mut polonius_facts: Option<AllFacts<RustcFacts>>,
111+
polonius_context: Option<PoloniusContext>,
90112
) -> NllOutput<'tcx> {
91113
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
92-
let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default()
93-
|| is_polonius_legacy_enabled;
94114
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
95115
|| is_polonius_legacy_enabled;
96-
let mut polonius_facts =
97-
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
98-
99-
let location_map = Rc::new(DenseLocationMap::new(body));
100-
101-
// Run the MIR type-checker.
102-
let MirTypeckResults { constraints, universal_region_relations, polonius_context } =
103-
type_check::type_check(
104-
root_cx,
105-
infcx,
106-
body,
107-
promoted,
108-
universal_regions,
109-
location_table,
110-
borrow_set,
111-
&mut polonius_facts,
112-
flow_inits,
113-
move_data,
114-
Rc::clone(&location_map),
115-
);
116-
117-
let (constraints, deferred_opaque_type_errors) = handle_opaque_type_uses(
118-
root_cx,
119-
infcx,
120-
constraints,
121-
&universal_region_relations,
122-
Rc::clone(&location_map),
123-
);
124-
125116
// If requested, emit legacy polonius facts.
126117
polonius::legacy::emit_facts(
127118
&mut polonius_facts,
@@ -169,10 +160,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
169160
regioncx.solve(infcx, body, polonius_output.clone());
170161

171162
if let Some(guar) = nll_errors.has_errors() {
172-
// Suppress unhelpful extra errors in `infer_opaque_types`.
173163
infcx.set_tainted_by_errors(guar);
174-
} else if !deferred_opaque_type_errors.is_empty() {
175-
regioncx.emit_deferred_opaque_type_errors(root_cx, infcx, deferred_opaque_type_errors);
176164
}
177165

178166
NllOutput {

0 commit comments

Comments
 (0)