summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src')
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs6
-rw-r--r--compiler/rustc_borrowck/src/constraint_generation.rs248
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs1
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs193
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs52
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs111
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs64
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs187
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs11
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs162
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs41
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs110
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/var_name.rs9
-rw-r--r--compiler/rustc_borrowck/src/lib.rs103
-rw-r--r--compiler/rustc_borrowck/src/location.rs1
-rw-r--r--compiler/rustc_borrowck/src/nll.rs207
-rw-r--r--compiler/rustc_borrowck/src/path_utils.rs5
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs (renamed from compiler/rustc_borrowck/src/invalidation.rs)47
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_kills.rs147
-rw-r--r--compiler/rustc_borrowck/src/polonius/mod.rs188
-rw-r--r--compiler/rustc_borrowck/src/region_infer/dump_mir.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/graphviz.rs1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs66
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs148
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs7
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs10
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs88
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs80
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs121
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs4
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs74
-rw-r--r--compiler/rustc_borrowck/src/used_muts.rs2
37 files changed, 1362 insertions, 1155 deletions
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 5248a649c..948af0395 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -107,7 +107,7 @@ impl LocalsStateAtExit {
LocalsStateAtExit::AllAreInvalidated
} else {
let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body.local_decls.len()));
- has_storage_dead.visit_body(&body);
+ has_storage_dead.visit_body(body);
let mut has_storage_dead_or_moved = has_storage_dead.0;
for move_out in &move_data.moves {
if let Some(index) = move_data.base_local(move_out.path) {
@@ -128,7 +128,7 @@ impl<'tcx> BorrowSet<'tcx> {
) -> Self {
let mut visitor = GatherBorrows {
tcx,
- body: &body,
+ body: body,
location_map: Default::default(),
activation_map: Default::default(),
local_map: Default::default(),
@@ -140,7 +140,7 @@ impl<'tcx> BorrowSet<'tcx> {
),
};
- for (block, block_data) in traversal::preorder(&body) {
+ for (block, block_data) in traversal::preorder(body) {
visitor.visit_basic_block_data(block, block_data);
}
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
deleted file mode 100644
index 1f642099f..000000000
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ /dev/null
@@ -1,248 +0,0 @@
-#![deny(rustc::untranslatable_diagnostic)]
-#![deny(rustc::diagnostic_outside_of_impl)]
-use rustc_infer::infer::InferCtxt;
-use rustc_middle::mir::visit::TyContext;
-use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{
- Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, SourceInfo, Statement,
- StatementKind, Terminator, TerminatorKind, UserTypeProjection,
-};
-use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
-
-use crate::{
- borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict,
- region_infer::values::LivenessValues,
-};
-
-pub(super) fn generate_constraints<'tcx>(
- infcx: &InferCtxt<'tcx>,
- liveness_constraints: &mut LivenessValues<RegionVid>,
- all_facts: &mut Option<AllFacts>,
- location_table: &LocationTable,
- body: &Body<'tcx>,
- borrow_set: &BorrowSet<'tcx>,
-) {
- let mut cg = ConstraintGeneration {
- borrow_set,
- infcx,
- liveness_constraints,
- location_table,
- all_facts,
- body,
- };
-
- for (bb, data) in body.basic_blocks.iter_enumerated() {
- cg.visit_basic_block_data(bb, data);
- }
-}
-
-/// 'cg = the duration of the constraint generation process itself.
-struct ConstraintGeneration<'cg, 'tcx> {
- infcx: &'cg InferCtxt<'tcx>,
- all_facts: &'cg mut Option<AllFacts>,
- location_table: &'cg LocationTable,
- liveness_constraints: &'cg mut LivenessValues<RegionVid>,
- borrow_set: &'cg BorrowSet<'tcx>,
- body: &'cg Body<'tcx>,
-}
-
-impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> {
- /// We sometimes have `args` within an rvalue, or within a
- /// call. Make them live at the location where they appear.
- fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) {
- self.add_regular_live_constraint(*args, location);
- self.super_args(args);
- }
-
- /// We sometimes have `region` within an rvalue, or within a
- /// call. Make them live at the location where they appear.
- fn visit_region(&mut self, region: ty::Region<'tcx>, location: Location) {
- self.add_regular_live_constraint(region, location);
- self.super_region(region);
- }
-
- /// We sometimes have `ty` within an rvalue, or within a
- /// call. Make them live at the location where they appear.
- fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) {
- match ty_context {
- TyContext::ReturnTy(SourceInfo { span, .. })
- | TyContext::YieldTy(SourceInfo { span, .. })
- | TyContext::UserTy(span)
- | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
- span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context);
- }
- TyContext::Location(location) => {
- self.add_regular_live_constraint(ty, location);
- }
- }
-
- self.super_ty(ty);
- }
-
- fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
- if let Some(all_facts) = self.all_facts {
- let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
- all_facts.cfg_edge.push((
- self.location_table.start_index(location),
- self.location_table.mid_index(location),
- ));
-
- all_facts.cfg_edge.push((
- self.location_table.mid_index(location),
- self.location_table.start_index(location.successor_within_block()),
- ));
-
- // If there are borrows on this now dead local, we need to record them as `killed`.
- if let StatementKind::StorageDead(local) = statement.kind {
- record_killed_borrows_for_local(
- all_facts,
- self.borrow_set,
- self.location_table,
- local,
- location,
- );
- }
- }
-
- self.super_statement(statement, location);
- }
-
- fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
- // When we see `X = ...`, then kill borrows of
- // `(*X).foo` and so forth.
- self.record_killed_borrows_for_place(*place, location);
-
- self.super_assign(place, rvalue, location);
- }
-
- fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
- if let Some(all_facts) = self.all_facts {
- let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
- all_facts.cfg_edge.push((
- self.location_table.start_index(location),
- self.location_table.mid_index(location),
- ));
-
- let successor_blocks = terminator.successors();
- all_facts.cfg_edge.reserve(successor_blocks.size_hint().0);
- for successor_block in successor_blocks {
- all_facts.cfg_edge.push((
- self.location_table.mid_index(location),
- self.location_table.start_index(successor_block.start_location()),
- ));
- }
- }
-
- // A `Call` terminator's return value can be a local which has borrows,
- // so we need to record those as `killed` as well.
- if let TerminatorKind::Call { destination, .. } = terminator.kind {
- self.record_killed_borrows_for_place(destination, location);
- }
-
- self.super_terminator(terminator, location);
- }
-
- fn visit_ascribe_user_ty(
- &mut self,
- _place: &Place<'tcx>,
- _variance: ty::Variance,
- _user_ty: &UserTypeProjection,
- _location: Location,
- ) {
- }
-}
-
-impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> {
- /// Some variable with type `live_ty` is "regular live" at
- /// `location` -- i.e., it may be used later. This means that all
- /// regions appearing in the type `live_ty` must be live at
- /// `location`.
- fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location)
- where
- T: TypeVisitable<TyCtxt<'tcx>>,
- {
- debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location);
-
- self.infcx.tcx.for_each_free_region(&live_ty, |live_region| {
- let vid = live_region.as_var();
- self.liveness_constraints.add_element(vid, location);
- });
- }
-
- /// When recording facts for Polonius, records the borrows on the specified place
- /// as `killed`. For example, when assigning to a local, or on a call's return destination.
- fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) {
- if let Some(all_facts) = self.all_facts {
- let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
-
- // Depending on the `Place` we're killing:
- // - if it's a local, or a single deref of a local,
- // we kill all the borrows on the local.
- // - if it's a deeper projection, we have to filter which
- // of the borrows are killed: the ones whose `borrowed_place`
- // conflicts with the `place`.
- match place.as_ref() {
- PlaceRef { local, projection: &[] }
- | PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
- debug!(
- "Recording `killed` facts for borrows of local={:?} at location={:?}",
- local, location
- );
-
- record_killed_borrows_for_local(
- all_facts,
- self.borrow_set,
- self.location_table,
- local,
- location,
- );
- }
-
- PlaceRef { local, projection: &[.., _] } => {
- // Kill conflicting borrows of the innermost local.
- debug!(
- "Recording `killed` facts for borrows of \
- innermost projected local={:?} at location={:?}",
- local, location
- );
-
- if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
- for &borrow_index in borrow_indices {
- let places_conflict = places_conflict::places_conflict(
- self.infcx.tcx,
- self.body,
- self.borrow_set[borrow_index].borrowed_place,
- place,
- places_conflict::PlaceConflictBias::NoOverlap,
- );
-
- if places_conflict {
- let location_index = self.location_table.mid_index(location);
- all_facts.loan_killed_at.push((borrow_index, location_index));
- }
- }
- }
- }
- }
- }
- }
-}
-
-/// When recording facts for Polonius, records the borrows on the specified local as `killed`.
-fn record_killed_borrows_for_local(
- all_facts: &mut AllFacts,
- borrow_set: &BorrowSet<'_>,
- location_table: &LocationTable,
- local: Local,
- location: Location,
-) {
- if let Some(borrow_indices) = borrow_set.local_map.get(&local) {
- all_facts.loan_killed_at.reserve(borrow_indices.len());
- for &borrow_index in borrow_indices {
- let location_index = location_table.mid_index(location);
- all_facts.loan_killed_at.push((borrow_index, location_index));
- }
- }
-}
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 315886bbe..041ac75ec 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -122,6 +122,7 @@ rustc_index::newtype_index! {
}
rustc_index::newtype_index! {
+ #[orderable]
#[debug_format = "ConstraintSccIndex({})"]
pub struct ConstraintSccIndex {}
}
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 8676d2ba7..1bd891bdd 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -10,105 +10,93 @@ use rustc_middle::ty::RegionVid;
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
use rustc_mir_dataflow::ResultsVisitable;
-use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
-use rustc_mir_dataflow::{Analysis, Direction, Results};
+use rustc_mir_dataflow::{fmt::DebugWithContext, GenKill};
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, Results};
use std::fmt;
use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext};
-/// A tuple with named fields that can hold either the results or the transient state of the
-/// dataflow analyses used by the borrow checker.
-#[derive(Debug)]
-pub struct BorrowckAnalyses<B, U, E> {
- pub borrows: B,
- pub uninits: U,
- pub ever_inits: E,
-}
-
/// The results of the dataflow analyses used by the borrow checker.
-pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses<
- Results<'tcx, Borrows<'mir, 'tcx>>,
- Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
- Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
->;
+pub struct BorrowckResults<'mir, 'tcx> {
+ pub(crate) borrows: Results<'tcx, Borrows<'mir, 'tcx>>,
+ pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
+ pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
+}
/// The transient state of the dataflow analyses used by the borrow checker.
-pub type BorrowckFlowState<'mir, 'tcx> =
- <BorrowckResults<'mir, 'tcx> as ResultsVisitable<'tcx>>::FlowState;
-
-macro_rules! impl_visitable {
- ( $(
- $T:ident { $( $field:ident : $A:ident ),* $(,)? }
- )* ) => { $(
- impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*>
- where
- $( $A: Analysis<'tcx, Direction = D>, )*
- {
- type Direction = D;
- type FlowState = $T<$( $A::Domain ),*>;
+#[derive(Debug)]
+pub struct BorrowckFlowState<'mir, 'tcx> {
+ pub(crate) borrows: <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
+ pub(crate) uninits: <MaybeUninitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
+ pub(crate) ever_inits: <EverInitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
+}
- fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
- $T {
- $( $field: self.$field.analysis.bottom_value(body) ),*
- }
- }
+impl<'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'mir, 'tcx> {
+ // All three analyses are forward, but we have to use just one here.
+ type Direction = <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Direction;
+ type FlowState = BorrowckFlowState<'mir, 'tcx>;
- fn reset_to_block_entry(
- &self,
- state: &mut Self::FlowState,
- block: BasicBlock,
- ) {
- $( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )*
- }
+ fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
+ BorrowckFlowState {
+ borrows: self.borrows.analysis.bottom_value(body),
+ uninits: self.uninits.analysis.bottom_value(body),
+ ever_inits: self.ever_inits.analysis.bottom_value(body),
+ }
+ }
- fn reconstruct_before_statement_effect(
- &mut self,
- state: &mut Self::FlowState,
- stmt: &mir::Statement<'tcx>,
- loc: Location,
- ) {
- $( self.$field.analysis
- .apply_before_statement_effect(&mut state.$field, stmt, loc); )*
- }
+ fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
+ state.borrows.clone_from(&self.borrows.entry_set_for_block(block));
+ state.uninits.clone_from(&self.uninits.entry_set_for_block(block));
+ state.ever_inits.clone_from(&self.ever_inits.entry_set_for_block(block));
+ }
- fn reconstruct_statement_effect(
- &mut self,
- state: &mut Self::FlowState,
- stmt: &mir::Statement<'tcx>,
- loc: Location,
- ) {
- $( self.$field.analysis
- .apply_statement_effect(&mut state.$field, stmt, loc); )*
- }
+ fn reconstruct_before_statement_effect(
+ &mut self,
+ state: &mut Self::FlowState,
+ stmt: &mir::Statement<'tcx>,
+ loc: Location,
+ ) {
+ self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
+ self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
+ self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
+ }
- fn reconstruct_before_terminator_effect(
- &mut self,
- state: &mut Self::FlowState,
- term: &mir::Terminator<'tcx>,
- loc: Location,
- ) {
- $( self.$field.analysis
- .apply_before_terminator_effect(&mut state.$field, term, loc); )*
- }
+ fn reconstruct_statement_effect(
+ &mut self,
+ state: &mut Self::FlowState,
+ stmt: &mir::Statement<'tcx>,
+ loc: Location,
+ ) {
+ self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
+ self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
+ self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
+ }
- fn reconstruct_terminator_effect(
- &mut self,
- state: &mut Self::FlowState,
- term: &mir::Terminator<'tcx>,
- loc: Location,
- ) {
- $( self.$field.analysis
- .apply_terminator_effect(&mut state.$field, term, loc); )*
- }
- }
- )* }
-}
+ fn reconstruct_before_terminator_effect(
+ &mut self,
+ state: &mut Self::FlowState,
+ term: &mir::Terminator<'tcx>,
+ loc: Location,
+ ) {
+ self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
+ self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
+ self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
+ }
-impl_visitable! {
- BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E }
+ fn reconstruct_terminator_effect(
+ &mut self,
+ state: &mut Self::FlowState,
+ term: &mir::Terminator<'tcx>,
+ loc: Location,
+ ) {
+ self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
+ self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
+ self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
+ }
}
rustc_index::newtype_index! {
+ #[orderable]
#[debug_format = "bw{}"]
pub struct BorrowIndex {}
}
@@ -120,24 +108,24 @@ rustc_index::newtype_index! {
/// `BorrowIndex`, and maps each such index to a `BorrowData`
/// describing the borrow. These indexes are used for representing the
/// borrows in compact bitvectors.
-pub struct Borrows<'a, 'tcx> {
+pub struct Borrows<'mir, 'tcx> {
tcx: TyCtxt<'tcx>,
- body: &'a Body<'tcx>,
+ body: &'mir Body<'tcx>,
- borrow_set: &'a BorrowSet<'tcx>,
+ borrow_set: &'mir BorrowSet<'tcx>,
borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
}
-struct OutOfScopePrecomputer<'a, 'tcx> {
+struct OutOfScopePrecomputer<'mir, 'tcx> {
visited: BitSet<mir::BasicBlock>,
visit_stack: Vec<mir::BasicBlock>,
- body: &'a Body<'tcx>,
- regioncx: &'a RegionInferenceContext<'tcx>,
+ body: &'mir Body<'tcx>,
+ regioncx: &'mir RegionInferenceContext<'tcx>,
borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
}
-impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
- fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
+impl<'mir, 'tcx> OutOfScopePrecomputer<'mir, 'tcx> {
+ fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self {
OutOfScopePrecomputer {
visited: BitSet::new_empty(body.basic_blocks.len()),
visit_stack: vec![],
@@ -240,17 +228,17 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
prec.borrows_out_of_scope_at_location
}
-struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
+struct PoloniusOutOfScopePrecomputer<'mir, 'tcx> {
visited: BitSet<mir::BasicBlock>,
visit_stack: Vec<mir::BasicBlock>,
- body: &'a Body<'tcx>,
- regioncx: &'a RegionInferenceContext<'tcx>,
+ body: &'mir Body<'tcx>,
+ regioncx: &'mir RegionInferenceContext<'tcx>,
loans_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
}
-impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
- fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
+impl<'mir, 'tcx> PoloniusOutOfScopePrecomputer<'mir, 'tcx> {
+ fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self {
Self {
visited: BitSet::new_empty(body.basic_blocks.len()),
visit_stack: vec![],
@@ -403,12 +391,12 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
}
}
-impl<'a, 'tcx> Borrows<'a, 'tcx> {
+impl<'mir, 'tcx> Borrows<'mir, 'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
- body: &'a Body<'tcx>,
- regioncx: &'a RegionInferenceContext<'tcx>,
- borrow_set: &'a BorrowSet<'tcx>,
+ body: &'mir Body<'tcx>,
+ regioncx: &'mir RegionInferenceContext<'tcx>,
+ borrow_set: &'mir BorrowSet<'tcx>,
) -> Self {
let mut borrows_out_of_scope_at_location =
calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set);
@@ -431,7 +419,8 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
assert_eq!(
borrows_out_of_scope_at_location, polonius_prec.loans_out_of_scope_at_location,
- "the loans out of scope must be the same as the borrows out of scope"
+ "polonius loan scopes differ from NLL borrow scopes, for body {:?}",
+ body.span,
);
borrows_out_of_scope_at_location = polonius_prec.loans_out_of_scope_at_location;
@@ -596,7 +585,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
fn before_terminator_effect(
&mut self,
- trans: &mut impl GenKill<Self::Idx>,
+ trans: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
location: Location,
) {
@@ -623,7 +612,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
fn call_return_effect(
&mut self,
- _trans: &mut impl GenKill<Self::Idx>,
+ _trans: &mut Self::Domain,
_block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index cfcf31fce..924e68fa9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -10,6 +10,8 @@ use rustc_infer::infer::RegionVariableOrigin;
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
use rustc_infer::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::RePlaceholder;
+use rustc_middle::ty::Region;
use rustc_middle::ty::RegionVid;
use rustc_middle::ty::UniverseIndex;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -205,6 +207,8 @@ trait TypeOpInfo<'tcx> {
let span = cause.span;
let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
+ debug!(?nice_error);
+
if let Some(nice_error) = nice_error {
mbcx.buffer_error(nice_error);
} else {
@@ -381,7 +385,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
// We generally shouldn't have errors here because the query was
- // already run, but there's no point using `delay_span_bug`
+ // already run, but there's no point using `span_delayed_bug`
// when we're going to emit an error here anyway.
let _errors = ocx.select_all_or_error();
let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone());
@@ -404,19 +408,41 @@ fn try_extract_error_from_region_constraints<'tcx>(
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- let (sub_region, cause) =
- region_constraints.constraints.iter().find_map(|(constraint, cause)| {
- match *constraint {
- Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
- Some((sub, cause.clone()))
- }
- // FIXME: Should this check the universe of the var?
- Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
- Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
- }
- _ => None,
+ let matches =
+ |a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) {
+ (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
+ _ => a_region == b_region,
+ };
+ let check = |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| {
+ match *constraint {
+ Constraint::RegSubReg(sub, sup)
+ if ((exact && sup == placeholder_region)
+ || (!exact && matches(sup, placeholder_region)))
+ && sup != sub =>
+ {
+ Some((sub, cause.clone()))
+ }
+ // FIXME: Should this check the universe of the var?
+ Constraint::VarSubReg(vid, sup)
+ if ((exact && sup == placeholder_region)
+ || (!exact && matches(sup, placeholder_region))) =>
+ {
+ Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
}
- })?;
+ _ => None,
+ }
+ };
+ let mut info = region_constraints
+ .constraints
+ .iter()
+ .find_map(|(constraint, cause)| check(constraint, cause, true));
+ if info.is_none() {
+ info = region_constraints
+ .constraints
+ .iter()
+ .find_map(|(constraint, cause)| check(constraint, cause, false));
+ }
+ let (sub_region, cause) = info?;
debug!(?sub_region, "cause = {:#?}", cause);
let error = match (error_region, *sub_region) {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 9a8f1c97e..db0f4559a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -18,7 +18,7 @@ use rustc_middle::mir::{
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
VarBindingForm,
};
-use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
+use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty, TyCtxt};
use rustc_middle::util::CallKind;
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
@@ -398,7 +398,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
let hir_id = hir.parent_id(expr.hir_id);
- if let Some(parent) = hir.find(hir_id) {
+ if let Some(parent) = self.infcx.tcx.opt_hir_node(hir_id) {
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
&& let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
@@ -413,7 +413,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(None, &[][..], 0)
};
if let Some(def_id) = def_id
- && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id))
+ && let Some(node) = self
+ .infcx
+ .tcx
+ .opt_hir_node(self.infcx.tcx.local_def_id_to_hir_id(def_id))
&& let Some(fn_sig) = node.fn_sig()
&& let Some(ident) = node.ident()
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
@@ -445,7 +448,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&& let hir::ExprKind::Path(hir::QPath::LangItem(
LangItem::IntoIterIntoIter,
_,
- _,
)) = call_expr.kind
{
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
@@ -490,7 +492,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut spans = vec![];
for init_idx in inits {
let init = &self.move_data.inits[*init_idx];
- let span = init.span(&self.body);
+ let span = init.span(self.body);
if !span.is_dummy() {
spans.push(span);
}
@@ -518,7 +520,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let body = map.body(body_id);
let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
- visitor.visit_body(&body);
+ visitor.visit_body(body);
let mut show_assign_sugg = false;
let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
@@ -614,7 +616,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
let mut visitor = LetVisitor { decl_span, sugg_span: None };
- visitor.visit_body(&body);
+ visitor.visit_body(body);
if let Some(span) = visitor.sugg_span {
self.suggest_assign_value(&mut err, moved_place, span);
}
@@ -779,7 +781,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return;
};
// Try to find predicates on *generic params* that would allow copying `ty`
- let ocx = ObligationCtxt::new(&self.infcx);
+ let ocx = ObligationCtxt::new(self.infcx);
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
let cause = ObligationCause::misc(span, self.mir_def_id());
@@ -856,7 +858,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.explain_why_borrow_contains_point(location, borrow, None)
.add_explanation_to_diagnostic(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&mut err,
"",
@@ -903,7 +905,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.explain_why_borrow_contains_point(location, borrow, None)
.add_explanation_to_diagnostic(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&mut err,
"",
@@ -1136,7 +1138,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
});
} else {
issued_spans.var_subdiag(
- Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic),
+ Some(self.infcx.tcx.sess.dcx()),
&mut err,
Some(issued_borrow.kind),
|kind, var_span| {
@@ -1153,7 +1155,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
borrow_spans.var_subdiag(
- Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic),
+ Some(self.infcx.tcx.sess.dcx()),
&mut err,
Some(gen_borrow_kind),
|kind, var_span| {
@@ -1174,7 +1176,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&mut err,
first_borrow_desc,
@@ -1318,7 +1320,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let tcx = self.infcx.tcx;
let hir = tcx.hir();
- let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return };
+ let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
let typeck_results = tcx.typeck(self.mir_def_id());
struct ExprFinder<'hir> {
@@ -1346,11 +1348,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// };
// corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`.
if let hir::ExprKind::Call(path, [arg]) = ex.kind
- && let hir::ExprKind::Path(hir::QPath::LangItem(
- LangItem::IntoIterIntoIter,
- _,
- _,
- )) = path.kind
+ && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
+ path.kind
&& arg.span.contains(self.issue_span)
{
// Find `IntoIterator::into_iter(<head>)`
@@ -1368,10 +1367,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
..
}) = stmt.kind
&& let hir::ExprKind::Call(path, _args) = call.kind
- && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _)) =
+ && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _)) =
path.kind
&& let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind
- && let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path
+ && let hir::QPath::LangItem(LangItem::OptionSome, pat_span) = path
&& call.span.contains(self.issue_span)
{
// Find `<pat>` and the span for the whole `for` loop.
@@ -1513,7 +1512,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let local_ty = self.body.local_decls[local].ty;
// Get the body the error happens in
- let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return };
+ let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
let body_expr = hir.body(body_id).value;
@@ -1562,7 +1561,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Check that the parent of the closure is a method call,
// with receiver matching with local's type (modulo refs)
let parent = hir.parent_id(closure_expr.hir_id);
- if let hir::Node::Expr(parent) = hir.get(parent) {
+ if let hir::Node::Expr(parent) = tcx.hir_node(parent) {
if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
let recv_ty = typeck_results.expr_ty(recv);
@@ -1578,8 +1577,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return;
};
let sig = args.as_closure().sig();
- let tupled_params =
- tcx.erase_late_bound_regions(sig.inputs().iter().next().unwrap().map_bound(|&b| b));
+ let tupled_params = tcx.instantiate_bound_regions_with_erased(
+ sig.inputs().iter().next().unwrap().map_bound(|&b| b),
+ );
let ty::Tuple(params) = tupled_params.kind() else { return };
// Find the first argument with a matching type, get its name
@@ -1638,15 +1638,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
issued_spans: &UseSpans<'tcx>,
) {
let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
- let hir = self.infcx.tcx.hir();
- struct ExpressionFinder<'hir> {
+ struct ExpressionFinder<'tcx> {
capture_span: Span,
closure_change_spans: Vec<Span>,
closure_arg_span: Option<Span>,
in_closure: bool,
suggest_arg: String,
- hir: rustc_middle::hir::map::Map<'hir>,
+ tcx: TyCtxt<'tcx>,
closure_local_id: Option<hir::HirId>,
closure_call_changes: Vec<(Span, String)>,
}
@@ -1660,7 +1659,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn_decl: hir::FnDecl { inputs, .. },
..
}) = e.kind
- && let Some(hir::Node::Expr(body)) = self.hir.find(body.hir_id)
+ && let Some(hir::Node::Expr(body)) = self.tcx.opt_hir_node(body.hir_id)
{
self.suggest_arg = "this: &Self".to_string();
if inputs.len() > 0 {
@@ -1725,8 +1724,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some(hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(_fn_sig, body_id),
..
- })) = hir.find(self.mir_hir_id())
- && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
+ })) = self.infcx.tcx.opt_hir_node(self.mir_hir_id())
+ && let Some(hir::Node::Expr(expr)) = self.infcx.tcx.opt_hir_node(body_id.hir_id)
{
let mut finder = ExpressionFinder {
capture_span: *capture_kind_span,
@@ -1736,7 +1735,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
suggest_arg: String::new(),
closure_local_id: None,
closure_call_changes: vec![],
- hir,
+ tcx: self.infcx.tcx,
};
finder.visit_expr(expr);
@@ -1931,7 +1930,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
- let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
+ let explanation = self.explain_why_borrow_contains_point(location, borrow, kind_place);
debug!(?place_desc, ?explanation);
@@ -2000,14 +1999,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
location,
&name,
- &borrow,
+ borrow,
drop_span,
borrow_spans,
explanation,
),
(None, explanation) => self.report_temporary_value_does_not_live_long_enough(
location,
- &borrow,
+ borrow,
drop_span,
borrow_spans,
proper_span,
@@ -2075,8 +2074,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.map(|name| format!("function `{name}`"))
.unwrap_or_else(|| {
match &self.infcx.tcx.def_kind(self.mir_def_id()) {
+ DefKind::Closure
+ if self
+ .infcx
+ .tcx
+ .is_coroutine(self.mir_def_id().to_def_id()) =>
+ {
+ "enclosing coroutine"
+ }
DefKind::Closure => "enclosing closure",
- DefKind::Coroutine => "enclosing coroutine",
kind => bug!("expected closure or coroutine, found {:?}", kind),
}
.to_string()
@@ -2097,7 +2103,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else {
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&mut err,
"",
@@ -2118,7 +2124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&mut err,
"",
@@ -2179,7 +2185,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&mut err,
"",
@@ -2290,7 +2296,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let proper_span = proper_span.source_callsite();
if let Some(scope) = self.body.source_scopes.get(source_info.scope)
&& let ClearCrossCrate::Set(scope_data) = &scope.local_data
- && let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root)
+ && let Some(node) = self.infcx.tcx.opt_hir_node(scope_data.lint_root)
&& let Some(id) = node.body_id()
&& let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
{
@@ -2348,7 +2354,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Applicability::MaybeIncorrect,
);
} else {
- err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used");
+ err.note("the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used");
err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>");
}
suggested = true;
@@ -2364,7 +2370,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&mut err,
"",
@@ -2513,12 +2519,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
CoroutineKind::Gen(kind) => match kind {
CoroutineSource::Block => "gen block",
CoroutineSource::Closure => "gen closure",
- _ => bug!("gen block/closure expected, but gen function found."),
+ CoroutineSource::Fn => {
+ bug!("gen block/closure expected, but gen function found.")
+ }
+ },
+ CoroutineKind::AsyncGen(kind) => match kind {
+ CoroutineSource::Block => "async gen block",
+ CoroutineSource::Closure => "async gen closure",
+ CoroutineSource::Fn => {
+ bug!("gen block/closure expected, but gen function found.")
+ }
},
CoroutineKind::Async(async_kind) => match async_kind {
CoroutineSource::Block => "async block",
CoroutineSource::Closure => "async closure",
- _ => bug!("async block/closure expected, but async function found."),
+ CoroutineSource::Fn => {
+ bug!("async block/closure expected, but async function found.")
+ }
},
CoroutineKind::Coroutine => "coroutine",
},
@@ -2841,7 +2858,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&mut err,
"",
@@ -3019,7 +3036,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
let mut visitor = FakeReadCauseFinder { place, cause: None };
- visitor.visit_body(&self.body);
+ visitor.visit_body(self.body);
match visitor.cause {
Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
Some(FakeReadCause::ForIndex) => Some("indexing expression"),
@@ -3246,7 +3263,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
let is_closure = self.infcx.tcx.is_closure(did.to_def_id());
- let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
+ let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did);
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
// We need to work out which arguments to highlight. We do this by looking
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 8a930ca59..f1e712d81 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -5,12 +5,13 @@ use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_index::IndexSlice;
use rustc_infer::infer::NllRegionVariableOrigin;
+use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
use rustc_middle::mir::{
Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location,
Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind,
};
use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{sym, DesugaringKind, Span};
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
@@ -86,7 +87,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind
&& let [hir::PathSegment { ident, args: None, .. }] = p.segments
&& let hir::def::Res::Local(hir_id) = p.res
- && let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id)
+ && let Some(hir::Node::Pat(pat)) = tcx.opt_hir_node(hir_id)
{
err.span_label(pat.span, format!("binding `{ident}` declared here"));
}
@@ -290,12 +291,69 @@ impl<'tcx> BorrowExplanation<'tcx> {
}
}
+ if let ConstraintCategory::Cast { unsize_to: Some(unsize_ty) } = category {
+ self.add_object_lifetime_default_note(tcx, err, unsize_ty);
+ }
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
}
_ => {}
}
}
+ fn add_object_lifetime_default_note(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ err: &mut Diagnostic,
+ unsize_ty: Ty<'tcx>,
+ ) {
+ if let ty::Adt(def, args) = unsize_ty.kind() {
+ // We try to elaborate the object lifetime defaults and present those to the user. This should
+ // make it clear where the region constraint is coming from.
+ let generics = tcx.generics_of(def.did());
+
+ let mut has_dyn = false;
+ let mut failed = false;
+
+ let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
+ if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
+ let default = tcx.object_lifetime_default(param.def_id);
+
+ let re_static = tcx.lifetimes.re_static;
+
+ let implied_region = match default {
+ // This is not entirely precise.
+ ObjectLifetimeDefault::Empty => re_static,
+ ObjectLifetimeDefault::Ambiguous => {
+ failed = true;
+ re_static
+ }
+ ObjectLifetimeDefault::Param(param_def_id) => {
+ let index = generics.param_def_id_to_index[&param_def_id] as usize;
+ args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(|| {
+ failed = true;
+ re_static
+ })
+ }
+ ObjectLifetimeDefault::Static => re_static,
+ };
+
+ has_dyn = true;
+
+ Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
+ } else {
+ arg
+ }
+ });
+ let elaborated_ty = Ty::new_adt(tcx, *def, tcx.mk_args_from_iter(elaborated_args));
+
+ if has_dyn && !failed {
+ err.note(format!(
+ "due to object lifetime defaults, `{unsize_ty}` actually means `{elaborated_ty}`"
+ ));
+ }
+ }
+ }
+
fn add_lifetime_bound_suggestion_to_diagnostic(
&self,
err: &mut Diagnostic,
@@ -364,7 +422,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
kind_place: Option<(WriteKind, Place<'tcx>)>,
) -> BorrowExplanation<'tcx> {
let regioncx = &self.regioncx;
- let body: &Body<'_> = &self.body;
+ let body: &Body<'_> = self.body;
let tcx = self.infcx.tcx;
let borrow_region_vid = borrow.region;
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index c4323fef9..ee3213654 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -10,7 +10,8 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::CoroutineKind;
use rustc_index::IndexSlice;
-use rustc_infer::infer::LateBoundRegionConversionTime;
+use rustc_infer::infer::BoundRegionConversionTime;
+use rustc_infer::traits::{FulfillmentErrorCode, SelectionError};
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
@@ -24,10 +25,9 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
use rustc_span::def_id::LocalDefId;
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::{FieldIdx, VariantIdx};
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{
- type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
-};
+use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
@@ -124,7 +124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.eager_subdiagnostic(
- &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+ self.infcx.tcx.sess.dcx(),
OnClosureNote::InvokedTwice {
place_name: &ty::place_to_string_for_capture(
self.infcx.tcx,
@@ -146,7 +146,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.eager_subdiagnostic(
- &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+ self.infcx.tcx.sess.dcx(),
OnClosureNote::MovedTwice {
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
span: *span,
@@ -217,9 +217,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
projection: place.projection.split_at(index + 1).0,
}) {
let var_index = field.index();
- buf = self.upvars[var_index].place.to_string(self.infcx.tcx);
+ buf = self.upvars[var_index].to_string(self.infcx.tcx);
ok = Ok(());
- if !self.upvars[var_index].by_ref {
+ if !self.upvars[var_index].is_by_ref() {
buf.insert(0, '*');
}
} else {
@@ -250,7 +250,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
local,
projection: place.projection.split_at(index + 1).0,
}) {
- buf = self.upvars[field.index()].place.to_string(self.infcx.tcx);
+ buf = self.upvars[field.index()].to_string(self.infcx.tcx);
ok = Ok(());
} else {
let field_name = self.describe_field(
@@ -354,7 +354,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty::Adt(def, _) => {
let variant = if let Some(idx) = variant_index {
assert!(def.is_enum());
- &def.variant(idx)
+ def.variant(idx)
} else {
def.non_enum_variant()
};
@@ -462,7 +462,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// lifetimes without names with the value `'0`.
if let ty::Ref(region, ..) = ty.kind() {
match **region {
- ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
+ ty::ReBound(_, ty::BoundRegion { kind: br, .. })
| ty::RePlaceholder(ty::PlaceholderRegion {
bound: ty::BoundRegion { kind: br, .. },
..
@@ -482,7 +482,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let region = if let ty::Ref(region, ..) = ty.kind() {
match **region {
- ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
+ ty::ReBound(_, ty::BoundRegion { kind: br, .. })
| ty::RePlaceholder(ty::PlaceholderRegion {
bound: ty::BoundRegion { kind: br, .. },
..
@@ -624,7 +624,7 @@ impl UseSpans<'_> {
/// Add a subdiagnostic to the use of the captured variable, if it exists.
pub(super) fn var_subdiag(
self,
- handler: Option<&rustc_errors::Handler>,
+ dcx: Option<&rustc_errors::DiagCtxt>,
err: &mut Diagnostic,
kind: Option<rustc_middle::mir::BorrowKind>,
f: impl FnOnce(Option<CoroutineKind>, Span) -> CaptureVarCause,
@@ -646,7 +646,7 @@ impl UseSpans<'_> {
});
};
let diag = f(coroutine_kind, path_span);
- match handler {
+ match dcx {
Some(hd) => err.eager_subdiagnostic(hd, diag),
None => err.subdiagnostic(diag),
};
@@ -851,7 +851,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
{
let Some((method_did, method_args)) = rustc_middle::util::find_self_call(
self.infcx.tcx,
- &self.body,
+ self.body,
target_temp,
location.block,
) else {
@@ -958,7 +958,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"closure_span: def_id={:?} target_place={:?} places={:?}",
def_id, target_place, places
);
- let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
@@ -1043,12 +1043,43 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
CallKind::Normal { self_arg, desugaring, method_did, method_args } => {
let self_arg = self_arg.unwrap();
+ let mut has_sugg = false;
let tcx = self.infcx.tcx;
+ // Avoid pointing to the same function in multiple different
+ // error messages.
+ if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
+ self.explain_iterator_advancement_in_for_loop_if_applicable(
+ err,
+ span,
+ &move_spans,
+ );
+
+ let func = tcx.def_path_str(method_did);
+ err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
+ func,
+ place_name: place_name.clone(),
+ span: self_arg.span,
+ });
+ }
+ let parent_did = tcx.parent(method_did);
+ let parent_self_ty =
+ matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
+ .then_some(parent_did)
+ .and_then(|did| match tcx.type_of(did).instantiate_identity().kind() {
+ ty::Adt(def, ..) => Some(def.did()),
+ _ => None,
+ });
+ let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
+ matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
+ });
+ if is_option_or_result && maybe_reinitialized_locations_is_empty {
+ err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
+ }
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
let ty = moved_place.ty(self.body, tcx).ty;
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
Some(def_id) => type_known_to_meet_bound_modulo_regions(
- &self.infcx,
+ self.infcx,
self.param_env,
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
def_id,
@@ -1108,72 +1139,92 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Erase and shadow everything that could be passed to the new infcx.
let ty = moved_place.ty(self.body, tcx).ty;
- if let ty::Adt(def, args) = ty.kind()
+ if let ty::Adt(def, args) = ty.peel_refs().kind()
&& Some(def.did()) == tcx.lang_items().pin_type()
&& let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind()
&& let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
fn_call_span,
- LateBoundRegionConversionTime::FnCall,
+ BoundRegionConversionTime::FnCall,
tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0),
)
&& self.infcx.can_eq(self.param_env, ty, self_ty)
{
err.eager_subdiagnostic(
- &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+ self.infcx.tcx.sess.dcx(),
CaptureReasonSuggest::FreshReborrow {
span: move_span.shrink_to_hi(),
},
);
+ has_sugg = true;
}
- if let Some(clone_trait) = tcx.lang_items().clone_trait()
- && let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty])
- && let o = Obligation::new(
- tcx,
- ObligationCause::dummy(),
- self.param_env,
- ty::Binder::dummy(trait_ref),
- )
- && self.infcx.predicate_must_hold_modulo_regions(&o)
- {
- err.span_suggestion_verbose(
- move_span.shrink_to_hi(),
- "you can `clone` the value and consume it, but this might not be \
- your desired behavior",
- ".clone()".to_string(),
- Applicability::MaybeIncorrect,
- );
+ if let Some(clone_trait) = tcx.lang_items().clone_trait() {
+ let sugg = if moved_place
+ .iter_projections()
+ .any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
+ {
+ vec![
+ // We use the fully-qualified path because `.clone()` can
+ // sometimes choose `<&T as Clone>` instead of `<T as Clone>`
+ // when going through auto-deref, so this ensures that doesn't
+ // happen, causing suggestions for `.clone().clone()`.
+ (move_span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")),
+ (move_span.shrink_to_hi(), ")".to_string()),
+ ]
+ } else {
+ vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
+ };
+ if let Some(errors) =
+ self.infcx.could_impl_trait(clone_trait, ty, self.param_env)
+ && !has_sugg
+ {
+ let msg = match &errors[..] {
+ [] => "you can `clone` the value and consume it, but this \
+ might not be your desired behavior"
+ .to_string(),
+ [error] => {
+ format!(
+ "you could `clone` the value and consume it, if \
+ the `{}` trait bound could be satisfied",
+ error.obligation.predicate,
+ )
+ }
+ [errors @ .., last] => {
+ format!(
+ "you could `clone` the value and consume it, if \
+ the following trait bounds could be satisfied: {} \
+ and `{}`",
+ errors
+ .iter()
+ .map(|e| format!("`{}`", e.obligation.predicate))
+ .collect::<Vec<_>>()
+ .join(", "),
+ last.obligation.predicate,
+ )
+ }
+ };
+ err.multipart_suggestion_verbose(
+ msg,
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ for error in errors {
+ if let FulfillmentErrorCode::CodeSelectionError(
+ SelectionError::Unimplemented,
+ ) = error.code
+ && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
+ pred,
+ )) = error.obligation.predicate.kind().skip_binder()
+ {
+ self.infcx.err_ctxt().suggest_derive(
+ &error.obligation,
+ err,
+ error.obligation.predicate.kind().rebind(pred),
+ );
+ }
+ }
+ }
}
}
- // Avoid pointing to the same function in multiple different
- // error messages.
- if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
- self.explain_iterator_advancement_in_for_loop_if_applicable(
- err,
- span,
- &move_spans,
- );
-
- let func = tcx.def_path_str(method_did);
- err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
- func,
- place_name,
- span: self_arg.span,
- });
- }
- let parent_did = tcx.parent(method_did);
- let parent_self_ty =
- matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
- .then_some(parent_did)
- .and_then(|did| match tcx.type_of(did).instantiate_identity().kind() {
- ty::Adt(def, ..) => Some(def.did()),
- _ => None,
- });
- let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
- matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
- });
- if is_option_or_result && maybe_reinitialized_locations_is_empty {
- err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
- }
}
// Other desugarings takes &self, which cannot cause a move
_ => {}
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 41d6b98d7..43487b85a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -321,7 +321,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let deref_base = match deref_target_place.projection.as_ref() {
[proj_base @ .., ProjectionElem::Deref] => {
- PlaceRef { local: deref_target_place.local, projection: &proj_base }
+ PlaceRef { local: deref_target_place.local, projection: proj_base }
}
_ => bug!("deref_target_place is not a deref projection"),
};
@@ -363,8 +363,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
format!("captured variable in an `{closure_kind}` closure");
let upvar = &self.upvars[upvar_field.unwrap().index()];
- let upvar_hir_id = upvar.place.get_root_variable();
- let upvar_name = upvar.place.to_string(self.infcx.tcx);
+ let upvar_hir_id = upvar.get_root_variable();
+ let upvar_name = upvar.to_string(self.infcx.tcx);
let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
let place_name = self.describe_any_place(move_place.as_ref());
@@ -583,7 +583,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty: bind_to.ty,
- place: &place_desc,
+ place: place_desc,
span: binding_span,
});
}
@@ -607,7 +607,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(adt) = local_ty.ty_adt_def()
&& adt.repr().packed()
- && let ExpnKind::Macro(MacroKind::Derive, name) = self.body.span.ctxt().outer_expn_data().kind
+ && let ExpnKind::Macro(MacroKind::Derive, name) =
+ self.body.span.ctxt().outer_expn_data().kind
{
err.note(format!("`#[derive({name})]` triggers a move because taking references to the fields of a packed struct is undefined behaviour"));
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index dde46eef6..c3c1f1293 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -3,8 +3,9 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
+use rustc_infer::traits;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
-use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt};
use rustc_middle::{
hir::place::PlaceBase,
mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
@@ -12,6 +13,8 @@ use rustc_middle::{
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{sym, BytePos, DesugaringKind, Span};
use rustc_target::abi::FieldIdx;
+use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
use crate::diagnostics::BorrowedContentSource;
use crate::util::FindAssignments;
@@ -67,7 +70,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let imm_borrow_derefed = self.upvars[upvar_index.index()]
.place
- .place
.deref_tys()
.any(|ty| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not)));
@@ -85,7 +87,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
- let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx);
+ let name = self.upvars[upvar_index.index()].to_string(self.infcx.tcx);
reason = format!(", as `{name}` is not declared as mutable");
}
}
@@ -388,13 +390,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
));
- let captured_place = &self.upvars[upvar_index.index()].place;
+ let captured_place = self.upvars[upvar_index.index()];
err.span_label(span, format!("cannot {act}"));
let upvar_hir_id = captured_place.get_root_variable();
- if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
+ if let Some(Node::Pat(pat)) = self.infcx.tcx.opt_hir_node(upvar_hir_id)
&& let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, upvar_ident, _) =
pat.kind
{
@@ -659,9 +661,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if self.body.local_kind(local) != LocalKind::Arg {
return (false, None);
}
- let hir_map = self.infcx.tcx.hir();
let my_def = self.body.source.def_id();
- let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap());
+ let my_hir = self.infcx.tcx.local_def_id_to_hir_id(my_def.as_local().unwrap());
let Some(td) =
self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
else {
@@ -669,7 +670,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
(
true,
- td.as_local().and_then(|tld| match hir_map.find_by_def_id(tld) {
+ td.as_local().and_then(|tld| match self.infcx.tcx.opt_hir_node_by_def_id(tld) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Trait(_, _, _, _, items),
..
@@ -680,25 +681,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if !matches!(k, hir::AssocItemKind::Fn { .. }) {
continue;
}
- if hir_map.name(hi) != hir_map.name(my_hir) {
+ if self.infcx.tcx.hir().name(hi) != self.infcx.tcx.hir().name(my_hir) {
continue;
}
f_in_trait_opt = Some(hi);
break;
}
- f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
- Some(Node::TraitItem(hir::TraitItem {
- kind:
- hir::TraitItemKind::Fn(
- hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
- _,
- ),
- ..
- })) => {
- let hir::Ty { span, .. } = inputs[local.index() - 1];
- Some(span)
+ f_in_trait_opt.and_then(|f_in_trait| {
+ match self.infcx.tcx.opt_hir_node(f_in_trait) {
+ Some(Node::TraitItem(hir::TraitItem {
+ kind:
+ hir::TraitItemKind::Fn(
+ hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
+ _,
+ ),
+ ..
+ })) => {
+ let hir::Ty { span, .. } = inputs[local.index() - 1];
+ Some(span)
+ }
+ _ => None,
}
- _ => None,
})
}
_ => None,
@@ -739,12 +742,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
- let hir_map = self.infcx.tcx.hir();
let def_id = self.body.source.def_id();
let hir_id = if let Some(local_def_id) = def_id.as_local()
- && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
+ && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
{
- let body = hir_map.body(body_id);
+ let body = self.infcx.tcx.hir().body(body_id);
let mut v = BindingFinder { span: pat_span, hir_id: None };
v.visit_body(body);
v.hir_id
@@ -760,7 +762,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&& let Some(hir::Node::Local(hir::Local {
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
..
- })) = hir_map.find(hir_id)
+ })) = self.infcx.tcx.opt_hir_node(hir_id)
&& let Ok(name) =
self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
{
@@ -940,7 +942,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let closure_id = self.mir_hir_id();
let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
let fn_call_id = hir.parent_id(closure_id);
- let node = hir.get(fn_call_id);
+ let node = self.infcx.tcx.hir_node(fn_call_id);
let def_id = hir.enclosing_body_owner(fn_call_id);
let mut look_at_return = true;
// If we can detect the expression to be an `fn` call where the closure was an argument,
@@ -999,7 +1001,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if look_at_return && hir.get_return_block(closure_id).is_some() {
// ...otherwise we are probably in the tail expression of the function, point at the
// return type.
- match hir.get_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
+ match self.infcx.tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. })
| hir::Node::TraitItem(hir::TraitItem {
ident,
@@ -1197,12 +1199,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
hir::intravisit::walk_stmt(self, s);
}
}
- let hir_map = self.infcx.tcx.hir();
let def_id = self.body.source.def_id();
let hir_id = if let Some(local_def_id) = def_id.as_local()
- && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
+ && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
{
- let body = hir_map.body(body_id);
+ let body = self.infcx.tcx.hir().body(body_id);
let mut v = BindingFinder { span: err_label_span, hir_id: None };
v.visit_body(body);
v.hir_id
@@ -1211,8 +1212,105 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
if let Some(hir_id) = hir_id
- && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
+ && let Some(hir::Node::Local(local)) = self.infcx.tcx.opt_hir_node(hir_id)
{
+ let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
+ if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
+ && let Some(expr) = local.init
+ && let ty = tables.node_type_opt(expr.hir_id)
+ && let Some(ty) = ty
+ && let ty::Ref(..) = ty.kind()
+ {
+ match self
+ .infcx
+ .could_impl_trait(clone_trait, ty.peel_refs(), self.param_env)
+ .as_deref()
+ {
+ Some([]) => {
+ // The type implements Clone.
+ err.span_help(
+ expr.span,
+ format!(
+ "you can `clone` the `{}` value and consume it, but this \
+ might not be your desired behavior",
+ ty.peel_refs(),
+ ),
+ );
+ }
+ None => {
+ if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) =
+ expr.kind
+ && segment.ident.name == sym::clone
+ {
+ err.span_help(
+ span,
+ format!(
+ "`{}` doesn't implement `Clone`, so this call clones \
+ the reference `{ty}`",
+ ty.peel_refs(),
+ ),
+ );
+ }
+ // The type doesn't implement Clone.
+ let trait_ref = ty::Binder::dummy(ty::TraitRef::new(
+ self.infcx.tcx,
+ clone_trait,
+ [ty.peel_refs()],
+ ));
+ let obligation = traits::Obligation::new(
+ self.infcx.tcx,
+ traits::ObligationCause::dummy(),
+ self.param_env,
+ trait_ref,
+ );
+ self.infcx.err_ctxt().suggest_derive(
+ &obligation,
+ err,
+ trait_ref.to_predicate(self.infcx.tcx),
+ );
+ }
+ Some(errors) => {
+ if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) =
+ expr.kind
+ && segment.ident.name == sym::clone
+ {
+ err.span_help(
+ span,
+ format!(
+ "`{}` doesn't implement `Clone` because its \
+ implementations trait bounds could not be met, so \
+ this call clones the reference `{ty}`",
+ ty.peel_refs(),
+ ),
+ );
+ err.note(format!(
+ "the following trait bounds weren't met: {}",
+ errors
+ .iter()
+ .map(|e| e.obligation.predicate.to_string())
+ .collect::<Vec<_>>()
+ .join("\n"),
+ ));
+ }
+ // The type doesn't implement Clone because of unmet obligations.
+ for error in errors {
+ if let traits::FulfillmentErrorCode::CodeSelectionError(
+ traits::SelectionError::Unimplemented,
+ ) = error.code
+ && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
+ pred,
+ )) = error.obligation.predicate.kind().skip_binder()
+ {
+ self.infcx.err_ctxt().suggest_derive(
+ &error.obligation,
+ err,
+ error.obligation.predicate.kind().rebind(pred),
+ );
+ }
+ }
+ }
+ }
+ }
let (changing, span, sugg) = match local.ty {
Some(ty) => ("changing", ty.span, message),
None => {
@@ -1397,7 +1495,7 @@ fn get_mut_span_in_struct_field<'tcx>(
&& let ty::Adt(def, _) = ty.kind()
&& let field = def.all_fields().nth(field.index())?
// Use the HIR types to construct the diagnostic message.
- && let node = tcx.hir().find_by_def_id(field.did.as_local()?)?
+ && let node = tcx.opt_hir_node_by_def_id(field.did.as_local()?)?
// Now we're dealing with the actual struct that we're going to suggest a change to,
// we can expect a field that is an immutable reference to a type.
&& let hir::Node::Field(field) = node
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index b6eb9ae98..66275888c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -50,8 +50,8 @@ impl OutlivesSuggestionBuilder {
// naming the `'self` lifetime in methods, etc.
fn region_name_is_suggestable(name: &RegionName) -> bool {
match name.source {
- RegionNameSource::NamedEarlyBoundRegion(..)
- | RegionNameSource::NamedFreeRegion(..)
+ RegionNameSource::NamedEarlyParamRegion(..)
+ | RegionNameSource::NamedLateParamRegion(..)
| RegionNameSource::Static => true,
// Don't give suggestions for upvars, closure return types, or other unnameable
@@ -206,7 +206,7 @@ impl OutlivesSuggestionBuilder {
// If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
// list of diagnostics.
let mut diag = if suggested.len() == 1 {
- mbcx.infcx.tcx.sess.diagnostic().struct_help(match suggested.last().unwrap() {
+ mbcx.infcx.tcx.sess.dcx().struct_help(match suggested.last().unwrap() {
SuggestedConstraint::Outlives(a, bs) => {
let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
format!("add bound `{a}: {}`", bs.join(" + "))
@@ -223,7 +223,7 @@ impl OutlivesSuggestionBuilder {
.infcx
.tcx
.sess
- .diagnostic()
+ .dcx()
.struct_help("the following changes may resolve your lifetime errors");
// Add suggestions.
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index a0a809123..759f5e910 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -35,7 +35,7 @@ use crate::session_diagnostics::{
LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
};
-use super::{OutlivesSuggestionBuilder, RegionName};
+use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
nll::ConstraintDescription,
@@ -53,7 +53,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
ConstraintCategory::Yield => "yielding this value ",
ConstraintCategory::UseAsConst => "using this value as a constant ",
ConstraintCategory::UseAsStatic => "using this value as a static ",
- ConstraintCategory::Cast => "cast ",
+ ConstraintCategory::Cast { .. } => "cast ",
ConstraintCategory::CallArgument(_) => "argument ",
ConstraintCategory::TypeAnnotation => "type annotation ",
ConstraintCategory::ClosureBounds => "closure body ",
@@ -84,7 +84,7 @@ impl<'tcx> RegionErrors<'tcx> {
#[track_caller]
pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
let val = val.into();
- self.1.sess.delay_span_bug(DUMMY_SP, format!("{val:?}"));
+ self.1.sess.span_delayed_bug(DUMMY_SP, format!("{val:?}"));
self.0.push(val);
}
pub fn is_empty(&self) -> bool {
@@ -95,6 +95,12 @@ impl<'tcx> RegionErrors<'tcx> {
}
}
+impl std::fmt::Debug for RegionErrors<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_tuple("RegionErrors").field(&self.0).finish()
+ }
+}
+
#[derive(Clone, Debug)]
pub(crate) enum RegionErrorKind<'tcx> {
/// A generic bound failure for a type test (`T: 'a`).
@@ -181,8 +187,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// Returns `true` if a closure is inferred to be an `FnMut` closure.
fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
- if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref()
- && let ty::BoundRegionKind::BrEnv = free_region.bound_region
+ if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref()
+ && let ty::BoundRegionKind::BrEnv = late_param.bound_region
&& let DefiningTy::Closure(_, args) = self.regioncx.universal_regions().defining_ty
{
return args.as_closure().kind() == ty::ClosureKind::FnMut;
@@ -209,7 +215,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.map(|placeholder| {
if let Some(id) = placeholder.bound.kind.get_id()
&& let Some(placeholder_id) = id.as_local()
- && let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id)
+ && let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id)
&& let Some(generics_impl) = hir.get_parent(gat_hir_id).generics()
{
Some((gat_hir_id, generics_impl))
@@ -230,7 +236,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
if bound_generic_params
.iter()
- .rfind(|bgp| hir.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
+ .rfind(|bgp| self.infcx.tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
.is_some()
{
for bound in *bounds {
@@ -599,7 +605,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
let captured_place = &self.upvars[upvar_field.index()].place;
- let defined_hir = match captured_place.place.base {
+ let defined_hir = match captured_place.base {
PlaceBase::Local(hirid) => Some(hirid),
PlaceBase::Upvar(upvar) => Some(upvar.var_path.hir_id),
_ => None,
@@ -644,14 +650,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&self.upvars,
errci.fr,
);
let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
self.infcx.tcx,
- &self.body,
+ self.body,
&self.local_names,
&self.upvars,
errci.outlived_fr,
@@ -757,7 +763,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let err = LifetimeOutliveErr { span: *span };
let mut diag = self.infcx.tcx.sess.create_err(err);
- let fr_name = self.give_region_a_name(*fr).unwrap();
+ // In certain scenarios, such as the one described in issue #118021,
+ // we might encounter a lifetime that cannot be named.
+ // These situations are bound to result in errors.
+ // To prevent an immediate ICE, we opt to create a dummy name instead.
+ let fr_name = self.give_region_a_name(*fr).unwrap_or(RegionName {
+ name: kw::UnderscoreLifetime,
+ source: RegionNameSource::Static,
+ });
fr_name.highlight_region_name(&mut diag);
let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap();
outlived_fr_name.highlight_region_name(&mut diag);
@@ -958,7 +971,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
for found_did in found_dids {
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
- hir_v.visit_ty(&self_ty);
+ hir_v.visit_ty(self_ty);
debug!("trait spans found: {:?}", traits);
for span in &traits {
let mut multi_span: MultiSpan = vec![*span].into();
@@ -995,7 +1008,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.infcx
.tcx
.is_suitable_region(sub)
- .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.boundregion))
+ .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sub, &anon_reg.bound_region))
else {
return;
};
@@ -1004,7 +1017,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.infcx
.tcx
.is_suitable_region(sup)
- .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.boundregion))
+ .and_then(|anon_reg| find_anon_type(self.infcx.tcx, sup, &anon_reg.bound_region))
else {
return;
};
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index d38cfbc54..8441dfaa7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -23,14 +23,14 @@ pub(crate) struct RegionName {
}
/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
-/// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`.
+/// was named by the user would get `NamedLateParamRegion` and `'static` lifetime would get `Static`.
/// This helps to print the right kinds of diagnostics.
#[derive(Debug, Clone)]
pub(crate) enum RegionNameSource {
/// A bound (not free) region that was instantiated at the def site (not an HRTB).
- NamedEarlyBoundRegion(Span),
+ NamedEarlyParamRegion(Span),
/// A free region that the user has a name (`'a`) for.
- NamedFreeRegion(Span),
+ NamedLateParamRegion(Span),
/// The `'static` region.
Static,
/// The free region corresponding to the environment of a closure.
@@ -69,8 +69,8 @@ pub(crate) enum RegionNameHighlight {
impl RegionName {
pub(crate) fn was_named(&self) -> bool {
match self.source {
- RegionNameSource::NamedEarlyBoundRegion(..)
- | RegionNameSource::NamedFreeRegion(..)
+ RegionNameSource::NamedEarlyParamRegion(..)
+ | RegionNameSource::NamedLateParamRegion(..)
| RegionNameSource::Static => true,
RegionNameSource::SynthesizedFreeEnvRegion(..)
| RegionNameSource::AnonRegionFromArgument(..)
@@ -85,8 +85,8 @@ impl RegionName {
pub(crate) fn span(&self) -> Option<Span> {
match self.source {
RegionNameSource::Static => None,
- RegionNameSource::NamedEarlyBoundRegion(span)
- | RegionNameSource::NamedFreeRegion(span)
+ RegionNameSource::NamedEarlyParamRegion(span)
+ | RegionNameSource::NamedLateParamRegion(span)
| RegionNameSource::SynthesizedFreeEnvRegion(span, _)
| RegionNameSource::AnonRegionFromUpvar(span, _)
| RegionNameSource::AnonRegionFromYieldTy(span, _)
@@ -104,8 +104,8 @@ impl RegionName {
pub(crate) fn highlight_region_name(&self, diag: &mut Diagnostic) {
match &self.source {
- RegionNameSource::NamedFreeRegion(span)
- | RegionNameSource::NamedEarlyBoundRegion(span) => {
+ RegionNameSource::NamedLateParamRegion(span)
+ | RegionNameSource::NamedEarlyParamRegion(span) => {
diag.span_label(*span, format!("lifetime `{self}` defined here"));
}
RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
@@ -199,7 +199,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
}
pub(crate) fn mir_hir_id(&self) -> hir::HirId {
- self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id())
+ self.infcx.tcx.local_def_id_to_hir_id(self.mir_def_id())
}
/// Generate a synthetic region named `'N`, where `N` is the next value of the counter. Then,
@@ -280,28 +280,31 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
debug!("give_region_a_name: error_region = {:?}", error_region);
match *error_region {
- ty::ReEarlyBound(ebr) => ebr.has_name().then(|| {
+ ty::ReEarlyParam(ebr) => ebr.has_name().then(|| {
let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
- RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyBoundRegion(span) }
+ RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyParamRegion(span) }
}),
ty::ReStatic => {
Some(RegionName { name: kw::StaticLifetime, source: RegionNameSource::Static })
}
- ty::ReFree(free_region) => match free_region.bound_region {
+ ty::ReLateParam(late_param) => match late_param.bound_region {
ty::BoundRegionKind::BrNamed(region_def_id, name) => {
// Get the span to point to, even if we don't use the name.
let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP);
debug!(
"bound region named: {:?}, is_named: {:?}",
name,
- free_region.bound_region.is_named()
+ late_param.bound_region.is_named()
);
- if free_region.bound_region.is_named() {
+ if late_param.bound_region.is_named() {
// A named region that is actually named.
- Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) })
+ Some(RegionName {
+ name,
+ source: RegionNameSource::NamedLateParamRegion(span),
+ })
} else if tcx.asyncness(self.mir_hir_id().owner).is_async() {
// If we spuriously thought that the region is named, we should let the
// system generate a true name for error messages. Currently this can
@@ -357,7 +360,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::BoundRegionKind::BrAnon => None,
},
- ty::ReLateBound(..)
+ ty::ReBound(..)
| ty::ReVar(..)
| ty::RePlaceholder(..)
| ty::ReErased
@@ -384,7 +387,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys
[implicit_inputs + argument_index];
let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
- &self.body,
+ self.body,
&self.local_names,
argument_index,
);
@@ -616,8 +619,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
_,
) => {
// HIR lowering sometimes doesn't catch this in erroneous
- // programs, so we need to use delay_span_bug here. See #82126.
- self.infcx.tcx.sess.delay_span_bug(
+ // programs, so we need to use span_delayed_bug here. See #82126.
+ self.infcx.tcx.sess.span_delayed_bug(
hir_arg.span(),
format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
);
@@ -669,7 +672,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let mir_hir_id = self.mir_hir_id();
- let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) {
+ let (return_span, mir_description, hir_ty) = match tcx.hir_node(mir_hir_id) {
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }),
..
@@ -681,12 +684,12 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
};
let mir_description = match hir.body(body).coroutine_kind {
- Some(hir::CoroutineKind::Async(gen)) => match gen {
+ Some(hir::CoroutineKind::Async(src)) => match src {
hir::CoroutineSource::Block => " of async block",
hir::CoroutineSource::Closure => " of async closure",
hir::CoroutineSource::Fn => {
let parent_item =
- hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
+ tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
let output = &parent_item
.fn_decl()
.expect("coroutine lowered from async fn should be in fn")
@@ -698,12 +701,12 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
" of async function"
}
},
- Some(hir::CoroutineKind::Gen(gen)) => match gen {
+ Some(hir::CoroutineKind::Gen(src)) => match src {
hir::CoroutineSource::Block => " of gen block",
hir::CoroutineSource::Closure => " of gen closure",
hir::CoroutineSource::Fn => {
let parent_item =
- hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
+ tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
let output = &parent_item
.fn_decl()
.expect("coroutine lowered from gen fn should be in fn")
@@ -712,6 +715,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
" of gen function"
}
},
+
+ Some(hir::CoroutineKind::AsyncGen(src)) => match src {
+ hir::CoroutineSource::Block => " of async gen block",
+ hir::CoroutineSource::Closure => " of async gen closure",
+ hir::CoroutineSource::Fn => {
+ let parent_item =
+ tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
+ let output = &parent_item
+ .fn_decl()
+ .expect("coroutine lowered from async gen fn should be in fn")
+ .output;
+ span = output.span();
+ " of async gen function"
+ }
+ },
Some(hir::CoroutineKind::Coroutine) => " of coroutine",
None => " of closure",
};
@@ -770,28 +788,18 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
};
let opaque_ty = hir.item(id);
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- bounds:
- [
- hir::GenericBound::LangItemTrait(
- hir::LangItem::Future,
- _,
- _,
- hir::GenericArgs {
- bindings:
- [
- hir::TypeBinding {
- ident: Ident { name: sym::Output, .. },
- kind:
- hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) },
- ..
- },
- ],
- ..
- },
- ),
- ],
+ bounds: [hir::GenericBound::Trait(trait_ref, _)],
..
}) = opaque_ty.kind
+ && let Some(segment) = trait_ref.trait_ref.path.segments.last()
+ && let Some(args) = segment.args
+ && let [
+ hir::TypeBinding {
+ ident: Ident { name: sym::Output, .. },
+ kind: hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) },
+ ..
+ },
+ ] = args.bindings
{
ty
} else {
@@ -823,7 +831,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let type_name =
self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
- let yield_span = match tcx.hir().get(self.mir_hir_id()) {
+ let yield_span = match tcx.hir_node(self.mir_hir_id()) {
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
@@ -847,7 +855,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
&self,
fr: RegionVid,
) -> Option<RegionName> {
- let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else {
+ let ty::ReEarlyParam(region) = *self.to_error_region(fr)? else {
return None;
};
if region.has_name() {
@@ -862,7 +870,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let found = tcx
.any_free_region_meets(&tcx.type_of(region_parent).instantiate_identity(), |r| {
- *r == ty::ReEarlyBound(region)
+ *r == ty::ReEarlyParam(region)
});
Some(RegionName {
@@ -881,7 +889,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
&self,
fr: RegionVid,
) -> Option<RegionName> {
- let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else {
+ let ty::ReEarlyParam(region) = *self.to_error_region(fr)? else {
return None;
};
if region.has_name() {
@@ -943,7 +951,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
&self,
clauses: &[ty::Clause<'tcx>],
ty: Ty<'tcx>,
- region: ty::EarlyBoundRegion,
+ region: ty::EarlyParamRegion,
) -> bool {
let tcx = self.infcx.tcx;
ty.walk().any(|arg| {
@@ -956,7 +964,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
_ => return false,
}
- tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyBound(region))
+ tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyParam(region))
})
} else {
false
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 3a104c524..28e07f2a8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -2,10 +2,9 @@
#![deny(rustc::diagnostic_outside_of_impl)]
use crate::region_infer::RegionInferenceContext;
-use crate::Upvar;
use rustc_index::IndexSlice;
use rustc_middle::mir::{Body, Local};
-use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_middle::ty::{self, RegionVid, TyCtxt};
use rustc_span::symbol::Symbol;
use rustc_span::Span;
@@ -15,7 +14,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
local_names: &IndexSlice<Local, Option<Symbol>>,
- upvars: &[Upvar<'tcx>],
+ upvars: &[&ty::CapturedPlace<'tcx>],
fr: RegionVid,
) -> Option<(Option<Symbol>, Span)> {
debug!("get_var_name_and_span_for_region(fr={fr:?})");
@@ -66,10 +65,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn get_upvar_name_and_span_for_region(
&self,
tcx: TyCtxt<'tcx>,
- upvars: &[Upvar<'tcx>],
+ upvars: &[&ty::CapturedPlace<'tcx>],
upvar_index: usize,
) -> (Symbol, Span) {
- let upvar_hir_id = upvars[upvar_index].place.get_root_variable();
+ let upvar_hir_id = upvars[upvar_index].get_root_variable();
debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}");
let upvar_name = tcx.hir().name(upvar_hir_id);
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 5787ea13e..43f48f579 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1,8 +1,8 @@
//! This query borrow-checks the MIR to (further) ensure it is not broken.
#![allow(internal_features)]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
-#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![feature(rustdoc_internals)]
+#![doc(rust_logo)]
#![feature(associated_type_bounds)]
#![feature(box_patterns)]
#![feature(let_chains)]
@@ -22,8 +22,7 @@ extern crate tracing;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::dominators::Dominators;
-use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage};
-use rustc_fluent_macro::fluent_messages;
+use rustc_errors::{Diagnostic, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
@@ -35,7 +34,7 @@ use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::*;
use rustc_middle::query::Providers;
use rustc_middle::traits::DefiningAnchor;
-use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
use rustc_session::lint::builtin::UNUSED_MUT;
use rustc_span::{Span, Symbol};
use rustc_target::abi::FieldIdx;
@@ -43,6 +42,7 @@ use rustc_target::abi::FieldIdx;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::BTreeMap;
+use std::marker::PhantomData;
use std::ops::Deref;
use std::rc::Rc;
@@ -65,19 +65,18 @@ use self::path_utils::*;
pub mod borrow_set;
mod borrowck_errors;
-mod constraint_generation;
mod constraints;
mod dataflow;
mod def_use;
mod diagnostics;
mod facts;
-mod invalidation;
mod location;
mod member_constraints;
mod nll;
mod path_utils;
mod place_ext;
mod places_conflict;
+mod polonius;
mod prefixes;
mod region_infer;
mod renumber;
@@ -98,19 +97,10 @@ use places_conflict::{places_conflict, PlaceConflictBias};
use region_infer::RegionInferenceContext;
use renumber::RegionCtxt;
-fluent_messages! { "../messages.ftl" }
-
-// FIXME(eddyb) perhaps move this somewhere more centrally.
-#[derive(Debug)]
-struct Upvar<'tcx> {
- place: CapturedPlace<'tcx>,
-
- /// If true, the capture is behind a reference.
- by_ref: bool,
-}
+rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
/// Associate some local constants with the `'tcx` lifetime
-struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>);
+struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
impl<'tcx> TyCtxtConsts<'tcx> {
const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
}
@@ -135,7 +125,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
return tcx.arena.alloc(result);
}
- let hir_owner = tcx.hir().local_def_id_to_hir_id(def).owner;
+ let hir_owner = tcx.local_def_id_to_hir_id(def).owner;
let infcx =
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build();
@@ -193,18 +183,6 @@ fn do_mir_borrowck<'tcx>(
infcx.set_tainted_by_errors(e);
errors.set_tainted_by_errors(e);
}
- let upvars: Vec<_> = tcx
- .closure_captures(def)
- .iter()
- .map(|&captured_place| {
- let capture = captured_place.info.capture_kind;
- let by_ref = match capture {
- ty::UpvarCapture::ByValue => false,
- ty::UpvarCapture::ByRef(..) => true,
- };
- Upvar { place: captured_place.clone(), by_ref }
- })
- .collect();
// Replace all regions with fresh inference variables. This
// requires first making our own copy of the MIR. This copy will
@@ -216,21 +194,20 @@ fn do_mir_borrowck<'tcx>(
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);
- let location_table = &location_table_owned;
+ let location_table = LocationTable::new(body);
- let move_data = MoveData::gather_moves(&body, tcx, param_env, |_| true);
+ let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
let promoted_move_data = promoted
.iter_enumerated()
- .map(|(idx, body)| (idx, MoveData::gather_moves(&body, tcx, param_env, |_| true)));
+ .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, param_env, |_| true)));
let mdpe = MoveDataParamEnv { move_data, param_env };
- let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe)
- .into_engine(tcx, &body)
+ let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+ .into_engine(tcx, body)
.pass_name("borrowck")
.iterate_to_fixpoint()
- .into_results_cursor(&body);
+ .into_results_cursor(body);
let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
let borrow_set =
@@ -249,24 +226,24 @@ fn do_mir_borrowck<'tcx>(
free_regions,
body,
&promoted,
- location_table,
+ &location_table,
param_env,
&mut flow_inits,
&mdpe.move_data,
&borrow_set,
- &upvars,
+ tcx.closure_captures(def),
consumer_options,
);
// 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,
- &body,
+ body,
&regioncx,
&opt_closure_req,
&opaque_type_values,
@@ -288,7 +265,7 @@ fn do_mir_borrowck<'tcx>(
.into_engine(tcx, body)
.pass_name("borrowck")
.iterate_to_fixpoint();
- let flow_ever_inits = EverInitializedPlaces::new(tcx, body, &mdpe)
+ let flow_ever_inits = EverInitializedPlaces::new(body, &mdpe)
.into_engine(tcx, body)
.pass_name("borrowck")
.iterate_to_fixpoint();
@@ -313,7 +290,7 @@ fn do_mir_borrowck<'tcx>(
param_env,
body: promoted_body,
move_data: &move_data,
- location_table, // no need to create a real one for the promoted, it is not used
+ location_table: &location_table, // no need to create a real one for the promoted, it is not used
movable_coroutine,
fn_self_span_reported: Default::default(),
locals_are_invalidated_at_exit,
@@ -324,7 +301,7 @@ fn do_mir_borrowck<'tcx>(
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
borrow_set: Rc::clone(&borrow_set),
- upvars: Vec::new(),
+ upvars: &[],
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
@@ -354,7 +331,7 @@ fn do_mir_borrowck<'tcx>(
param_env,
body,
move_data: &mdpe.move_data,
- location_table,
+ location_table: &location_table,
movable_coroutine,
locals_are_invalidated_at_exit,
fn_self_span_reported: Default::default(),
@@ -365,7 +342,7 @@ fn do_mir_borrowck<'tcx>(
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
borrow_set: Rc::clone(&borrow_set),
- upvars,
+ upvars: tcx.closure_captures(def),
local_names,
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
@@ -456,7 +433,7 @@ fn do_mir_borrowck<'tcx>(
promoted,
borrow_set,
region_inference_context: regioncx,
- location_table: polonius_input.as_ref().map(|_| location_table_owned),
+ location_table: polonius_input.as_ref().map(|_| location_table),
input_facts: polonius_input,
output_facts,
}))
@@ -584,7 +561,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
borrow_set: Rc<BorrowSet<'tcx>>,
/// Information about upvars not necessarily preserved in types or MIR
- upvars: Vec<Upvar<'tcx>>,
+ upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
/// Names of local (user) variables (extracted from `var_debug_info`).
local_names: IndexVec<Local, Option<Symbol>>,
@@ -1041,9 +1018,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
flow_state: &Flows<'cx, 'tcx>,
) -> bool {
let mut error_reported = false;
- let tcx = self.infcx.tcx;
- let body = self.body;
- let borrow_set = self.borrow_set.clone();
+ let borrow_set = Rc::clone(&self.borrow_set);
// Use polonius output if it has been enabled.
let mut polonius_output;
@@ -1060,8 +1035,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
each_borrow_involving_path(
self,
- tcx,
- body,
+ self.infcx.tcx,
+ self.body,
location,
(sd, place_span.0),
&borrow_set,
@@ -1538,7 +1513,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if places_conflict::borrow_conflicts_with_place(
self.infcx.tcx,
- &self.body,
+ self.body,
place,
borrow.kind,
root_place,
@@ -2155,11 +2130,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&& !self.has_buffered_errors()
{
// rust-lang/rust#46908: In pure NLL mode this code path should be
- // unreachable, but we use `delay_span_bug` because we can hit this when
+ // unreachable, but we use `span_delayed_bug` because we can hit this when
// dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
// enabled. We don't want to ICE for that case, as other errors will have
// been emitted (#52262).
- self.infcx.tcx.sess.delay_span_bug(
+ self.infcx.tcx.sess.span_delayed_bug(
span,
format!(
"Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
@@ -2193,7 +2168,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// If this is a mutate access to an immutable local variable with no projections
// report the error as an illegal reassignment
let init = &self.move_data.inits[init_index];
- let assigned_span = init.span(&self.body);
+ let assigned_span = init.span(self.body);
self.report_illegal_reassignment(location, (place, span), assigned_span, place);
} else {
self.report_mutability_error(place, span, the_place_err, error_access, location)
@@ -2294,7 +2269,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// unique path to the `&mut`
hir::Mutability::Mut => {
let mode = match self.is_upvar_field_projection(place) {
- Some(field) if self.upvars[field.index()].by_ref => {
+ Some(field)
+ if self.upvars[field.index()].is_by_ref() =>
+ {
is_local_mutation_allowed
}
_ => LocalMutationIsAllowed::Yes,
@@ -2342,7 +2319,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
place={:?}, place_base={:?}",
upvar, is_local_mutation_allowed, place, place_base
);
- match (upvar.place.mutability, is_local_mutation_allowed) {
+ match (upvar.mutability, is_local_mutation_allowed) {
(
Mutability::Not,
LocalMutationIsAllowed::No
@@ -2451,7 +2428,7 @@ mod error {
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) {
if let None = self.tainted_by_errors {
- self.tainted_by_errors = Some(self.tcx.sess.delay_span_bug(
+ self.tainted_by_errors = Some(self.tcx.sess.span_delayed_bug(
t.span.clone_ignoring_labels(),
"diagnostic buffered but not emitted",
))
@@ -2525,8 +2502,8 @@ mod error {
if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
- for mut diag in self.errors.buffered.drain(..) {
- self.infcx.tcx.sess.diagnostic().emit_diagnostic(&mut diag);
+ for diag in self.errors.buffered.drain(..) {
+ self.infcx.tcx.sess.dcx().emit_diagnostic(diag);
}
}
diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs
index 0e669abfd..6f0939316 100644
--- a/compiler/rustc_borrowck/src/location.rs
+++ b/compiler/rustc_borrowck/src/location.rs
@@ -20,6 +20,7 @@ pub struct LocationTable {
}
rustc_index::newtype_index! {
+ #[orderable]
#[debug_format = "LocationIndex({})"]
pub struct LocationIndex {}
}
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 0ea4401a8..6781c6a75 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -2,16 +2,17 @@
#![deny(rustc::diagnostic_outside_of_impl)]
//! The entry point of the NLL borrow checker.
+use polonius_engine::{Algorithm, Output};
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def_id::LocalDefId;
use rustc_index::IndexSlice;
use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
-use rustc_middle::mir::{
- Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted,
- START_BLOCK,
-};
+use rustc_middle::mir::{Body, ClosureOutlivesSubject, ClosureRegionRequirements, Promoted};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::MoveData;
+use rustc_mir_dataflow::ResultsCursor;
use rustc_span::symbol::sym;
use std::env;
use std::io;
@@ -19,25 +20,18 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::str::FromStr;
-use polonius_engine::{Algorithm, Output};
-
-use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
-use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
-use rustc_mir_dataflow::ResultsCursor;
-
use crate::{
borrow_set::BorrowSet,
- constraint_generation,
consumers::ConsumerOptions,
diagnostics::RegionErrors,
facts::{AllFacts, AllFactsExt, RustcFacts},
- invalidation,
location::LocationTable,
+ polonius,
region_infer::{values::RegionValueElements, RegionInferenceContext},
renumber,
type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
universal_regions::UniversalRegions,
- BorrowckInferCtxt, Upvar,
+ BorrowckInferCtxt,
};
pub type PoloniusOutput = Output<RustcFacts>;
@@ -78,81 +72,6 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
universal_regions
}
-// This function populates an AllFacts instance with base facts related to
-// MovePaths and needed for the move analysis.
-fn populate_polonius_move_facts(
- all_facts: &mut AllFacts,
- move_data: &MoveData<'_>,
- location_table: &LocationTable,
- body: &Body<'_>,
-) {
- all_facts
- .path_is_var
- .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
-
- for (child, move_path) in move_data.move_paths.iter_enumerated() {
- if let Some(parent) = move_path.parent {
- all_facts.child_path.push((child, parent));
- }
- }
-
- let fn_entry_start =
- location_table.start_index(Location { block: START_BLOCK, statement_index: 0 });
-
- // initialized_at
- for init in move_data.inits.iter() {
- match init.location {
- InitLocation::Statement(location) => {
- let block_data = &body[location.block];
- let is_terminator = location.statement_index == block_data.statements.len();
-
- if is_terminator && init.kind == InitKind::NonPanicPathOnly {
- // We are at the terminator of an init that has a panic path,
- // and where the init should not happen on panic
-
- for successor in block_data.terminator().successors() {
- if body[successor].is_cleanup {
- continue;
- }
-
- // The initialization happened in (or rather, when arriving at)
- // the successors, but not in the unwind block.
- let first_statement = Location { block: successor, statement_index: 0 };
- all_facts
- .path_assigned_at_base
- .push((init.path, location_table.start_index(first_statement)));
- }
- } else {
- // In all other cases, the initialization just happens at the
- // midpoint, like any other effect.
- all_facts
- .path_assigned_at_base
- .push((init.path, location_table.mid_index(location)));
- }
- }
- // Arguments are initialized on function entry
- InitLocation::Argument(local) => {
- assert!(body.local_kind(local) == LocalKind::Arg);
- all_facts.path_assigned_at_base.push((init.path, fn_entry_start));
- }
- }
- }
-
- for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
- if body.local_kind(local) != LocalKind::Arg {
- // Non-arguments start out deinitialised; we simulate this with an
- // initial move:
- all_facts.path_moved_at_base.push((path, fn_entry_start));
- }
- }
-
- // moved_out_at
- // deinitialisation is assumed to always happen!
- all_facts
- .path_moved_at_base
- .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
-}
-
/// Computes the (non-lexical) regions from the input MIR.
///
/// This may result in errors being reported.
@@ -166,7 +85,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>,
move_data: &MoveData<'tcx>,
borrow_set: &BorrowSet<'tcx>,
- upvars: &[Upvar<'tcx>],
+ upvars: &[&ty::CapturedPlace<'tcx>],
consumer_options: Option<ConsumerOptions>,
) -> NllOutput<'tcx> {
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
@@ -179,70 +98,26 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
let universal_regions = Rc::new(universal_regions);
- let elements = &Rc::new(RegionValueElements::new(&body));
+ let elements = &Rc::new(RegionValueElements::new(body));
// Run the MIR type-checker.
- let MirTypeckResults {
- constraints,
- universal_region_relations,
- opaque_type_values,
- live_loans,
- } = type_check::type_check(
- infcx,
- param_env,
- body,
- promoted,
- &universal_regions,
- location_table,
- borrow_set,
- &mut all_facts,
- flow_inits,
- move_data,
- elements,
- upvars,
- polonius_input,
- );
-
- if let Some(all_facts) = &mut all_facts {
- let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation");
- all_facts.universal_region.extend(universal_regions.universal_regions());
- populate_polonius_move_facts(all_facts, move_data, location_table, &body);
-
- // Emit universal regions facts, and their relations, for Polonius.
- //
- // 1: universal regions are modeled in Polonius as a pair:
- // - the universal region vid itself.
- // - a "placeholder loan" associated to this universal region. Since they don't exist in
- // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
- // added to the existing number of loans, as if they succeeded them in the set.
- //
- let borrow_count = borrow_set.len();
- debug!(
- "compute_regions: polonius placeholders, num_universals={}, borrow_count={}",
- universal_regions.len(),
- borrow_count
+ let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
+ type_check::type_check(
+ infcx,
+ param_env,
+ body,
+ promoted,
+ &universal_regions,
+ location_table,
+ borrow_set,
+ &mut all_facts,
+ flow_inits,
+ move_data,
+ elements,
+ upvars,
+ polonius_input,
);
- for universal_region in universal_regions.universal_regions() {
- let universal_region_idx = universal_region.index();
- let placeholder_loan_idx = borrow_count + universal_region_idx;
- all_facts.placeholder.push((universal_region, placeholder_loan_idx.into()));
- }
-
- // 2: the universal region relations `outlives` constraints are emitted as
- // `known_placeholder_subset` facts.
- for (fr1, fr2) in universal_region_relations.known_outlives() {
- if fr1 != fr2 {
- debug!(
- "compute_regions: emitting polonius `known_placeholder_subset` \
- fr1={:?}, fr2={:?}",
- fr1, fr2
- );
- all_facts.known_placeholder_subset.push((fr1, fr2));
- }
- }
- }
-
// Create the region inference context, taking ownership of the
// region inference data that was contained in `infcx`, and the
// base constraints generated by the type-check.
@@ -250,7 +125,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
let MirTypeckRegionConstraints {
placeholder_indices,
placeholder_index_to_region: _,
- mut liveness_constraints,
+ liveness_constraints,
outlives_constraints,
member_constraints,
universe_causes,
@@ -258,13 +133,16 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
} = constraints;
let placeholder_indices = Rc::new(placeholder_indices);
- constraint_generation::generate_constraints(
- infcx,
- &mut liveness_constraints,
+ // If requested, emit legacy polonius facts.
+ polonius::emit_facts(
&mut all_facts,
+ infcx.tcx,
location_table,
- &body,
+ body,
borrow_set,
+ move_data,
+ &universal_regions,
+ &universal_region_relations,
);
let mut regioncx = RegionInferenceContext::new(
@@ -279,17 +157,12 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
type_tests,
liveness_constraints,
elements,
- live_loans,
);
- // Generate various additional constraints.
- invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set);
-
- let def_id = body.source.def_id();
-
- // Dump facts if requested.
+ // If requested: dump NLL facts, and run legacy polonius analysis.
let polonius_output = all_facts.as_ref().and_then(|all_facts| {
if infcx.tcx.sess.opts.unstable_opts.nll_facts {
+ let def_id = body.source.def_id();
let def_path = infcx.tcx.def_path(def_id);
let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir)
.join(def_path.to_filename_friendly_no_crate());
@@ -302,7 +175,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
let algorithm = Algorithm::from_str(&algorithm).unwrap();
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
- Some(Rc::new(Output::compute(&all_facts, algorithm, false)))
+ Some(Rc::new(Output::compute(all_facts, algorithm, false)))
} else {
None
}
@@ -310,17 +183,17 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
// Solve the region constraints.
let (closure_region_requirements, nll_errors) =
- regioncx.solve(infcx, param_env, &body, polonius_output.clone());
+ regioncx.solve(infcx, param_env, body, polonius_output.clone());
if !nll_errors.is_empty() {
// Suppress unhelpful extra errors in `infer_opaque_types`.
- infcx.set_tainted_by_errors(infcx.tcx.sess.delay_span_bug(
+ infcx.set_tainted_by_errors(infcx.tcx.sess.span_delayed_bug(
body.span,
"`compute_regions` tainted `infcx` with errors but did not emit any errors",
));
}
- let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values);
+ let remapped_opaque_tys = regioncx.infer_opaque_types(infcx, opaque_type_values);
NllOutput {
regioncx,
@@ -407,7 +280,7 @@ pub(super) fn dump_annotation<'tcx>(
let def_span = tcx.def_span(body.source.def_id());
let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
- let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "external requirements");
+ let mut err = tcx.sess.dcx().struct_span_note(def_span, "external requirements");
regioncx.annotate(tcx, &mut err);
@@ -426,7 +299,7 @@ pub(super) fn dump_annotation<'tcx>(
err
} else {
- let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "no external requirements");
+ let mut err = tcx.sess.dcx().struct_span_note(def_span, "no external requirements");
regioncx.annotate(tcx, &mut err);
err
diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
index 51e318f08..2d997dfad 100644
--- a/compiler/rustc_borrowck/src/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -4,7 +4,6 @@ use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
use crate::places_conflict;
use crate::AccessDepth;
use crate::BorrowIndex;
-use crate::Upvar;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::BorrowKind;
use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem};
@@ -150,7 +149,7 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
/// of a closure type.
pub(crate) fn is_upvar_field_projection<'tcx>(
tcx: TyCtxt<'tcx>,
- upvars: &[Upvar<'tcx>],
+ upvars: &[&rustc_middle::ty::CapturedPlace<'tcx>],
place_ref: PlaceRef<'tcx>,
body: &Body<'tcx>,
) -> Option<FieldIdx> {
@@ -166,7 +165,7 @@ pub(crate) fn is_upvar_field_projection<'tcx>(
Some((place_base, ProjectionElem::Field(field, _ty))) => {
let base_ty = place_base.ty(body, tcx).ty;
if (base_ty.is_closure() || base_ty.is_coroutine())
- && (!by_ref || upvars[field.index()].by_ref)
+ && (!by_ref || upvars[field.index()].is_by_ref())
{
Some(field)
} else {
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index ec6d7b74e..232bd7418 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -14,34 +14,21 @@ use crate::{
ReadOrWrite, Reservation, Shallow, Write, WriteKind,
};
-pub(super) fn generate_invalidates<'tcx>(
+/// Emit `loan_invalidated_at` facts.
+pub(super) fn emit_loan_invalidations<'tcx>(
tcx: TyCtxt<'tcx>,
- all_facts: &mut Option<AllFacts>,
+ all_facts: &mut AllFacts,
location_table: &LocationTable,
body: &Body<'tcx>,
borrow_set: &BorrowSet<'tcx>,
) {
- if all_facts.is_none() {
- // Nothing to do if we don't have any facts
- return;
- }
-
- if let Some(all_facts) = all_facts {
- let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
- let dominators = body.basic_blocks.dominators();
- let mut ig = InvalidationGenerator {
- all_facts,
- borrow_set,
- tcx,
- location_table,
- body: &body,
- dominators,
- };
- ig.visit_body(body);
- }
+ let dominators = body.basic_blocks.dominators();
+ let mut visitor =
+ LoanInvalidationsGenerator { all_facts, borrow_set, tcx, location_table, body, dominators };
+ visitor.visit_body(body);
}
-struct InvalidationGenerator<'cx, 'tcx> {
+struct LoanInvalidationsGenerator<'cx, 'tcx> {
tcx: TyCtxt<'tcx>,
all_facts: &'cx mut AllFacts,
location_table: &'cx LocationTable,
@@ -52,7 +39,7 @@ struct InvalidationGenerator<'cx, 'tcx> {
/// Visits the whole MIR and generates `invalidates()` facts.
/// Most of the code implementing this was stolen from `borrow_check/mod.rs`.
-impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
+impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
self.check_activations(location);
@@ -214,7 +201,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
}
}
-impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
+impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
/// Simulates mutation of a place.
fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) {
self.access_place(
@@ -348,20 +335,16 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
rw: ReadOrWrite,
) {
debug!(
- "invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \
- rw={:?})",
+ "check_access_for_conflict(location={:?}, place={:?}, sd={:?}, rw={:?})",
location, place, sd, rw,
);
- let tcx = self.tcx;
- let body = self.body;
- let borrow_set = self.borrow_set;
each_borrow_involving_path(
self,
- tcx,
- body,
+ self.tcx,
+ self.body,
location,
(sd, place),
- borrow_set,
+ self.borrow_set,
|_| true,
|this, borrow_index, borrow| {
match (rw, borrow.kind) {
@@ -383,7 +366,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
(Read(_), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
- if !is_active(&this.dominators, borrow, location) {
+ if !is_active(this.dominators, borrow, location) {
// If the borrow isn't active yet, reads don't invalidate it
assert!(allow_two_phase_borrow(borrow.kind));
return Control::Continue;
diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/loan_kills.rs
new file mode 100644
index 000000000..5df943837
--- /dev/null
+++ b/compiler/rustc_borrowck/src/polonius/loan_kills.rs
@@ -0,0 +1,147 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::{
+ Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
+ Terminator, TerminatorKind,
+};
+use rustc_middle::ty::TyCtxt;
+
+use crate::{borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict};
+
+/// Emit `loan_killed_at` and `cfg_edge` facts at the same time.
+pub(super) fn emit_loan_kills<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ all_facts: &mut AllFacts,
+ location_table: &LocationTable,
+ body: &Body<'tcx>,
+ borrow_set: &BorrowSet<'tcx>,
+) {
+ let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, all_facts, body };
+ for (bb, data) in body.basic_blocks.iter_enumerated() {
+ visitor.visit_basic_block_data(bb, data);
+ }
+}
+
+struct LoanKillsGenerator<'cx, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ all_facts: &'cx mut AllFacts,
+ location_table: &'cx LocationTable,
+ borrow_set: &'cx BorrowSet<'tcx>,
+ body: &'cx Body<'tcx>,
+}
+
+impl<'cx, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'cx, 'tcx> {
+ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+ // Also record CFG facts here.
+ self.all_facts.cfg_edge.push((
+ self.location_table.start_index(location),
+ self.location_table.mid_index(location),
+ ));
+
+ self.all_facts.cfg_edge.push((
+ self.location_table.mid_index(location),
+ self.location_table.start_index(location.successor_within_block()),
+ ));
+
+ // If there are borrows on this now dead local, we need to record them as `killed`.
+ if let StatementKind::StorageDead(local) = statement.kind {
+ self.record_killed_borrows_for_local(local, location);
+ }
+
+ self.super_statement(statement, location);
+ }
+
+ fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
+ // When we see `X = ...`, then kill borrows of
+ // `(*X).foo` and so forth.
+ self.record_killed_borrows_for_place(*place, location);
+ self.super_assign(place, rvalue, location);
+ }
+
+ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+ // Also record CFG facts here.
+ self.all_facts.cfg_edge.push((
+ self.location_table.start_index(location),
+ self.location_table.mid_index(location),
+ ));
+
+ let successor_blocks = terminator.successors();
+ self.all_facts.cfg_edge.reserve(successor_blocks.size_hint().0);
+ for successor_block in successor_blocks {
+ self.all_facts.cfg_edge.push((
+ self.location_table.mid_index(location),
+ self.location_table.start_index(successor_block.start_location()),
+ ));
+ }
+
+ // A `Call` terminator's return value can be a local which has borrows,
+ // so we need to record those as `killed` as well.
+ if let TerminatorKind::Call { destination, .. } = terminator.kind {
+ self.record_killed_borrows_for_place(destination, location);
+ }
+
+ self.super_terminator(terminator, location);
+ }
+}
+
+impl<'tcx> LoanKillsGenerator<'_, 'tcx> {
+ /// Records the borrows on the specified place as `killed`. For example, when assigning to a
+ /// local, or on a call's return destination.
+ fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) {
+ // Depending on the `Place` we're killing:
+ // - if it's a local, or a single deref of a local,
+ // we kill all the borrows on the local.
+ // - if it's a deeper projection, we have to filter which
+ // of the borrows are killed: the ones whose `borrowed_place`
+ // conflicts with the `place`.
+ match place.as_ref() {
+ PlaceRef { local, projection: &[] }
+ | PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
+ debug!(
+ "Recording `killed` facts for borrows of local={:?} at location={:?}",
+ local, location
+ );
+
+ self.record_killed_borrows_for_local(local, location);
+ }
+
+ PlaceRef { local, projection: &[.., _] } => {
+ // Kill conflicting borrows of the innermost local.
+ debug!(
+ "Recording `killed` facts for borrows of \
+ innermost projected local={:?} at location={:?}",
+ local, location
+ );
+
+ if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
+ for &borrow_index in borrow_indices {
+ let places_conflict = places_conflict::places_conflict(
+ self.tcx,
+ self.body,
+ self.borrow_set[borrow_index].borrowed_place,
+ place,
+ places_conflict::PlaceConflictBias::NoOverlap,
+ );
+
+ if places_conflict {
+ let location_index = self.location_table.mid_index(location);
+ self.all_facts.loan_killed_at.push((borrow_index, location_index));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /// Records the borrows on the specified local as `killed`.
+ fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) {
+ if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
+ let location_index = self.location_table.mid_index(location);
+ self.all_facts.loan_killed_at.reserve(borrow_indices.len());
+ for &borrow_index in borrow_indices {
+ self.all_facts.loan_killed_at.push((borrow_index, location_index));
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs
new file mode 100644
index 000000000..40126d50d
--- /dev/null
+++ b/compiler/rustc_borrowck/src/polonius/mod.rs
@@ -0,0 +1,188 @@
+//! Functions dedicated to fact generation for the `-Zpolonius=legacy` datalog implementation.
+//!
+//! Will be removed in the future, once the in-tree `-Zpolonius=next` implementation reaches feature
+//! parity.
+
+use rustc_middle::mir::{Body, LocalKind, Location, START_BLOCK};
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
+
+use crate::borrow_set::BorrowSet;
+use crate::facts::AllFacts;
+use crate::location::LocationTable;
+use crate::type_check::free_region_relations::UniversalRegionRelations;
+use crate::universal_regions::UniversalRegions;
+
+mod loan_invalidations;
+mod loan_kills;
+
+/// When requested, emit most of the facts needed by polonius:
+/// - moves and assignments
+/// - universal regions and their relations
+/// - CFG points and edges
+/// - loan kills
+/// - loan invalidations
+///
+/// The rest of the facts are emitted during typeck and liveness.
+pub(crate) fn emit_facts<'tcx>(
+ all_facts: &mut Option<AllFacts>,
+ tcx: TyCtxt<'tcx>,
+ location_table: &LocationTable,
+ body: &Body<'tcx>,
+ borrow_set: &BorrowSet<'tcx>,
+ move_data: &MoveData<'_>,
+ universal_regions: &UniversalRegions<'_>,
+ universal_region_relations: &UniversalRegionRelations<'_>,
+) {
+ let Some(all_facts) = all_facts else {
+ // We don't do anything if there are no facts to fill.
+ return;
+ };
+ let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
+ emit_move_facts(all_facts, move_data, location_table, body);
+ emit_universal_region_facts(
+ all_facts,
+ borrow_set,
+ &universal_regions,
+ &universal_region_relations,
+ );
+ emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
+ emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);
+}
+
+/// Emit facts needed for move/init analysis: moves and assignments.
+fn emit_move_facts(
+ all_facts: &mut AllFacts,
+ move_data: &MoveData<'_>,
+ location_table: &LocationTable,
+ body: &Body<'_>,
+) {
+ all_facts
+ .path_is_var
+ .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
+
+ for (child, move_path) in move_data.move_paths.iter_enumerated() {
+ if let Some(parent) = move_path.parent {
+ all_facts.child_path.push((child, parent));
+ }
+ }
+
+ let fn_entry_start =
+ location_table.start_index(Location { block: START_BLOCK, statement_index: 0 });
+
+ // initialized_at
+ for init in move_data.inits.iter() {
+ match init.location {
+ InitLocation::Statement(location) => {
+ let block_data = &body[location.block];
+ let is_terminator = location.statement_index == block_data.statements.len();
+
+ if is_terminator && init.kind == InitKind::NonPanicPathOnly {
+ // We are at the terminator of an init that has a panic path,
+ // and where the init should not happen on panic
+
+ for successor in block_data.terminator().successors() {
+ if body[successor].is_cleanup {
+ continue;
+ }
+
+ // The initialization happened in (or rather, when arriving at)
+ // the successors, but not in the unwind block.
+ let first_statement = Location { block: successor, statement_index: 0 };
+ all_facts
+ .path_assigned_at_base
+ .push((init.path, location_table.start_index(first_statement)));
+ }
+ } else {
+ // In all other cases, the initialization just happens at the
+ // midpoint, like any other effect.
+ all_facts
+ .path_assigned_at_base
+ .push((init.path, location_table.mid_index(location)));
+ }
+ }
+ // Arguments are initialized on function entry
+ InitLocation::Argument(local) => {
+ assert!(body.local_kind(local) == LocalKind::Arg);
+ all_facts.path_assigned_at_base.push((init.path, fn_entry_start));
+ }
+ }
+ }
+
+ for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
+ if body.local_kind(local) != LocalKind::Arg {
+ // Non-arguments start out deinitialised; we simulate this with an
+ // initial move:
+ all_facts.path_moved_at_base.push((path, fn_entry_start));
+ }
+ }
+
+ // moved_out_at
+ // deinitialisation is assumed to always happen!
+ all_facts
+ .path_moved_at_base
+ .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
+}
+
+/// Emit universal regions facts, and their relations.
+fn emit_universal_region_facts(
+ all_facts: &mut AllFacts,
+ borrow_set: &BorrowSet<'_>,
+ universal_regions: &UniversalRegions<'_>,
+ universal_region_relations: &UniversalRegionRelations<'_>,
+) {
+ // 1: universal regions are modeled in Polonius as a pair:
+ // - the universal region vid itself.
+ // - a "placeholder loan" associated to this universal region. Since they don't exist in
+ // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
+ // added to the existing number of loans, as if they succeeded them in the set.
+ //
+ all_facts.universal_region.extend(universal_regions.universal_regions());
+ let borrow_count = borrow_set.len();
+ debug!(
+ "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
+ universal_regions.len(),
+ borrow_count
+ );
+
+ for universal_region in universal_regions.universal_regions() {
+ let universal_region_idx = universal_region.index();
+ let placeholder_loan_idx = borrow_count + universal_region_idx;
+ all_facts.placeholder.push((universal_region, placeholder_loan_idx.into()));
+ }
+
+ // 2: the universal region relations `outlives` constraints are emitted as
+ // `known_placeholder_subset` facts.
+ for (fr1, fr2) in universal_region_relations.known_outlives() {
+ if fr1 != fr2 {
+ debug!(
+ "emit_universal_region_facts: emitting polonius `known_placeholder_subset` \
+ fr1={:?}, fr2={:?}",
+ fr1, fr2
+ );
+ all_facts.known_placeholder_subset.push((fr1, fr2));
+ }
+ }
+}
+
+/// Emit facts about loan invalidations.
+fn emit_loan_invalidations_facts<'tcx>(
+ all_facts: &mut AllFacts,
+ tcx: TyCtxt<'tcx>,
+ location_table: &LocationTable,
+ body: &Body<'tcx>,
+ borrow_set: &BorrowSet<'tcx>,
+) {
+ loan_invalidations::emit_loan_invalidations(tcx, all_facts, location_table, body, borrow_set);
+}
+
+/// Emit facts about CFG points and edges, as well as locations where loans are killed.
+fn emit_cfg_and_loan_kills_facts<'tcx>(
+ all_facts: &mut AllFacts,
+ tcx: TyCtxt<'tcx>,
+ location_table: &LocationTable,
+ body: &Body<'tcx>,
+ borrow_set: &BorrowSet<'tcx>,
+) {
+ loan_kills::emit_loan_kills(tcx, all_facts, location_table, body, borrow_set);
+}
diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
index 4d620ac9d..cfbb2766c 100644
--- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
+++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
@@ -67,7 +67,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
with_msg: &mut dyn FnMut(&str) -> io::Result<()>,
) -> io::Result<()> {
for region in self.definitions.indices() {
- let value = self.liveness_constraints.region_value_str(region);
+ let value = self.liveness_constraints.pretty_print_live_points(region);
if value != "{}" {
with_msg(&format!("{region:?} live at {value}"))?;
}
diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
index a0cf22e93..408c8390e 100644
--- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs
+++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
@@ -8,7 +8,6 @@ use std::borrow::Cow;
use std::io::{self, Write};
use super::*;
-use crate::constraints::OutlivesConstraint;
use rustc_graphviz as dot;
impl<'tcx> RegionInferenceContext<'tcx> {
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index b1f91a056..948221e94 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_index::bit_set::SparseBitMatrix;
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
@@ -31,8 +30,8 @@ use crate::{
nll::PoloniusOutput,
region_infer::reverse_sccs::ReverseSccGraph,
region_infer::values::{
- LivenessValues, PlaceholderIndices, PointIndex, RegionElement, RegionValueElements,
- RegionValues, ToElementIndex,
+ LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
+ ToElementIndex,
},
type_check::{free_region_relations::UniversalRegionRelations, Locations},
universal_regions::UniversalRegions,
@@ -59,7 +58,7 @@ pub struct RegionInferenceContext<'tcx> {
/// regions, these start out empty and steadily grow, though for
/// each universally quantified region R they start out containing
/// the entire CFG and `end(R)`.
- liveness_constraints: LivenessValues<RegionVid>,
+ liveness_constraints: LivenessValues,
/// The outlives constraints computed by the type-check.
constraints: Frozen<OutlivesConstraintSet<'tcx>>,
@@ -120,9 +119,6 @@ pub struct RegionInferenceContext<'tcx> {
/// Information about how the universally quantified regions in
/// scope on this function relate to one another.
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-
- /// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`.
- live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
}
/// Each time that `apply_member_constraint` is successful, it appends
@@ -151,6 +147,7 @@ pub(crate) struct AppliedMemberConstraint {
pub(crate) member_constraint_index: NllMemberConstraintIndex,
}
+#[derive(Debug)]
pub(crate) struct RegionDefinition<'tcx> {
/// What kind of variable is this -- a free region? existential
/// variable? etc. (See the `NllRegionVariableOrigin` for more
@@ -332,9 +329,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
type_tests: Vec<TypeTest<'tcx>>,
- liveness_constraints: LivenessValues<RegionVid>,
+ liveness_constraints: LivenessValues,
elements: &Rc<RegionValueElements>,
- live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
) -> Self {
debug!("universal_regions: {:#?}", universal_regions);
debug!("outlives constraints: {:#?}", outlives_constraints);
@@ -359,7 +355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let mut scc_values =
RegionValues::new(elements, universal_regions.len(), &placeholder_indices);
- for region in liveness_constraints.rows() {
+ for region in liveness_constraints.regions() {
let scc = constraint_sccs.scc(region);
scc_values.merge_liveness(scc, region, &liveness_constraints);
}
@@ -388,7 +384,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
type_tests,
universal_regions,
universal_region_relations,
- live_loans,
};
result.init_free_and_bound_regions();
@@ -679,13 +674,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// eagerly.
let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
- self.check_type_tests(
- infcx,
- param_env,
- body,
- outlives_requirements.as_mut(),
- &mut errors_buffer,
- );
+ self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
+
+ debug!(?errors_buffer);
+ debug!(?outlives_requirements);
// In Polonius mode, the errors about missing universal region relations are in the output
// and need to be emitted or propagated. Otherwise, we need to check whether the
@@ -700,10 +692,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer);
}
+ debug!(?errors_buffer);
+
if errors_buffer.is_empty() {
self.check_member_constraints(infcx, &mut errors_buffer);
}
+ debug!(?errors_buffer);
+
let outlives_requirements = outlives_requirements.unwrap_or_default();
if outlives_requirements.is_empty() {
@@ -936,7 +932,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn check_type_tests(
&self,
infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut RegionErrors<'tcx>,
@@ -954,7 +949,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let generic_ty = type_test.generic_kind.to_ty(tcx);
if self.eval_verify_bound(
infcx,
- param_env,
generic_ty,
type_test.lower_bound,
&type_test.verify_bound,
@@ -965,7 +959,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
if self.try_promote_type_test(
infcx,
- param_env,
body,
type_test,
propagated_outlives_requirements,
@@ -1023,7 +1016,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn try_promote_type_test(
&self,
infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
type_test: &TypeTest<'tcx>,
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
@@ -1085,7 +1077,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// where `ur` is a local bound -- we are sometimes in a
// position to prove things that our caller cannot. See
// #53570 for an example.
- if self.eval_verify_bound(infcx, param_env, generic_ty, ur, &type_test.verify_bound) {
+ if self.eval_verify_bound(infcx, generic_ty, ur, &type_test.verify_bound) {
continue;
}
@@ -1268,7 +1260,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn eval_verify_bound(
&self,
infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_bound: &VerifyBound<'tcx>,
@@ -1277,7 +1268,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
match verify_bound {
VerifyBound::IfEq(verify_if_eq_b) => {
- self.eval_if_eq(infcx, param_env, generic_ty, lower_bound, *verify_if_eq_b)
+ self.eval_if_eq(infcx, generic_ty, lower_bound, *verify_if_eq_b)
}
VerifyBound::IsEmpty => {
@@ -1291,11 +1282,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
- self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
+ self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound)
}),
VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
- self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
+ self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound)
}),
}
}
@@ -1303,19 +1294,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn eval_if_eq(
&self,
infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_if_eq_b: ty::Binder<'tcx, VerifyIfEq<'tcx>>,
) -> bool {
let generic_ty = self.normalize_to_scc_representatives(infcx.tcx, generic_ty);
let verify_if_eq_b = self.normalize_to_scc_representatives(infcx.tcx, verify_if_eq_b);
- match test_type_match::extract_verify_if_eq(
- infcx.tcx,
- param_env,
- &verify_if_eq_b,
- generic_ty,
- ) {
+ match test_type_match::extract_verify_if_eq(infcx.tcx, &verify_if_eq_b, generic_ty) {
Some(r) => {
let r_vid = self.to_region_vid(r);
self.eval_outlives(r_vid, lower_bound)
@@ -1457,6 +1442,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
errors_buffer: &mut RegionErrors<'tcx>,
) {
for (fr, fr_definition) in self.definitions.iter_enumerated() {
+ debug!(?fr, ?fr_definition);
match fr_definition.origin {
NllRegionVariableOrigin::FreeRegion => {
// Go through each of the universal regions `fr` and check that
@@ -1963,15 +1949,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
None
}
- /// Finds some region R such that `fr1: R` and `R` is live at `elem`.
+ /// Finds some region R such that `fr1: R` and `R` is live at `location`.
#[instrument(skip(self), level = "trace", ret)]
- pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
+ pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid {
trace!(scc = ?self.constraint_sccs.scc(fr1));
trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
self.find_constraint_paths_between_regions(fr1, |r| {
- // First look for some `r` such that `fr1: r` and `r` is live at `elem`
- trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r));
- self.liveness_constraints.contains(r, elem)
+ // First look for some `r` such that `fr1: r` and `r` is live at `location`
+ trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r));
+ self.liveness_constraints.is_live_at(r, location)
})
.or_else(|| {
// If we fail to find that, we may find some `r` such that
@@ -2316,7 +2302,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
let point = self.liveness_constraints.point_from_location(location);
- self.live_loans.contains(point, loan_idx)
+ self.liveness_constraints.is_loan_live_at(loan_idx, point)
}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index fb0e5811c..3764e4c40 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -36,7 +36,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// call `infer_opaque_definition_from_instantiation` to get the inferred
/// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
/// compares lifetimes directly, so we need to map the inference variables
- /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
+ /// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`.
///
/// First we map all the lifetimes in the concrete type to an equal
/// universal region that occurs in the concrete type's args, in this case
@@ -315,7 +315,7 @@ fn check_opaque_type_well_formed<'tcx>(
parent_def_id = tcx.local_parent(parent_def_id);
}
- // FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error`
+ // FIXME(-Znext-solver): We probably should use `DefiningAnchor::Error`
// and prepopulate this `InferCtxt` with known opaque values, rather than
// using the `Bind` anchor here. For now it's fine.
let infcx = tcx
@@ -386,7 +386,7 @@ fn check_opaque_type_parameter_valid(
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Lifetime(lt) if is_ty_alias => {
- matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+ matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_))
}
// FIXME(#113916): we can't currently check for unique lifetime params,
// see that issue for more. We will also have to ignore unused lifetime
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 38452df32..dc3ee849d 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -11,6 +11,8 @@ use rustc_middle::ty::{self, RegionVid};
use std::fmt::Debug;
use std::rc::Rc;
+use crate::dataflow::BorrowIndex;
+
/// Maps between a `Location` and a `PointIndex` (and vice versa).
pub(crate) struct RegionValueElements {
/// For each basic block, how many points are contained within?
@@ -90,6 +92,7 @@ impl RegionValueElements {
rustc_index::newtype_index! {
/// A single integer representing a `Location` in the MIR control-flow
/// graph. Constructed efficiently from `RegionValueElements`.
+ #[orderable]
#[debug_format = "PointIndex({})"]
pub struct PointIndex {}
}
@@ -116,71 +119,132 @@ pub(crate) enum RegionElement {
PlaceholderRegion(ty::PlaceholderRegion),
}
-/// When we initially compute liveness, we use an interval matrix storing
-/// liveness ranges for each region-vid.
-pub(crate) struct LivenessValues<N: Idx> {
+/// Records the CFG locations where each region is live. When we initially compute liveness, we use
+/// an interval matrix storing liveness ranges for each region-vid.
+pub(crate) struct LivenessValues {
+ /// The map from locations to points.
elements: Rc<RegionValueElements>,
- points: SparseIntervalMatrix<N, PointIndex>,
+
+ /// For each region: the points where it is live.
+ points: SparseIntervalMatrix<RegionVid, PointIndex>,
+
+ /// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at
+ /// that point.
+ pub(crate) loans: Option<LiveLoans>,
}
-impl<N: Idx> LivenessValues<N> {
- /// Creates a new set of "region values" that tracks causal information.
- /// Each of the regions in num_region_variables will be initialized with an
- /// empty set of points and no causal information.
+/// Data used to compute the loans that are live at a given point in the CFG, when using
+/// `-Zpolonius=next`.
+pub(crate) struct LiveLoans {
+ /// The set of loans that flow into a given region. When individual regions are marked as live
+ /// in the CFG, these inflowing loans are recorded as live.
+ pub(crate) inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
+
+ /// The set of loans that are live at a given point in the CFG.
+ pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
+}
+
+impl LiveLoans {
+ pub(crate) fn new(num_loans: usize) -> Self {
+ LiveLoans {
+ live_loans: SparseBitMatrix::new(num_loans),
+ inflowing_loans: SparseBitMatrix::new(num_loans),
+ }
+ }
+}
+
+impl LivenessValues {
+ /// Create an empty map of regions to locations where they're live.
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
- Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
+ LivenessValues {
+ points: SparseIntervalMatrix::new(elements.num_points),
+ elements,
+ loans: None,
+ }
}
/// Iterate through each region that has a value in this set.
- pub(crate) fn rows(&self) -> impl Iterator<Item = N> {
+ pub(crate) fn regions(&self) -> impl Iterator<Item = RegionVid> {
self.points.rows()
}
- /// Adds the given element to the value for the given region. Returns whether
- /// the element is newly added (i.e., was not already present).
- pub(crate) fn add_element(&mut self, row: N, location: Location) -> bool {
- debug!("LivenessValues::add(r={:?}, location={:?})", row, location);
- let index = self.elements.point_from_location(location);
- self.points.insert(row, index)
+ /// Records `region` as being live at the given `location`.
+ pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
+ debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
+ let point = self.elements.point_from_location(location);
+ self.points.insert(region, point);
+
+ // When available, record the loans flowing into this region as live at the given point.
+ if let Some(loans) = self.loans.as_mut() {
+ if let Some(inflowing) = loans.inflowing_loans.row(region) {
+ loans.live_loans.union_row(point, inflowing);
+ }
+ }
}
- /// Adds all the elements in the given bit array into the given
- /// region. Returns whether any of them are newly added.
- pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
- debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
- self.points.union_row(row, locations)
+ /// Records `region` as being live at all the given `points`.
+ pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
+ debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
+ self.points.union_row(region, points);
+
+ // When available, record the loans flowing into this region as live at the given points.
+ if let Some(loans) = self.loans.as_mut() {
+ if let Some(inflowing) = loans.inflowing_loans.row(region) {
+ if !inflowing.is_empty() {
+ for point in points.iter() {
+ loans.live_loans.union_row(point, inflowing);
+ }
+ }
+ }
+ }
}
- /// Adds all the control-flow points to the values for `r`.
- pub(crate) fn add_all_points(&mut self, row: N) {
- self.points.insert_all_into_row(row);
+ /// Records `region` as being live at all the control-flow points.
+ pub(crate) fn add_all_points(&mut self, region: RegionVid) {
+ self.points.insert_all_into_row(region);
}
- /// Returns `true` if the region `r` contains the given element.
- pub(crate) fn contains(&self, row: N, location: Location) -> bool {
- let index = self.elements.point_from_location(location);
- self.points.row(row).is_some_and(|r| r.contains(index))
+ /// Returns whether `region` is marked live at the given `location`.
+ pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
+ let point = self.elements.point_from_location(location);
+ self.points.row(region).is_some_and(|r| r.contains(point))
+ }
+
+ /// Returns whether `region` is marked live at any location.
+ pub(crate) fn is_live_anywhere(&self, region: RegionVid) -> bool {
+ self.live_points(region).next().is_some()
}
- /// Returns an iterator of all the elements contained by the region `r`
- pub(crate) fn get_elements(&self, row: N) -> impl Iterator<Item = Location> + '_ {
+ /// Returns an iterator of all the points where `region` is live.
+ fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> + '_ {
self.points
- .row(row)
+ .row(region)
.into_iter()
.flat_map(|set| set.iter())
- .take_while(move |&p| self.elements.point_in_range(p))
- .map(move |p| self.elements.to_location(p))
+ .take_while(|&p| self.elements.point_in_range(p))
}
- /// Returns a "pretty" string value of the region. Meant for debugging.
- pub(crate) fn region_value_str(&self, r: N) -> String {
- region_value_str(self.get_elements(r).map(RegionElement::Location))
+ /// For debugging purposes, returns a pretty-printed string of the points where the `region` is
+ /// live.
+ pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
+ pretty_print_region_elements(
+ self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))),
+ )
}
#[inline]
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
self.elements.point_from_location(location)
}
+
+ /// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
+ pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
+ self.loans
+ .as_ref()
+ .expect("Accessing live loans requires `-Zpolonius=next`")
+ .live_loans
+ .contains(point, loan_idx)
+ }
}
/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
@@ -307,7 +371,7 @@ impl<N: Idx> RegionValues<N> {
/// `self[to] |= values[from]`, essentially: that is, take all the
/// elements for the region `from` from `values` and add them to
/// the region `to` in `self`.
- pub(crate) fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
+ pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) {
if let Some(set) = values.points.row(from) {
self.points.union_row(to, set);
}
@@ -376,7 +440,7 @@ impl<N: Idx> RegionValues<N> {
/// Returns a "pretty" string value of the region. Meant for debugging.
pub(crate) fn region_value_str(&self, r: N) -> String {
- region_value_str(self.elements_contained_in(r))
+ pretty_print_region_elements(self.elements_contained_in(r))
}
}
@@ -420,11 +484,12 @@ impl ToElementIndex for ty::PlaceholderRegion {
}
}
-pub(crate) fn location_set_str(
+/// For debugging purposes, returns a pretty-printed string of the given points.
+pub(crate) fn pretty_print_points(
elements: &RegionValueElements,
points: impl IntoIterator<Item = PointIndex>,
) -> String {
- region_value_str(
+ pretty_print_region_elements(
points
.into_iter()
.take_while(|&p| elements.point_in_range(p))
@@ -433,7 +498,8 @@ pub(crate) fn location_set_str(
)
}
-fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String {
+/// For debugging purposes, returns a pretty-printed string of the given region elements.
+fn pretty_print_region_elements(elements: impl IntoIterator<Item = RegionElement>) -> String {
let mut result = String::new();
result.push('{');
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index ec0131c53..a31d39e14 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -28,6 +28,9 @@ pub fn renumber_mir<'tcx>(
renumberer.visit_body(body);
}
+// FIXME(@lcnr): A lot of these variants overlap and it seems like
+// this type is only used to decide which region should be used
+// as representative. This should be cleaned up.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) enum RegionCtxt {
Location(Location),
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index c84256f8f..4a76d877a 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -7,7 +7,7 @@ use rustc_infer::infer::region_constraints::GenericKind;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
@@ -303,7 +303,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
Locations::All(span),
span,
ConstraintCategory::Internal,
- &mut self.constraints,
+ self.constraints,
)
.convert_all(data);
}
@@ -321,6 +321,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
.ok()?;
debug!(?bounds, ?constraints);
+ // Because of #109628, we may have unexpected placeholders. Ignore them!
+ // FIXME(#109628): panic in this case once the issue is fixed.
+ let bounds = bounds.into_iter().filter(|bound| !bound.has_placeholders());
self.add_outlives_bounds(bounds);
constraints
}
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index d053d0a4b..8e141bb38 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,7 +7,7 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
-use rustc_infer::infer::LateBoundRegionConversionTime;
+use rustc_infer::infer::BoundRegionConversionTime;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
@@ -35,7 +35,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
body.span,
- LateBoundRegionConversionTime::FnCall,
+ BoundRegionConversionTime::FnCall,
user_provided_sig,
);
@@ -77,7 +77,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if argument_index + 1 >= body.local_decls.len() {
self.tcx()
.sess
- .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
+ .span_delayed_bug(body.span, "found more normalized_input_ty than local_decls");
break;
}
@@ -101,10 +101,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
// We will not have a universal_regions.yield_ty if we yield (by accident)
- // outside of a coroutine and return an `impl Trait`, so emit a delay_span_bug
+ // outside of a coroutine and return an `impl Trait`, so emit a span_delayed_bug
// because we don't want to panic in an assert here if we've already got errors.
if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
- self.tcx().sess.delay_span_bug(
+ self.tcx().sess.span_delayed_bug(
body.span,
format!(
"Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index a9ca94567..7433c94a0 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -80,7 +80,7 @@ impl LocalUseMap {
live_locals.iter().for_each(|&local| locals_with_use_data[local] = true);
LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data }
- .visit_body(&body);
+ .visit_body(body);
local_use_map
}
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index f1ad0ca55..dc4695fd2 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -1,7 +1,9 @@
use itertools::{Either, Itertools};
use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::mir::{Body, Local};
-use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_middle::mir::visit::{TyContext, Visitor};
+use rustc_middle::mir::{Body, Local, Location, SourceInfo};
+use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt};
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor;
@@ -11,7 +13,7 @@ use crate::{
constraints::OutlivesConstraintSet,
facts::{AllFacts, AllFactsExt},
location::LocationTable,
- region_infer::values::RegionValueElements,
+ region_infer::values::{LivenessValues, RegionValueElements},
universal_regions::UniversalRegions,
};
@@ -42,11 +44,11 @@ pub(super) fn generate<'mir, 'tcx>(
let free_regions = regions_that_outlive_free_regions(
typeck.infcx.num_region_vars(),
- &typeck.borrowck_context.universal_regions,
+ typeck.borrowck_context.universal_regions,
&typeck.borrowck_context.constraints.outlives_constraints,
);
let (relevant_live_locals, boring_locals) =
- compute_relevant_live_locals(typeck.tcx(), &free_regions, &body);
+ compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx());
let polonius_drop_used = facts_enabled.then(|| {
@@ -65,6 +67,14 @@ pub(super) fn generate<'mir, 'tcx>(
boring_locals,
polonius_drop_used,
);
+
+ // Mark regions that should be live where they appear within rvalues or within a call: like
+ // args, regions, and types.
+ record_regular_live_regions(
+ typeck.tcx(),
+ &mut typeck.borrowck_context.constraints.liveness_constraints,
+ body,
+ );
}
// The purpose of `compute_relevant_live_locals` is to define the subset of `Local`
@@ -132,3 +142,71 @@ fn regions_that_outlive_free_regions<'tcx>(
// Return the final set of things we visited.
outlives_free_region
}
+
+/// Some variables are "regular live" at `location` -- i.e., they may be used later. This means that
+/// all regions appearing in their type must be live at `location`.
+fn record_regular_live_regions<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ liveness_constraints: &mut LivenessValues,
+ body: &Body<'tcx>,
+) {
+ let mut visitor = LiveVariablesVisitor { tcx, liveness_constraints };
+ for (bb, data) in body.basic_blocks.iter_enumerated() {
+ visitor.visit_basic_block_data(bb, data);
+ }
+}
+
+/// Visitor looking for regions that should be live within rvalues or calls.
+struct LiveVariablesVisitor<'cx, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ liveness_constraints: &'cx mut LivenessValues,
+}
+
+impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> {
+ /// We sometimes have `args` within an rvalue, or within a
+ /// call. Make them live at the location where they appear.
+ fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) {
+ self.record_regions_live_at(*args, location);
+ self.super_args(args);
+ }
+
+ /// We sometimes have `region`s within an rvalue, or within a
+ /// call. Make them live at the location where they appear.
+ fn visit_region(&mut self, region: Region<'tcx>, location: Location) {
+ self.record_regions_live_at(region, location);
+ self.super_region(region);
+ }
+
+ /// We sometimes have `ty`s within an rvalue, or within a
+ /// call. Make them live at the location where they appear.
+ fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) {
+ match ty_context {
+ TyContext::ReturnTy(SourceInfo { span, .. })
+ | TyContext::YieldTy(SourceInfo { span, .. })
+ | TyContext::UserTy(span)
+ | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
+ span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context);
+ }
+ TyContext::Location(location) => {
+ self.record_regions_live_at(ty, location);
+ }
+ }
+
+ self.super_ty(ty);
+ }
+}
+
+impl<'cx, 'tcx> LiveVariablesVisitor<'cx, 'tcx> {
+ /// Some variable is "regular live" at `location` -- i.e., it may be used later. This means that
+ /// all regions appearing in the type of `value` must be live at `location`.
+ fn record_regions_live_at<T>(&mut self, value: T, location: Location)
+ where
+ T: TypeVisitable<TyCtxt<'tcx>>,
+ {
+ debug!("record_regions_live_at(value={:?}, location={:?})", value, location);
+ self.tcx.for_each_free_region(&value, |live_region| {
+ let live_region_vid = live_region.as_var();
+ self.liveness_constraints.add_location(live_region_vid, location);
+ });
+ }
+}
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index c621df371..45f7b07fd 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -100,7 +100,7 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
location_table,
move_data,
};
- extractor.visit_body(&body);
+ extractor.visit_body(body);
facts.var_dropped_at.extend(
dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))),
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index e616449cc..c718d57be 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -1,12 +1,12 @@
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::WithSuccessors;
-use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
+use rustc_index::bit_set::HybridBitSet;
use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::for_liveness;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
use rustc_middle::traits::query::DropckOutlivesResult;
-use rustc_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
+use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -16,9 +16,8 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
use rustc_mir_dataflow::ResultsCursor;
-use crate::dataflow::BorrowIndex;
use crate::{
- region_infer::values::{self, PointIndex, RegionValueElements},
+ region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements},
type_check::liveness::local_use_map::LocalUseMap,
type_check::liveness::polonius,
type_check::NormalizeLocation,
@@ -49,22 +48,17 @@ pub(super) fn trace<'mir, 'tcx>(
boring_locals: Vec<Local>,
polonius_drop_used: Option<Vec<(Local, Location)>>,
) {
- debug!("trace()");
-
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
- let num_loans = typeck.borrowck_context.borrow_set.len();
- let mut inflowing_loans = SparseBitMatrix::new(num_loans);
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
- let borrowck_context = &typeck.borrowck_context;
+ let borrowck_context = &mut typeck.borrowck_context;
let borrow_set = &borrowck_context.borrow_set;
- let constraint_set = &borrowck_context.constraints.outlives_constraints;
-
- let num_region_vars = typeck.infcx.num_region_vars();
- let graph = constraint_set.graph(num_region_vars);
+ let mut live_loans = LiveLoans::new(borrow_set.len());
+ let outlives_constraints = &borrowck_context.constraints.outlives_constraints;
+ let graph = outlives_constraints.graph(typeck.infcx.num_region_vars());
let region_graph =
- graph.region_graph(&constraint_set, borrowck_context.universal_regions.fr_static);
+ graph.region_graph(outlives_constraints, borrowck_context.universal_regions.fr_static);
// Traverse each issuing region's constraints, and record the loan as flowing into the
// outlived region.
@@ -75,9 +69,13 @@ pub(super) fn trace<'mir, 'tcx>(
continue;
}
- inflowing_loans.insert(succ, loan);
+ live_loans.inflowing_loans.insert(succ, loan);
}
}
+
+ // Store the inflowing loans in the liveness constraints: they will be used to compute live
+ // loans when liveness data is recorded there.
+ borrowck_context.constraints.liveness_constraints.loans = Some(live_loans);
};
let cx = LivenessContext {
@@ -88,7 +86,6 @@ pub(super) fn trace<'mir, 'tcx>(
local_use_map,
move_data,
drop_data: FxIndexMap::default(),
- inflowing_loans,
};
let mut results = LivenessResults::new(cx);
@@ -126,9 +123,6 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
/// Index indicating where each variable is assigned, used, or
/// dropped.
local_use_map: &'me LocalUseMap,
-
- /// Set of loans that flow into a given region, when using `-Zpolonius=next`.
- inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
}
struct DropData<'tcx> {
@@ -489,7 +483,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
}
let move_paths = &self.flow_inits.analysis().move_data().move_paths;
- move_paths[mpi].find_descendant(&move_paths, |mpi| state.contains(mpi)).is_some()
+ move_paths[mpi].find_descendant(move_paths, |mpi| state.contains(mpi)).is_some()
}
/// Returns `true` if the local variable (or some part of it) is initialized in
@@ -519,14 +513,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
live_at: &IntervalSet<PointIndex>,
) {
debug!("add_use_live_facts_for(value={:?})", value);
-
- Self::make_all_regions_live(
- self.elements,
- &mut self.typeck,
- value,
- live_at,
- &self.inflowing_loans,
- );
+ Self::make_all_regions_live(self.elements, self.typeck, value, live_at);
}
/// Some variable with type `live_ty` is "drop live" at `location`
@@ -550,7 +537,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
dropped_local,
dropped_ty,
drop_locations,
- values::location_set_str(self.elements, live_at.iter()),
+ values::pretty_print_points(self.elements, live_at.iter()),
);
let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
@@ -577,15 +564,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
for &kind in &drop_data.dropck_result.kinds {
- Self::make_all_regions_live(
- self.elements,
- &mut self.typeck,
- kind,
- live_at,
- &self.inflowing_loans,
- );
-
- polonius::add_drop_of_var_derefs_origin(&mut self.typeck, dropped_local, &kind);
+ Self::make_all_regions_live(self.elements, self.typeck, kind, live_at);
+ polonius::add_drop_of_var_derefs_origin(self.typeck, dropped_local, &kind);
}
}
@@ -594,20 +574,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
typeck: &mut TypeChecker<'_, 'tcx>,
value: impl TypeVisitable<TyCtxt<'tcx>>,
live_at: &IntervalSet<PointIndex>,
- inflowing_loans: &SparseBitMatrix<RegionVid, BorrowIndex>,
) {
debug!("make_all_regions_live(value={:?})", value);
debug!(
"make_all_regions_live: live_at={}",
- values::location_set_str(elements, live_at.iter()),
+ values::pretty_print_points(elements, live_at.iter()),
);
- // When using `-Zpolonius=next`, we want to record the loans that flow into this value's
- // regions as being live at the given `live_at` points: this will be used to compute the
- // location where a loan goes out of scope.
- let num_loans = typeck.borrowck_context.borrow_set.len();
- let value_loans = &mut HybridBitSet::new_empty(num_loans);
-
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
tcx: typeck.tcx(),
param_env: typeck.param_env,
@@ -618,22 +591,9 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
.borrowck_context
.constraints
.liveness_constraints
- .add_elements(live_region_vid, live_at);
-
- // There can only be inflowing loans for this region when we are using
- // `-Zpolonius=next`.
- if let Some(inflowing) = inflowing_loans.row(live_region_vid) {
- value_loans.union(inflowing);
- }
+ .add_points(live_region_vid, live_at);
},
});
-
- // Record the loans reaching the value.
- if !value_loans.is_empty() {
- for point in live_at.iter() {
- typeck.borrowck_context.live_loans.union_row(point, value_loans);
- }
- }
}
fn compute_drop_data(
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 608d01039..5247d5f69 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -14,18 +14,16 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
-use rustc_index::bit_set::SparseBitMatrix;
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
- InferCtxt, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
+ BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
};
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::AssertKind;
use rustc_middle::mir::*;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::ObligationCause;
@@ -51,8 +49,6 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor;
-use crate::dataflow::BorrowIndex;
-use crate::region_infer::values::PointIndex;
use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst};
use crate::{
borrow_set::BorrowSet,
@@ -68,7 +64,7 @@ use crate::{
region_infer::TypeTest,
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
universal_regions::{DefiningTy, UniversalRegions},
- BorrowckInferCtxt, Upvar,
+ BorrowckInferCtxt,
};
macro_rules! span_mirbug {
@@ -138,7 +134,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>,
- upvars: &[Upvar<'tcx>],
+ upvars: &[&ty::CapturedPlace<'tcx>],
use_polonius: bool,
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
@@ -166,9 +162,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
debug!(?normalized_inputs_and_output);
- // When using `-Zpolonius=next`, liveness will record the set of live loans per point.
- let mut live_loans = SparseBitMatrix::new(borrow_set.len());
-
let mut borrowck_context = BorrowCheckContext {
universal_regions,
location_table,
@@ -176,7 +169,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
all_facts,
constraints: &mut constraints,
upvars,
- live_loans: &mut live_loans,
};
let mut checker = TypeChecker::new(
@@ -191,11 +183,11 @@ pub(crate) fn type_check<'mir, 'tcx>(
checker.check_user_type_annotations();
let mut verifier = TypeVerifier::new(&mut checker, promoted);
- verifier.visit_body(&body);
+ verifier.visit_body(body);
checker.typeck_mir(body);
- checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
- checker.check_signature_annotation(&body);
+ checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output);
+ checker.check_signature_annotation(body);
liveness::generate(
&mut checker,
@@ -232,7 +224,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
if hidden_type.has_non_region_infer() {
- let reported = infcx.tcx.sess.delay_span_bug(
+ let reported = infcx.tcx.sess.span_delayed_bug(
decl.hidden_type.span,
format!("could not resolve {:#?}", hidden_type.ty.kind()),
);
@@ -243,7 +235,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
})
.collect();
- MirTypeckResults { constraints, universal_region_relations, opaque_type_values, live_loans }
+ MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
}
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
@@ -274,9 +266,9 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
#[track_caller]
fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) {
// We sometimes see MIR failures (notably predicate failures) due to
- // the fact that we check rvalue sized predicates here. So use `delay_span_bug`
+ // the fact that we check rvalue sized predicates here. So use `span_delayed_bug`
// to avoid reporting bugs in those cases.
- tcx.sess.diagnostic().delay_span_bug(span, msg);
+ tcx.sess.dcx().span_delayed_bug(span, msg);
}
enum FieldAccessError {
@@ -318,7 +310,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
.borrowck_context
.constraints
.liveness_constraints
- .add_element(live_region_vid, location);
+ .add_location(live_region_vid, location);
});
// HACK(compiler-errors): Constants that are gathered into Body.required_consts
@@ -389,7 +381,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
self.cx.ascribe_user_type(
constant.const_.ty(),
UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }),
- locations.span(&self.cx.body),
+ locations.span(self.cx.body),
);
}
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
@@ -553,7 +545,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
let all_facts = &mut None;
let mut constraints = Default::default();
let mut liveness_constraints =
- LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
+ LivenessValues::new(Rc::new(RegionValueElements::new(promoted_body)));
// Don't try to add borrow_region facts for the promoted MIR
let mut swap_constraints = |this: &mut Self| {
@@ -570,7 +562,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
swap_constraints(self);
- self.visit_body(&promoted_body);
+ self.visit_body(promoted_body);
self.cx.typeck_mir(promoted_body);
@@ -592,16 +584,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
self.cx.borrowck_context.constraints.outlives_constraints.push(constraint)
}
- for region in liveness_constraints.rows() {
+ for region in liveness_constraints.regions() {
// If the region is live at at least one location in the promoted MIR,
// then add a liveness constraint to the main MIR for this region
// at the location provided as an argument to this method
- if liveness_constraints.get_elements(region).next().is_some() {
+ if liveness_constraints.is_live_anywhere(region) {
self.cx
.borrowck_context
.constraints
.liveness_constraints
- .add_element(region, location);
+ .add_location(region, location);
}
}
}
@@ -857,11 +849,7 @@ struct BorrowCheckContext<'a, 'tcx> {
all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>,
pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
- upvars: &'a [Upvar<'tcx>],
-
- /// The set of loans that are live at a given point in the CFG, filled in by `liveness::trace`,
- /// when using `-Zpolonius=next`.
- pub(crate) live_loans: &'a mut SparseBitMatrix<PointIndex, BorrowIndex>,
+ upvars: &'a [&'a ty::CapturedPlace<'tcx>],
}
/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions
@@ -870,9 +858,6 @@ pub(crate) struct MirTypeckResults<'tcx> {
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
-
- /// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`.
- pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
}
/// A collection of region constraints that must be satisfied for the
@@ -899,7 +884,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
/// not otherwise appear in the MIR -- in particular, the
/// late-bound regions that it instantiates at call-sites -- and
/// hence it must report on their liveness constraints.
- pub(crate) liveness_constraints: LivenessValues<RegionVid>,
+ pub(crate) liveness_constraints: LivenessValues,
pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>,
@@ -1018,16 +1003,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
reported_errors: Default::default(),
};
- // FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
+ // FIXME(-Znext-solver): A bit dubious that we're only registering
// predefined opaques in the typeck root.
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
- checker.register_predefined_opaques_in_new_solver();
+ checker.register_predefined_opaques_for_next_solver();
}
checker
}
- pub(super) fn register_predefined_opaques_in_new_solver(&mut self) {
+ pub(super) fn register_predefined_opaques_for_next_solver(&mut self) {
// OK to use the identity arguments for each opaque type key, since
// we remap opaques from HIR typeck back to their definition params.
let opaques: Vec<_> = self
@@ -1082,7 +1067,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
if result.is_err() {
- self.infcx.tcx.sess.delay_span_bug(
+ self.infcx.tcx.sess.span_delayed_bug(
self.body.span,
"failed re-defining predefined opaques in mir typeck",
);
@@ -1127,7 +1112,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
locations,
locations.span(self.body),
category,
- &mut self.borrowck_context.constraints,
+ self.borrowck_context.constraints,
)
.convert_all(data);
}
@@ -1202,7 +1187,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.infcx.tcx
}
- #[instrument(skip(self, body, location), level = "debug")]
+ #[instrument(skip(self, body), level = "debug")]
fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) {
let tcx = self.tcx();
debug!("stmt kind: {:?}", stmt.kind);
@@ -1387,7 +1372,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return;
}
};
- let (sig, map) = tcx.replace_late_bound_regions(sig, |br| {
+ let (sig, map) = tcx.instantiate_bound_regions(sig, |br| {
use crate::renumber::RegionCtxt;
let region_ctxt_fn = || {
@@ -1401,10 +1386,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
};
self.infcx.next_region_var(
- LateBoundRegion(
+ BoundRegion(
term.source_info.span,
br.kind,
- LateBoundRegionConversionTime::FnCall,
+ BoundRegionConversionTime::FnCall,
),
region_ctxt_fn,
)
@@ -1443,7 +1428,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.borrowck_context
.constraints
.liveness_constraints
- .add_element(region_vid, term_location);
+ .add_location(region_vid, term_location);
}
self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source);
@@ -1854,7 +1839,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
for op in ops {
self.check_operand(op, location);
}
- self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
+ self.check_aggregate_rvalue(body, rvalue, ak, ops, location)
}
Rvalue::Repeat(operand, len) => {
@@ -1934,7 +1919,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
*ty,
ty_fn_ptr_from,
location.to_locations(),
- ConstraintCategory::Cast,
+ ConstraintCategory::Cast { unsize_to: None },
) {
span_mirbug!(
self,
@@ -1959,7 +1944,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
*ty,
ty_fn_ptr_from,
location.to_locations(),
- ConstraintCategory::Cast,
+ ConstraintCategory::Cast { unsize_to: None },
) {
span_mirbug!(
self,
@@ -1988,7 +1973,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
*ty,
ty_fn_ptr_from,
location.to_locations(),
- ConstraintCategory::Cast,
+ ConstraintCategory::Cast { unsize_to: None },
) {
span_mirbug!(
self,
@@ -2013,7 +1998,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.prove_trait_ref(
trait_ref,
location.to_locations(),
- ConstraintCategory::Cast,
+ ConstraintCategory::Cast {
+ unsize_to: Some(tcx.fold_regions(ty, |r, _| {
+ if let ty::ReVar(_) = r.kind() {
+ tcx.lifetimes.re_erased
+ } else {
+ r
+ }
+ })),
+ },
);
}
@@ -2033,7 +2026,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.iter()
.map(|predicate| predicate.with_self_ty(tcx, self_ty)),
location.to_locations(),
- ConstraintCategory::Cast,
+ ConstraintCategory::Cast { unsize_to: None },
);
let outlives_predicate = tcx.mk_predicate(Binder::dummy(
@@ -2044,7 +2037,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.prove_predicate(
outlives_predicate,
location.to_locations(),
- ConstraintCategory::Cast,
+ ConstraintCategory::Cast { unsize_to: None },
);
}
@@ -2065,7 +2058,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
*ty_from,
*ty_to,
location.to_locations(),
- ConstraintCategory::Cast,
+ ConstraintCategory::Cast { unsize_to: None },
) {
span_mirbug!(
self,
@@ -2131,7 +2124,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
*ty_elem,
*ty_to,
location.to_locations(),
- ConstraintCategory::Cast,
+ ConstraintCategory::Cast { unsize_to: None },
) {
span_mirbug!(
self,
@@ -2292,7 +2285,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
- self.add_reborrow_constraint(&body, location, *region, borrowed_place);
+ self.add_reborrow_constraint(body, location, *region, borrowed_place);
}
Rvalue::BinaryOp(
@@ -2504,7 +2497,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let tcx = self.infcx.tcx;
let field = path_utils::is_upvar_field_projection(
tcx,
- &self.borrowck_context.upvars,
+ self.borrowck_context.upvars,
borrowed_place.as_ref(),
body,
);
@@ -2660,13 +2653,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location.to_locations(),
DUMMY_SP, // irrelevant; will be overridden.
ConstraintCategory::Boring, // same as above.
- &mut self.borrowck_context.constraints,
+ self.borrowck_context.constraints,
)
- .apply_closure_requirements(
- &closure_requirements,
- def_id.to_def_id(),
- args,
- );
+ .apply_closure_requirements(closure_requirements, def_id.to_def_id(), args);
}
// Now equate closure args to regions inherited from `typeck_root_def_id`. Fixes #98589.
@@ -2674,8 +2663,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
let parent_args = match tcx.def_kind(def_id) {
+ DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => {
+ args.as_coroutine().parent_args()
+ }
DefKind::Closure => args.as_closure().parent_args(),
- DefKind::Coroutine => args.as_coroutine().parent_args(),
DefKind::InlineConst => args.as_inline_const().parent_args(),
other => bug!("unexpected item {:?}", other),
};
@@ -2706,7 +2697,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
debug!(?body.span);
for (local, local_decl) in body.local_decls.iter_enumerated() {
- self.check_local(&body, local, local_decl);
+ self.check_local(body, local, local_decl);
}
for (block, block_data) in body.basic_blocks.iter_enumerated() {
@@ -2719,8 +2710,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location.statement_index += 1;
}
- self.check_terminator(&body, block_data.terminator(), location);
- self.check_iscleanup(&body, block_data);
+ self.check_terminator(body, block_data.terminator(), location);
+ self.check_iscleanup(body, block_data);
}
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index c1f82e19c..ee0bd1310 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -107,12 +107,12 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
fn next_existential_region_var(
&mut self,
from_forall: bool,
- _name: Option<Symbol>,
+ name: Option<Symbol>,
) -> ty::Region<'tcx> {
let origin = NllRegionVariableOrigin::Existential { from_forall };
let reg_var =
- self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(_name));
+ self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name));
reg_var
}
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 7897a5a63..2b83c7871 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -462,7 +462,6 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// "Liberate" the late-bound regions. These correspond to
// "local" free regions.
-
let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
@@ -665,7 +664,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
kind: ty::BrEnv,
};
- let env_region = ty::Region::new_late_bound(tcx, ty::INNERMOST, br);
+ let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
let closure_ty = tcx.closure_env_ty(def_id, args, env_region).unwrap();
// The "inputs" of the closure in the
@@ -738,18 +737,6 @@ trait InferCtxtExt<'tcx> {
) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>;
-
- fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
- &self,
- mir_def_id: LocalDefId,
- indices: &mut UniversalRegionIndices<'tcx>,
- );
-
- fn replace_late_bound_regions_with_nll_infer_vars_in_item(
- &self,
- mir_def_id: LocalDefId,
- indices: &mut UniversalRegionIndices<'tcx>,
- );
}
impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
@@ -781,10 +768,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
- let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
+ let (value, _map) = self.tcx.instantiate_bound_regions(value, |br| {
debug!(?br);
let liberated_region =
- ty::Region::new_free(self.tcx, all_outlive_scope.to_def_id(), br.kind);
+ ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), br.kind);
let region_vid = {
let name = match br.kind.get_name() {
Some(name) => name,
@@ -800,61 +787,13 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
});
value
}
-
- /// Finds late-bound regions that do not appear in the parameter listing and adds them to the
- /// indices vector. Typically, we identify late-bound regions as we process the inputs and
- /// outputs of the closure/function. However, sometimes there are late-bound regions which do
- /// not appear in the fn parameters but which are nonetheless in scope. The simplest case of
- /// this are unused functions, like fn foo<'a>() { } (see e.g., #51351). Despite not being used,
- /// users can still reference these regions (e.g., let x: &'a u32 = &22;), so we need to create
- /// entries for them and store them in the indices map. This code iterates over the complete
- /// set of late-bound regions and checks for any that we have not yet seen, adding them to the
- /// inputs vector.
- #[instrument(skip(self, indices))]
- fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
- &self,
- mir_def_id: LocalDefId,
- indices: &mut UniversalRegionIndices<'tcx>,
- ) {
- for_each_late_bound_region_in_recursive_scope(self.tcx, mir_def_id, |r| {
- debug!(?r);
- if !indices.indices.contains_key(&r) {
- let region_vid = {
- let name = r.get_name_or_anon();
- self.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
- };
-
- debug!(?region_vid);
- indices.insert_late_bound_region(r, region_vid.as_var());
- }
- });
- }
-
- #[instrument(skip(self, indices))]
- fn replace_late_bound_regions_with_nll_infer_vars_in_item(
- &self,
- mir_def_id: LocalDefId,
- indices: &mut UniversalRegionIndices<'tcx>,
- ) {
- for_each_late_bound_region_in_item(self.tcx, mir_def_id, |r| {
- debug!(?r);
- if !indices.indices.contains_key(&r) {
- let region_vid = {
- let name = r.get_name_or_anon();
- self.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
- };
-
- indices.insert_late_bound_region(r, region_vid.as_var());
- }
- });
- }
}
impl<'tcx> UniversalRegionIndices<'tcx> {
/// Initially, the `UniversalRegionIndices` map contains only the
/// early-bound regions in scope. Once that is all setup, we come
/// in later and instantiate the late-bound regions, and then we
- /// insert the `ReFree` version of those into the map as
+ /// insert the `ReLateParam` version of those into the map as
/// well. These are used for error reporting.
fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) {
debug!("insert_late_bound_region({:?}, {:?})", r, vid);
@@ -929,11 +868,12 @@ fn for_each_late_bound_region_in_item<'tcx>(
return;
}
- for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) {
+ for bound_var in tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)) {
let ty::BoundVariableKind::Region(bound_region) = bound_var else {
continue;
};
- let liberated_region = ty::Region::new_free(tcx, mir_def_id.to_def_id(), bound_region);
+ let liberated_region =
+ ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), bound_region);
f(liberated_region);
}
}
diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs
index c5991e0bc..6ac8e1ba7 100644
--- a/compiler/rustc_borrowck/src/used_muts.rs
+++ b/compiler/rustc_borrowck/src/used_muts.rs
@@ -35,7 +35,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
never_initialized_mut_locals: &mut never_initialized_mut_locals,
mbcx: self,
};
- visitor.visit_body(&visitor.mbcx.body);
+ visitor.visit_body(visitor.mbcx.body);
}
// Take the union of the existed `used_mut` set with those variables we've found were