Skip to content

Commit 60ec986

Browse files
committed
Auto merge of #138499 - lcnr:borrowck-typeck_root, r=<try>
borrowck typeck children together with their root This introduces new cycle errors, even with `feature(inline_const_pat)` removed, see the `non-structural-match-types-cycle-err.rs` test. The new cycle error happens as the layout of `async`-blocks relies on their `optimized_mir`. As that now depends on `mir_borrowck` of its typeck parent, computing the layout of an `async`-block during MIR building, e.g. when evaluating a named `const` pattern. I think there's currently no way to have a named const pattern whose type references an async block while being allowed? cc `@oli-obk` `@RalfJung` I cannot think of other cases where we currently rely on the MIR of a typeck children while borrowchecking their parent. The crater run came back without any breakage. My work here will prevent any future features which rely on this as we'll get locked into borrowchecking them together as I continue to work on rust-lang/types-team#129, cc `@rust-lang/types.` r? compiler-errors
2 parents d5b4c2e + e60daca commit 60ec986

File tree

22 files changed

+462
-423
lines changed

22 files changed

+462
-423
lines changed

Diff for: compiler/rustc_borrowck/src/consumers.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +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};
1819

1920
/// Options determining the output behavior of [`get_body_with_borrowck_facts`].
2021
///
@@ -97,8 +98,9 @@ pub struct BodyWithBorrowckFacts<'tcx> {
9798
/// * Polonius is highly unstable, so expect regular changes in its signature or other details.
9899
pub fn get_body_with_borrowck_facts(
99100
tcx: TyCtxt<'_>,
100-
def: LocalDefId,
101+
def_id: LocalDefId,
101102
options: ConsumerOptions,
102103
) -> BodyWithBorrowckFacts<'_> {
103-
*super::do_mir_borrowck(tcx, def, Some(options)).1.unwrap()
104+
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
105+
*do_mir_borrowck(&mut root_cx, def_id, Some(options)).1.unwrap()
104106
}

Diff for: compiler/rustc_borrowck/src/lib.rs

+194-45
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use std::cell::RefCell;
2121
use std::marker::PhantomData;
2222
use std::ops::{ControlFlow, Deref};
2323

24+
use root_cx::BorrowCheckRootCtxt;
2425
use rustc_abi::FieldIdx;
2526
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
2627
use rustc_data_structures::graph::dominators::Dominators;
@@ -35,7 +36,7 @@ use rustc_infer::infer::{
3536
};
3637
use rustc_middle::mir::*;
3738
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};
3940
use rustc_middle::{bug, span_bug};
4041
use rustc_mir_dataflow::impls::{
4142
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
@@ -45,7 +46,7 @@ use rustc_mir_dataflow::move_paths::{
4546
};
4647
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
4748
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
48-
use rustc_span::{Span, Symbol};
49+
use rustc_span::{ErrorGuaranteed, Span, Symbol};
4950
use smallvec::SmallVec;
5051
use tracing::{debug, instrument};
5152

@@ -73,14 +74,14 @@ mod def_use;
7374
mod diagnostics;
7475
mod member_constraints;
7576
mod nll;
76-
mod opaque_types;
7777
mod path_utils;
7878
mod place_ext;
7979
mod places_conflict;
8080
mod polonius;
8181
mod prefixes;
8282
mod region_infer;
8383
mod renumber;
84+
mod root_cx;
8485
mod session_diagnostics;
8586
mod type_check;
8687
mod universal_regions;
@@ -102,44 +103,194 @@ pub fn provide(providers: &mut Providers) {
102103
*providers = Providers { mir_borrowck, ..*providers };
103104
}
104105

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()));
106111
let (input_body, _) = tcx.mir_promoted(def);
112+
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
113+
107114
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()
118129
}
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>,
119200

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,
122203

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+
}
124273
}
125274

126275
/// Perform the actual borrow checking.
127276
///
128277
/// Use `consumer_options: None` for the default behavior of returning
129278
/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according
130279
/// to the given [`ConsumerOptions`].
131-
#[instrument(skip(tcx), level = "debug")]
280+
#[instrument(skip(root_cx), level = "debug")]
132281
fn do_mir_borrowck<'tcx>(
133-
tcx: TyCtxt<'tcx>,
282+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
134283
def: LocalDefId,
135284
consumer_options: Option<ConsumerOptions>,
136285
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
286+
let tcx = root_cx.tcx;
137287
let infcx = BorrowckInferCtxt::new(tcx, def);
138288
let (input_body, promoted) = tcx.mir_promoted(def);
139289
let input_body: &Body<'_> = &input_body.borrow();
140290
let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
141291
if let Some(e) = input_body.tainted_by_errors {
142292
infcx.set_tainted_by_errors(e);
293+
root_cx.set_tainted_by_errors(e);
143294
}
144295

145296
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
@@ -191,13 +342,13 @@ fn do_mir_borrowck<'tcx>(
191342
// Compute non-lexical lifetimes.
192343
let nll::NllOutput {
193344
regioncx,
194-
concrete_opaque_types,
195345
polonius_input,
196346
polonius_output,
197347
opt_closure_req,
198348
nll_errors,
199349
polonius_diagnostics,
200350
} = nll::compute_regions(
351+
root_cx,
201352
&infcx,
202353
free_regions,
203354
body,
@@ -216,26 +367,19 @@ fn do_mir_borrowck<'tcx>(
216367
// We also have a `#[rustc_regions]` annotation that causes us to dump
217368
// information.
218369
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);
227371

228372
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+
};
239383

240384
// While promoteds should mostly be correct by construction, we need to check them for
241385
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
@@ -246,6 +390,7 @@ fn do_mir_borrowck<'tcx>(
246390
// this check out of `MirBorrowckCtxt`, actually doing so is far from trivial.
247391
let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
248392
let mut promoted_mbcx = MirBorrowckCtxt {
393+
root_cx,
249394
infcx: &infcx,
250395
body: promoted_body,
251396
move_data: &move_data,
@@ -286,6 +431,7 @@ fn do_mir_borrowck<'tcx>(
286431
}
287432

288433
let mut mbcx = MirBorrowckCtxt {
434+
root_cx,
289435
infcx: &infcx,
290436
body,
291437
move_data: &move_data,
@@ -353,13 +499,13 @@ fn do_mir_borrowck<'tcx>(
353499

354500
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
355501
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+
}
357505

358506
let result = BorrowCheckResult {
359-
concrete_opaque_types: concrete_opaque_types.into_inner(),
360507
closure_requirements: opt_closure_req,
361508
used_mut_upvars: mbcx.used_mut_upvars,
362-
tainted_by_errors,
363509
};
364510

365511
let body_with_facts = if consumer_options.is_some() {
@@ -512,6 +658,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
512658
}
513659

514660
struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
661+
root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
515662
infcx: &'infcx BorrowckInferCtxt<'tcx>,
516663
body: &'a Body<'tcx>,
517664
move_data: &'a MoveData<'tcx>,
@@ -1385,11 +1532,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
13851532
| AggregateKind::CoroutineClosure(def_id, _)
13861533
| AggregateKind::Coroutine(def_id, _) => {
13871534
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);
13901536
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]);
13931542
}
13941543
}
13951544
AggregateKind::Adt(..)

0 commit comments

Comments
 (0)