summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck')
-rw-r--r--compiler/rustc_borrowck/src/constraint_generation.rs2
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs11
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs34
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs64
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs160
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs156
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs18
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs26
-rw-r--r--compiler/rustc_borrowck/src/lib.rs56
-rw-r--r--compiler/rustc_borrowck/src/location.rs5
-rw-r--r--compiler/rustc_borrowck/src/nll.rs5
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs15
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs192
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs57
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs4
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs30
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs125
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs35
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs69
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs64
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs223
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs22
27 files changed, 831 insertions, 569 deletions
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
index 5e9cec5c3..144fd15fc 100644
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -31,7 +31,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
body,
};
- for (bb, data) in body.basic_blocks().iter_enumerated() {
+ for (bb, data) in body.basic_blocks.iter_enumerated() {
cg.visit_basic_block_data(bb, data);
}
}
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index a504d0c91..df0412813 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -21,10 +21,7 @@ pub(crate) struct OutlivesConstraintSet<'tcx> {
impl<'tcx> OutlivesConstraintSet<'tcx> {
pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
- debug!(
- "OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
- constraint.sup, constraint.sub, constraint.locations
- );
+ debug!("OutlivesConstraintSet::push({:?})", constraint);
if constraint.sup == constraint.sub {
// 'a: 'a is pretty uninteresting
return;
@@ -73,7 +70,7 @@ impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
}
}
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
pub struct OutlivesConstraint<'tcx> {
// NB. The ordering here is not significant for correctness, but
// it is for convenience. Before we dump the constraints in the
@@ -105,8 +102,8 @@ impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
- "({:?}: {:?}) due to {:?} ({:?})",
- self.sup, self.sub, self.locations, self.variance_info
+ "({:?}: {:?}) due to {:?} ({:?}) ({:?})",
+ self.sup, self.sub, self.locations, self.variance_info, self.category,
)
}
}
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 97d5a8d15..9f7a4d499 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -143,7 +143,7 @@ struct OutOfScopePrecomputer<'a, 'tcx> {
impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
OutOfScopePrecomputer {
- visited: BitSet::new_empty(body.basic_blocks().len()),
+ visited: BitSet::new_empty(body.basic_blocks.len()),
visit_stack: vec![],
body,
regioncx,
@@ -391,7 +391,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
| mir::StatementKind::Retag { .. }
| mir::StatementKind::AscribeUserType(..)
| mir::StatementKind::Coverage(..)
- | mir::StatementKind::CopyNonOverlapping(..)
+ | mir::StatementKind::Intrinsic(..)
| mir::StatementKind::Nop => {}
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 1ef2b0ae9..b1def1892 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -484,9 +484,7 @@ fn try_extract_error_from_region_constraints<'tcx>(
};
nice_error.try_report_from_nll().or_else(|| {
if let SubregionOrigin::Subtype(trace) = cause {
- Some(
- infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
- )
+ Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch))
} else {
None
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 8bc8964bb..f2204c242 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -258,7 +258,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let ty = place.ty(self.body, self.infcx.tcx).ty;
// If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
- if is_loop_move & !in_pattern {
+ // Same for if we're in a loop, see #101119.
+ if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
err.span_suggestion_verbose(
@@ -451,7 +452,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn suggest_borrow_fn_like(
&self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ err: &mut Diagnostic,
ty: Ty<'tcx>,
move_sites: &[MoveSite],
value_name: &str,
@@ -526,12 +527,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
true
}
- fn suggest_adding_copy_bounds(
- &self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
- ty: Ty<'tcx>,
- span: Span,
- ) {
+ fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
let tcx = self.infcx.tcx;
let generics = tcx.generics_of(self.mir_def_id());
@@ -1124,6 +1120,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// short a lifetime. (But sometimes it is more useful to report
/// it as a more direct conflict between the execution of a
/// `Drop::drop` with an aliasing borrow.)
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn report_borrowed_value_does_not_live_long_enough(
&mut self,
location: Location,
@@ -1131,13 +1128,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
place_span: (Place<'tcx>, Span),
kind: Option<WriteKind>,
) {
- debug!(
- "report_borrowed_value_does_not_live_long_enough(\
- {:?}, {:?}, {:?}, {:?}\
- )",
- location, borrow, place_span, kind
- );
-
let drop_span = place_span.1;
let root_place =
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
@@ -1194,10 +1184,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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);
- debug!(
- "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
- place_desc, explanation
- );
+ debug!(?place_desc, ?explanation);
+
let err = match (place_desc, explanation) {
// If the outlives constraint comes from inside the closure,
// for example:
@@ -1469,6 +1457,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err
}
+ #[instrument(level = "debug", skip(self))]
fn report_temporary_value_does_not_live_long_enough(
&mut self,
location: Location,
@@ -1478,13 +1467,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
proper_span: Span,
explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
- debug!(
- "report_temporary_value_does_not_live_long_enough(\
- {:?}, {:?}, {:?}, {:?}\
- )",
- location, borrow, drop_span, proper_span
- );
-
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
explanation
{
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 72aee0267..1c01e78ab 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt};
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{sym, DesugaringKind, Span};
-use crate::region_infer::BlameConstraint;
+use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
WriteKind,
@@ -38,6 +38,7 @@ pub(crate) enum BorrowExplanation<'tcx> {
span: Span,
region_name: RegionName,
opt_place_desc: Option<String>,
+ extra_info: Vec<ExtraConstraintInfo>,
},
Unexplained,
}
@@ -243,6 +244,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
ref region_name,
ref opt_place_desc,
from_closure: _,
+ ref extra_info,
} => {
region_name.highlight_region_name(err);
@@ -268,18 +270,30 @@ impl<'tcx> BorrowExplanation<'tcx> {
);
};
+ for extra in extra_info {
+ match extra {
+ ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
+ err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+ }
+ }
+ }
+
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
}
_ => {}
}
}
- pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic(
+
+ fn add_lifetime_bound_suggestion_to_diagnostic(
&self,
err: &mut Diagnostic,
category: &ConstraintCategory<'tcx>,
span: Span,
region_name: &RegionName,
) {
+ if !span.is_desugaring(DesugaringKind::OpaqueTy) {
+ return;
+ }
if let ConstraintCategory::OpaqueType = category {
let suggestable_name =
if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime };
@@ -305,18 +319,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&self,
borrow_region: RegionVid,
outlived_region: RegionVid,
- ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>) {
- let BlameConstraint { category, from_closure, cause, variance_info: _ } =
- self.regioncx.best_blame_constraint(
- &self.body,
- borrow_region,
- NllRegionVariableOrigin::FreeRegion,
- |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
- );
+ ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
+ let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
+ borrow_region,
+ NllRegionVariableOrigin::FreeRegion,
+ |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
+ );
+ let BlameConstraint { category, from_closure, cause, .. } = blame_constraint;
let outlived_fr_name = self.give_region_a_name(outlived_region);
- (category, from_closure, cause.span, outlived_fr_name)
+ (category, from_closure, cause.span, outlived_fr_name, extra_info)
}
/// Returns structured explanation for *why* the borrow contains the
@@ -332,26 +345,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// - second half is the place being accessed
///
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn explain_why_borrow_contains_point(
&self,
location: Location,
borrow: &BorrowData<'tcx>,
kind_place: Option<(WriteKind, Place<'tcx>)>,
) -> BorrowExplanation<'tcx> {
- debug!(
- "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
- location, borrow, kind_place
- );
-
let regioncx = &self.regioncx;
let body: &Body<'_> = &self.body;
let tcx = self.infcx.tcx;
let borrow_region_vid = borrow.region;
- debug!("explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid);
+ debug!(?borrow_region_vid);
let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
- debug!("explain_why_borrow_contains_point: region_sub={:?}", region_sub);
+ debug!(?region_sub);
match find_use::find(body, regioncx, tcx, region_sub, location) {
Some(Cause::LiveVar(local, location)) => {
@@ -392,7 +401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None => {
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
- let (category, from_closure, span, region_name) =
+ let (category, from_closure, span, region_name, extra_info) =
self.free_region_constraint_info(borrow_region_vid, region);
if let Some(region_name) = region_name {
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
@@ -402,19 +411,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span,
region_name,
opt_place_desc,
+ extra_info,
}
} else {
- debug!(
- "explain_why_borrow_contains_point: \
- Could not generate a region name"
- );
+ debug!("Could not generate a region name");
BorrowExplanation::Unexplained
}
} else {
- debug!(
- "explain_why_borrow_contains_point: \
- Could not generate an error region vid"
- );
+ debug!("Could not generate an error region vid");
BorrowExplanation::Unexplained
}
}
@@ -455,7 +459,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return outmost_back_edge;
}
- let block = &self.body.basic_blocks()[location.block];
+ let block = &self.body.basic_blocks[location.block];
if location.statement_index < block.statements.len() {
let successor = location.successor_within_block();
@@ -514,7 +518,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
if loop_head.dominates(from, &self.dominators) {
- let block = &self.body.basic_blocks()[from.block];
+ let block = &self.body.basic_blocks[from.block];
if from.statement_index < block.statements.len() {
let successor = from.successor_within_block();
@@ -564,7 +568,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
UseSpans::PatUse(span)
| UseSpans::OtherUse(span)
| UseSpans::FnSelfUse { var_span: span, .. } => {
- let block = &self.body.basic_blocks()[location.block];
+ let block = &self.body.basic_blocks[location.block];
let kind = if let Some(&Statement {
kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 098e8de94..683084cf0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1086,14 +1086,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
),
);
}
- if is_option_or_result && maybe_reinitialized_locations_is_empty {
- err.span_suggestion_verbose(
- fn_call_span.shrink_to_lo(),
- "consider calling `.as_ref()` to borrow the type's contents",
- "as_ref().",
- Applicability::MachineApplicable,
- );
- }
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
@@ -1102,6 +1094,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
);
}
+ if is_option_or_result && maybe_reinitialized_locations_is_empty {
+ err.span_label(
+ var_span,
+ "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents",
+ );
+ }
}
// 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 cb3cd479a..8d4c38d3a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -88,7 +88,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(StatementKind::Assign(box (
place,
Rvalue::Use(Operand::Move(move_from)),
- ))) = self.body.basic_blocks()[location.block]
+ ))) = self.body.basic_blocks[location.block]
.statements
.get(location.statement_index)
.map(|stmt| &stmt.kind)
@@ -360,7 +360,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
diag.span_label(upvar_span, "captured outer variable");
diag.span_label(
- self.body.span,
+ self.infcx.tcx.def_span(def_id),
format!("captured by this `{closure_kind}` closure"),
);
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 0ad4abbce..6b5014fa9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1,23 +1,23 @@
+use rustc_errors::{
+ Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed,
+};
use rustc_hir as hir;
+use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
use rustc_middle::hir::map::Map;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{
hir::place::PlaceBase,
- mir::{
- self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo,
- LocalKind, Location,
- },
+ mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{sym, BytePos, Span};
use crate::diagnostics::BorrowedContentSource;
use crate::MirBorrowckCtxt;
use rustc_const_eval::util::collect_writes::FindAssignments;
-use rustc_errors::{Applicability, Diagnostic};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum AccessKind {
@@ -309,7 +309,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&& !matches!(
decl.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
- ImplicitSelfKind::MutRef
+ hir::ImplicitSelfKind::MutRef
))))
)
{
@@ -364,7 +364,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
&& let hir::PatKind::Binding(
- hir::BindingAnnotation::Unannotated,
+ hir::BindingAnnotation::NONE,
_,
upvar_ident,
_,
@@ -614,6 +614,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
"trait `IndexMut` is required to modify indexed content, \
but it is not implemented for `{ty}`",
));
+ self.suggest_map_index_mut_alternatives(ty, &mut err, span);
}
_ => (),
}
@@ -627,6 +628,127 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.buffer_error(err);
}
+ fn suggest_map_index_mut_alternatives(
+ &self,
+ ty: Ty<'_>,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ span: Span,
+ ) {
+ let Some(adt) = ty.ty_adt_def() else { return };
+ let did = adt.did();
+ if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
+ || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
+ {
+ struct V<'a, 'b, 'tcx, G: EmissionGuarantee> {
+ assign_span: Span,
+ err: &'a mut DiagnosticBuilder<'b, G>,
+ ty: Ty<'tcx>,
+ suggested: bool,
+ }
+ impl<'a, 'b: 'a, 'hir, 'tcx, G: EmissionGuarantee> Visitor<'hir> for V<'a, 'b, 'tcx, G> {
+ fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) {
+ hir::intravisit::walk_stmt(self, stmt);
+ let expr = match stmt.kind {
+ hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
+ hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr,
+ _ => {
+ return;
+ }
+ };
+ if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
+ && let hir::ExprKind::Index(val, index) = place.kind
+ && (expr.span == self.assign_span || place.span == self.assign_span)
+ {
+ // val[index] = rv;
+ // ---------- place
+ self.err.multipart_suggestions(
+ &format!(
+ "to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
+ self.ty,
+ ),
+ vec![
+ vec![ // val.insert(index, rv);
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".insert(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(rv.span.lo()),
+ ", ".to_string(),
+ ),
+ (rv.span.shrink_to_hi(), ")".to_string()),
+ ],
+ vec![ // val.get_mut(index).map(|v| { *v = rv; });
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".get_mut(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(place.span.hi()),
+ ").map(|val| { *val".to_string(),
+ ),
+ (
+ rv.span.shrink_to_hi(),
+ "; })".to_string(),
+ ),
+ ],
+ vec![ // let x = val.entry(index).or_insert(rv);
+ (val.span.shrink_to_lo(), "let val = ".to_string()),
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".entry(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(rv.span.lo()),
+ ").or_insert(".to_string(),
+ ),
+ (rv.span.shrink_to_hi(), ")".to_string()),
+ ],
+ ].into_iter(),
+ Applicability::MachineApplicable,
+ );
+ self.suggested = true;
+ } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
+ && let hir::ExprKind::Index(val, index) = receiver.kind
+ && expr.span == self.assign_span
+ {
+ // val[index].path(args..);
+ self.err.multipart_suggestion(
+ &format!("to modify a `{}` use `.get_mut()`", self.ty),
+ vec![
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".get_mut(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(receiver.span.hi()),
+ ").map(|val| val".to_string(),
+ ),
+ (sp.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ self.suggested = true;
+ }
+ }
+ }
+ let hir_map = self.infcx.tcx.hir();
+ let def_id = self.body.source.def_id();
+ let hir_id = hir_map.local_def_id_to_hir_id(def_id.as_local().unwrap());
+ let node = hir_map.find(hir_id);
+ let Some(hir::Node::Item(item)) = node else { return; };
+ let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
+ let body = self.infcx.tcx.hir().body(body_id);
+ let mut v = V { assign_span: span, err, ty, suggested: false };
+ v.visit_body(body);
+ if !v.suggested {
+ err.help(&format!(
+ "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
+ ));
+ }
+ }
+ }
+
/// User cannot make signature of a trait mutable without changing the
/// trait. So we find if this error belongs to a trait and if so we move
/// suggestion to the trait or disable it if it is out of scope of this crate
@@ -786,11 +908,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
[
Expr {
kind:
- MethodCall(
- path_segment,
- _args,
- span,
- ),
+ MethodCall(path_segment, _, _, span),
hir_id,
..
},
@@ -810,10 +928,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
_,
) = hir_map.body(fn_body_id).value.kind
{
- let opt_suggestions = path_segment
- .hir_id
- .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
- .and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
+ let opt_suggestions = self
+ .infcx
+ .tcx
+ .typeck(path_segment.hir_id.owner)
+ .type_dependent_def_id(*hir_id)
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
.map(|def_id| self.infcx.tcx.associated_items(def_id))
.map(|assoc_items| {
@@ -851,6 +970,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let hir = self.infcx.tcx.hir();
let closure_id = self.mir_hir_id();
+ let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
let fn_call_id = hir.get_parent_node(closure_id);
let node = hir.get(fn_call_id);
let def_id = hir.enclosing_body_owner(fn_call_id);
@@ -902,7 +1022,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(span) = arg {
err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
err.span_label(func.span, "expects `Fn` instead of `FnMut`");
- err.span_label(self.body.span, "in this closure");
+ err.span_label(closure_span, "in this closure");
look_at_return = false;
}
}
@@ -928,7 +1048,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
sig.decl.output.span(),
"change this to return `FnMut` instead of `Fn`",
);
- err.span_label(self.body.span, "in this closure");
+ err.span_label(closure_span, "in this closure");
}
_ => {}
}
@@ -952,7 +1072,7 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
//
// Deliberately fall into this case for all implicit self types,
// so that we don't fall in to the next case with them.
- *kind == mir::ImplicitSelfKind::MutRef
+ *kind == hir::ImplicitSelfKind::MutRef
}
_ if Some(kw::SelfLower) == local_name => {
// Otherwise, check if the name is the `self` keyword - in which case
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index d359d7efb..35c3df768 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -6,7 +6,6 @@ use rustc_errors::Diagnostic;
use rustc_middle::ty::RegionVid;
use smallvec::SmallVec;
use std::collections::BTreeMap;
-use tracing::debug;
use crate::MirBorrowckCtxt;
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 176090c3b..34be2874f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
//! Error reporting machinery for lifetime errors.
use rustc_data_structures::fx::FxHashSet;
@@ -23,10 +25,13 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use crate::borrowck_errors;
-use crate::session_diagnostics::GenericDoesNotLiveLongEnough;
+use crate::session_diagnostics::{
+ FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
+ LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
+};
use super::{OutlivesSuggestionBuilder, RegionName};
-use crate::region_infer::BlameConstraint;
+use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
nll::ConstraintDescription,
region_infer::{values::RegionElement, TypeTest},
@@ -229,7 +234,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
let (_, cause) = self.regioncx.find_outlives_blame_span(
- &self.body,
longer_fr,
NllRegionVariableOrigin::Placeholder(placeholder),
error_vid,
@@ -350,10 +354,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
) {
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
- let BlameConstraint { category, cause, variance_info, from_closure: _ } =
- self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
+ let (blame_constraint, extra_info) =
+ self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
});
+ let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;
debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
@@ -462,6 +467,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
+ for extra in extra_info {
+ match extra {
+ ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
+ diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+ }
+ }
+ }
+
self.buffer_error(diag);
}
@@ -488,12 +501,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
- let mut diag = self
- .infcx
- .tcx
- .sess
- .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
-
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
if let ty::Opaque(def_id, _) = *output_ty.kind() {
output_ty = self.infcx.tcx.type_of(def_id)
@@ -501,19 +508,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
debug!("report_fnmut_error: output_ty={:?}", output_ty);
- let message = match output_ty.kind() {
- ty::Closure(_, _) => {
- "returns a closure that contains a reference to a captured variable, which then \
- escapes the closure body"
- }
- ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => {
- "returns an `async` block that contains a reference to a captured variable, which then \
- escapes the closure body"
- }
- _ => "returns a reference to a captured variable which escapes the closure body",
+ let err = FnMutError {
+ span: *span,
+ ty_err: match output_ty.kind() {
+ ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span },
+ ty::Adt(def, _)
+ if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) =>
+ {
+ FnMutReturnTypeErr::ReturnAsyncBlock { span: *span }
+ }
+ _ => FnMutReturnTypeErr::ReturnRef { span: *span },
+ },
};
- diag.span_label(*span, message);
+ let mut diag = self.infcx.tcx.sess.create_err(err);
if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty {
@@ -532,20 +540,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
let upvar_span = upvars_map.get(&def_hir).unwrap().span;
- diag.span_label(upvar_def_span, "variable defined here");
- diag.span_label(upvar_span, "variable captured here");
+ diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span });
+ diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span });
}
}
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
- diag.span_label(fr_span, "inferred to be a `FnMut` closure");
+ diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
}
- diag.note(
- "`FnMut` closures only have access to their captured variables while they are \
- executing...",
- );
- diag.note("...therefore, they cannot allow references to captured variables to escape");
+ self.suggest_move_on_borrowing_closure(&mut diag);
diag
}
@@ -562,6 +566,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// LL | ref_obj(x)
/// | ^^^^^^^^^^ `x` escapes the function body here
/// ```
+ #[instrument(level = "debug", skip(self))]
fn report_escaping_data_error(
&self,
errci: &ErrorConstraintInfo<'tcx>,
@@ -680,42 +685,37 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
..
} = errci;
- let mut diag =
- self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough");
-
let (_, mir_def_name) =
self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id());
+ 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();
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);
- match (category, outlived_fr_is_local, fr_is_local) {
- (ConstraintCategory::Return(_), true, _) => {
- diag.span_label(
- *span,
- format!(
- "{mir_def_name} was supposed to return data with lifetime `{outlived_fr_name}` but it is returning \
- data with lifetime `{fr_name}`",
- ),
- );
- }
- _ => {
- diag.span_label(
- *span,
- format!(
- "{}requires that `{}` must outlive `{}`",
- category.description(),
- fr_name,
- outlived_fr_name,
- ),
- );
- }
- }
+ let err_category = match (category, outlived_fr_is_local, fr_is_local) {
+ (ConstraintCategory::Return(_), true, _) => LifetimeReturnCategoryErr::WrongReturn {
+ span: *span,
+ mir_def_name,
+ outlived_fr_name,
+ fr_name: &fr_name,
+ },
+ _ => LifetimeReturnCategoryErr::ShortReturn {
+ span: *span,
+ category_desc: category.description(),
+ free_region_name: &fr_name,
+ outlived_fr_name,
+ },
+ };
+
+ diag.subdiagnostic(err_category);
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
+ self.suggest_move_on_borrowing_closure(&mut diag);
diag
}
@@ -783,7 +783,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn maybe_suggest_constrain_dyn_trait_impl(
&self,
- diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ diag: &mut Diagnostic,
f: Region<'tcx>,
o: Region<'tcx>,
category: &ConstraintCategory<'tcx>,
@@ -860,7 +860,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
ident.span,
"calling this method introduces the `impl`'s 'static` requirement",
);
- err.span_note(multi_span, "the used `impl` has a `'static` requirement");
+ err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
err.span_suggestion_verbose(
span.shrink_to_hi(),
"consider relaxing the implicit `'static` requirement",
@@ -901,4 +901,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
}
+
+ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
+ let map = self.infcx.tcx.hir();
+ let body_id = map.body_owned_by(self.mir_def_id());
+ let expr = &map.body(body_id).value;
+ let mut closure_span = None::<rustc_span::Span>;
+ match expr.kind {
+ hir::ExprKind::MethodCall(.., args, _) => {
+ for arg in args {
+ if let hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ ..
+ }) = arg.kind
+ {
+ closure_span = Some(arg.span.shrink_to_lo());
+ break;
+ }
+ }
+ }
+ hir::ExprKind::Block(blk, _) => {
+ if let Some(ref expr) = blk.expr {
+ // only when the block is a closure
+ if let hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ ..
+ }) = expr.kind
+ {
+ closure_span = Some(expr.span.shrink_to_lo());
+ }
+ }
+ }
+ _ => {}
+ }
+ if let Some(closure_span) = closure_span {
+ diag.span_suggestion_verbose(
+ closure_span,
+ "consider adding 'move' keyword before the nested closure",
+ "move ",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index a87e8bd5b..6c1eaa809 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -265,7 +265,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// *user* has a name for. In that case, we'll be able to map
/// `fr` to a `Region<'tcx>`, and that region will be one of
/// named variants.
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?;
@@ -357,11 +357,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::BoundRegionKind::BrAnon(_) => None,
},
- ty::ReLateBound(..)
- | ty::ReVar(..)
- | ty::RePlaceholder(..)
- | ty::ReEmpty(_)
- | ty::ReErased => None,
+ ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
}
}
@@ -373,7 +369,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | fn foo(x: &u32) { .. }
/// ------- fully elaborated type of `x` is `&'1 u32`
/// ```
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_arguments(
&self,
fr: RegionVid,
@@ -662,7 +658,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | let x = Some(&22);
/// - fully elaborated type of `x` is `Option<&'1 u32>`
/// ```
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
@@ -682,7 +678,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// must be a closure since, in a free fn, such an argument would
/// have to either also appear in an argument (if using elision)
/// or be early bound (named, not in argument).
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
let tcx = self.infcx.tcx;
let hir = tcx.hir();
@@ -772,7 +768,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
let hir = self.infcx.tcx.hir();
- let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
+ let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else {
span_bug!(
hir_ty.span,
"lowered return type of async fn is not OpaqueDef: {:?}",
@@ -814,7 +810,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
}
}
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_yield_ty(
&self,
fr: RegionVid,
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index ec521b1cf..3157f861d 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -1,6 +1,6 @@
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
+use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
@@ -63,23 +63,24 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
StatementKind::FakeRead(box (_, _)) => {
// Only relevant for initialized/liveness/safety checks.
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+ self.consume_operand(location, op);
+ }
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
ref src,
ref dst,
ref count,
- }) => {
+ })) => {
self.consume_operand(location, src);
self.consume_operand(location, dst);
self.consume_operand(location, count);
}
- StatementKind::Nop
+ // Only relevant for mir typeck
+ StatementKind::AscribeUserType(..)
+ // Doesn't have any language semantics
| StatementKind::Coverage(..)
- | StatementKind::AscribeUserType(..)
- | StatementKind::Retag { .. }
- | StatementKind::StorageLive(..) => {
- // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
- // to borrow check.
- }
+ // Does not actually affect borrowck
+ | StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
location,
@@ -88,7 +89,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
LocalMutationIsAllowed::Yes,
);
}
- StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ StatementKind::Nop
+ | StatementKind::Retag { .. }
+ | StatementKind::Deinit(..)
+ | StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
}
}
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 3d8b07382..86da87d06 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -3,7 +3,7 @@
#![allow(rustc::potential_query_instability)]
#![feature(box_patterns)]
#![feature(let_chains)]
-#![feature(let_else)]
+#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
@@ -19,15 +19,15 @@ extern crate tracing;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::dominators::Dominators;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::ChunkedBitSet;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::{
- traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
- PlaceRef, VarDebugInfoContents,
+ traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
+ Place, PlaceElem, PlaceRef, VarDebugInfoContents,
};
use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
@@ -51,6 +51,8 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveE
use rustc_mir_dataflow::Analysis;
use rustc_mir_dataflow::MoveDataParamEnv;
+use crate::session_diagnostics::VarNeedNotMut;
+
use self::diagnostics::{AccessKind, RegionName};
use self::location::LocationTable;
use self::prefixes::PrefixSet;
@@ -425,17 +427,9 @@ fn do_mir_borrowck<'a, 'tcx>(
continue;
}
- tcx.struct_span_lint_hir(UNUSED_MUT, lint_root, span, |lint| {
- let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
- lint.build("variable does not need to be mutable")
- .span_suggestion_short(
- mut_span,
- "remove this `mut`",
- "",
- Applicability::MachineApplicable,
- )
- .emit();
- })
+ let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
+
+ tcx.emit_spanned_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
}
let tainted_by_errors = mbcx.emit_errors();
@@ -597,22 +591,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
flow_state,
);
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
- ..
- }) => {
- span_bug!(
+ StatementKind::Intrinsic(box ref kind) => match kind {
+ NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
+ NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
span,
"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
)
}
- StatementKind::Nop
+ // Only relevant for mir typeck
+ StatementKind::AscribeUserType(..)
+ // Doesn't have any language semantics
| StatementKind::Coverage(..)
- | StatementKind::AscribeUserType(..)
- | StatementKind::Retag { .. }
- | StatementKind::StorageLive(..) => {
- // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
- // to borrow check.
- }
+ // Does not actually affect borrowck
+ | StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
location,
@@ -622,7 +613,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
flow_state,
);
}
- StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ StatementKind::Nop
+ | StatementKind::Retag { .. }
+ | StatementKind::Deinit(..)
+ | StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
}
}
@@ -982,6 +976,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
+ #[instrument(level = "debug", skip(self, flow_state))]
fn check_access_for_conflict(
&mut self,
location: Location,
@@ -990,11 +985,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
rw: ReadOrWrite,
flow_state: &Flows<'cx, 'tcx>,
) -> bool {
- debug!(
- "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})",
- location, place_span, sd, rw,
- );
-
let mut error_reported = false;
let tcx = self.infcx.tcx;
let body = self.body;
@@ -1458,13 +1448,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Checks whether a borrow of this place is invalidated when the function
/// exits
+ #[instrument(level = "debug", skip(self))]
fn check_for_invalidation_at_exit(
&mut self,
location: Location,
borrow: &BorrowData<'tcx>,
span: Span,
) {
- debug!("check_for_invalidation_at_exit({:?})", borrow);
let place = borrow.borrowed_place;
let mut root_place = PlaceRef { local: place.local, projection: &[] };
diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs
index 70a311694..877944d3d 100644
--- a/compiler/rustc_borrowck/src/location.rs
+++ b/compiler/rustc_borrowck/src/location.rs
@@ -33,7 +33,7 @@ impl LocationTable {
pub(crate) fn new(body: &Body<'_>) -> Self {
let mut num_points = 0;
let statements_before_block = body
- .basic_blocks()
+ .basic_blocks
.iter()
.map(|block_data| {
let v = num_points;
@@ -86,8 +86,7 @@ impl LocationTable {
let (block, &first_index) = self
.statements_before_block
.iter_enumerated()
- .filter(|(_, first_index)| **first_index <= point_index)
- .last()
+ .rfind(|&(_, &first_index)| first_index <= point_index)
.unwrap();
let statement_index = (point_index - first_index) / 2;
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 0961203d7..12b2481cc 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -389,8 +389,9 @@ pub(super) fn dump_annotation<'a, 'tcx>(
// viewing the intraprocedural state, the -Zdump-mir output is
// better.
+ 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(body.span, "external requirements");
+ let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "external requirements");
regioncx.annotate(tcx, &mut err);
@@ -409,7 +410,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
err
} else {
- let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements");
+ let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "no external requirements");
regioncx.annotate(tcx, &mut err);
err
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 97335fd0d..6e5a96bee 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -44,6 +44,7 @@ pub(crate) fn places_conflict<'tcx>(
/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
/// array indices, for example) should be interpreted - this depends on what the caller wants in
/// order to make the conservative choice and preserve soundness.
+#[instrument(level = "debug", skip(tcx, body))]
pub(super) fn borrow_conflicts_with_place<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
@@ -53,11 +54,6 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
access: AccessDepth,
bias: PlaceConflictBias,
) -> bool {
- debug!(
- "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})",
- borrow_place, access_place, access, bias,
- );
-
// This Local/Local case is handled by the more general code below, but
// it's so common that it's a speed win to check for it first.
if let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() {
@@ -140,10 +136,9 @@ fn place_components_conflict<'tcx>(
for (i, (borrow_c, &access_c)) in
iter::zip(borrow_place.projection, access_place.projection).enumerate()
{
- debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
- let borrow_proj_base = &borrow_place.projection[..i];
+ debug!(?borrow_c, ?access_c);
- debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
+ let borrow_proj_base = &borrow_place.projection[..i];
// Borrow and access path both have more components.
//
@@ -180,7 +175,7 @@ fn place_components_conflict<'tcx>(
// idea, at least for now, so just give up and
// report a conflict. This is unsafe code anyway so
// the user could always use raw pointers.
- debug!("borrow_conflicts_with_place: arbitrary -> conflict");
+ debug!("arbitrary -> conflict");
return true;
}
Overlap::EqualOrDisjoint => {
@@ -189,7 +184,7 @@ fn place_components_conflict<'tcx>(
Overlap::Disjoint => {
// We have proven the borrow disjoint - further
// projections will remain disjoint.
- debug!("borrow_conflicts_with_place: disjoint");
+ debug!("disjoint");
return false;
}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 2894c6d29..244e6e342 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -135,7 +135,6 @@ pub struct RegionInferenceContext<'tcx> {
/// adds a new lower bound to the SCC it is analyzing: so you wind up
/// with `'R: 'O` where `'R` is the pick-region and `'O` is the
/// minimal viable option.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct AppliedMemberConstraint {
/// The SCC that was affected. (The "member region".)
///
@@ -246,6 +245,11 @@ enum Trace<'tcx> {
NotVisited,
}
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum ExtraConstraintInfo {
+ PlaceholderFromPredicate(Span),
+}
+
impl<'tcx> RegionInferenceContext<'tcx> {
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
@@ -591,13 +595,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// constraints were too strong, and if so, emit or propagate those errors.
if infcx.tcx.sess.opts.unstable_opts.polonius {
self.check_polonius_subset_errors(
- body,
outlives_requirements.as_mut(),
&mut errors_buffer,
polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"),
);
} else {
- self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer);
+ self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer);
}
if errors_buffer.is_empty() {
@@ -1139,7 +1142,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// include the CFG anyhow.
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
/// a result `'y`.
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
debug!(r = %self.region_value_str(r));
@@ -1151,8 +1154,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
}
- debug!(?lub);
-
lub
}
@@ -1167,8 +1168,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Therefore, this method should only be used in diagnostic code,
/// where displaying *some* named universal region is better than
/// falling back to 'static.
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
- debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
+ debug!("{}", self.region_value_str(r));
// Find the smallest universal region that contains all other
// universal regions within `region`.
@@ -1177,7 +1179,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let static_r = self.universal_regions.fr_static;
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
- debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub);
+ debug!(?ur, ?lub, ?new_lub);
// The upper bound of two non-static regions is static: this
// means we know nothing about the relationship between these
// two regions. Pick a 'better' one to use when constructing
@@ -1201,7 +1203,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
- debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub);
+ debug!(?r, ?lub);
lub
}
@@ -1332,15 +1334,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
// Evaluate whether `sup_region: sub_region`.
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
debug!(
- "eval_outlives: sup_region's value = {:?} universal={:?}",
+ "sup_region's value = {:?} universal={:?}",
self.region_value_str(sup_region),
self.universal_regions.is_universal_region(sup_region),
);
debug!(
- "eval_outlives: sub_region's value = {:?} universal={:?}",
+ "sub_region's value = {:?} universal={:?}",
self.region_value_str(sub_region),
self.universal_regions.is_universal_region(sub_region),
);
@@ -1353,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// true if `'sup` outlives static.
if !self.universe_compatible(sub_region_scc, sup_region_scc) {
debug!(
- "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
+ "sub universe `{sub_region_scc:?}` is not nameable \
by super `{sup_region_scc:?}`, promoting to static",
);
@@ -1374,9 +1376,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
});
if !universal_outlives {
- debug!(
- "eval_outlives: returning false because sub region contains a universal region not present in super"
- );
+ debug!("sub region contains a universal region not present in super");
return false;
}
@@ -1385,15 +1385,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if self.universal_regions.is_universal_region(sup_region) {
// Micro-opt: universal regions contain all points.
- debug!(
- "eval_outlives: returning true because super is universal and hence contains all points"
- );
+ debug!("super is universal and hence contains all points");
return true;
}
- let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
- debug!("returning {} because of comparison between points in sup/sub", result);
- result
+ debug!("comparison between points in sup/sub");
+
+ self.scc_values.contains_points(sup_region_scc, sub_region_scc)
}
/// Once regions have been propagated, this method is used to see
@@ -1415,7 +1413,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// report them as errors.
fn check_universal_regions(
&self,
- body: &Body<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut RegionErrors<'tcx>,
) {
@@ -1426,7 +1423,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// they did not grow too large, accumulating any requirements
// for our caller into the `outlives_requirements` vector.
self.check_universal_region(
- body,
fr,
&mut propagated_outlives_requirements,
errors_buffer,
@@ -1467,7 +1463,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// report them as errors.
fn check_polonius_subset_errors(
&self,
- body: &Body<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut RegionErrors<'tcx>,
polonius_output: Rc<PoloniusOutput>,
@@ -1514,7 +1509,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let propagated = self.try_propagate_universal_region_error(
*longer_fr,
*shorter_fr,
- body,
&mut propagated_outlives_requirements,
);
if propagated == RegionRelationCheckResult::Error {
@@ -1554,13 +1548,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
///
/// Things that are to be propagated are accumulated into the
/// `outlives_requirements` vector.
- #[instrument(
- skip(self, body, propagated_outlives_requirements, errors_buffer),
- level = "debug"
- )]
+ #[instrument(skip(self, propagated_outlives_requirements, errors_buffer), level = "debug")]
fn check_universal_region(
&self,
- body: &Body<'tcx>,
longer_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut RegionErrors<'tcx>,
@@ -1583,7 +1573,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let RegionRelationCheckResult::Error = self.check_universal_region_relation(
longer_fr,
representative,
- body,
propagated_outlives_requirements,
) {
errors_buffer.push(RegionErrorKind::RegionError {
@@ -1603,7 +1592,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let RegionRelationCheckResult::Error = self.check_universal_region_relation(
longer_fr,
shorter_fr,
- body,
propagated_outlives_requirements,
) {
// We only report the first region error. Subsequent errors are hidden so as
@@ -1628,7 +1616,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
- body: &Body<'tcx>,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
) -> RegionRelationCheckResult {
// If it is known that `fr: o`, carry on.
@@ -1644,7 +1631,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.try_propagate_universal_region_error(
longer_fr,
shorter_fr,
- body,
propagated_outlives_requirements,
)
}
@@ -1656,7 +1642,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
- body: &Body<'tcx>,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
) -> RegionRelationCheckResult {
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
@@ -1668,7 +1653,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
let blame_span_category = self.find_outlives_blame_span(
- body,
longer_fr,
NllRegionVariableOrigin::FreeRegion,
shorter_fr,
@@ -1822,50 +1806,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn retrieve_closure_constraint_info(
&self,
- _body: &Body<'tcx>,
- constraint: &OutlivesConstraint<'tcx>,
- ) -> BlameConstraint<'tcx> {
- let loc = match constraint.locations {
- Locations::All(span) => {
- return BlameConstraint {
- category: constraint.category,
- from_closure: false,
- cause: ObligationCause::dummy_with_span(span),
- variance_info: constraint.variance_info,
- };
+ constraint: OutlivesConstraint<'tcx>,
+ ) -> Option<(ConstraintCategory<'tcx>, Span)> {
+ match constraint.locations {
+ Locations::All(_) => None,
+ Locations::Single(loc) => {
+ self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)).copied()
}
- Locations::Single(loc) => loc,
- };
-
- let opt_span_category =
- self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
- opt_span_category
- .map(|&(category, span)| BlameConstraint {
- category,
- from_closure: true,
- cause: ObligationCause::dummy_with_span(span),
- variance_info: constraint.variance_info,
- })
- .unwrap_or(BlameConstraint {
- category: constraint.category,
- from_closure: false,
- cause: ObligationCause::dummy_with_span(constraint.span),
- variance_info: constraint.variance_info,
- })
+ }
}
/// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
pub(crate) fn find_outlives_blame_span(
&self,
- body: &Body<'tcx>,
fr1: RegionVid,
fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid,
) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
- let BlameConstraint { category, cause, .. } =
- self.best_blame_constraint(body, fr1, fr1_origin, |r| {
- self.provides_universal_region(r, fr1, fr2)
- });
+ let BlameConstraint { category, cause, .. } = self
+ .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2))
+ .0;
(category, cause)
}
@@ -1970,7 +1930,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
/// Finds some region R such that `fr1: R` and `R` is live at `elem`.
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
trace!(scc = ?self.constraint_sccs.scc(fr1));
trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
@@ -2048,23 +2008,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// creating a constraint path that forces `R` to outlive
/// `from_region`, and then finding the best choices within that
/// path to blame.
+ #[instrument(level = "debug", skip(self, target_test))]
pub(crate) fn best_blame_constraint(
&self,
- body: &Body<'tcx>,
from_region: RegionVid,
from_region_origin: NllRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool,
- ) -> BlameConstraint<'tcx> {
- debug!(
- "best_blame_constraint(from_region={:?}, from_region_origin={:?})",
- from_region, from_region_origin
- );
-
+ ) -> (BlameConstraint<'tcx>, Vec<ExtraConstraintInfo>) {
// Find all paths
let (path, target_region) =
self.find_constraint_paths_between_regions(from_region, target_test).unwrap();
debug!(
- "best_blame_constraint: path={:#?}",
+ "path={:#?}",
path.iter()
.map(|c| format!(
"{:?} ({:?}: {:?})",
@@ -2075,6 +2030,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.collect::<Vec<_>>()
);
+ let mut extra_info = vec![];
+ for constraint in path.iter() {
+ let outlived = constraint.sub;
+ let Some(origin) = self.var_infos.get(outlived) else { continue; };
+ let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin else { continue; };
+ debug!(?constraint, ?p);
+ let ConstraintCategory::Predicate(span) = constraint.category else { continue; };
+ extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span));
+ // We only want to point to one
+ break;
+ }
+
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
// Instead, we use it to produce an improved `ObligationCauseCode`.
// FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
@@ -2100,23 +2067,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
.iter()
.map(|constraint| {
- if constraint.category == ConstraintCategory::ClosureBounds {
- self.retrieve_closure_constraint_info(body, &constraint)
- } else {
- BlameConstraint {
- category: constraint.category,
- from_closure: false,
- cause: ObligationCause::new(
- constraint.span,
- CRATE_HIR_ID,
- cause_code.clone(),
- ),
- variance_info: constraint.variance_info,
- }
+ let (category, span, from_closure, cause_code) =
+ if constraint.category == ConstraintCategory::ClosureBounds {
+ if let Some((category, span)) =
+ self.retrieve_closure_constraint_info(*constraint)
+ {
+ (category, span, true, ObligationCauseCode::MiscObligation)
+ } else {
+ (
+ constraint.category,
+ constraint.span,
+ false,
+ ObligationCauseCode::MiscObligation,
+ )
+ }
+ } else {
+ (constraint.category, constraint.span, false, cause_code.clone())
+ };
+ BlameConstraint {
+ category,
+ from_closure,
+ cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code),
+ variance_info: constraint.variance_info,
+ outlives_constraint: *constraint,
}
})
.collect();
- debug!("best_blame_constraint: categorized_path={:#?}", categorized_path);
+ debug!("categorized_path={:#?}", categorized_path);
// To find the best span to cite, we first try to look for the
// final constraint that is interesting and where the `sup` is
@@ -2214,10 +2191,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let best_choice =
if blame_source { range.rev().find(find_region) } else { range.find(find_region) };
- debug!(
- "best_blame_constraint: best_choice={:?} blame_source={}",
- best_choice, blame_source
- );
+ debug!(?best_choice, ?blame_source, ?extra_info);
if let Some(i) = best_choice {
if let Some(next) = categorized_path.get(i + 1) {
@@ -2226,7 +2200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
{
// The return expression is being influenced by the return type being
// impl Trait, point at the return type and not the return expr.
- return next.clone();
+ return (next.clone(), extra_info);
}
}
@@ -2246,7 +2220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
- return categorized_path[i].clone();
+ return (categorized_path[i].clone(), extra_info);
}
// If that search fails, that is.. unusual. Maybe everything
@@ -2254,9 +2228,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// appears to be the most interesting point to report to the
// user via an even more ad-hoc guess.
categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
- debug!("best_blame_constraint: sorted_path={:#?}", categorized_path);
+ debug!("sorted_path={:#?}", categorized_path);
- categorized_path.remove(0)
+ (categorized_path.remove(0), extra_info)
}
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
@@ -2338,7 +2312,13 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
outlives_requirement={:?}",
region, outlived_region, outlives_requirement,
);
- ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region))
+ (
+ ty::Binder::dummy(ty::OutlivesPredicate(
+ region.into(),
+ outlived_region,
+ )),
+ ConstraintCategory::BoringNoLocation,
+ )
}
ClosureOutlivesSubject::Ty(ty) => {
@@ -2348,7 +2328,10 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
outlives_requirement={:?}",
ty, outlived_region, outlives_requirement,
);
- ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region))
+ (
+ ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)),
+ ConstraintCategory::BoringNoLocation,
+ )
}
}
})
@@ -2362,4 +2345,5 @@ pub struct BlameConstraint<'tcx> {
pub from_closure: bool,
pub cause: ObligationCause<'tcx>,
pub variance_info: ty::VarianceDiagInfo<'tcx>,
+ pub outlives_constraint: OutlivesConstraint<'tcx>,
}
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index d6712b6a4..9d088642f 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -16,6 +16,8 @@ use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::TraitEngineExt as _;
+use crate::session_diagnostics::ConstNotUsedTraitAlias;
+
use super::RegionInferenceContext;
impl<'tcx> RegionInferenceContext<'tcx> {
@@ -58,7 +60,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
/// which has no `external_name` in which case we use `'empty` as the
/// region to pass to `infer_opaque_definition_from_instantiation`.
- #[instrument(level = "debug", skip(self, infcx))]
+ #[instrument(level = "debug", skip(self, infcx), ret)]
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'_, 'tcx>,
@@ -107,7 +109,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.iter()
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
- .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
+ .unwrap_or(infcx.tcx.lifetimes.re_erased),
_ => region,
});
@@ -431,7 +433,7 @@ struct ReverseMapper<'tcx> {
key: ty::OpaqueTypeKey<'tcx>,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
- map_missing_regions_to_empty: bool,
+ do_not_error: bool,
/// initially `Some`, set to `None` once error has been reported
hidden_ty: Option<Ty<'tcx>>,
@@ -448,29 +450,19 @@ impl<'tcx> ReverseMapper<'tcx> {
hidden_ty: Ty<'tcx>,
span: Span,
) -> Self {
- Self {
- tcx,
- key,
- map,
- map_missing_regions_to_empty: false,
- hidden_ty: Some(hidden_ty),
- span,
- }
+ Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span }
}
- fn fold_kind_mapping_missing_regions_to_empty(
- &mut self,
- kind: GenericArg<'tcx>,
- ) -> GenericArg<'tcx> {
- assert!(!self.map_missing_regions_to_empty);
- self.map_missing_regions_to_empty = true;
+ fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
+ assert!(!self.do_not_error);
+ self.do_not_error = true;
let kind = kind.fold_with(self);
- self.map_missing_regions_to_empty = false;
+ self.do_not_error = false;
kind
}
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
- assert!(!self.map_missing_regions_to_empty);
+ assert!(!self.do_not_error);
kind.fold_with(self)
}
}
@@ -494,9 +486,9 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
ty::ReErased => return r,
// The regions that we expect from borrow checking.
- ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
+ ty::ReEarlyBound(_) | ty::ReFree(_) => {}
- ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
+ ty::RePlaceholder(_) | ty::ReVar(_) => {
// All of the regions in the type should either have been
// erased by writeback, or mapped back to named regions by
// borrow checking.
@@ -508,7 +500,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
match self.map.get(&r.into()).map(|k| k.unpack()) {
Some(GenericArgKind::Lifetime(r1)) => r1,
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
- None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
+ None if self.do_not_error => self.tcx.lifetimes.re_static,
None if generics.parent.is_some() => {
if let Some(hidden_ty) = self.hidden_ty.take() {
unexpected_hidden_region_diagnostic(
@@ -520,7 +512,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
)
.emit();
}
- self.tcx.lifetimes.re_root_empty
+ self.tcx.lifetimes.re_static
}
None => {
self.tcx
@@ -572,7 +564,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
if index < generics.parent_count {
// Accommodate missing regions in the parent kinds...
- self.fold_kind_mapping_missing_regions_to_empty(kind)
+ self.fold_kind_no_missing_regions_error(kind)
} else {
// ...but not elsewhere.
self.fold_kind_normally(kind)
@@ -587,7 +579,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
if index < generics.parent_count {
// Accommodate missing regions in the parent kinds...
- self.fold_kind_mapping_missing_regions_to_empty(kind)
+ self.fold_kind_no_missing_regions_error(kind)
} else {
// ...but not elsewhere.
self.fold_kind_normally(kind)
@@ -639,17 +631,10 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
Some(GenericArgKind::Const(c1)) => c1,
Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
None => {
- self.tcx
- .sess
- .struct_span_err(
- self.span,
- &format!(
- "const parameter `{}` is part of concrete type but not \
- used in parameter list for the `impl Trait` type alias",
- ct
- ),
- )
- .emit();
+ self.tcx.sess.emit_err(ConstNotUsedTraitAlias {
+ ct: ct.to_string(),
+ span: self.span,
+ });
self.tcx().const_error(ct.ty())
}
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index c81ef10f7..de20a4bb4 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -25,7 +25,7 @@ impl RegionValueElements {
pub(crate) fn new(body: &Body<'_>) -> Self {
let mut num_points = 0;
let statements_before_block: IndexVec<BasicBlock, usize> = body
- .basic_blocks()
+ .basic_blocks
.iter()
.map(|block_data| {
let v = num_points;
@@ -37,7 +37,7 @@ impl RegionValueElements {
debug!("RegionValueElements: num_points={:#?}", num_points);
let mut basic_blocks = IndexVec::with_capacity(num_points);
- for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
+ for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
}
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 7a8ce621c..63b2088f7 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -2,6 +2,7 @@ use rustc_index::vec::IndexVec;
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::mir::visit::{MutVisitor, TyContext};
use rustc_middle::mir::{Body, Location, Promoted};
+use rustc_middle::mir::{Constant, ConstantKind};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -37,6 +38,21 @@ where
})
}
+// FIXME(valtrees): This function is necessary because `fold_regions`
+// panics for mir constants in the visitor.
+//
+// Once `visit_mir_constant` is removed we can also remove this function
+// and just use `renumber_regions`.
+fn renumber_regions_in_mir_constant<'tcx>(
+ infcx: &InferCtxt<'_, 'tcx>,
+ value: ConstantKind<'tcx>,
+) -> ConstantKind<'tcx> {
+ infcx.tcx.super_fold_regions(value, |_region, _depth| {
+ let origin = NllRegionVariableOrigin::Existential { from_forall: false };
+ infcx.next_nll_region_var(origin)
+ })
+}
+
struct NllVisitor<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
}
@@ -48,6 +64,13 @@ impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
{
renumber_regions(self.infcx, value)
}
+
+ fn renumber_regions_in_mir_constant(
+ &mut self,
+ value: ConstantKind<'tcx>,
+ ) -> ConstantKind<'tcx> {
+ renumber_regions_in_mir_constant(self.infcx, value)
+ }
}
impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
@@ -77,7 +100,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
debug!(?region);
}
- fn visit_const(&mut self, constant: &mut ty::Const<'tcx>, _location: Location) {
- *constant = self.renumber_regions(*constant);
+ #[instrument(skip(self), level = "debug")]
+ fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) {
+ let literal = constant.literal;
+ constant.literal = self.renumber_regions_in_mir_constant(literal);
+ debug!("constant: {:#?}", constant);
}
}
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 895723d44..5d750c6ca 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -1,9 +1,12 @@
-use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_errors::{IntoDiagnosticArg, MultiSpan};
+use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::Span;
+use crate::diagnostics::RegionName;
+
#[derive(SessionDiagnostic)]
-#[error(borrowck::move_unsized, code = "E0161")]
+#[diag(borrowck::move_unsized, code = "E0161")]
pub(crate) struct MoveUnsized<'tcx> {
pub ty: Ty<'tcx>,
#[primary_span]
@@ -12,7 +15,7 @@ pub(crate) struct MoveUnsized<'tcx> {
}
#[derive(SessionDiagnostic)]
-#[error(borrowck::higher_ranked_lifetime_error)]
+#[diag(borrowck::higher_ranked_lifetime_error)]
pub(crate) struct HigherRankedLifetimeError {
#[subdiagnostic]
pub cause: Option<HigherRankedErrorCause>,
@@ -29,16 +32,128 @@ pub(crate) enum HigherRankedErrorCause {
}
#[derive(SessionDiagnostic)]
-#[error(borrowck::higher_ranked_subtype_error)]
+#[diag(borrowck::higher_ranked_subtype_error)]
pub(crate) struct HigherRankedSubtypeError {
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
-#[error(borrowck::generic_does_not_live_long_enough)]
+#[diag(borrowck::generic_does_not_live_long_enough)]
pub(crate) struct GenericDoesNotLiveLongEnough {
pub kind: String,
#[primary_span]
pub span: Span,
}
+
+#[derive(LintDiagnostic)]
+#[diag(borrowck::var_does_not_need_mut)]
+pub(crate) struct VarNeedNotMut {
+ #[suggestion_short(applicability = "machine-applicable", code = "")]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(borrowck::const_not_used_in_type_alias)]
+pub(crate) struct ConstNotUsedTraitAlias {
+ pub ct: String,
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(borrowck::var_cannot_escape_closure)]
+#[note]
+#[note(borrowck::cannot_escape)]
+pub(crate) struct FnMutError {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub ty_err: FnMutReturnTypeErr,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum VarHereDenote {
+ #[label(borrowck::var_here_captured)]
+ Captured {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(borrowck::var_here_defined)]
+ Defined {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(borrowck::closure_inferred_mut)]
+ FnMutInferred {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum FnMutReturnTypeErr {
+ #[label(borrowck::returned_closure_escaped)]
+ ReturnClosure {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(borrowck::returned_async_block_escaped)]
+ ReturnAsyncBlock {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(borrowck::returned_ref_escaped)]
+ ReturnRef {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(borrowck::lifetime_constraints_error)]
+pub(crate) struct LifetimeOutliveErr {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum LifetimeReturnCategoryErr<'a> {
+ #[label(borrowck::returned_lifetime_wrong)]
+ WrongReturn {
+ #[primary_span]
+ span: Span,
+ mir_def_name: &'a str,
+ outlived_fr_name: RegionName,
+ fr_name: &'a RegionName,
+ },
+ #[label(borrowck::returned_lifetime_short)]
+ ShortReturn {
+ #[primary_span]
+ span: Span,
+ category_desc: &'static str,
+ free_region_name: &'a RegionName,
+ outlived_fr_name: RegionName,
+ },
+}
+
+impl IntoDiagnosticArg for &RegionName {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ format!("{}", self).into_diagnostic_arg()
+ }
+}
+
+impl IntoDiagnosticArg for RegionName {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ format!("{}", self).into_diagnostic_arg()
+ }
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum RequireStaticErr {
+ #[note(borrowck::used_impl_require_static)]
+ UsedImpl {
+ #[primary_span]
+ multi_span: MultiSpan,
+ },
+}
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 6cfe5efb6..9271a2f4d 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -24,8 +24,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
/// **Any `rustc_infer::infer` operations that might generate region
/// constraints should occur within this method so that those
/// constraints can be properly localized!**
- #[instrument(skip(self, category, op), level = "trace")]
- pub(super) fn fully_perform_op<R, Op>(
+ #[instrument(skip(self, op), level = "trace")]
+ pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
&mut self,
locations: Locations,
category: ConstraintCategory<'tcx>,
@@ -39,6 +39,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
+ debug!(?output, ?constraints);
+
if let Some(data) = constraints {
self.push_region_constraints(locations, category, data);
}
@@ -90,17 +92,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
locations: Locations,
category: ConstraintCategory<'tcx>,
) {
- self.prove_predicates(
- Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
+ self.prove_predicate(
+ ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
polarity: ty::ImplPolarity::Positive,
- }))),
+ }))
+ .to_predicate(self.tcx()),
locations,
category,
);
}
+ #[instrument(level = "debug", skip(self))]
pub(super) fn normalize_and_prove_instantiated_predicates(
&mut self,
// Keep this parameter for now, in case we start using
@@ -115,8 +119,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.zip(instantiated_predicates.spans.into_iter())
{
debug!(?predicate);
- let predicate = self.normalize(predicate, locations);
- self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
+ let category = ConstraintCategory::Predicate(span);
+ let predicate = self.normalize_with_category(predicate, locations, category);
+ self.prove_predicate(predicate, locations, category);
}
}
@@ -152,15 +157,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
})
}
- #[instrument(skip(self), level = "debug")]
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
where
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
{
+ self.normalize_with_category(value, location, ConstraintCategory::Boring)
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ pub(super) fn normalize_with_category<T>(
+ &mut self,
+ value: T,
+ location: impl NormalizeLocation,
+ category: ConstraintCategory<'tcx>,
+ ) -> T
+ where
+ T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
+ {
let param_env = self.param_env;
self.fully_perform_op(
location.to_locations(),
- ConstraintCategory::Boring,
+ category,
param_env.and(type_op::normalize::Normalize::new(value)),
)
.unwrap_or_else(|NoSolution| {
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 167960918..71eae0583 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{Span, DUMMY_SP};
@@ -86,7 +86,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
}
- pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
+ fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
debug!("generate: constraints at: {:#?}", self.locations);
// Extract out various useful fields we'll need below.
@@ -98,34 +98,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// region constraints like `for<'a> 'a: 'b`. At some point
// when we move to universes, we will, and this assertion
// will start to fail.
- let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound vars", query_constraint,);
- });
+ let ty::OutlivesPredicate(k1, r2) =
+ query_constraint.0.no_bound_vars().unwrap_or_else(|| {
+ bug!("query_constraint {:?} contained bound vars", query_constraint,);
+ });
+
+ let constraint_category = query_constraint.1;
match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
let r1_vid = self.to_region_vid(r1);
let r2_vid = self.to_region_vid(r2);
- self.add_outlives(r1_vid, r2_vid);
+ self.add_outlives(r1_vid, r2_vid, constraint_category);
}
- GenericArgKind::Type(mut t1) => {
+ GenericArgKind::Type(t1) => {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
- // Placeholder regions need to be converted now because it may
- // create new region variables, which can't be done later when
- // verifying these bounds.
- if t1.has_placeholders() {
- t1 = tcx.fold_regions(t1, |r, _| match *r {
- ty::RePlaceholder(placeholder) => {
- self.constraints.placeholder_region(self.infcx, placeholder)
- }
- _ => r,
- });
- }
-
TypeOutlives::new(
&mut *self,
tcx,
@@ -133,7 +124,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
Some(implicit_region_bound),
param_env,
)
- .type_must_outlive(origin, t1, r2);
+ .type_must_outlive(origin, t1, r2, constraint_category);
}
GenericArgKind::Const(_) => {
@@ -143,6 +134,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
}
+ /// Placeholder regions need to be converted eagerly because it may
+ /// create new region variables, which we must not do when verifying
+ /// our region bounds.
+ ///
+ /// FIXME: This should get removed once higher ranked region obligations
+ /// are dealt with during trait solving.
+ fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+ if value.has_placeholders() {
+ self.tcx.fold_regions(value, |r, _| match *r {
+ ty::RePlaceholder(placeholder) => {
+ self.constraints.placeholder_region(self.infcx, placeholder)
+ }
+ _ => r,
+ })
+ } else {
+ value
+ }
+ }
+
fn verify_to_type_test(
&mut self,
generic_kind: GenericKind<'tcx>,
@@ -150,7 +160,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
verify_bound: VerifyBound<'tcx>,
) -> TypeTest<'tcx> {
let lower_bound = self.to_region_vid(region);
-
TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
}
@@ -162,10 +171,19 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
}
- fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
+ fn add_outlives(
+ &mut self,
+ sup: ty::RegionVid,
+ sub: ty::RegionVid,
+ category: ConstraintCategory<'tcx>,
+ ) {
+ let category = match self.category {
+ ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
+ _ => self.category,
+ };
self.constraints.outlives_constraints.push(OutlivesConstraint {
locations: self.locations,
- category: self.category,
+ category,
span: self.span,
sub,
sup,
@@ -185,10 +203,11 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
_origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
+ constraint_category: ConstraintCategory<'tcx>,
) {
let b = self.to_region_vid(b);
let a = self.to_region_vid(a);
- self.add_outlives(b, a);
+ self.add_outlives(b, a, constraint_category);
}
fn push_verify(
@@ -198,6 +217,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
a: ty::Region<'tcx>,
bound: VerifyBound<'tcx>,
) {
+ let kind = self.replace_placeholders_with_nll(kind);
+ let bound = self.replace_placeholders_with_nll(bound);
let type_test = self.verify_to_type_test(kind, a, bound);
self.add_type_test(type_test);
}
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 cc0318ede..f1b1c33a1 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -1,5 +1,5 @@
use rustc_data_structures::frozen::Frozen;
-use rustc_data_structures::transitive_relation::TransitiveRelation;
+use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -61,25 +61,13 @@ pub(crate) fn create<'tcx>(
constraints,
universal_regions: universal_regions.clone(),
region_bound_pairs: Default::default(),
- relations: UniversalRegionRelations {
- universal_regions: universal_regions.clone(),
- outlives: Default::default(),
- inverse_outlives: Default::default(),
- },
+ outlives: Default::default(),
+ inverse_outlives: Default::default(),
}
.create()
}
impl UniversalRegionRelations<'_> {
- /// Records in the `outlives_relation` (and
- /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
- /// builder below.
- fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
- debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
- self.outlives.add(fr_a, fr_b);
- self.inverse_outlives.add(fr_b, fr_a);
- }
-
/// Given two universal regions, returns the postdominating
/// upper-bound (effectively the least upper bound).
///
@@ -216,11 +204,20 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> {
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
// outputs:
- relations: UniversalRegionRelations<'tcx>,
+ outlives: TransitiveRelationBuilder<RegionVid>,
+ inverse_outlives: TransitiveRelationBuilder<RegionVid>,
region_bound_pairs: RegionBoundPairs<'tcx>,
}
impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
+ /// Records in the `outlives_relation` (and
+ /// `inverse_outlives_relation`) that `fr_a: fr_b`.
+ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
+ debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
+ self.outlives.add(fr_a, fr_b);
+ self.inverse_outlives.add(fr_b, fr_a);
+ }
+
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
let unnormalized_input_output_tys = self
.universal_regions
@@ -242,10 +239,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let constraint_sets: Vec<_> = unnormalized_input_output_tys
.flat_map(|ty| {
debug!("build: input_or_output={:?}", ty);
- // We only add implied bounds for the normalized type as the unnormalized
- // type may not actually get checked by the caller.
- //
- // Can otherwise be unsound, see #91068.
+ // We add implied bounds from both the unnormalized and normalized ty.
+ // See issue #87748
+ let constraints_implied1 = self.add_implied_bounds(ty);
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
@@ -269,13 +265,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// }
// impl Foo for () {
// type Bar = ();
- // fn foo(&self) ->&() {}
+ // fn foo(&self) -> &() {}
// }
// ```
// Both &Self::Bar and &() are WF
- let constraints_implied = self.add_implied_bounds(norm_ty);
+ let constraints_implied2 =
+ if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
normalized_inputs_and_output.push(norm_ty);
- constraints1.into_iter().chain(constraints_implied)
+ constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
})
.collect();
@@ -292,9 +289,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let fr_fn_body = self.universal_regions.fr_fn_body;
for fr in self.universal_regions.universal_regions() {
debug!("build: relating free region {:?} to itself and to 'static", fr);
- self.relations.relate_universal_regions(fr, fr);
- self.relations.relate_universal_regions(fr_static, fr);
- self.relations.relate_universal_regions(fr, fr_fn_body);
+ self.relate_universal_regions(fr, fr);
+ self.relate_universal_regions(fr_static, fr);
+ self.relate_universal_regions(fr, fr_fn_body);
}
for data in &constraint_sets {
@@ -313,7 +310,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
CreateResult {
- universal_region_relations: Frozen::freeze(self.relations),
+ universal_region_relations: Frozen::freeze(UniversalRegionRelations {
+ universal_regions: self.universal_regions,
+ outlives: self.outlives.freeze(),
+ inverse_outlives: self.inverse_outlives.freeze(),
+ }),
region_bound_pairs: self.region_bound_pairs,
normalized_inputs_and_output,
}
@@ -346,17 +347,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
match outlives_bound {
OutlivesBound::RegionSubRegion(r1, r2) => {
- // `where Type:` is lowered to `where Type: 'empty` so that
- // we check `Type` is well formed, but there's no use for
- // this bound here.
- if r1.is_empty() {
- return;
- }
-
// The bound says that `r1 <= r2`; we store `r2: r1`.
let r1 = self.universal_regions.to_region_vid(r1);
let r2 = self.universal_regions.to_region_vid(r2);
- self.relations.relate_universal_regions(r2, r1);
+ self.relate_universal_regions(r2, r1);
}
OutlivesBound::RegionSubParam(r_a, param_b) => {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d32b1edcd..3713ec3f5 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
- self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
- OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
+ self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
+ OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType,
+ UserTypeAnnotationIndex,
};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP};
@@ -178,97 +179,15 @@ pub(crate) fn type_check<'mir, 'tcx>(
upvars,
};
- let opaque_type_values = type_check_internal(
+ let mut checker = TypeChecker::new(
infcx,
- param_env,
body,
- promoted,
+ param_env,
&region_bound_pairs,
implicit_region_bound,
&mut borrowck_context,
- |mut cx| {
- debug!("inside extra closure of type_check_internal");
- cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
- liveness::generate(
- &mut cx,
- body,
- elements,
- flow_inits,
- move_data,
- location_table,
- use_polonius,
- );
-
- translate_outlives_facts(&mut cx);
- let opaque_type_values =
- infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-
- opaque_type_values
- .into_iter()
- .map(|(opaque_type_key, decl)| {
- cx.fully_perform_op(
- Locations::All(body.span),
- ConstraintCategory::OpaqueType,
- CustomTypeOp::new(
- |infcx| {
- infcx.register_member_constraints(
- param_env,
- opaque_type_key,
- decl.hidden_type.ty,
- decl.hidden_type.span,
- );
- Ok(InferOk { value: (), obligations: vec![] })
- },
- || "opaque_type_map".to_string(),
- ),
- )
- .unwrap();
- 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_infer_types_or_consts() {
- infcx.tcx.sess.delay_span_bug(
- decl.hidden_type.span,
- &format!("could not resolve {:#?}", hidden_type.ty.kind()),
- );
- hidden_type.ty = infcx.tcx.ty_error();
- }
-
- (opaque_type_key, (hidden_type, decl.origin))
- })
- .collect()
- },
);
- MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
-}
-
-#[instrument(
- skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra),
- level = "debug"
-)]
-fn type_check_internal<'a, 'tcx, R>(
- infcx: &'a InferCtxt<'a, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- body: &'a Body<'tcx>,
- promoted: &'a IndexVec<Promoted, Body<'tcx>>,
- region_bound_pairs: &'a RegionBoundPairs<'tcx>,
- implicit_region_bound: ty::Region<'tcx>,
- borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
- extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
-) -> R {
- debug!("body: {:#?}", body);
- let mut checker = TypeChecker::new(
- infcx,
- body,
- param_env,
- region_bound_pairs,
- implicit_region_bound,
- borrowck_context,
- );
let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);
@@ -280,7 +199,56 @@ fn type_check_internal<'a, 'tcx, R>(
checker.typeck_mir(body);
}
- extra(checker)
+ checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
+ liveness::generate(
+ &mut checker,
+ body,
+ elements,
+ flow_inits,
+ move_data,
+ location_table,
+ use_polonius,
+ );
+
+ translate_outlives_facts(&mut checker);
+ let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+
+ let opaque_type_values = opaque_type_values
+ .into_iter()
+ .map(|(opaque_type_key, decl)| {
+ checker
+ .fully_perform_op(
+ Locations::All(body.span),
+ ConstraintCategory::OpaqueType,
+ CustomTypeOp::new(
+ |infcx| {
+ infcx.register_member_constraints(
+ param_env,
+ opaque_type_key,
+ decl.hidden_type.ty,
+ decl.hidden_type.span,
+ );
+ Ok(InferOk { value: (), obligations: vec![] })
+ },
+ || "opaque_type_map".to_string(),
+ ),
+ )
+ .unwrap();
+ 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_infer_types_or_consts() {
+ infcx.tcx.sess.delay_span_bug(
+ decl.hidden_type.span,
+ &format!("could not resolve {:#?}", hidden_type.ty.kind()),
+ );
+ hidden_type.ty = infcx.tcx.ty_error();
+ }
+
+ (opaque_type_key, (hidden_type, decl.origin))
+ })
+ .collect();
+
+ MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
}
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
@@ -344,6 +312,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
+ debug!(?constant, ?location, "visit_constant");
+
self.super_constant(constant, location);
let ty = self.sanitize_type(constant, constant.literal.ty());
@@ -387,11 +357,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
let tcx = self.tcx();
let maybe_uneval = match constant.literal {
ConstantKind::Ty(ct) => match ct.kind() {
- ty::ConstKind::Unevaluated(uv) => Some(uv),
+ ty::ConstKind::Unevaluated(_) => {
+ bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct)
+ }
_ => None,
},
+ ConstantKind::Unevaluated(uv, _) => Some(uv),
_ => None,
};
+
if let Some(uv) = maybe_uneval {
if let Some(promoted) = uv.promoted {
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
@@ -1076,6 +1050,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
+ debug!(?annotation);
match annotation {
UserType::Ty(mut ty) => {
ty = self.normalize(ty, Locations::All(span));
@@ -1334,12 +1309,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
- ..
- }) => span_bug!(
- stmt.source_info.span,
- "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
- ),
+ StatementKind::Intrinsic(box ref kind) => match kind {
+ NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location),
+ NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
+ stmt.source_info.span,
+ "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics",
+ ),
+ },
StatementKind::FakeRead(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
@@ -1448,9 +1424,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
))
});
debug!(?sig);
- let sig = self.normalize(sig, term_location);
- self.check_call_dest(body, term, &sig, *destination, target, term_location);
-
+ // IMPORTANT: We have to prove well formed for the function signature before
+ // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
+ // get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
+ //
+ // Normalization results in a well formed type if the input is well formed, so we
+ // don't have to check it twice.
+ //
+ // See #91068 for an example.
self.prove_predicates(
sig.inputs_and_output
.iter()
@@ -1458,6 +1439,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
term_location.to_locations(),
ConstraintCategory::Boring,
);
+ let sig = self.normalize(sig, term_location);
+ self.check_call_dest(body, term, &sig, *destination, target, term_location);
// The ordinary liveness rules will ensure that all
// regions in the type of the callee are live here. We
@@ -1834,14 +1817,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+ debug!(?op, ?location, "check_operand");
+
if let Operand::Constant(constant) = op {
let maybe_uneval = match constant.literal {
- ConstantKind::Ty(ct) => match ct.kind() {
- ty::ConstKind::Unevaluated(uv) => Some(uv),
- _ => None,
- },
- _ => None,
+ ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
+ ConstantKind::Unevaluated(uv, _) => Some(uv),
};
+
if let Some(uv) = maybe_uneval {
if uv.promoted.is_none() {
let tcx = self.tcx();
@@ -1904,7 +1887,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
- &Rvalue::NullaryOp(_, ty) => {
+ &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => {
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]),
@@ -2033,6 +2016,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
+ CastKind::DynStar => {
+ // get the constraints from the target type (`dyn* Clone`)
+ //
+ // apply them to prove that the source type `Foo` implements `Clone` etc
+ let (existential_predicates, region) = match ty.kind() {
+ Dynamic(predicates, region, ty::DynStar) => (predicates, region),
+ _ => panic!("Invalid dyn* cast_ty"),
+ };
+
+ let self_ty = op.ty(body, tcx);
+
+ self.prove_predicates(
+ existential_predicates
+ .iter()
+ .map(|predicate| predicate.with_self_ty(tcx, self_ty)),
+ location.to_locations(),
+ ConstraintCategory::Cast,
+ );
+
+ let outlives_predicate =
+ tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
+ ty::OutlivesPredicate(self_ty, *region),
+ )));
+ self.prove_predicate(
+ outlives_predicate,
+ location.to_locations(),
+ ConstraintCategory::Cast,
+ );
+ }
+
CastKind::Pointer(PointerCast::MutToConstPointer) => {
let ty::RawPtr(ty::TypeAndMut {
ty: ty_from,
@@ -2584,7 +2597,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.enumerate()
.filter_map(|(idx, constraint)| {
let ty::OutlivesPredicate(k1, r2) =
- constraint.no_bound_vars().unwrap_or_else(|| {
+ constraint.0.no_bound_vars().unwrap_or_else(|| {
bug!("query_constraint {:?} contained bound vars", constraint,);
});
@@ -2659,7 +2672,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.check_local(&body, local, local_decl);
}
- for (block, block_data) in body.basic_blocks().iter_enumerated() {
+ for (block, block_data) in body.basic_blocks.iter_enumerated() {
let mut location = Location { block, statement_index: 0 };
for stmt in &block_data.statements {
if !stmt.source_info.span.is_dummy() {
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 2a7713bc4..8cf9ed53d 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -54,13 +54,6 @@ pub struct UniversalRegions<'tcx> {
/// The total number of universal region variables instantiated.
num_universals: usize,
- /// A special region variable created for the `'empty(U0)` region.
- /// Note that this is **not** a "universal" region, as it doesn't
- /// represent a universally bound placeholder or any such thing.
- /// But we do create it here in this type because it's a useful region
- /// to have around in a few limited cases.
- pub root_empty: RegionVid,
-
/// The "defining" type for this function, with all universal
/// regions instantiated. For a closure or generator, this is the
/// closure type, but for a top-level function it's the `FnDef`.
@@ -323,11 +316,7 @@ impl<'tcx> UniversalRegions<'tcx> {
/// See `UniversalRegionIndices::to_region_vid`.
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
- if let ty::ReEmpty(ty::UniverseIndex::ROOT) = *r {
- self.root_empty
- } else {
- self.indices.to_region_vid(r)
- }
+ self.indices.to_region_vid(r)
}
/// As part of the NLL unit tests, you can annotate a function with
@@ -501,16 +490,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
_ => None,
};
- let root_empty = self
- .infcx
- .next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true })
- .to_region_vid();
-
UniversalRegions {
indices,
fr_static,
fr_fn_body,
- root_empty,
first_extern_index,
first_local_index,
num_universals,
@@ -768,10 +751,9 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
) {
- debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
- debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
+ debug!(?r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
debug!(?region_vid);