diff options
Diffstat (limited to 'compiler/rustc_borrowck/src')
32 files changed, 693 insertions, 488 deletions
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 952e18c1e57..4a9904891ec 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -84,7 +84,7 @@ pub enum LocalsStateAtExit { } impl LocalsStateAtExit { - fn build( + fn build<'tcx>( locals_are_invalidated_at_exit: bool, body: &Body<'tcx>, move_data: &MoveData<'tcx>, diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 98378a98684..d41143ee763 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -72,7 +72,7 @@ impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> { } } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(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 diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 7db8d4520d4..f0036f09c38 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -5,10 +5,9 @@ use rustc_middle::ty::RegionVid; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; use rustc_mir_dataflow::ResultsVisitable; -use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill}; +use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill}; use rustc_mir_dataflow::{Analysis, Direction, Results}; use std::fmt; -use std::iter; use crate::{ places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, @@ -385,14 +384,6 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { self.kill_borrows_on_place(trans, Place::from(local)); } - mir::StatementKind::LlvmInlineAsm(ref asm) => { - for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) { - if !kind.is_indirect && !kind.is_rw { - self.kill_borrows_on_place(trans, *output); - } - } - } - mir::StatementKind::FakeRead(..) | mir::StatementKind::SetDiscriminant { .. } | mir::StatementKind::StorageLive(..) @@ -434,9 +425,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { &self, _trans: &mut impl GenKill<Self::Idx>, _block: mir::BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - _dest_place: mir::Place<'tcx>, + _return_places: CallReturnPlaces<'_, 'tcx>, ) { } } diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index 689ec249a2f..eec994f88b9 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -16,9 +16,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> { PlaceContext::MutatingUse(MutatingUseContext::Store) | - // This is potentially both a def and a use... - PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | - // We let Call define the result in both the success and // unwind cases. This is not really correct, however it // does not seem to be observable due to the way that we @@ -26,6 +23,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> { // the def in call only to the input from the success // path and not the unwind path. -nmatsakis PlaceContext::MutatingUse(MutatingUseContext::Call) | + PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | PlaceContext::MutatingUse(MutatingUseContext::Yield) | // Storage live and storage dead aren't proper defines, but we can ignore diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 15309ccd8df..96326ef2d5a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -31,7 +31,7 @@ enum UniverseInfoInner<'tcx> { Other, } -impl UniverseInfo<'tcx> { +impl<'tcx> UniverseInfo<'tcx> { crate fn other() -> UniverseInfo<'tcx> { UniverseInfo(UniverseInfoInner::Other) } @@ -191,7 +191,7 @@ struct PredicateQuery<'tcx> { base_universe: ty::UniverseIndex, } -impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> { +impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate)); @@ -231,7 +231,7 @@ struct NormalizeQuery<'tcx, T> { base_universe: ty::UniverseIndex, } -impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> +impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> where T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx, { @@ -291,7 +291,7 @@ struct AscribeUserTypeQuery<'tcx> { base_universe: ty::UniverseIndex, } -impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { +impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, // and is only the fallback when the nice error fails. Consider improving this some more. @@ -339,7 +339,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( // We generally shouldn't have errors here because the query was // already run, but there's no point using `delay_span_bug` // when we're going to emit an error here anyway. - let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new); + let _errors = fulfill_cx.select_all_or_error(infcx); let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| { debug!("{:#?}", region_constraints); @@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( error_region, cause.clone(), placeholder_region, + vec![], ), ), (Some(error_region), _) => NiceRegionError::new( diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 439c728798d..ba111d394ec 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -15,16 +15,18 @@ use rustc_span::symbol::sym; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; +use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; +use crate::diagnostics::find_all_local_uses; use crate::{ borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, }; use super::{ - explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName, - RegionNameSource, UseSpans, + explain_borrow::{BorrowExplanation, LaterUseKind}, + FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans, }; #[derive(Debug)] @@ -407,14 +409,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let generics = tcx.generics_of(self.mir_def_id()); let param = generics.type_param(¶m_ty, tcx); if let Some(generics) = tcx - .hir() - .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id())) + .typeck_root_def_id(self.mir_def_id().to_def_id()) + .as_local() + .and_then(|def_id| tcx.hir().get_generics(def_id)) { suggest_constraining_type_param( tcx, generics, &mut err, - ¶m.name.as_str(), + param.name.as_str(), "Copy", None, ); @@ -768,9 +771,92 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some((issued_span, span)), ); + self.suggest_using_local_if_applicable( + &mut err, + location, + (place, span), + gen_borrow_kind, + issued_borrow, + explanation, + ); + err } + #[instrument(level = "debug", skip(self, err))] + fn suggest_using_local_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + location: Location, + (place, span): (Place<'tcx>, Span), + gen_borrow_kind: BorrowKind, + issued_borrow: &BorrowData<'tcx>, + explanation: BorrowExplanation, + ) { + let used_in_call = + matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _)); + if !used_in_call { + debug!("not later used in call"); + return; + } + + let outer_call_loc = + if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { + loc + } else { + issued_borrow.reserve_location + }; + let outer_call_stmt = self.body.stmt_at(outer_call_loc); + + let inner_param_location = location; + let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else { + debug!("`inner_param_location` {:?} is not for a statement", inner_param_location); + return; + }; + let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else { + debug!( + "`inner_param_location` {:?} is not for an assignment: {:?}", + inner_param_location, inner_param_stmt + ); + return; + }; + let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local); + let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| { + let Either::Right(term) = self.body.stmt_at(loc) else { + debug!("{:?} is a statement, so it can't be a call", loc); + return None; + }; + let TerminatorKind::Call { args, .. } = &term.kind else { + debug!("not a call: {:?}", term); + return None; + }; + debug!("checking call args for uses of inner_param: {:?}", args); + if args.contains(&Operand::Move(inner_param)) { + Some((loc,term)) + } else { + None + } + }) else { + debug!("no uses of inner_param found as a by-move call arg"); + return; + }; + debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc); + + let inner_call_span = inner_call_term.source_info.span; + let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span; + if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) { + // FIXME: This stops the suggestion in some cases where it should be emitted. + // Fix the spans for those cases so it's emitted correctly. + debug!( + "outer span {:?} does not strictly contain inner span {:?}", + outer_call_span, inner_call_span + ); + return; + } + err.span_help(inner_call_span, "try adding a local storing this argument..."); + err.span_help(outer_call_span, "...and then using that local as the argument to this call"); + } + fn suggest_split_at_mut_if_applicable( &self, err: &mut DiagnosticBuilder<'_>, @@ -977,9 +1063,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(ref name), BorrowExplanation::MustBeValidFor { category: - category - @ - (ConstraintCategory::Return(_) + category @ (ConstraintCategory::Return(_) | ConstraintCategory::CallArgument | ConstraintCategory::OpaqueType), from_closure: false, @@ -1515,8 +1599,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, mpi: MovePathIndex, ) -> (Vec<MoveSite>, Vec<Location>) { - fn predecessor_locations( - body: &'a mir::Body<'tcx>, + fn predecessor_locations<'a>( + body: &'a mir::Body<'_>, location: Location, ) -> impl Iterator<Item = Location> + 'a { if location.statement_index == 0 { diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 79973ab170c..db8268c8e2e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -13,7 +13,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{sym, DesugaringKind, Span}; use crate::region_infer::BlameConstraint; use crate::{ @@ -135,7 +135,16 @@ impl BorrowExplanation { should_note_order, } => { let local_decl = &body.local_decls[dropped_local]; - let (dtor_desc, type_desc) = match local_decl.ty.kind() { + let mut ty = local_decl.ty; + if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) { + if let ty::Adt(adt, substs) = local_decl.ty.kind() { + if tcx.is_diagnostic_item(sym::Option, adt.did) { + // in for loop desugaring, only look at the `Some(..)` inner type + ty = substs.type_at(0); + } + } + } + let (dtor_desc, type_desc) = match ty.kind() { // If type is an ADT that implements Drop, then // simplify output by reporting just the ADT name. ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => { diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs new file mode 100644 index 00000000000..49d9caae711 --- /dev/null +++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs @@ -0,0 +1,26 @@ +use std::collections::BTreeSet; + +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location}; + +/// Find all uses of (including assignments to) a [`Local`]. +/// +/// Uses `BTreeSet` so output is deterministic. +pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet<Location> { + let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() }; + visitor.visit_body(body); + visitor.uses +} + +struct AllLocalUsesVisitor { + for_local: Local, + uses: BTreeSet<Location>, +} + +impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor { + fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) { + if *local == self.for_local { + self.uses.insert(location); + } + } +} diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index a4df277a7b0..84acfbf941d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,16 +13,13 @@ use rustc_middle::mir::{ use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; -use rustc_span::{ - hygiene::{DesugaringKind, ForLoopLoc}, - symbol::sym, - Span, -}; +use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span}; use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; +mod find_all_local_uses; mod find_use; mod outlives_suggestion; mod region_name; @@ -209,7 +206,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { let local_info = &self.body.local_decls[local].local_info; if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { - buf.push_str(&self.infcx.tcx.item_name(def_id).as_str()); + buf.push_str(self.infcx.tcx.item_name(def_id).as_str()); } else { unreachable!(); } @@ -321,7 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let decl = &self.body.local_decls[local]; match self.local_names[local] { Some(name) if !decl.from_compiler_desugaring() => { - buf.push_str(&name.as_str()); + buf.push_str(name.as_str()); Ok(()) } _ => Err(()), @@ -375,7 +372,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { def.non_enum_variant() }; - variant.fields[field.index()].ident.to_string() + variant.fields[field.index()].name.to_string() } ty::Tuple(_) => field.index().to_string(), ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { @@ -412,7 +409,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Add a note that a type does not implement `Copy` pub(super) fn note_type_does_not_implement_copy( &self, - err: &mut DiagnosticBuilder<'a>, + err: &mut DiagnosticBuilder<'_>, place_desc: &str, ty: Ty<'tcx>, span: Option<Span>, @@ -736,21 +733,19 @@ pub(super) enum BorrowedContentSource<'tcx> { OverloadedIndex(Ty<'tcx>), } -impl BorrowedContentSource<'tcx> { +impl<'tcx> BorrowedContentSource<'tcx> { pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String { match *self { BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(), BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(), BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(), - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { - "an `Rc`".to_string() - } - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { - "an `Arc`".to_string() - } - _ => format!("dereference of `{}`", ty), - }, + BorrowedContentSource::OverloadedDeref(ty) => ty + .ty_adt_def() + .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? { + name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)), + _ => None, + }) + .unwrap_or_else(|| format!("dereference of `{}`", ty)), BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty), } } @@ -774,15 +769,13 @@ impl BorrowedContentSource<'tcx> { BorrowedContentSource::DerefMutableRef => { bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") } - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { - "an `Rc`".to_string() - } - ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { - "an `Arc`".to_string() - } - _ => format!("a dereference of `{}`", ty), - }, + BorrowedContentSource::OverloadedDeref(ty) => ty + .ty_adt_def() + .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? { + name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)), + _ => None, + }) + .unwrap_or_else(|| format!("dereference of `{}`", ty)), BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty), } } @@ -955,10 +948,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let kind = kind.unwrap_or_else(|| { // This isn't a 'special' use of `self` debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); - let implicit_into_iter = matches!( - fn_call_span.desugaring_kind(), - Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) - ); + let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn() + && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop); let parent_self_ty = parent .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl) .and_then(|did| match tcx.type_of(did).kind() { @@ -966,8 +957,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => None, }); let is_option_or_result = parent_self_ty.map_or(false, |def_id| { - tcx.is_diagnostic_item(sym::Option, def_id) - || tcx.is_diagnostic_item(sym::Result, def_id) + matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) }); FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result } }); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index d5ff4c6766f..8ed50075ecb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -165,10 +165,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { local: _, projection: - [.., ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..)], + [ + .., + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(..), + ], } => bug!("Unexpected immutable place."), } @@ -217,19 +220,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { local, projection: - [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref], + [ + proj_base @ .., + ProjectionElem::Deref, + ProjectionElem::Field(field, _), + ProjectionElem::Deref, + ], } => { err.span_label(span, format!("cannot {ACT}", ACT = act)); - if let Some((span, message)) = annotate_struct_field( + if let Some(span) = get_mut_span_in_struct_field( self.infcx.tcx, Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty, field, ) { - err.span_suggestion( + err.span_suggestion_verbose( span, "consider changing this to be mutable", - message, + " mut ".into(), Applicability::MaybeIncorrect, ); } @@ -445,15 +453,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }, ))) => { // check if the RHS is from desugaring - let locations = self.body.find_assignments(local); - let opt_assignment_rhs_span = locations - .first() - .map(|&location| self.body.source_info(location).span); - let opt_desugaring_kind = - opt_assignment_rhs_span.and_then(|span| span.desugaring_kind()); - match opt_desugaring_kind { + let opt_assignment_rhs_span = + self.body.find_assignments(local).first().map(|&location| { + if let Some(mir::Statement { + source_info: _, + kind: + mir::StatementKind::Assign(box ( + _, + mir::Rvalue::Use(mir::Operand::Copy(place)), + )), + }) = self.body[location.block] + .statements + .get(location.statement_index) + { + self.body.local_decls[place.local].source_info.span + } else { + self.body.source_info(location).span + } + }); + match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) { // on for loops, RHS points to the iterator part - Some(DesugaringKind::ForLoop(_)) => { + Some(DesugaringKind::ForLoop) => { self.suggest_similar_mut_method_for_for_loop(&mut err); Some(( false, @@ -608,42 +628,39 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; ( true, - td.as_local().and_then(|tld| { - let h = hir_map.local_def_id_to_hir_id(tld); - match hir_map.find(h) { - Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, _, _, items), - .. - })) => { - let mut f_in_trait_opt = None; - for hir::TraitItemRef { id: fi, kind: k, .. } in *items { - let hi = fi.hir_id(); - if !matches!(k, hir::AssocItemKind::Fn { .. }) { - continue; - } - if hir_map.name(hi) != hir_map.name(my_hir) { - continue; - } - f_in_trait_opt = Some(hi); - break; + td.as_local().and_then(|tld| match hir_map.find_by_def_id(tld) { + Some(Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, _, _, items), + .. + })) => { + let mut f_in_trait_opt = None; + for hir::TraitItemRef { id: fi, kind: k, .. } in *items { + let hi = fi.hir_id(); + if !matches!(k, hir::AssocItemKind::Fn { .. }) { + continue; } - f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) { - Some(Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn( - hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. }, - _, - ), - .. - })) => { - let hir::Ty { span, .. } = inputs[local.index() - 1]; - Some(span) - } - _ => None, - }) + if hir_map.name(hi) != hir_map.name(my_hir) { + continue; + } + f_in_trait_opt = Some(hi); + break; } - _ => None, + f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) { + Some(Node::TraitItem(hir::TraitItem { + kind: + hir::TraitItemKind::Fn( + hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. }, + _, + ), + .. + })) => { + let hir::Ty { span, .. } = inputs[local.index() - 1]; + Some(span) + } + _ => None, + }) } + _ => None, }), ) } @@ -686,13 +703,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &origin_projection, ) { match captured_place.info.capture_kind { - ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, - .. - }) => { + ty::UpvarCapture::ByRef( + ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, + ) => { capture_reason = format!("mutable borrow of `{}`", upvar); } - ty::UpvarCapture::ByValue(_) => { + ty::UpvarCapture::ByValue => { capture_reason = format!("possible mutation of `{}`", upvar); } _ => bug!("upvar `{}` borrowed, but not mutably", upvar), @@ -727,7 +743,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { HirId, ImplItem, ImplItemKind, Item, ItemKind, }; - fn maybe_body_id_of_fn(hir_map: &Map<'tcx>, id: HirId) -> Option<BodyId> { + fn maybe_body_id_of_fn(hir_map: &Map<'_>, id: HirId) -> Option<BodyId> { match hir_map.find(id) { Some(Node::Item(Item { kind: ItemKind::Fn(_, _, body_id), .. })) | Some(Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })) => { @@ -751,11 +767,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { kind: Call( _, - [Expr { - kind: MethodCall(path_segment, ..), - hir_id, - .. - }, ..], + [ + Expr { + kind: MethodCall(path_segment, ..), + hir_id, + .. + }, + .., + ], ), .. }, @@ -779,7 +798,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .map(|assoc_items| { assoc_items .in_definition_order() - .map(|assoc_item_def| assoc_item_def.ident) + .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx)) .filter(|&ident| { let original_method_ident = path_segment.ident; original_method_ident != ident @@ -874,7 +893,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if look_at_return && hir.get_return_block(closure_id).is_some() { // ...otherwise we are probably in the tail expression of the function, point at the // return type. - match hir.get(hir.get_parent_item(fn_call_id)) { + match hir.get_by_def_id(hir.get_parent_item(fn_call_id)) { hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) | hir::Node::TraitItem(hir::TraitItem { ident, @@ -1036,47 +1055,31 @@ fn is_closure_or_generator(ty: Ty<'_>) -> bool { ty.is_closure() || ty.is_generator() } -/// Adds a suggestion to a struct definition given a field access to a local. -/// This function expects the local to be a reference to a struct in order to produce a suggestion. +/// Given a field that needs to be mutable, returns a span where the " mut " could go. +/// This function expects the local to be a reference to a struct in order to produce a span. /// /// ```text -/// LL | s: &'a String -/// | ---------- use `&'a mut String` here to make mutable +/// LL | s: &'a String +/// | ^^^ returns a span taking up the space here /// ``` -fn annotate_struct_field( +fn get_mut_span_in_struct_field<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, field: &mir::Field, -) -> Option<(Span, String)> { +) -> Option<Span> { // Expect our local to be a reference to a struct of some kind. if let ty::Ref(_, ty, _) = ty.kind() { if let ty::Adt(def, _) = ty.kind() { let field = def.all_fields().nth(field.index())?; // Use the HIR types to construct the diagnostic message. - let hir_id = tcx.hir().local_def_id_to_hir_id(field.did.as_local()?); - let node = tcx.hir().find(hir_id)?; + let node = tcx.hir().find_by_def_id(field.did.as_local()?)?; // Now we're dealing with the actual struct that we're going to suggest a change to, // we can expect a field that is an immutable reference to a type. if let hir::Node::Field(field) = node { - if let hir::TyKind::Rptr( - lifetime, - hir::MutTy { mutbl: hir::Mutability::Not, ref ty }, - ) = field.ty.kind + if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = + field.ty.kind { - // Get the snippets in two parts - the named lifetime (if there is one) and - // type being referenced, that way we can reconstruct the snippet without loss - // of detail. - let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?; - let lifetime_snippet = if !lifetime.is_elided() { - format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?) - } else { - String::new() - }; - - return Some(( - field.ty.span, - format!("&{}mut {}", lifetime_snippet, &*type_snippet,), - )); + return Some(lifetime.span.between(ty.span)); } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 11cdbe84acc..df23eaf24bc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::{ error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, }; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; -use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span}; @@ -334,13 +334,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match variance_info { ty::VarianceDiagInfo::None => {} - ty::VarianceDiagInfo::Mut { kind, ty } => { - let kind_name = match kind { - ty::VarianceDiagMutKind::Ref => "reference", - ty::VarianceDiagMutKind::RawPtr => "pointer", + ty::VarianceDiagInfo::Invariant { ty, param_index } => { + let (desc, note) = match ty.kind() { + ty::RawPtr(ty_mut) => { + assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut); + ( + format!("a mutable pointer to {}", ty_mut.ty), + "mutable pointers are invariant over their type parameter".to_string(), + ) + } + ty::Ref(_, inner_ty, mutbl) => { + assert_eq!(*mutbl, rustc_hir::Mutability::Mut); + ( + format!("a mutable reference to {}", inner_ty), + "mutable references are invariant over their type parameter" + .to_string(), + ) + } + ty::Adt(adt, substs) => { + let generic_arg = substs[param_index as usize]; + let identity_substs = + InternalSubsts::identity_for_item(self.infcx.tcx, adt.did); + let base_ty = self.infcx.tcx.mk_adt(adt, identity_substs); + let base_generic_arg = identity_substs[param_index as usize]; + let adt_desc = adt.descr(); + + let desc = format!( + "the type {ty}, which makes the generic argument {generic_arg} invariant" + ); + let note = format!( + "the {adt_desc} {base_ty} is invariant over the parameter {base_generic_arg}" + ); + (desc, note) + } + _ => panic!("Unexpected type {:?}", ty), }; - diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",)); - diag.note(&format!("mutable {kind_name}s are invariant over their type parameter")); + diag.note(&format!("requirement occurs because of {desc}",)); + diag.note(¬e); diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance"); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 5edb52b0b65..01cc72121c7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -584,7 +584,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) } - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => { + hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => { // In this case, the user left off the lifetime; so // they wrote something like: // @@ -704,7 +704,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::AsyncGeneratorKind::Block => " of async block", hir::AsyncGeneratorKind::Closure => " of async closure", hir::AsyncGeneratorKind::Fn => { - let parent_item = hir.get(hir.get_parent_item(mir_hir_id)); + let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id)); let output = &parent_item .fn_decl() .expect("generator lowered from async fn should be in fn") @@ -769,20 +769,27 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let opaque_ty = hir.item(id); if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: - [hir::GenericBound::LangItemTrait( - hir::LangItem::Future, - _, - _, - hir::GenericArgs { - bindings: - [hir::TypeBinding { - ident: Ident { name: sym::Output, .. }, - kind: hir::TypeBindingKind::Equality { ty }, - .. - }], - .. - }, - )], + [ + hir::GenericBound::LangItemTrait( + hir::LangItem::Future, + _, + _, + hir::GenericArgs { + bindings: + [ + hir::TypeBinding { + ident: Ident { name: sym::Output, .. }, + kind: + hir::TypeBindingKind::Equality { + term: hir::Term::Ty(ty), + }, + .. + }, + ], + .. + }, + ), + ], .. }) = opaque_ty.kind { diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index efd34f4e0a5..73ced63e4d7 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -5,12 +5,11 @@ use rustc_middle::mir::{BorrowKind, Mutability, Operand}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{Statement, StatementKind}; use rustc_middle::ty::TyCtxt; -use std::iter; use crate::{ borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth, - Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode, - Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind, + Activation, ArtificialField, BorrowIndex, Deep, LocalMutationIsAllowed, Read, ReadKind, + ReadOrWrite, Reservation, Shallow, Write, WriteKind, }; pub(super) fn generate_invalidates<'tcx>( @@ -59,37 +58,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { StatementKind::Assign(box (lhs, rhs)) => { self.consume_rvalue(location, rhs); - self.mutate_place(location, *lhs, Shallow(None), JustWrite); + self.mutate_place(location, *lhs, Shallow(None)); } StatementKind::FakeRead(box (_, _)) => { // Only relevant for initialized/liveness/safety checks. } StatementKind::SetDiscriminant { place, variant_index: _ } => { - self.mutate_place(location, **place, Shallow(None), JustWrite); - } - StatementKind::LlvmInlineAsm(asm) => { - for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) { - if o.is_indirect { - // FIXME(eddyb) indirect inline asm outputs should - // be encoded through MIR place derefs instead. - self.access_place( - location, - *output, - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - ); - } else { - self.mutate_place( - location, - *output, - if o.is_rw { Deep } else { Shallow(None) }, - if o.is_rw { WriteAndRead } else { JustWrite }, - ); - } - } - for (_, input) in asm.inputs.iter() { - self.consume_operand(location, input); - } + self.mutate_place(location, **place, Shallow(None)); } StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { ref src, @@ -142,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { target: _, unwind: _, } => { - self.mutate_place(location, *drop_place, Deep, JustWrite); + self.mutate_place(location, *drop_place, Deep); self.consume_operand(location, new_value); } TerminatorKind::Call { @@ -158,7 +133,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.consume_operand(location, arg); } if let Some((dest, _ /*bb*/)) = destination { - self.mutate_place(location, *dest, Deep, JustWrite); + self.mutate_place(location, *dest, Deep); } } TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { @@ -181,7 +156,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } } - self.mutate_place(location, *resume_arg, Deep, JustWrite); + self.mutate_place(location, *resume_arg, Deep); } TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { // Invalidate all borrows of local places @@ -199,6 +174,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { options: _, line_spans: _, destination: _, + cleanup: _, } => { for op in operands { match *op { @@ -207,13 +183,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } InlineAsmOperand::Out { reg: _, late: _, place, .. } => { if let Some(place) = place { - self.mutate_place(location, place, Shallow(None), JustWrite); + self.mutate_place(location, place, Shallow(None)); } } InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { self.consume_operand(location, in_value); if let Some(out_place) = out_place { - self.mutate_place(location, out_place, Shallow(None), JustWrite); + self.mutate_place(location, out_place, Shallow(None)); } } InlineAsmOperand::Const { value: _ } @@ -237,13 +213,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { /// Simulates mutation of a place. - fn mutate_place( - &mut self, - location: Location, - place: Place<'tcx>, - kind: AccessDepth, - _mode: MutateMode, - ) { + fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) { self.access_place( location, place, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index aca7d3174f6..1e9acb114b7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -3,9 +3,6 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(crate_visibility_modifier)] -#![feature(format_args_capture)] -#![feature(in_band_lifetimes)] -#![feature(iter_zip)] #![feature(let_else)] #![feature(min_specialization)] #![feature(stmt_expr_attributes)] @@ -43,7 +40,6 @@ use either::Either; use smallvec::SmallVec; use std::cell::RefCell; use std::collections::BTreeMap; -use std::iter; use std::mem; use std::rc::Rc; @@ -58,7 +54,6 @@ use rustc_mir_dataflow::MoveDataParamEnv; use self::diagnostics::{AccessKind, RegionName}; use self::location::LocationTable; use self::prefixes::PrefixSet; -use self::MutateMode::{JustWrite, WriteAndRead}; use facts::AllFacts; use self::path_utils::*; @@ -189,7 +184,7 @@ fn do_mir_borrowck<'a, 'tcx>( .map(|captured_place| { let capture = captured_place.info.capture_kind; let by_ref = match capture { - ty::UpvarCapture::ByValue(_) => false, + ty::UpvarCapture::ByValue => false, ty::UpvarCapture::ByRef(..) => true, }; Upvar { place: captured_place.clone(), by_ref } @@ -633,7 +628,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx StatementKind::Assign(box (lhs, ref rhs)) => { self.consume_rvalue(location, (rhs, span), flow_state); - self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state); + self.mutate_place(location, (*lhs, span), Shallow(None), flow_state); } StatementKind::FakeRead(box (_, ref place)) => { // Read for match doesn't access any memory and is used to @@ -654,41 +649,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx ); } StatementKind::SetDiscriminant { place, variant_index: _ } => { - self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state); + self.mutate_place(location, (**place, span), Shallow(None), flow_state); } - StatementKind::LlvmInlineAsm(ref asm) => { - for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) { - if o.is_indirect { - // FIXME(eddyb) indirect inline asm outputs should - // be encoded through MIR place derefs instead. - self.access_place( - location, - (*output, o.span), - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - flow_state, - ); - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (output.as_ref(), o.span), - flow_state, - ); - } else { - self.mutate_place( - location, - (*output, o.span), - if o.is_rw { Deep } else { Shallow(None) }, - if o.is_rw { WriteAndRead } else { JustWrite }, - flow_state, - ); - } - } - for (_, input) in asm.inputs.iter() { - self.consume_operand(location, (input, span), flow_state); - } - } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { .. }) => { @@ -753,7 +715,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx target: _, unwind: _, } => { - self.mutate_place(loc, (drop_place, span), Deep, JustWrite, flow_state); + self.mutate_place(loc, (drop_place, span), Deep, flow_state); self.consume_operand(loc, (new_value, span), flow_state); } TerminatorKind::Call { @@ -769,7 +731,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx self.consume_operand(loc, (arg, span), flow_state); } if let Some((dest, _ /*bb*/)) = *destination { - self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state); + self.mutate_place(loc, (dest, span), Deep, flow_state); } } TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { @@ -783,7 +745,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => { self.consume_operand(loc, (value, span), flow_state); - self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state); + self.mutate_place(loc, (resume_arg, span), Deep, flow_state); } TerminatorKind::InlineAsm { @@ -792,6 +754,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx options: _, line_spans: _, destination: _, + cleanup: _, } => { for op in operands { match *op { @@ -800,13 +763,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx } InlineAsmOperand::Out { reg: _, late: _, place, .. } => { if let Some(place) = place { - self.mutate_place( - loc, - (place, span), - Shallow(None), - JustWrite, - flow_state, - ); + self.mutate_place(loc, (place, span), Shallow(None), flow_state); } } InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { @@ -816,7 +773,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx loc, (out_place, span), Shallow(None), - JustWrite, flow_state, ); } @@ -888,12 +844,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum MutateMode { - JustWrite, - WriteAndRead, -} - use self::AccessDepth::{Deep, Shallow}; use self::ReadOrWrite::{Activation, Read, Reservation, Write}; @@ -979,7 +929,6 @@ enum LocalMutationIsAllowed { #[derive(Copy, Clone, Debug)] enum InitializationRequiringAction { - Update, Borrow, MatchOn, Use, @@ -996,7 +945,6 @@ struct RootPlace<'tcx> { impl InitializationRequiringAction { fn as_noun(self) -> &'static str { match self { - InitializationRequiringAction::Update => "update", InitializationRequiringAction::Borrow => "borrow", InitializationRequiringAction::MatchOn => "use", // no good noun InitializationRequiringAction::Use => "use", @@ -1007,7 +955,6 @@ impl InitializationRequiringAction { fn as_verb_in_past_tense(self) -> &'static str { match self { - InitializationRequiringAction::Update => "updated", InitializationRequiringAction::Borrow => "borrowed", InitializationRequiringAction::MatchOn => "matched on", InitializationRequiringAction::Use => "used", @@ -1244,23 +1191,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, place_span: (Place<'tcx>, Span), kind: AccessDepth, - mode: MutateMode, flow_state: &Flows<'cx, 'tcx>, ) { - // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd. - match mode { - MutateMode::WriteAndRead => { - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Update, - (place_span.0.as_ref(), place_span.1), - flow_state, - ); - } - MutateMode::JustWrite => { - self.check_if_assigned_path_is_moved(location, place_span, flow_state); - } - } + // Write of P[i] or *P requires P init'd. + self.check_if_assigned_path_is_moved(location, place_span, flow_state); // Special case: you can assign an immutable local variable // (e.g., `x = ...`) so long as it has never been initialized @@ -1396,10 +1330,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::NullaryOp(_op, _ty) => { // nullary ops take no dynamic input; no borrowck effect. - // - // FIXME: is above actually true? Do we want to track - // the fact that uninitialized data can be created via - // `NullOp::Box`? } Rvalue::Aggregate(ref aggregate_kind, ref operands) => { diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs index f22d355e613..0fe44328fd9 100644 --- a/compiler/rustc_borrowck/src/member_constraints.rs +++ b/compiler/rustc_borrowck/src/member_constraints.rs @@ -53,7 +53,7 @@ rustc_index::newtype_index! { } } -impl Default for MemberConstraintSet<'tcx, ty::RegionVid> { +impl Default for MemberConstraintSet<'_, ty::RegionVid> { fn default() -> Self { Self { first_constraints: Default::default(), @@ -97,7 +97,7 @@ impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> { } } -impl<R1> MemberConstraintSet<'tcx, R1> +impl<'tcx, R1> MemberConstraintSet<'tcx, R1> where R1: Copy + Hash + Eq, { @@ -140,7 +140,7 @@ where } } -impl<R> MemberConstraintSet<'tcx, R> +impl<R> MemberConstraintSet<'_, R> where R: Copy + Hash + Eq, { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index e5924f9d084..6ffab165779 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( errors_buffer: &mut Vec<Diagnostic>, ) { let tcx = infcx.tcx; - let base_def_id = tcx.closure_base_def_id(body.source.def_id()); + let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); if !tcx.has_attr(base_def_id, sym::rustc_regions) { return; } diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index d5d00b467ee..b2c8dfc82c2 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -141,7 +141,7 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool { /// then returns the index of the field being projected. Note that this closure will always /// be `self` in the current MIR, because that is the only time we directly access the fields /// of a closure type. -pub(crate) fn is_upvar_field_projection( +pub(crate) fn is_upvar_field_projection<'tcx>( tcx: TyCtxt<'tcx>, upvars: &[Upvar<'tcx>], place_ref: PlaceRef<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index cfd3acb6bde..97233b930c3 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); - constraints.sort(); + constraints.sort_by_key(|c| (c.sup, c.sub)); for constraint in &constraints { let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint; let (name, arg) = match locations { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f4a5da1fe36..d9120ff2457 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -569,7 +569,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // to store those. Otherwise, we'll pass in `None` to the // functions below, which will trigger them to report errors // eagerly. - let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new); + let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new); self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer); @@ -612,7 +612,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn propagate_constraints(&mut self, _body: &Body<'tcx>) { debug!("constraints={:#?}", { let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); - constraints.sort(); + constraints.sort_by_key(|c| (c.sup, c.sub)); constraints .into_iter() .map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub))) @@ -2229,7 +2229,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx tcx, closure_substs, self.num_external_vids, - tcx.closure_base_def_id(closure_def_id), + tcx.typeck_root_def_id(closure_def_id), ); debug!("apply_requirements: closure_mapping={:?}", closure_mapping); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 4eb7be542e7..76b3be7976c 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -173,7 +173,7 @@ fn check_opaque_type_parameter_valid( // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. // // which would error here on all of the `'static` args. - OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true, + OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true, // Check these OpaqueTyOrigin::TyAlias => {} } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 8819039c752..4a70535c63b 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -1,5 +1,7 @@ use rustc_data_structures::fx::FxIndexSet; -use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; +use rustc_index::bit_set::SparseBitMatrix; +use rustc_index::interval::IntervalSet; +use rustc_index::interval::SparseIntervalMatrix; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; use rustc_middle::mir::{BasicBlock, Body, Location}; @@ -60,6 +62,11 @@ impl RegionValueElements { PointIndex::new(start_index) } + /// Return the PointIndex for the block start of this index. + crate fn to_block_start(&self, index: PointIndex) -> PointIndex { + PointIndex::new(self.statements_before_block[self.basic_blocks[index]]) + } + /// Converts a `PointIndex` back to a location. O(1). crate fn to_location(&self, index: PointIndex) -> Location { assert!(index.index() < self.num_points); @@ -76,29 +83,6 @@ impl RegionValueElements { crate fn point_in_range(&self, index: PointIndex) -> bool { index.index() < self.num_points } - - /// Pushes all predecessors of `index` onto `stack`. - crate fn push_predecessors( - &self, - body: &Body<'_>, - index: PointIndex, - stack: &mut Vec<PointIndex>, - ) { - let Location { block, statement_index } = self.to_location(index); - if statement_index == 0 { - // If this is a basic block head, then the predecessors are - // the terminators of other basic blocks - stack.extend( - body.predecessors()[block] - .iter() - .map(|&pred_bb| body.terminator_loc(pred_bb)) - .map(|pred_loc| self.point_from_location(pred_loc)), - ); - } else { - // Otherwise, the pred is just the previous statement - stack.push(PointIndex::new(index.index() - 1)); - } - } } rustc_index::newtype_index! { @@ -128,11 +112,11 @@ crate enum RegionElement { PlaceholderRegion(ty::PlaceholderRegion), } -/// When we initially compute liveness, we use a bit matrix storing -/// points for each region-vid. +/// When we initially compute liveness, we use an interval matrix storing +/// liveness ranges for each region-vid. crate struct LivenessValues<N: Idx> { elements: Rc<RegionValueElements>, - points: SparseBitMatrix<N, PointIndex>, + points: SparseIntervalMatrix<N, PointIndex>, } impl<N: Idx> LivenessValues<N> { @@ -140,7 +124,7 @@ impl<N: Idx> LivenessValues<N> { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. crate fn new(elements: Rc<RegionValueElements>) -> Self { - Self { points: SparseBitMatrix::new(elements.num_points), elements } + Self { points: SparseIntervalMatrix::new(elements.num_points), elements } } /// Iterate through each region that has a value in this set. @@ -158,7 +142,7 @@ impl<N: Idx> LivenessValues<N> { /// Adds all the elements in the given bit array into the given /// region. Returns whether any of them are newly added. - crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool { + crate fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool { debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); self.points.union_row(row, locations) } @@ -171,7 +155,7 @@ impl<N: Idx> LivenessValues<N> { /// Returns `true` if the region `r` contains the given element. crate fn contains(&self, row: N, location: Location) -> bool { let index = self.elements.point_from_location(location); - self.points.contains(row, index) + self.points.row(row).map_or(false, |r| r.contains(index)) } /// Returns an iterator of all the elements contained by the region `r` @@ -239,7 +223,7 @@ impl PlaceholderIndices { crate struct RegionValues<N: Idx> { elements: Rc<RegionValueElements>, placeholder_indices: Rc<PlaceholderIndices>, - points: SparseBitMatrix<N, PointIndex>, + points: SparseIntervalMatrix<N, PointIndex>, free_regions: SparseBitMatrix<N, RegionVid>, /// Placeholders represent bound regions -- so something like `'a` @@ -259,7 +243,7 @@ impl<N: Idx> RegionValues<N> { let num_placeholders = placeholder_indices.len(); Self { elements: elements.clone(), - points: SparseBitMatrix::new(elements.num_points), + points: SparseIntervalMatrix::new(elements.num_points), placeholder_indices: placeholder_indices.clone(), free_regions: SparseBitMatrix::new(num_universal_regions), placeholders: SparseBitMatrix::new(num_placeholders), diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 20567610f65..4b6cab24cdb 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -1,7 +1,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, PlaceElem, Promoted}; +use rustc_middle::mir::{Body, Location, Promoted}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -62,22 +62,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { debug!(?ty); } - fn process_projection_elem( - &mut self, - elem: PlaceElem<'tcx>, - _: Location, - ) -> Option<PlaceElem<'tcx>> { - if let PlaceElem::Field(field, ty) = elem { - let new_ty = self.renumber_regions(ty); - - if new_ty != ty { - return Some(PlaceElem::Field(field, new_ty)); - } - } - - None - } - #[instrument(skip(self), level = "debug")] fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { *substs = self.renumber_regions(*substs); diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index ab1a7461b4b..a3b39591f8d 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,6 +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::TypeFoldable; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::DUMMY_SP; @@ -95,11 +96,23 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.add_outlives(r1_vid, r2_vid); } - GenericArgKind::Type(t1) => { + GenericArgKind::Type(mut 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, &mut false, |r, _| match *r { + ty::RegionKind::RePlaceholder(placeholder) => { + self.constraints.placeholder_region(self.infcx, placeholder) + } + _ => r, + }); + } + TypeOutlives::new( &mut *self, tcx, 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 f71cf09ecf6..fec6bdf314b 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -58,7 +58,7 @@ crate struct CreateResult<'tcx> { crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, } -crate fn create( +crate fn create<'tcx>( infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: Option<ty::Region<'tcx>>, @@ -81,7 +81,7 @@ crate fn create( .create() } -impl UniversalRegionRelations<'tcx> { +impl UniversalRegionRelations<'_> { /// Records in the `outlives_relation` (and /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the /// builder below. @@ -110,7 +110,7 @@ impl UniversalRegionRelations<'tcx> { /// outlives `fr` and (b) is not local. /// /// (*) If there are multiple competing choices, we return all of them. - crate fn non_local_upper_bounds(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> { + crate fn non_local_upper_bounds<'a>(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> { debug!("non_local_upper_bound(fr={:?})", fr); let res = self.non_local_bounds(&self.inverse_outlives, fr); assert!(!res.is_empty(), "can't find an upper bound!?"); @@ -232,7 +232,7 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> { region_bound_pairs: RegionBoundPairs<'tcx>, } -impl UniversalRegionRelationsBuilder<'cx, 'tcx> { +impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { crate fn create(mut self) -> CreateResult<'tcx> { let unnormalized_input_output_tys = self .universal_regions @@ -256,7 +256,6 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { debug!("build: input_or_output={:?}", ty); // We add implied bounds from both the unnormalized and normalized ty // See issue #87748 - let constraints_implied_1 = self.add_implied_bounds(ty); let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self .param_env .and(type_op::normalize::Normalize::new(ty)) @@ -284,10 +283,9 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { // } // ``` // Both &Self::Bar and &() are WF - let constraints_implied_2 = - if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None }; + let constraints_implied = self.add_implied_bounds(norm_ty); normalized_inputs_and_output.push(norm_ty); - constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2) + constraints1.into_iter().chain(constraints_implied) }) .collect(); diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 24332690bec..bc740de5150 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -7,13 +7,16 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). +use crate::type_check::constraint_conversion::ConstraintConversion; use rustc_index::vec::Idx; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::*; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use rustc_span::Span; -use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; +use rustc_trait_selection::traits::query::Fallible; +use type_op::TypeOpOutput; use crate::universal_regions::UniversalRegions; @@ -30,6 +33,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let (&normalized_output_ty, normalized_input_tys) = normalized_inputs_and_output.split_last().unwrap(); + debug!(?normalized_output_ty); + debug!(?normalized_input_tys); + let mir_def_id = body.source.def_id().expect_local(); // If the user explicitly annotated the input types, extract @@ -75,10 +81,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .delay_span_bug(body.span, "found more normalized_input_ty than local_decls"); break; } + // In MIR, argument N is stored in local N+1. let local = Local::new(argument_index + 1); let mir_input_ty = body.local_decls[local].ty; + let mir_input_span = body.local_decls[local].source_info.span; self.equate_normalized_input_or_output( normalized_input_ty, @@ -100,6 +108,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // If the user explicitly annotated the input types, enforce those. let user_provided_input_ty = self.normalize(user_provided_input_ty, Locations::All(mir_input_span)); + self.equate_normalized_input_or_output( user_provided_input_ty, mir_input_ty, @@ -108,9 +117,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some()); - if let Some(mir_yield_ty) = body.yield_ty() { - let ur_yield_ty = universal_regions.yield_ty.unwrap(); + debug!( + "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}", + body.yield_ty(), + universal_regions.yield_ty + ); + + // We will not have a universal_regions.yield_ty if we yield (by accident) + // outside of a generator and return an `impl Trait`, so emit a delay_span_bug + // because we don't want to panic in an assert here if we've already got errors. + if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() { + self.tcx().sess.delay_span_bug( + body.span, + &format!( + "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})", + body.yield_ty(), + universal_regions.yield_ty, + ), + ); + } + + if let (Some(mir_yield_ty), Some(ur_yield_ty)) = + (body.yield_ty(), universal_regions.yield_ty) + { let yield_span = body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span); } @@ -167,30 +196,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd // like to normalize *before* inserting into `local_decls`, but // doing so ends up causing some other trouble. - let b = match self - .infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .normalize(b) - { - Ok(n) => { - debug!("equate_inputs_and_outputs: {:?}", n); - if n.obligations.iter().all(|o| { - matches!( - o.predicate.kind().skip_binder(), - ty::PredicateKind::RegionOutlives(_) - | ty::PredicateKind::TypeOutlives(_) - ) - }) { - n.value - } else { - b - } - } + let b = match self.normalize_and_add_constraints(b) { + Ok(n) => n, Err(_) => { debug!("equate_inputs_and_outputs: NoSolution"); b } }; + // Note: if we have to introduce new placeholders during normalization above, then we won't have // added those universes to the universe info, which we would want in `relate_tys`. if let Err(terr) = @@ -207,4 +220,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } + + pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> { + let TypeOpOutput { output: norm_ty, constraints, .. } = + self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?; + + debug!("{:?} normalized to {:?}", t, norm_ty); + + for data in constraints.into_iter().collect::<Vec<_>>() { + ConstraintConversion::new( + self.infcx, + &self.borrowck_context.universal_regions, + &self.region_bound_pairs, + Some(self.implicit_region_bound), + self.param_env, + Locations::All(DUMMY_SP), + ConstraintCategory::Internal, + &mut self.borrowck_context.constraints, + ) + .convert_all(&*data); + } + + Ok(norm_ty) + } } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index 8b74abd94c0..dd23683fae8 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -152,7 +152,7 @@ impl LocalUseMapBuild<'_> { } } -impl Visitor<'tcx> for LocalUseMapBuild<'_> { +impl Visitor<'_> for LocalUseMapBuild<'_> { fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { if self.locals_with_use_data[local] { match def_use::categorize(context) { diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 1e712354d6a..f18fe1f43d4 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -74,7 +74,7 @@ pub(super) fn generate<'mir, 'tcx>( // to compute whether a variable `X` is live if that variable contains // some region `R` in its type where `R` is not known to outlive a free // region (i.e., where `R` may be valid for just a subset of the fn body). -fn compute_live_locals( +fn compute_live_locals<'tcx>( tcx: TyCtxt<'tcx>, free_regions: &FxHashSet<RegionVid>, body: &Body<'tcx>, @@ -104,7 +104,7 @@ fn compute_live_locals( /// regions. For these regions, we do not need to compute /// liveness, since the outlives constraints will ensure that they /// are live over the whole fn body anyhow. -fn regions_that_outlive_free_regions( +fn regions_that_outlive_free_regions<'tcx>( num_region_vars: usize, universal_regions: &UniversalRegions<'tcx>, constraint_set: &OutlivesConstraintSet<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs index 79ab8b713f9..ee067c4872f 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs @@ -53,7 +53,7 @@ impl UseFactsExtractor<'_> { } } -impl Visitor<'tcx> for UseFactsExtractor<'_> { +impl Visitor<'_> for UseFactsExtractor<'_> { fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { match def_use::categorize(context) { Some(DefUse::Def) => self.insert_def(local, location), @@ -63,7 +63,7 @@ impl Visitor<'tcx> for UseFactsExtractor<'_> { } } - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + fn visit_place(&mut self, place: &Place<'_>, context: PlaceContext, location: Location) { self.super_place(place, context, location); match context { PlaceContext::NonMutatingUse(_) => { @@ -82,7 +82,7 @@ impl Visitor<'tcx> for UseFactsExtractor<'_> { } } -pub(super) fn populate_access_facts( +pub(super) fn populate_access_facts<'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, location_table: &LocationTable, @@ -123,7 +123,7 @@ pub(super) fn populate_access_facts( // For every potentially drop()-touched region `region` in `local`'s type // (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact. -pub(super) fn add_drop_of_var_derefs_origin( +pub(super) fn add_drop_of_var_derefs_origin<'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, local: Local, kind: &GenericArg<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 1671c7c627e..169de23facc 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::bit_set::HybridBitSet; +use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::ty::{Ty, TypeFoldable}; @@ -34,7 +35,7 @@ use crate::{ /// DROP-LIVE set are to the liveness sets for regions found in the /// `dropck_outlives` result of the variable's type (in particular, /// this respects `#[may_dangle]` annotations). -pub(super) fn trace( +pub(super) fn trace<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &Rc<RegionValueElements>, @@ -105,12 +106,12 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { /// Points where the current variable is "use live" -- meaning /// that there is a future "full use" that may use its value. - use_live_at: HybridBitSet<PointIndex>, + use_live_at: IntervalSet<PointIndex>, /// Points where the current variable is "drop live" -- meaning /// that there is no future "full use" that may use its value, but /// there is a future drop. - drop_live_at: HybridBitSet<PointIndex>, + drop_live_at: IntervalSet<PointIndex>, /// Locations where drops may occur. drop_locations: Vec<Location>, @@ -119,14 +120,14 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { stack: Vec<PointIndex>, } -impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { +impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self { let num_points = cx.elements.num_points(); LivenessResults { cx, defs: HybridBitSet::new_empty(num_points), - use_live_at: HybridBitSet::new_empty(num_points), - drop_live_at: HybridBitSet::new_empty(num_points), + use_live_at: IntervalSet::new(num_points), + drop_live_at: IntervalSet::new(num_points), drop_locations: vec![], stack: vec![], } @@ -165,12 +166,12 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { drop_used: Vec<(Local, Location)>, live_locals: FxHashSet<Local>, ) { - let locations = HybridBitSet::new_empty(self.cx.elements.num_points()); + let locations = IntervalSet::new(self.cx.elements.num_points()); for (local, location) in drop_used { if !live_locals.contains(&local) { let local_ty = self.cx.body.local_decls[local].ty; - if local_ty.has_free_regions(self.cx.typeck.tcx()) { + if local_ty.has_free_regions() { self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); } } @@ -205,12 +206,42 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { self.stack.extend(self.cx.local_use_map.uses(local)); while let Some(p) = self.stack.pop() { - if self.defs.contains(p) { + // We are live in this block from the closest to us of: + // + // * Inclusively, the block start + // * Exclusively, the previous definition (if it's in this block) + // * Exclusively, the previous live_at setting (an optimization) + let block_start = self.cx.elements.to_block_start(p); + let previous_defs = self.defs.last_set_in(block_start..=p); + let previous_live_at = self.use_live_at.last_set_in(block_start..=p); + + let exclusive_start = match (previous_defs, previous_live_at) { + (Some(a), Some(b)) => Some(std::cmp::max(a, b)), + (Some(a), None) | (None, Some(a)) => Some(a), + (None, None) => None, + }; + + if let Some(exclusive) = exclusive_start { + self.use_live_at.insert_range(exclusive + 1..=p); + + // If we have a bound after the start of the block, we should + // not add the predecessors for this block. continue; - } - - if self.use_live_at.insert(p) { - self.cx.elements.push_predecessors(self.cx.body, p, &mut self.stack) + } else { + // Add all the elements of this block. + self.use_live_at.insert_range(block_start..=p); + + // Then add the predecessors for this block, which are the + // terminators of predecessor basic blocks. Push those onto the + // stack so that the next iteration(s) will process them. + + let block = self.cx.elements.to_location(block_start).block; + self.stack.extend( + self.cx.body.predecessors()[block] + .iter() + .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb)) + .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)), + ); } } } @@ -388,7 +419,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { } } -impl LivenessContext<'_, '_, '_, 'tcx> { +impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { /// Returns `true` if the local variable (or some part of it) is initialized at the current /// cursor position. Callers should call one of the `seek` methods immediately before to point /// the cursor to the desired location. @@ -426,7 +457,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> { fn add_use_live_facts_for( &mut self, value: impl TypeFoldable<'tcx>, - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!("add_use_live_facts_for(value={:?})", value); @@ -443,7 +474,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> { dropped_local: Local, dropped_ty: Ty<'tcx>, drop_locations: &[Location], - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!( "add_drop_live_constraint(\ @@ -491,7 +522,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> { elements: &RegionValueElements, typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeFoldable<'tcx>, - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!("make_all_regions_live(value={:?})", value); debug!( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7e6a481ca69..73103643e3e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::vec_map::VecMap; use rustc_errors::struct_span_err; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; @@ -30,7 +31,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, - ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, + ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, }; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; @@ -311,6 +312,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { } } +#[track_caller] fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) { // We sometimes see MIR failures (notably predicate failures) due to // the fact that we check rvalue sized predicates here. So use `delay_span_bug` @@ -424,7 +426,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( constant.literal.ty(), uv.def.did, - UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None }, + UserSubsts { substs: uv.substs, user_self_ty: None }, )), ) { span_mirbug!( @@ -655,7 +657,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // If the region is live at at least one location in the promoted MIR, // then add a liveness constraint to the main MIR for this region // at the location provided as an argument to this method - if let Some(_) = liveness_constraints.get_elements(region).next() { + if liveness_constraints.get_elements(region).next().is_some() { self.cx .borrowck_context .constraints @@ -756,6 +758,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }, ProjectionElem::Field(field, fty) => { let fty = self.sanitize_type(place, fty); + let fty = self.cx.normalize(fty, location); match self.field_ty(place, base, field, location) { Ok(ty) => { let ty = self.cx.normalize(ty, location); @@ -892,11 +895,11 @@ struct TypeChecker<'a, 'tcx> { } struct BorrowCheckContext<'a, 'tcx> { - universal_regions: &'a UniversalRegions<'tcx>, + pub(crate) universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a LocationTable, all_facts: &'a mut Option<AllFacts>, borrow_set: &'a BorrowSet<'tcx>, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>, upvars: &'a [Upvar<'tcx>], } @@ -944,7 +947,7 @@ crate struct MirTypeckRegionConstraints<'tcx> { crate type_tests: Vec<TypeTest<'tcx>>, } -impl MirTypeckRegionConstraints<'tcx> { +impl<'tcx> MirTypeckRegionConstraints<'tcx> { fn placeholder_region( &mut self, infcx: &InferCtxt<'_, 'tcx>, @@ -1156,6 +1159,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) } + #[instrument(skip(self, category), level = "debug")] fn eq_types( &mut self, expected: Ty<'tcx>, @@ -1343,13 +1347,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // though. let category = match place.as_local() { Some(RETURN_PLACE) => { - if let BorrowCheckContext { - universal_regions: - UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, - .. - } = self.borrowck_context - { - if tcx.is_static(*def_id) { + let defining_ty = &self.borrowck_context.universal_regions.defining_ty; + if defining_ty.is_const() { + if tcx.is_static(defining_ty.def_id()) { ConstraintCategory::UseAsStatic } else { ConstraintCategory::UseAsConst @@ -1479,7 +1479,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { StatementKind::FakeRead(..) | StatementKind::StorageLive(..) | StatementKind::StorageDead(..) - | StatementKind::LlvmInlineAsm { .. } | StatementKind::Retag { .. } | StatementKind::Coverage(..) | StatementKind::Nop => {} @@ -1527,6 +1526,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { + self.check_operand(discr, term_location); + let discr_ty = discr.ty(body, tcx); if let Err(terr) = self.sub_types( discr_ty, @@ -1549,6 +1550,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // FIXME: check the values } TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { + self.check_operand(func, term_location); + for arg in args { + self.check_operand(arg, term_location); + } + let func_ty = func.ty(body, tcx); debug!("check_terminator: call, func_ty={:?}", func_ty); let sig = match func_ty.kind() { @@ -1593,6 +1599,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call); } TerminatorKind::Assert { ref cond, ref msg, .. } => { + self.check_operand(cond, term_location); + let cond_ty = cond.ty(body, tcx); if cond_ty != tcx.types.bool { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); @@ -1608,6 +1616,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } TerminatorKind::Yield { ref value, .. } => { + self.check_operand(value, term_location); + let value_ty = value.ty(body, tcx); match body.yield_ty() { None => span_mirbug!(self, term, "yield in non-generator"), @@ -1650,7 +1660,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(RETURN_PLACE) => { if let BorrowCheckContext { universal_regions: - UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, + UniversalRegions { + defining_ty: + DefiningTy::Const(def_id, _) + | DefiningTy::InlineConst(def_id, _), + .. + }, .. } = self.borrowck_context { @@ -1814,10 +1829,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.assert_iscleanup(body, block_data, unwind, true); } } - TerminatorKind::InlineAsm { destination, .. } => { + TerminatorKind::InlineAsm { destination, cleanup, .. } => { if let Some(target) = destination { self.assert_iscleanup(body, block_data, target, is_cleanup); } + if let Some(cleanup) = cleanup { + if is_cleanup { + span_mirbug!(self, block_data, "cleanup on cleanup block") + } + self.assert_iscleanup(body, block_data, cleanup, true); + } } } } @@ -1896,7 +1917,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let tcx = self.tcx(); match *ak { - AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => { + AggregateKind::Adt(adt_did, variant_index, substs, _, active_field_index) => { + let def = tcx.adt_def(adt_did); let variant = &def.variants[variant_index]; let adj_field_index = active_field_index.unwrap_or(field_index); if let Some(field) = variant.fields.get(adj_field_index) { @@ -1931,15 +1953,51 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) { + if let Operand::Constant(constant) = op { + let maybe_uneval = match constant.literal { + ConstantKind::Ty(ct) => match ct.val { + ty::ConstKind::Unevaluated(uv) => Some(uv), + _ => None, + }, + _ => None, + }; + if let Some(uv) = maybe_uneval { + if uv.promoted.is_none() { + let tcx = self.tcx(); + let def_id = uv.def.def_id_for_type_of(); + if tcx.def_kind(def_id) == DefKind::InlineConst { + let predicates = self.prove_closure_bounds( + tcx, + def_id.expect_local(), + uv.substs, + location, + ); + self.normalize_and_prove_instantiated_predicates( + def_id, + predicates, + location.to_locations(), + ); + } + } + } + } + } + fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { let tcx = self.tcx(); match rvalue { Rvalue::Aggregate(ak, ops) => { + for op in ops { + self.check_operand(op, location); + } self.check_aggregate_rvalue(&body, rvalue, ak, ops, location) } Rvalue::Repeat(operand, len) => { + self.check_operand(operand, location); + // If the length cannot be evaluated we must assume that the length can be larger // than 1. // If the length is larger than 1, the repeat expression will need to copy the @@ -1990,7 +2048,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => { + Rvalue::NullaryOp(_, ty) => { + let trait_ref = ty::TraitRef { + def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), + substs: tcx.mk_substs_trait(ty, &[]), + }; + + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); + } + + Rvalue::ShallowInitBox(operand, ty) => { + self.check_operand(operand, location); + let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), @@ -2004,6 +2077,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Rvalue::Cast(cast_kind, op, ty) => { + self.check_operand(op, location); + match cast_kind { CastKind::Pointer(PointerCast::ReifyFnPointer) => { let fn_sig = op.ty(body, tcx).fn_sig(tcx); @@ -2250,6 +2325,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, box (left, right), ) => { + self.check_operand(left, location); + self.check_operand(right, location); + let ty_left = left.ty(body, tcx); match ty_left.kind() { // Types with regions are comparable if they have a common super-type. @@ -2300,13 +2378,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => { + self.check_operand(operand, location); + } + + Rvalue::BinaryOp(_, box (left, right)) + | Rvalue::CheckedBinaryOp(_, box (left, right)) => { + self.check_operand(left, location); + self.check_operand(right, location); + } + Rvalue::AddressOf(..) | Rvalue::ThreadLocalRef(..) - | Rvalue::Use(..) | Rvalue::Len(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) => {} } } @@ -2539,8 +2623,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); let (def_id, instantiated_predicates) = match aggregate_kind { - AggregateKind::Adt(def, _, substs, _, _) => { - (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs)) + AggregateKind::Adt(adt_did, _, substs, _, _) => { + (*adt_did, tcx.predicates_of(*adt_did).instantiate(tcx, substs)) } // For closures, we have some **extra requirements** we diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 415d1abaa8b..cc3fe0a123c 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -51,7 +51,7 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { universe_info: UniverseInfo<'tcx>, } -impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { +impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { fn new( type_checker: &'me mut TypeChecker<'bccx, 'tcx>, locations: Locations, @@ -62,7 +62,7 @@ impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { } } -impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { +impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> { self.type_checker.param_env } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 147e2aead64..16a903d5e59 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt}; use std::iter; use crate::nll::ToRegionVid; @@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> { /// is that it has no inputs and a single return value, which is /// the value of the constant. Const(DefId, SubstsRef<'tcx>), + + /// The MIR represents an inline const. The signature has no inputs and a + /// single return value found via `InlineConstSubsts::ty`. + InlineConst(DefId, SubstsRef<'tcx>), } impl<'tcx> DefiningTy<'tcx> { @@ -121,7 +125,7 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Generator(_, substs, _) => { Either::Right(Either::Left(substs.as_generator().upvar_tys())) } - DefiningTy::FnDef(..) | DefiningTy::Const(..) => { + DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => { Either::Right(Either::Right(iter::empty())) } } @@ -133,7 +137,7 @@ impl<'tcx> DefiningTy<'tcx> { pub fn implicit_inputs(self) -> usize { match self { DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1, - DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0, + DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, } } @@ -142,7 +146,7 @@ impl<'tcx> DefiningTy<'tcx> { } pub fn is_const(&self) -> bool { - matches!(*self, DefiningTy::Const(..)) + matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..)) } pub fn def_id(&self) -> DefId { @@ -150,7 +154,8 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(def_id, ..) | DefiningTy::Generator(def_id, ..) | DefiningTy::FnDef(def_id, ..) - | DefiningTy::Const(def_id, ..) => def_id, + | DefiningTy::Const(def_id, ..) + | DefiningTy::InlineConst(def_id, ..) => def_id, } } } @@ -175,8 +180,9 @@ pub enum RegionClassification { /// anywhere. There is only one, `'static`. Global, - /// An **external** region is only relevant for closures. In that - /// case, it refers to regions that are free in the closure type + /// An **external** region is only relevant for + /// closures, generators, and inline consts. In that + /// case, it refers to regions that are free in the type /// -- basically, something bound in the surrounding context. /// /// Consider this example: @@ -193,8 +199,8 @@ pub enum RegionClassification { /// Here, the lifetimes `'a` and `'b` would be **external** to the /// closure. /// - /// If we are not analyzing a closure, there are no external - /// lifetimes. + /// If we are not analyzing a closure/generator/inline-const, + /// there are no external lifetimes. External, /// A **local** lifetime is one about which we know the full set @@ -242,7 +248,7 @@ impl<'tcx> UniversalRegions<'tcx> { tcx: TyCtxt<'tcx>, closure_substs: SubstsRef<'tcx>, expected_num_vars: usize, - closure_base_def_id: DefId, + typeck_root_def_id: DefId, ) -> IndexVec<RegionVid, ty::Region<'tcx>> { let mut region_mapping = IndexVec::with_capacity(expected_num_vars); region_mapping.push(tcx.lifetimes.re_static); @@ -250,7 +256,7 @@ impl<'tcx> UniversalRegions<'tcx> { region_mapping.push(fr); }); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { region_mapping.push(r); }); @@ -344,8 +350,8 @@ impl<'tcx> UniversalRegions<'tcx> { // tests, and the resulting print-outs include def-ids // and other things that are not stable across tests! // So we just include the region-vid. Annoying. - let closure_base_def_id = tcx.closure_base_def_id(def_id); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); }); } @@ -359,8 +365,8 @@ impl<'tcx> UniversalRegions<'tcx> { // FIXME: As above, we'd like to print out the region // `r` but doing so is not stable across architectures // and so forth. - let closure_base_def_id = tcx.closure_base_def_id(def_id); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); }); } @@ -376,6 +382,12 @@ impl<'tcx> UniversalRegions<'tcx> { tcx.def_path_str_with_substs(def_id, substs), )); } + DefiningTy::InlineConst(def_id, substs) => { + err.note(&format!( + "defining inline constant type: {}", + tcx.def_path_str_with_substs(def_id, substs), + )); + } } } } @@ -411,24 +423,32 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let mut indices = self.compute_indices(fr_static, defining_ty); debug!("build: indices={:?}", indices); - let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); - // If this is a closure or generator, then the late-bound regions from the enclosing - // function are actually external regions to us. For example, here, 'a is not local - // to the closure c (although it is local to the fn foo): - // fn foo<'a>() { - // let c = || { let x: &'a u32 = ...; } - // } - if self.mir_def.did.to_def_id() != closure_base_def_id { + // If this is is a 'root' body (not a closure/generator/inline const), then + // there are no extern regions, so the local regions start at the same + // position as the (empty) sub-list of extern regions + let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id { + first_extern_index + } else { + // If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing + // function are actually external regions to us. For example, here, 'a is not local + // to the closure c (although it is local to the fn foo): + // fn foo<'a>() { + // let c = || { let x: &'a u32 = ...; } + // } self.infcx - .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices) - } - - let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); + .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices); + // Any regions created during the execution of `defining_ty` or during the above + // late-bound region replacement are all considered 'extern' regions + self.infcx.num_region_vars() + }; // "Liberate" the late-bound regions. These correspond to // "local" free regions. - let first_local_index = self.infcx.num_region_vars(); + + let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); + let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( FR, self.mir_def.did, @@ -437,7 +457,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { ); // Converse of above, if this is a function then the late-bound regions declared on its // signature are local to the fn. - if self.mir_def.did.to_def_id() == closure_base_def_id { + if self.mir_def.did.to_def_id() == typeck_root_def_id { self.infcx .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices); } @@ -502,12 +522,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { /// see `DefiningTy` for details. fn defining_ty(&self) -> DefiningTy<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); match tcx.hir().body_owner_kind(self.mir_hir_id) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id { - tcx.type_of(closure_base_def_id) + let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id { + tcx.type_of(typeck_root_def_id) } else { let tables = tcx.typeck(self.mir_def.did); tables.node_type(self.mir_hir_id) @@ -534,11 +554,21 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { - assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id); - let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); - let substs = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); - DefiningTy::Const(self.mir_def.did.to_def_id(), substs) + let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id); + if self.mir_def.did.to_def_id() == typeck_root_def_id { + let substs = + self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); + DefiningTy::Const(self.mir_def.did.to_def_id(), substs) + } else { + let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id); + let substs = InlineConstSubsts::new( + tcx, + InlineConstSubstsParts { parent_substs: identity_substs, ty }, + ) + .substs; + let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs); + DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs) + } } } } @@ -553,17 +583,19 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> UniversalRegionIndices<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); - let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); + let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id); let fr_substs = match defining_ty { - DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => { + DefiningTy::Closure(_, ref substs) + | DefiningTy::Generator(_, ref substs, _) + | DefiningTy::InlineConst(_, ref substs) => { // In the case of closures, we rely on the fact that // the first N elements in the ClosureSubsts are - // inherited from the `closure_base_def_id`. + // inherited from the `typeck_root_def_id`. // Therefore, when we zip together (below) with // `identity_substs`, we will get only those regions // that correspond to early-bound regions declared on - // the `closure_base_def_id`. + // the `typeck_root_def_id`. assert!(substs.len() >= identity_substs.len()); assert_eq!(substs.regions().count(), identity_substs.regions().count()); substs @@ -648,6 +680,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = indices.fold_to_region_vids(tcx, ty); ty::Binder::dummy(tcx.intern_type_list(&[ty])) } + + DefiningTy::InlineConst(def_id, substs) => { + assert_eq!(self.mir_def.did.to_def_id(), def_id); + let ty = substs.as_inline_const().ty(); + ty::Binder::dummy(tcx.intern_type_list(&[ty])) + } } } } @@ -736,8 +774,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { indices: &mut UniversalRegionIndices<'tcx>, ) { debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); - let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id()); - for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| { + 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); if !indices.indices.contains_key(&r) { let region_vid = self.next_nll_region_var(FR); |
