summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/lib.rs')
-rw-r--r--compiler/rustc_borrowck/src/lib.rs118
1 files changed, 102 insertions, 16 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 73ea7314b..0f591460e 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1,6 +1,7 @@
//! This query borrow-checks the MIR to (further) ensure it is not broken.
#![allow(rustc::potential_query_instability)]
+#![feature(associated_type_bounds)]
#![feature(box_patterns)]
#![feature(let_chains)]
#![feature(min_specialization)]
@@ -20,12 +21,15 @@ extern crate tracing;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::{Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::ChunkedBitSet;
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{
+ DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
+};
+use rustc_macros::fluent_messages;
use rustc_middle::mir::{
traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
Place, PlaceElem, PlaceRef, VarDebugInfoContents,
@@ -43,6 +47,7 @@ use smallvec::SmallVec;
use std::cell::OnceCell;
use std::cell::RefCell;
use std::collections::BTreeMap;
+use std::ops::Deref;
use std::rc::Rc;
use rustc_mir_dataflow::impls::{
@@ -94,6 +99,9 @@ use nll::{PoloniusOutput, ToRegionVid};
use place_ext::PlaceExt;
use places_conflict::{places_conflict, PlaceConflictBias};
use region_infer::RegionInferenceContext;
+use renumber::RegionCtxt;
+
+fluent_messages! { "../locales/en-US.ftl" }
// FIXME(eddyb) perhaps move this somewhere more centrally.
#[derive(Debug)]
@@ -167,10 +175,10 @@ fn do_mir_borrowck<'tcx>(
return_body_with_facts: bool,
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
let def = input_body.source.with_opt_param().as_local().unwrap();
-
debug!(?def);
let tcx = infcx.tcx;
+ let infcx = BorrowckInferCtxt::new(infcx);
let param_env = tcx.param_env(def.did);
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
@@ -194,14 +202,14 @@ fn do_mir_borrowck<'tcx>(
let mut errors = error::BorrowckErrors::new(infcx.tcx);
// Gather the upvars of a closure, if any.
- let tables = tcx.typeck_opt_const_arg(def);
- if let Some(e) = tables.tainted_by_errors {
+ if let Some(e) = input_body.tainted_by_errors {
infcx.set_tainted_by_errors(e);
errors.set_tainted_by_errors(e);
}
- let upvars: Vec<_> = tables
- .closure_min_captures_flattened(def.did)
- .map(|captured_place| {
+ let upvars: Vec<_> = tcx
+ .closure_captures(def.did)
+ .iter()
+ .map(|&captured_place| {
let capture = captured_place.info.capture_kind;
let by_ref = match capture {
ty::UpvarCapture::ByValue => false,
@@ -218,7 +226,7 @@ fn do_mir_borrowck<'tcx>(
let mut body_owned = input_body.clone();
let mut promoted = input_promoted.clone();
let free_regions =
- nll::replace_regions_in_mir(infcx, param_env, &mut body_owned, &mut promoted);
+ nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted);
let body = &body_owned; // no further changes
let location_table_owned = LocationTable::new(body);
@@ -256,7 +264,7 @@ fn do_mir_borrowck<'tcx>(
opt_closure_req,
nll_errors,
} = nll::compute_regions(
- infcx,
+ &infcx,
free_regions,
body,
&promoted,
@@ -271,12 +279,12 @@ fn do_mir_borrowck<'tcx>(
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests, as well as helping with debugging.
- nll::dump_mir_results(infcx, &body, &regioncx, &opt_closure_req);
+ nll::dump_mir_results(&infcx, &body, &regioncx, &opt_closure_req);
// We also have a `#[rustc_regions]` annotation that causes us to dump
// information.
nll::dump_annotation(
- infcx,
+ &infcx,
&body,
&regioncx,
&opt_closure_req,
@@ -320,7 +328,7 @@ fn do_mir_borrowck<'tcx>(
if let Err((move_data, move_errors)) = move_data_results {
let mut promoted_mbcx = MirBorrowckCtxt {
- infcx,
+ infcx: &infcx,
param_env,
body: promoted_body,
move_data: &move_data,
@@ -349,7 +357,7 @@ fn do_mir_borrowck<'tcx>(
}
let mut mbcx = MirBorrowckCtxt {
- infcx,
+ infcx: &infcx,
param_env,
body,
move_data: &mdpe.move_data,
@@ -481,8 +489,84 @@ pub struct BodyWithBorrowckFacts<'tcx> {
pub location_table: LocationTable,
}
+pub struct BorrowckInferCtxt<'cx, 'tcx> {
+ pub(crate) infcx: &'cx InferCtxt<'tcx>,
+ pub(crate) reg_var_to_origin: RefCell<FxHashMap<ty::RegionVid, RegionCtxt>>,
+}
+
+impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
+ pub(crate) fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
+ BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) }
+ }
+
+ pub(crate) fn next_region_var<F>(
+ &self,
+ origin: RegionVariableOrigin,
+ get_ctxt_fn: F,
+ ) -> ty::Region<'tcx>
+ where
+ F: Fn() -> RegionCtxt,
+ {
+ let next_region = self.infcx.next_region_var(origin);
+ let vid = next_region
+ .as_var()
+ .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
+
+ if cfg!(debug_assertions) {
+ debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
+ let ctxt = get_ctxt_fn();
+ let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
+ let prev = var_to_origin.insert(vid, ctxt);
+
+ // This only makes sense if not called in a canonicalization context. If this
+ // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
+ // or modify how we track nll region vars for that map.
+ assert!(matches!(prev, None));
+ }
+
+ next_region
+ }
+
+ #[instrument(skip(self, get_ctxt_fn), level = "debug")]
+ pub(crate) fn next_nll_region_var<F>(
+ &self,
+ origin: NllRegionVariableOrigin,
+ get_ctxt_fn: F,
+ ) -> ty::Region<'tcx>
+ where
+ F: Fn() -> RegionCtxt,
+ {
+ let next_region = self.infcx.next_nll_region_var(origin.clone());
+ let vid = next_region
+ .as_var()
+ .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
+
+ if cfg!(debug_assertions) {
+ debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
+ let ctxt = get_ctxt_fn();
+ let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
+ let prev = var_to_origin.insert(vid, ctxt);
+
+ // This only makes sense if not called in a canonicalization context. If this
+ // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
+ // or modify how we track nll region vars for that map.
+ assert!(matches!(prev, None));
+ }
+
+ next_region
+ }
+}
+
+impl<'cx, 'tcx> Deref for BorrowckInferCtxt<'cx, 'tcx> {
+ type Target = InferCtxt<'tcx>;
+
+ fn deref(&self) -> &'cx Self::Target {
+ self.infcx
+ }
+}
+
struct MirBorrowckCtxt<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'tcx>,
+ infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &'cx Body<'tcx>,
move_data: &'cx MoveData<'tcx>,
@@ -609,7 +693,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
StatementKind::AscribeUserType(..)
// Doesn't have any language semantics
| StatementKind::Coverage(..)
- // Does not actually affect borrowck
+ // These do not actually affect borrowck
+ | StatementKind::ConstEvalCounter
| StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
@@ -1277,6 +1362,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// in order to populate our used_mut set.
match **aggregate_kind {
AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) => {
+ let def_id = def_id.expect_local();
let BorrowCheckResult { used_mut_upvars, .. } =
self.infcx.tcx.mir_borrowck(def_id);
debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);