diff options
Diffstat (limited to 'compiler')
55 files changed, 849 insertions, 757 deletions
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 4824f6346d4..6be20b0974d 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -30,7 +30,7 @@ pub struct BorrowSet<'tcx> { /// Map from local to all the borrows on that local. pub local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>, - pub(crate) locals_state_at_exit: LocalsStateAtExit, + pub locals_state_at_exit: LocalsStateAtExit, } impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> { @@ -153,7 +153,7 @@ impl<'tcx> BorrowSet<'tcx> { self.activation_map.get(&location).map_or(&[], |activations| &activations[..]) } - pub(crate) fn len(&self) -> usize { + pub fn len(&self) -> usize { self.location_map.len() } diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 3451b7db8ca..dc20b371d92 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -3,22 +3,95 @@ //! This file provides API for compiler consumers. use rustc_hir::def_id::LocalDefId; -use rustc_index::IndexSlice; +use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_middle::mir::Body; +use rustc_middle::mir::{Body, Promoted}; use rustc_middle::ty::TyCtxt; +use std::rc::Rc; + +use crate::borrow_set::BorrowSet; pub use super::{ + constraints::OutlivesConstraint, + dataflow::{calculate_borrows_out_of_scope_at_location, BorrowIndex, Borrows}, facts::{AllFacts as PoloniusInput, RustcFacts}, location::{LocationTable, RichLocation}, nll::PoloniusOutput, - BodyWithBorrowckFacts, + place_ext::PlaceExt, + places_conflict::{places_conflict, PlaceConflictBias}, + region_infer::RegionInferenceContext, }; -/// This function computes Polonius facts for the given body. It makes a copy of -/// the body because it needs to regenerate the region identifiers. This function -/// should never be invoked during a typical compilation session due to performance -/// issues with Polonius. +/// Options determining the output behavior of [`get_body_with_borrowck_facts`]. +/// +/// If executing under `-Z polonius` the choice here has no effect, and everything as if +/// [`PoloniusOutputFacts`](ConsumerOptions::PoloniusOutputFacts) had been selected +/// will be retrieved. +#[derive(Debug, Copy, Clone)] +pub enum ConsumerOptions { + /// Retrieve the [`Body`] along with the [`BorrowSet`](super::borrow_set::BorrowSet) + /// and [`RegionInferenceContext`]. If you would like the body only, use + /// [`TyCtxt::mir_promoted`]. + /// + /// These can be used in conjunction with [`calculate_borrows_out_of_scope_at_location`]. + RegionInferenceContext, + /// The recommended option. Retrieves the maximal amount of information + /// without significant slowdowns. + /// + /// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext), + /// and additionally retrieve the [`LocationTable`] and [`PoloniusInput`] that + /// would be given to Polonius. Critically, this does not run Polonius, which + /// one may want to avoid due to performance issues on large bodies. + PoloniusInputFacts, + /// Implies [`PoloniusInputFacts`](ConsumerOptions::PoloniusInputFacts), + /// and additionally runs Polonius to calculate the [`PoloniusOutput`]. + PoloniusOutputFacts, +} + +impl ConsumerOptions { + /// Should the Polonius input facts be computed? + pub(crate) fn polonius_input(&self) -> bool { + matches!(self, Self::PoloniusInputFacts | Self::PoloniusOutputFacts) + } + /// Should we run Polonius and collect the output facts? + pub(crate) fn polonius_output(&self) -> bool { + matches!(self, Self::PoloniusOutputFacts) + } +} + +/// A `Body` with information computed by the borrow checker. This struct is +/// intended to be consumed by compiler consumers. +/// +/// We need to include the MIR body here because the region identifiers must +/// match the ones in the Polonius facts. +pub struct BodyWithBorrowckFacts<'tcx> { + /// A mir body that contains region identifiers. + pub body: Body<'tcx>, + /// The mir bodies of promoteds. + pub promoted: IndexVec<Promoted, Body<'tcx>>, + /// The set of borrows occurring in `body` with data about them. + pub borrow_set: Rc<BorrowSet<'tcx>>, + /// Context generated during borrowck, intended to be passed to + /// [`calculate_borrows_out_of_scope_at_location`]. + pub region_inference_context: Rc<RegionInferenceContext<'tcx>>, + /// The table that maps Polonius points to locations in the table. + /// Populated when using [`ConsumerOptions::PoloniusInputFacts`] + /// or [`ConsumerOptions::PoloniusOutputFacts`]. + pub location_table: Option<LocationTable>, + /// Polonius input facts. + /// Populated when using [`ConsumerOptions::PoloniusInputFacts`] + /// or [`ConsumerOptions::PoloniusOutputFacts`]. + pub input_facts: Option<Box<PoloniusInput>>, + /// Polonius output facts. Populated when using + /// [`ConsumerOptions::PoloniusOutputFacts`]. + pub output_facts: Option<Rc<PoloniusOutput>>, +} + +/// This function computes borrowck facts for the given body. The [`ConsumerOptions`] +/// determine which facts are returned. This function makes a copy of the body because +/// it needs to regenerate the region identifiers. It should never be invoked during a +/// typical compilation session due to the unnecessary overhead of returning +/// [`BodyWithBorrowckFacts`]. /// /// Note: /// * This function will panic if the required body was already stolen. This @@ -28,10 +101,14 @@ pub use super::{ /// that shows how to do this at `tests/run-make/obtain-borrowck/`. /// /// * Polonius is highly unstable, so expect regular changes in its signature or other details. -pub fn get_body_with_borrowck_facts(tcx: TyCtxt<'_>, def: LocalDefId) -> BodyWithBorrowckFacts<'_> { +pub fn get_body_with_borrowck_facts( + tcx: TyCtxt<'_>, + def: LocalDefId, + options: ConsumerOptions, +) -> BodyWithBorrowckFacts<'_> { let (input_body, promoted) = tcx.mir_promoted(def); let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def)).build(); let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); - *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() + *super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap() } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 167f245361a..4fe4d7085d7 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -231,27 +231,32 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { } } +pub fn calculate_borrows_out_of_scope_at_location<'tcx>( + body: &Body<'tcx>, + regioncx: &RegionInferenceContext<'tcx>, + borrow_set: &BorrowSet<'tcx>, +) -> FxIndexMap<Location, Vec<BorrowIndex>> { + let mut prec = OutOfScopePrecomputer::new(body, regioncx); + for (borrow_index, borrow_data) in borrow_set.iter_enumerated() { + let borrow_region = borrow_data.region; + let location = borrow_data.reserve_location; + + prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location); + } + + prec.borrows_out_of_scope_at_location +} + impl<'a, 'tcx> Borrows<'a, 'tcx> { - pub(crate) fn new( + pub fn new( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, nonlexical_regioncx: &'a RegionInferenceContext<'tcx>, borrow_set: &'a BorrowSet<'tcx>, ) -> Self { - let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx); - for (borrow_index, borrow_data) in borrow_set.iter_enumerated() { - let borrow_region = borrow_data.region; - let location = borrow_data.reserve_location; - - prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location); - } - - Borrows { - tcx, - body, - borrow_set, - borrows_out_of_scope_at_location: prec.borrows_out_of_scope_at_location, - } + let borrows_out_of_scope_at_location = + calculate_borrows_out_of_scope_at_location(body, nonlexical_regioncx, borrow_set); + Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location } } pub fn location(&self, idx: BorrowIndex) -> &Location { diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 84f75caa692..f41795d60a0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -128,7 +128,7 @@ impl<'tcx> ToUniverseInfo<'tcx> } } -impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> { +impl<'tcx, F> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F>> { fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { // We can't rerun custom type ops. UniverseInfo::other() diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 863c92acdf4..036391d074d 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -46,7 +46,7 @@ struct InvalidationGenerator<'cx, 'tcx> { all_facts: &'cx mut AllFacts, location_table: &'cx LocationTable, body: &'cx Body<'tcx>, - dominators: Dominators<BasicBlock>, + dominators: &'cx Dominators<BasicBlock>, borrow_set: &'cx BorrowSet<'tcx>, } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index eb25d454339..5124aa459b6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -43,7 +43,6 @@ use rustc_target::abi::FieldIdx; use either::Either; use smallvec::SmallVec; -use std::cell::OnceCell; use std::cell::RefCell; use std::collections::BTreeMap; use std::ops::Deref; @@ -62,7 +61,7 @@ use crate::session_diagnostics::VarNeedNotMut; use self::diagnostics::{AccessKind, RegionName}; use self::location::LocationTable; use self::prefixes::PrefixSet; -use facts::AllFacts; +use consumers::{BodyWithBorrowckFacts, ConsumerOptions}; use self::path_utils::*; @@ -144,7 +143,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build(); let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); - let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, false).0; + let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0; debug!("mir_borrowck done"); tcx.arena.alloc(opt_closure_req) @@ -152,15 +151,15 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { /// Perform the actual borrow checking. /// -/// If `return_body_with_facts` is true, then return the body with non-erased -/// region ids on which the borrow checking was performed together with Polonius -/// facts. +/// Use `consumer_options: None` for the default behavior of returning +/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according +/// to the given [`ConsumerOptions`]. #[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")] fn do_mir_borrowck<'tcx>( infcx: &InferCtxt<'tcx>, input_body: &Body<'tcx>, input_promoted: &IndexSlice<Promoted, Body<'tcx>>, - return_body_with_facts: bool, + consumer_options: Option<ConsumerOptions>, ) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) { let def = input_body.source.def_id().expect_local(); debug!(?def); @@ -241,8 +240,6 @@ fn do_mir_borrowck<'tcx>( let borrow_set = Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); - let use_polonius = return_body_with_facts || infcx.tcx.sess.opts.unstable_opts.polonius; - // Compute non-lexical lifetimes. let nll::NllOutput { regioncx, @@ -262,7 +259,7 @@ fn do_mir_borrowck<'tcx>( &mdpe.move_data, &borrow_set, &upvars, - use_polonius, + consumer_options, ); // Dump MIR results into a file, if that is enabled. This let us @@ -331,7 +328,6 @@ fn do_mir_borrowck<'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - dominators: Default::default(), upvars: Vec::new(), local_names: IndexVec::from_elem(None, &promoted_body.local_decls), region_names: RefCell::default(), @@ -360,7 +356,6 @@ fn do_mir_borrowck<'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - dominators: Default::default(), upvars, local_names, region_names: RefCell::default(), @@ -444,13 +439,16 @@ fn do_mir_borrowck<'tcx>( tainted_by_errors, }; - let body_with_facts = if return_body_with_facts { - let output_facts = mbcx.polonius_output.expect("Polonius output was not computed"); + let body_with_facts = if consumer_options.is_some() { + let output_facts = mbcx.polonius_output; Some(Box::new(BodyWithBorrowckFacts { body: body_owned, - input_facts: *polonius_input.expect("Polonius input facts were not generated"), + promoted, + borrow_set, + region_inference_context: regioncx, + location_table: polonius_input.as_ref().map(|_| location_table_owned), + input_facts: polonius_input, output_facts, - location_table: location_table_owned, })) } else { None @@ -461,22 +459,6 @@ fn do_mir_borrowck<'tcx>( (result, body_with_facts) } -/// A `Body` with information computed by the borrow checker. This struct is -/// intended to be consumed by compiler consumers. -/// -/// We need to include the MIR body here because the region identifiers must -/// match the ones in the Polonius facts. -pub struct BodyWithBorrowckFacts<'tcx> { - /// A mir body that contains region identifiers. - pub body: Body<'tcx>, - /// Polonius input facts. - pub input_facts: AllFacts, - /// Polonius output facts. - pub output_facts: Rc<self::nll::PoloniusOutput>, - /// The table that maps Polonius points to locations in the table. - pub location_table: LocationTable, -} - pub struct BorrowckInferCtxt<'cx, 'tcx> { pub(crate) infcx: &'cx InferCtxt<'tcx>, pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>, @@ -591,9 +573,6 @@ struct MirBorrowckCtxt<'cx, 'tcx> { /// The set of borrows extracted from the MIR borrow_set: Rc<BorrowSet<'tcx>>, - /// Dominators for MIR - dominators: OnceCell<Dominators<BasicBlock>>, - /// Information about upvars not necessarily preserved in types or MIR upvars: Vec<Upvar<'tcx>>, @@ -2269,7 +2248,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } fn dominators(&self) -> &Dominators<BasicBlock> { - self.dominators.get_or_init(|| self.body.basic_blocks.dominators()) + // `BasicBlocks` computes dominators on-demand and caches them. + self.body.basic_blocks.dominators() } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index b6ccf924a5c..889acb3acbe 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -27,6 +27,7 @@ use rustc_mir_dataflow::ResultsCursor; use crate::{ borrow_set::BorrowSet, constraint_generation, + consumers::ConsumerOptions, diagnostics::RegionErrors, facts::{AllFacts, AllFactsExt, RustcFacts}, invalidation, @@ -165,10 +166,14 @@ pub(crate) fn compute_regions<'cx, 'tcx>( move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, upvars: &[Upvar<'tcx>], - use_polonius: bool, + consumer_options: Option<ConsumerOptions>, ) -> NllOutput<'tcx> { + let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default() + || infcx.tcx.sess.opts.unstable_opts.polonius; + let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default() + || infcx.tcx.sess.opts.unstable_opts.polonius; let mut all_facts = - (use_polonius || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); + (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); let universal_regions = Rc::new(universal_regions); @@ -189,7 +194,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( move_data, elements, upvars, - use_polonius, + polonius_input, ); if let Some(all_facts) = &mut all_facts { @@ -284,7 +289,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( all_facts.write_to_dir(dir_path, location_table).unwrap(); } - if use_polonius { + if polonius_output { let algorithm = env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid")); let algorithm = Algorithm::from_str(&algorithm).unwrap(); diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs index 85d207b2fc9..d521d0db213 100644 --- a/compiler/rustc_borrowck/src/place_ext.rs +++ b/compiler/rustc_borrowck/src/place_ext.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::{Body, Mutability, Place}; use rustc_middle::ty::{self, TyCtxt}; /// Extension methods for the `Place` type. -pub(crate) trait PlaceExt<'tcx> { +pub trait PlaceExt<'tcx> { /// Returns `true` if we can safely ignore borrows of this place. /// This is true whenever there is no action that the user can do /// to the place `self` that would invalidate the borrow. This is true diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 918fb2d6923..25c485b814f 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -16,7 +16,7 @@ use std::iter; /// being run in the calling context, the conservative choice is to assume the compared indices /// are disjoint (and therefore, do not overlap). #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub(crate) enum PlaceConflictBias { +pub enum PlaceConflictBias { Overlap, NoOverlap, } @@ -24,7 +24,7 @@ pub(crate) enum PlaceConflictBias { /// Helper function for checking if places conflict with a mutable borrow and deep access depth. /// This is used to check for places conflicting outside of the borrow checking code (such as in /// dataflow). -pub(crate) fn places_conflict<'tcx>( +pub fn places_conflict<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, borrow_place: Place<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 8fbe814c856..9bb46a50d3c 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -585,6 +585,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.universal_regions.to_region_vid(r) } + /// Returns an iterator over all the outlives constraints. + pub fn outlives_constraints(&self) -> impl Iterator<Item = OutlivesConstraint<'tcx>> + '_ { + self.constraints.outlives().iter().copied() + } + /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { self.universal_regions.annotate(tcx, err) @@ -698,7 +703,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(skip(self, _body), level = "debug")] fn propagate_constraints(&mut self, _body: &Body<'tcx>) { debug!("constraints={:#?}", { - let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); + let mut constraints: Vec<_> = self.outlives_constraints().collect(); constraints.sort_by_key(|c| (c.sup, c.sub)); constraints .into_iter() diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 309f23d9226..e9b5c47ce23 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -152,8 +152,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { let guar = ty.error_reported().err().unwrap_or_else(|| { prev.report_mismatch( &OpaqueHiddenType { ty, span: concrete_type.span }, + opaque_type_key.def_id, infcx.tcx, ) + .emit() }); prev.ty = infcx.tcx.ty_error(guar); } diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index b27d5d20532..95dcc8d4b19 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -1,13 +1,13 @@ use std::fmt; -use rustc_infer::infer::{canonical::Canonical, InferOk}; +use rustc_infer::infer::canonical::Canonical; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; use rustc_trait_selection::traits::query::{Fallible, NoSolution}; -use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; +use rustc_trait_selection::traits::ObligationCause; use crate::diagnostics::{ToUniverseInfo, UniverseInfo}; @@ -219,20 +219,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let cause = ObligationCause::dummy_with_span(span); let param_env = self.param_env; - let op = |infcx: &'_ _| { - let ocx = ObligationCtxt::new_in_snapshot(infcx); - let user_ty = ocx.normalize(&cause, param_env, user_ty); - ocx.eq(&cause, param_env, user_ty, mir_ty)?; - if !ocx.select_all_or_error().is_empty() { - return Err(NoSolution); - } - Ok(InferOk { value: (), obligations: vec![] }) - }; - self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, - type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()), + type_op::custom::CustomTypeOp::new( + |ocx| { + let user_ty = ocx.normalize(&cause, param_env, user_ty); + ocx.eq(&cause, param_env, user_ty, mir_ty)?; + Ok(()) + }, + "ascribe_user_type_skip_wf", + ), ) .unwrap_or_else(|err| { span_mirbug!( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fa4bc926f27..ab5e01e1952 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -20,7 +20,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ - InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin, + InferCtxt, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin, }; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; @@ -218,16 +218,16 @@ pub(crate) fn type_check<'mir, 'tcx>( Locations::All(body.span), ConstraintCategory::OpaqueType, CustomTypeOp::new( - |infcx| { - infcx.register_member_constraints( + |ocx| { + ocx.infcx.register_member_constraints( param_env, opaque_type_key, decl.hidden_type.ty, decl.hidden_type.span, ); - Ok(InferOk { value: (), obligations: vec![] }) + Ok(()) }, - || "opaque_type_map".to_string(), + "opaque_type_map", ), ) .unwrap(); @@ -2713,8 +2713,9 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { type ErrorInfo = InstantiateOpaqueType<'tcx>; fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { - let (mut output, region_constraints) = scrape_region_constraints(infcx, || { - Ok(InferOk { value: (), obligations: self.obligations.clone() }) + let (mut output, region_constraints) = scrape_region_constraints(infcx, |ocx| { + ocx.register_obligations(self.obligations.clone()); + Ok(()) })?; self.region_constraints = Some(region_constraints); output.error_info = Some(self); diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 7158c62b548..dd1f89e5b91 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -185,17 +185,25 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> } fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { - self.type_checker - .fully_perform_op( - self.locations, - self.category, - InstantiateOpaqueType { - obligations, - // These fields are filled in during execution of the operation - base_universe: None, - region_constraints: None, - }, - ) - .unwrap(); + match self.type_checker.fully_perform_op( + self.locations, + self.category, + InstantiateOpaqueType { + obligations, + // These fields are filled in during execution of the operation + base_universe: None, + region_constraints: None, + }, + ) { + Ok(()) => {} + Err(_) => { + // It's a bit redundant to delay a bug here, but I'd rather + // delay more bugs than accidentally not delay a bug at all. + self.type_checker.tcx().sess.delay_span_bug( + self.locations.span(self.type_checker.body), + "errors selecting obligation during MIR typeck", + ); + } + }; } } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 6a86237d79e..805843e5863 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -10,6 +10,7 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] +#![feature(impl_trait_in_assoc_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 994addf12eb..03be0654b50 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -16,7 +16,6 @@ use rustc_session::config::PrintRequest; use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; -use smallvec::{smallvec, SmallVec}; use std::ffi::{CStr, CString}; use std::path::Path; @@ -132,6 +131,60 @@ pub fn time_trace_profiler_finish(file_name: &Path) { } } +pub enum TargetFeatureFoldStrength<'a> { + // The feature is only tied when enabling the feature, disabling + // this feature shouldn't disable the tied feature. + EnableOnly(&'a str), + // The feature is tied for both enabling and disabling this feature. + Both(&'a str), +} + +impl<'a> TargetFeatureFoldStrength<'a> { + fn as_str(&self) -> &'a str { + match self { + TargetFeatureFoldStrength::EnableOnly(feat) => feat, + TargetFeatureFoldStrength::Both(feat) => feat, + } + } +} + +pub struct LLVMFeature<'a> { + pub llvm_feature_name: &'a str, + pub dependency: Option<TargetFeatureFoldStrength<'a>>, +} + +impl<'a> LLVMFeature<'a> { + pub fn new(llvm_feature_name: &'a str) -> Self { + Self { llvm_feature_name, dependency: None } + } + + pub fn with_dependency( + llvm_feature_name: &'a str, + dependency: TargetFeatureFoldStrength<'a>, + ) -> Self { + Self { llvm_feature_name, dependency: Some(dependency) } + } + + pub fn contains(&self, feat: &str) -> bool { + self.iter().any(|dep| dep == feat) + } + + pub fn iter(&'a self) -> impl Iterator<Item = &'a str> { + let dependencies = self.dependency.iter().map(|feat| feat.as_str()); + std::iter::once(self.llvm_feature_name).chain(dependencies) + } +} + +impl<'a> IntoIterator for LLVMFeature<'a> { + type Item = &'a str; + type IntoIter = impl Iterator<Item = &'a str>; + + fn into_iter(self) -> Self::IntoIter { + let dependencies = self.dependency.into_iter().map(|feat| feat.as_str()); + std::iter::once(self.llvm_feature_name).chain(dependencies) + } +} + // WARNING: the features after applying `to_llvm_features` must be known // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. @@ -147,36 +200,65 @@ pub fn time_trace_profiler_finish(file_name: &Path) { // Though note that Rust can also be build with an external precompiled version of LLVM // which might lead to failures if the oldest tested / supported LLVM version // doesn't yet support the relevant intrinsics -pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { +pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> { let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { - ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"], - ("x86", "pclmulqdq") => smallvec!["pclmul"], - ("x86", "rdrand") => smallvec!["rdrnd"], - ("x86", "bmi1") => smallvec!["bmi"], - ("x86", "cmpxchg16b") => smallvec!["cx16"], - ("aarch64", "rcpc2") => smallvec!["rcpc-immo"], - ("aarch64", "dpb") => smallvec!["ccpp"], - ("aarch64", "dpb2") => smallvec!["ccdp"], - ("aarch64", "frintts") => smallvec!["fptoint"], - ("aarch64", "fcma") => smallvec!["complxnum"], - ("aarch64", "pmuv3") => smallvec!["perfmon"], - ("aarch64", "paca") => smallvec!["pauth"], - ("aarch64", "pacg") => smallvec!["pauth"], - // Rust ties fp and neon together. In LLVM neon implicitly enables fp, - // but we manually enable neon when a feature only implicitly enables fp - ("aarch64", "f32mm") => smallvec!["f32mm", "neon"], - ("aarch64", "f64mm") => smallvec!["f64mm", "neon"], - ("aarch64", "fhm") => smallvec!["fp16fml", "neon"], - ("aarch64", "fp16") => smallvec!["fullfp16", "neon"], - ("aarch64", "jsconv") => smallvec!["jsconv", "neon"], - ("aarch64", "sve") => smallvec!["sve", "neon"], - ("aarch64", "sve2") => smallvec!["sve2", "neon"], - ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"], - ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"], - ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"], - ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"], - (_, s) => smallvec![s], + ("x86", "sse4.2") => { + LLVMFeature::with_dependency("sse4.2", TargetFeatureFoldStrength::EnableOnly("crc32")) + } + ("x86", "pclmulqdq") => LLVMFeature::new("pclmul"), + ("x86", "rdrand") => LLVMFeature::new("rdrnd"), + ("x86", "bmi1") => LLVMFeature::new("bmi"), + ("x86", "cmpxchg16b") => LLVMFeature::new("cx16"), + ("aarch64", "rcpc2") => LLVMFeature::new("rcpc-immo"), + ("aarch64", "dpb") => LLVMFeature::new("ccpp"), + ("aarch64", "dpb2") => LLVMFeature::new("ccdp"), + ("aarch64", "frintts") => LLVMFeature::new("fptoint"), + ("aarch64", "fcma") => LLVMFeature::new("complxnum"), + ("aarch64", "pmuv3") => LLVMFeature::new("perfmon"), + ("aarch64", "paca") => LLVMFeature::new("pauth"), + ("aarch64", "pacg") => LLVMFeature::new("pauth"), + // Rust ties fp and neon together. + ("aarch64", "neon") => { + LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8")) + } + // In LLVM neon implicitly enables fp, but we manually enable + // neon when a feature only implicitly enables fp + ("aarch64", "f32mm") => { + LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "f64mm") => { + LLVMFeature::with_dependency("f64mm", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "fhm") => { + LLVMFeature::with_dependency("fp16fml", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "fp16") => { + LLVMFeature::with_dependency("fullfp16", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "jsconv") => { + LLVMFeature::with_dependency("jsconv", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve") => { + LLVMFeature::with_dependency("sve", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2") => { + LLVMFeature::with_dependency("sve2", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2-aes") => { + LLVMFeature::with_dependency("sve2-aes", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2-sm4") => { + LLVMFeature::with_dependency("sve2-sm4", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2-sha3") => { + LLVMFeature::with_dependency("sve2-sha3", TargetFeatureFoldStrength::EnableOnly("neon")) + } + ("aarch64", "sve2-bitperm") => LLVMFeature::with_dependency( + "sve2-bitperm", + TargetFeatureFoldStrength::EnableOnly("neon"), + ), + (_, s) => LLVMFeature::new(s), } } @@ -274,18 +356,17 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { let mut rustc_target_features = supported_target_features(sess) .iter() .map(|(feature, _gate)| { - let desc = if let Some(llvm_feature) = to_llvm_features(sess, *feature).first() { - // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. + // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. + let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name; + let desc = match llvm_target_features.binary_search_by_key(&llvm_feature, |(f, _d)| f).ok() { Some(index) => { known_llvm_target_features.insert(llvm_feature); llvm_target_features[index].1 } None => "", - } - } else { - "" - }; + }; + (*feature, desc) }) .collect::<Vec<_>>(); @@ -469,10 +550,19 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two // different names when the LLVM name and the Rust name differ. + let llvm_feature = to_llvm_features(sess, feature); + Some( - to_llvm_features(sess, feature) - .into_iter() - .map(move |f| format!("{}{}", enable_disable, f)), + std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name)) + .chain(llvm_feature.dependency.into_iter().filter_map(move |feat| { + match (enable_disable, feat) { + ('-' | '+', TargetFeatureFoldStrength::Both(f)) + | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => { + Some(format!("{}{}", enable_disable, f)) + } + _ => None, + } + })), ) }) .flatten(); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 1e57f4248d2..cd56f85cccd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -144,7 +144,7 @@ pub fn get_linker<'a>( cmd, sess, target_cpu, - hinted_static: false, + hinted_static: None, is_ld: cc == Cc::No, is_gnu: flavor.is_gnu(), }) as Box<dyn Linker>, @@ -214,7 +214,7 @@ pub struct GccLinker<'a> { cmd: Command, sess: &'a Session, target_cpu: &'a str, - hinted_static: bool, // Keeps track of the current hinting mode. + hinted_static: Option<bool>, // Keeps track of the current hinting mode. // Link as ld is_ld: bool, is_gnu: bool, @@ -275,9 +275,9 @@ impl<'a> GccLinker<'a> { if !self.takes_hints() { return; } - if !self.hinted_static { + if self.hinted_static != Some(true) { self.linker_arg("-Bstatic"); - self.hinted_static = true; + self.hinted_static = Some(true); } } @@ -285,9 +285,9 @@ impl<'a> GccLinker<'a> { if !self.takes_hints() { return; } - if self.hinted_static { + if self.hinted_static != Some(false) { self.linker_arg("-Bdynamic"); - self.hinted_static = false; + self.hinted_static = Some(false); } } @@ -1484,25 +1484,25 @@ impl<'a> L4Bender<'a> { pub struct AixLinker<'a> { cmd: Command, sess: &'a Session, - hinted_static: bool, + hinted_static: Option<bool>, } impl<'a> AixLinker<'a> { pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { - AixLinker { cmd: cmd, sess: sess, hinted_static: false } + AixLinker { cmd: cmd, sess: sess, hinted_static: None } } fn hint_static(&mut self) { - if !self.hinted_static { + if self.hinted_static != Some(true) { self.cmd.arg("-bstatic"); - self.hinted_static = true; + self.hinted_static = Some(true); } } fn hint_dynamic(&mut self) { - if self.hinted_static { + if self.hinted_static != Some(false) { self.cmd.arg("-bdynamic"); - self.hinted_static = false; + self.hinted_static = Some(false); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 569599faa36..835074806e9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -84,7 +84,7 @@ impl DefLocation { struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { fx: &'mir FunctionCx<'a, 'tcx, Bx>, - dominators: Dominators<mir::BasicBlock>, + dominators: &'mir Dominators<mir::BasicBlock>, locals: IndexVec<mir::Local, LocalKind>, } diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 4e80a285186..11ad5b49df2 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -58,11 +58,12 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { // Types with identity (print the module path). ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs) | ty::FnDef(def_id, substs) - | ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) | ty::Closure(def_id, substs) | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), + ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"), ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"), } diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 594ed1ad2e7..a5db14d9102 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -26,7 +26,7 @@ rustc_index::newtype_index! { struct PreorderIndex {} } -pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> { +pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> { // compute the post order index (rank) for each node let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes()); @@ -244,7 +244,10 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> { let start_node = graph.start_node(); immediate_dominators[start_node] = None; - Dominators { start_node, post_order_rank, immediate_dominators } + + let time = compute_access_time(start_node, &immediate_dominators); + + Dominators { start_node, post_order_rank, immediate_dominators, time } } /// Evaluate the link-eval virtual forest, providing the currently minimum semi @@ -316,6 +319,7 @@ pub struct Dominators<N: Idx> { // possible to get its full list of dominators by looking up the dominator // of each dominator. (See the `impl Iterator for Iter` definition). immediate_dominators: IndexVec<N, Option<N>>, + time: IndexVec<N, Time>, } impl<Node: Idx> Dominators<Node> { @@ -333,12 +337,7 @@ impl<Node: Idx> Dominators<Node> { /// See the `impl Iterator for Iter` definition to understand how this works. pub fn dominators(&self, node: Node) -> Iter<'_, Node> { assert!(self.is_reachable(node), "node {node:?} is not reachable"); - Iter { dominators: self, node: Some(node) } - } - - pub fn dominates(&self, dom: Node, node: Node) -> bool { - // FIXME -- could be optimized by using post-order-rank - self.dominators(node).any(|n| n == dom) + Iter { dom_tree: self, node: Some(node) } } /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator @@ -348,10 +347,22 @@ impl<Node: Idx> Dominators<Node> { pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> { self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs]) } + + /// Returns true if `a` dominates `b`. + /// + /// # Panics + /// + /// Panics if `b` is unreachable. + pub fn dominates(&self, a: Node, b: Node) -> bool { + let a = self.time[a]; + let b = self.time[b]; + assert!(b.start != 0, "node {b:?} is not reachable"); + a.start <= b.start && b.finish <= a.finish + } } pub struct Iter<'dom, Node: Idx> { - dominators: &'dom Dominators<Node>, + dom_tree: &'dom Dominators<Node>, node: Option<Node>, } @@ -360,10 +371,74 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { fn next(&mut self) -> Option<Self::Item> { if let Some(node) = self.node { - self.node = self.dominators.immediate_dominator(node); + self.node = self.dom_tree.immediate_dominator(node); Some(node) } else { None } } } + +/// Describes the number of vertices discovered at the time when processing of a particular vertex +/// started and when it finished. Both values are zero for unreachable vertices. +#[derive(Copy, Clone, Default, Debug)] +struct Time { + start: u32, + finish: u32, +} + +fn compute_access_time<N: Idx>( + start_node: N, + immediate_dominators: &IndexSlice<N, Option<N>>, +) -> IndexVec<N, Time> { + // Transpose the dominator tree edges, so that child nodes of vertex v are stored in + // node[edges[v].start..edges[v].end]. + let mut edges: IndexVec<N, std::ops::Range<u32>> = + IndexVec::from_elem(0..0, immediate_dominators); + for &idom in immediate_dominators.iter() { + if let Some(idom) = idom { + edges[idom].end += 1; + } + } + let mut m = 0; + for e in edges.iter_mut() { + m += e.end; + e.start = m; + e.end = m; + } + let mut node = IndexVec::from_elem_n(Idx::new(0), m.try_into().unwrap()); + for (i, &idom) in immediate_dominators.iter_enumerated() { + if let Some(idom) = idom { + edges[idom].start -= 1; + node[edges[idom].start] = i; + } + } + + // Perform a depth-first search of the dominator tree. Record the number of vertices discovered + // when vertex v is discovered first as time[v].start, and when its processing is finished as + // time[v].finish. + let mut time: IndexVec<N, Time> = IndexVec::from_elem(Time::default(), immediate_dominators); + let mut stack = Vec::new(); + + let mut discovered = 1; + stack.push(start_node); + time[start_node].start = discovered; + + while let Some(&i) = stack.last() { + let e = &mut edges[i]; + if e.start == e.end { + // Finish processing vertex i. + time[i].finish = discovered; + stack.pop(); + } else { + let j = node[e.start]; + e.start += 1; + // Start processing vertex j. + discovered += 1; + time[j].start = discovered; + stack.push(j); + } + } + + time +} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5a80024f19b..074fbb1322c 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -478,6 +478,7 @@ pub enum StashKey { MaybeFruTypo, CallAssocMethod, TraitMissingMethod, + OpaqueHiddenTypeMismatch, } fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a33990813b8..e5b5dae551e 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -427,6 +427,8 @@ pub(super) fn explicit_predicates_of<'tcx>( // supertrait). if let ty::Alias(ty::Projection, projection) = ty.kind() { projection.substs == trait_identity_substs + // FIXME(return_type_notation): This check should be more robust + && !tcx.is_impl_trait_in_trait(projection.def_id) && tcx.associated_item(projection.def_id).container_id(tcx) == def_id.to_def_id() } else { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index ca430a5e863..97c6cb491d1 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -584,7 +584,8 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T debug!(?concrete_type, "found constraint"); if let Some(prev) = &mut self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { - let guar = prev.report_mismatch(&concrete_type, self.tcx); + let guar = + prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit(); prev.ty = self.tcx.ty_error(guar); } } else { @@ -678,10 +679,10 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T // Only check against typeck if we didn't already error if !hidden.ty.references_error() { for concrete_type in locator.typeck_types { - if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty) + if concrete_type.ty != tcx.erase_regions(hidden.ty) && !(concrete_type, hidden).references_error() { - hidden.report_mismatch(&concrete_type, tcx); + hidden.report_mismatch(&concrete_type, def_id, tcx).emit(); } } } @@ -722,7 +723,7 @@ fn find_opaque_ty_constraints_for_rpit( if concrete_type.ty != self.found.ty && !(concrete_type, self.found).references_error() { - self.found.report_mismatch(&concrete_type, self.tcx); + self.found.report_mismatch(&concrete_type, self.def_id, self.tcx).emit(); } } } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index bf8259ff70f..bfabd44bb57 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -32,6 +32,7 @@ pub(super) fn check_fn<'a, 'tcx>( fn_def_id: LocalDefId, body: &'tcx hir::Body<'tcx>, can_be_generator: Option<hir::Movability>, + params_can_be_unsized: bool, ) -> Option<GeneratorTypes<'tcx>> { let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id); @@ -94,7 +95,7 @@ pub(super) fn check_fn<'a, 'tcx>( // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params { + if param.pat.simple_ident().is_none() && !params_can_be_unsized { fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); } @@ -103,24 +104,8 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); - if let ty::Dynamic(_, _, ty::Dyn) = declared_ret_ty.kind() { - // FIXME: We need to verify that the return type is `Sized` after the return expression has - // been evaluated so that we have types available for all the nodes being returned, but that - // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this - // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, - // while keeping the current ordering we will ignore the tail expression's type because we - // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` - // because we will trigger "unreachable expression" lints unconditionally. - // Because of all of this, we perform a crude check to know whether the simplest `!Sized` - // case that a newcomer might make, returning a bare trait, and in that case we populate - // the tail expression's type so that the suggestion will be correct, but ignore all other - // possible cases. - fcx.check_expr(&body.value); - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - } else { - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - fcx.check_return_expr(&body.value, false); - } + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + fcx.check_return_expr(&body.value, false); // We insert the deferred_generator_interiors entry after visiting the body. // This ensures that all nested generators appear before the entry of this generator. diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 7046269c2de..9659a0ec13d 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -89,6 +89,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_def_id, body, closure.movability, + // Closure "rust-call" ABI doesn't support unsized params + false, ); let parent_substs = InternalSubsts::identity_for_item( diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 64426c4cbbb..b97b55d8f7e 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -212,7 +212,7 @@ fn typeck_with_fallback<'tcx>( let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = fcx.normalize(body.value.span, fn_sig); - check_fn(&mut fcx, fn_sig, decl, def_id, body, None); + check_fn(&mut fcx, fn_sig, decl, def_id, body, None, tcx.features().unsized_fn_params); } else { let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = body_ty { Some(fcx.next_ty_var(TypeVariableOrigin { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 59bf45f0ed2..98529b66602 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -471,7 +471,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_ty, method_self_ty, self.span, pick ); let cause = self.cause( - self.span, + self.self_expr.span, ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext { assoc_item: pick.item, param_env: self.param_env, @@ -482,13 +482,22 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } - Err(_) => { - span_bug!( - self.span, - "{} was a subtype of {} but now is not?", - self_ty, - method_self_ty - ); + Err(terr) => { + // FIXME(arbitrary_self_types): We probably should limit the + // situations where this can occur by adding additional restrictions + // to the feature, like the self type can't reference method substs. + if self.tcx.features().arbitrary_self_types { + self.err_ctxt() + .report_mismatched_types(&cause, method_self_ty, self_ty, terr) + .emit(); + } else { + span_bug!( + self.span, + "{} was a subtype of {} but now is not?", + self_ty, + method_self_ty + ); + } } } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 2daec205cfc..0f21fc1e662 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -5,7 +5,7 @@ use crate::FnCtxt; use hir::def_id::LocalDefId; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; @@ -82,10 +82,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.typeck_results.treat_byte_string_as_slice = mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice); - if let Some(e) = self.tainted_by_errors() { - wbcx.typeck_results.tainted_by_errors = Some(e); - } - debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results); self.tcx.arena.alloc(wbcx.typeck_results) @@ -118,12 +114,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ) -> WritebackCx<'cx, 'tcx> { let owner = body.id().hir_id.owner; - WritebackCx { + let mut wbcx = WritebackCx { fcx, typeck_results: ty::TypeckResults::new(owner), body, rustc_dump_user_substs, + }; + + // HACK: We specifically don't want the (opaque) error from tainting our + // inference context. That'll prevent us from doing opaque type inference + // later on in borrowck, which affects diagnostic spans pretty negatively. + if let Some(e) = fcx.tainted_by_errors() { + wbcx.typeck_results.tainted_by_errors = Some(e); } + + wbcx } fn tcx(&self) -> TyCtxt<'tcx> { @@ -578,13 +583,26 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { continue; } - let hidden_type = hidden_type.remap_generic_params_to_declaration_params( - opaque_type_key, - self.fcx.infcx.tcx, - true, - ); - - self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type); + let hidden_type = + self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params( + opaque_type_key, + self.tcx(), + true, + )); + + if let Some(last_opaque_ty) = self + .typeck_results + .concrete_opaque_types + .insert(opaque_type_key.def_id, hidden_type) + && last_opaque_ty.ty != hidden_type.ty + { + hidden_type + .report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx()) + .stash( + self.tcx().def_span(opaque_type_key.def_id), + StashKey::OpaqueHiddenTypeMismatch, + ); + } } } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 98ea9dc7501..209bf395624 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -148,11 +148,15 @@ impl CStore { assert_eq!(self.metas.len(), self.stable_crate_ids.len()); let num = CrateNum::new(self.stable_crate_ids.len()); if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) { - let crate_name0 = root.name(); - if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) { + // Check for (potential) conflicts with the local crate + if existing == LOCAL_CRATE { + Err(CrateError::SymbolConflictsCurrent(root.name())) + } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) + { + let crate_name0 = root.name(); Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)) } else { - Err(CrateError::SymbolConflictsCurrent(crate_name0)) + Err(CrateError::NotFound(root.name())) } } else { self.metas.push(None); diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 6ec691f73b7..1aab4adf0b3 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -961,6 +961,7 @@ pub(crate) enum CrateError { DlSym(String), LocatorCombined(Box<CombinedLocatorError>), NonDylibPlugin(Symbol), + NotFound(Symbol), } enum MetadataError<'a> { @@ -1131,6 +1132,18 @@ impl CrateError { CrateError::NonDylibPlugin(crate_name) => { sess.emit_err(errors::NoDylibPlugin { span, crate_name }); } + CrateError::NotFound(crate_name) => { + sess.emit_err(errors::CannotFindCrate { + span, + crate_name, + add_info: String::new(), + missing_core, + current_crate: sess.opts.crate_name.clone().unwrap_or("<unknown>".to_string()), + is_nightly_build: sess.is_nightly_build(), + profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime), + locator_triple: sess.opts.target_triple.clone(), + }); + } } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 364269095e0..7425963d30f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -323,7 +323,7 @@ provide! { tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } - traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } + traits => { tcx.arena.alloc_from_iter(cdata.get_traits()) } trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 40723f41959..f067bca4b0b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1938,7 +1938,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_traits(&mut self) -> LazyArray<DefIndex> { empty_proc_macro!(self); - self.lazy_array(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index)) + self.lazy_array(self.tcx.traits(LOCAL_CRATE).iter().map(|def_id| def_id.index)) } /// Encodes an index, mapping each trait to its (local) implementations. @@ -2329,7 +2329,7 @@ pub fn provide(providers: &mut Providers) { .get(&def_id) .expect("no traits in scope for a doc link") }, - traits_in_crate: |tcx, LocalCrate| { + traits: |tcx, LocalCrate| { let mut traits = Vec::new(); for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 1319ddbb877..9d70dbfa072 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -27,6 +27,7 @@ struct Cache { switch_sources: OnceCell<SwitchSources>, is_cyclic: OnceCell<bool>, postorder: OnceCell<Vec<BasicBlock>>, + dominators: OnceCell<Dominators<BasicBlock>>, } impl<'tcx> BasicBlocks<'tcx> { @@ -41,8 +42,8 @@ impl<'tcx> BasicBlocks<'tcx> { *self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self)) } - pub fn dominators(&self) -> Dominators<BasicBlock> { - dominators(&self) + pub fn dominators(&self) -> &Dominators<BasicBlock> { + self.cache.dominators.get_or_init(|| dominators(self)) } /// Returns predecessors for each basic block. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f5b42c80487..1528be42f6a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -38,7 +38,10 @@ use crate::traits::query::{ OutlivesBound, }; use crate::traits::specialization_graph; -use crate::traits::{self, ImplSource}; +use crate::traits::{ + CanonicalChalkEnvironmentAndGoal, CodegenObligationError, EvaluationResult, ImplSource, + ObjectSafetyViolation, ObligationCause, OverflowError, WellFormedLoc, +}; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; use crate::ty::subst::{GenericArg, SubstsRef}; @@ -1273,7 +1276,7 @@ rustc_queries! { query codegen_select_candidate( key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) - ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> { + ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { cache_on_disk_if { true } desc { |tcx| "computing candidate for `{}`", key.1 } } @@ -1294,7 +1297,7 @@ rustc_queries! { desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } } - query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { + query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] { desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) } } query check_is_object_safe(trait_id: DefId) -> bool { @@ -1838,8 +1841,7 @@ rustc_queries! { } /// A list of all traits in a crate, used by rustdoc and error reporting. - /// NOTE: Not named just `traits` due to a naming conflict. - query traits_in_crate(_: CrateNum) -> &'tcx [DefId] { + query traits(_: CrateNum) -> &'tcx [DefId] { desc { "fetching all traits in a crate" } separate_provide_extern } @@ -1953,12 +1955,12 @@ rustc_queries! { /// `infcx.predicate_must_hold()` instead. query evaluate_obligation( goal: CanonicalPredicateGoal<'tcx> - ) -> Result<traits::EvaluationResult, traits::OverflowError> { + ) -> Result<EvaluationResult, OverflowError> { desc { "evaluating trait selection obligation `{}`", goal.value.value } } query evaluate_goal( - goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx> + goal: CanonicalChalkEnvironmentAndGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution @@ -2128,8 +2130,8 @@ rustc_queries! { /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine, /// because the `ty::Ty`-based wfcheck is always run. query diagnostic_hir_wf_check( - key: (ty::Predicate<'tcx>, traits::WellFormedLoc) - ) -> &'tcx Option<traits::ObligationCause<'tcx>> { + key: (ty::Predicate<'tcx>, WellFormedLoc) + ) -> &'tcx Option<ObligationCause<'tcx>> { arena_cache eval_always no_hash diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index bbea3e1412b..5393dba8c2e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1199,7 +1199,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { iter::once(LOCAL_CRATE) .chain(self.crates(()).iter().copied()) - .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied()) + .flat_map(move |cnum| self.traits(cnum).iter().copied()) } #[inline] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ecb191676c2..c9cd644fab0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -37,7 +37,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; @@ -1439,14 +1439,26 @@ pub struct OpaqueHiddenType<'tcx> { } impl<'tcx> OpaqueHiddenType<'tcx> { - pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) -> ErrorGuaranteed { + pub fn report_mismatch( + &self, + other: &Self, + opaque_def_id: LocalDefId, + tcx: TyCtxt<'tcx>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + if let Some(diag) = tcx + .sess + .diagnostic() + .steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch) + { + diag.cancel(); + } // Found different concrete types for the opaque type. let sub_diag = if self.span == other.span { TypeMismatchReason::ConflictType { span: self.span } } else { TypeMismatchReason::PreviousUse { span: self.span } }; - tcx.sess.emit_err(OpaqueHiddenTypeMismatch { + tcx.sess.create_err(OpaqueHiddenTypeMismatch { self_ty: self.ty, other_ty: other.ty, other_span: other.span, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4491d78648f..a064174e261 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1164,6 +1164,22 @@ pub trait PrettyPrinter<'tcx>: traits.entry(trait_ref).or_default().extend(proj_ty); } + fn pretty_print_inherent_projection( + self, + alias_ty: &ty::AliasTy<'tcx>, + ) -> Result<Self::Path, Self::Error> { + let def_key = self.tcx().def_key(alias_ty.def_id); + self.path_generic_args( + |cx| { + cx.path_append( + |cx| cx.path_qualified(alias_ty.self_ty(), None), + &def_key.disambiguated_data, + ) + }, + &alias_ty.substs[1..], + ) + } + fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> { None } @@ -2821,7 +2837,11 @@ define_print_and_forward_display! { } ty::AliasTy<'tcx> { - p!(print_def_path(self.def_id, self.substs)); + if let DefKind::Impl { of_trait: false } = cx.tcx().def_kind(cx.tcx().parent(self.def_id)) { + p!(pretty_print_inherent_projection(self)) + } else { + p!(print_def_path(self.def_id, self.substs)); + } } ty::ClosureKind { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 5a0571f4bb7..e04dbbff9a7 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -151,10 +151,14 @@ pub struct TypeckResults<'tcx> { /// this field will be set to `Some(ErrorGuaranteed)`. pub tainted_by_errors: Option<ErrorGuaranteed>, - /// All the opaque types that have hidden types set - /// by this function. We also store the - /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, - /// even if they are only set in dead code (which doesn't show up in MIR). + /// All the opaque types that have hidden types set by this function. + /// We also store the type here, so that the compiler can use it as a hint + /// for figuring out hidden types, even if they are only set in dead code + /// (which doesn't show up in MIR). + /// + /// These types are mapped back to the opaque's identity substitutions + /// (with erased regions), which is why we don't associated substs with any + /// of these usages. pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c385b00692f..bcab4c0d24b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -15,6 +15,7 @@ use rustc_middle::mir::Place; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::cast::{mir_cast_kind, CastTy}; +use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; @@ -225,49 +226,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let (op,ty) = (Operand::Move(discr), discr_ty); - if let Abi::Scalar(scalar) = layout.unwrap().abi{ - if let Primitive::Int(_, signed) = scalar.primitive() { - let range = scalar.valid_range(&this.tcx); - // FIXME: Handle wraparound cases too. - if range.end >= range.start { - let mut assumer = |range: u128, bin_op: BinOp| { - // We will be overwriting this val if our scalar is signed value - // because sign extension on unsigned types might cause unintended things - let mut range_val = - ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty)); - let bool_ty = this.tcx.types.bool; - if signed { - let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range); - let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty)); - let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend); - range_val = ConstantKind::from_bits( - this.tcx, - truncated_val, - ty::ParamEnv::empty().and(discr_ty), - ); - } - let lit_op = this.literal_operand(expr.span, range_val); - let is_bin_op = this.temp(bool_ty, expr_span); - this.cfg.push_assign( - block, - source_info, - is_bin_op, - Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))), - ); - this.cfg.push( - block, - Statement { - source_info, - kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( - Operand::Copy(is_bin_op), - ))), - }, - ) - }; - assumer(range.end, BinOp::Ge); - assumer(range.start, BinOp::Le); - } - } + if let Abi::Scalar(scalar) = layout.unwrap().abi + && !scalar.is_always_valid(&this.tcx) + && let Primitive::Int(int_width, _signed) = scalar.primitive() + { + let unsigned_ty = int_width.to_ty(this.tcx, false); + let unsigned_place = this.temp(unsigned_ty, expr_span); + this.cfg.push_assign( + block, + source_info, + unsigned_place, + Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty)); + + let bool_ty = this.tcx.types.bool; + let range = scalar.valid_range(&this.tcx); + let merge_op = + if range.start <= range.end { + BinOp::BitAnd + } else { + BinOp::BitOr + }; + + let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> { + let range_val = + ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty)); + let lit_op = this.literal_operand(expr.span, range_val); + let is_bin_op = this.temp(bool_ty, expr_span); + this.cfg.push_assign( + block, + source_info, + is_bin_op, + Rvalue::BinaryOp(bin_op, Box::new((Operand::Copy(unsigned_place), lit_op))), + ); + is_bin_op + }; + let assert_place = if range.start == 0 { + comparer(range.end, BinOp::Le) + } else { + let start_place = comparer(range.start, BinOp::Ge); + let end_place = comparer(range.end, BinOp::Le); + let merge_place = this.temp(bool_ty, expr_span); + this.cfg.push_assign( + block, + source_info, + merge_place, + Rvalue::BinaryOp(merge_op, Box::new((Operand::Move(start_place), Operand::Move(end_place)))), + ); + merge_place + }; + this.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( + Operand::Move(assert_place), + ))), + }, + ); } (op,ty) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 986d2fd190d..ea1223fbca6 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -9,6 +9,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{self, BasicBlock, BasicBlockData, Terminator, TerminatorKind}; +use std::cmp::Ordering; use std::ops::{Index, IndexMut}; const ID_SEPARATOR: &str = ","; @@ -212,8 +213,12 @@ impl CoverageGraph { } #[inline(always)] - pub fn dominators(&self) -> &Dominators<BasicCoverageBlock> { - self.dominators.as_ref().unwrap() + pub fn rank_partial_cmp( + &self, + a: BasicCoverageBlock, + b: BasicCoverageBlock, + ) -> Option<Ordering> { + self.dominators.as_ref().unwrap().rank_partial_cmp(a, b) } } @@ -650,26 +655,6 @@ pub(super) fn find_loop_backedges( let mut backedges = IndexVec::from_elem_n(Vec::<BasicCoverageBlock>::new(), num_bcbs); // Identify loops by their backedges. - // - // The computational complexity is bounded by: n(s) x d where `n` is the number of - // `BasicCoverageBlock` nodes (the simplified/reduced representation of the CFG derived from the - // MIR); `s` is the average number of successors per node (which is most likely less than 2, and - // independent of the size of the function, so it can be treated as a constant); - // and `d` is the average number of dominators per node. - // - // The average number of dominators depends on the size and complexity of the function, and - // nodes near the start of the function's control flow graph typically have less dominators - // than nodes near the end of the CFG. Without doing a detailed mathematical analysis, I - // think the resulting complexity has the characteristics of O(n log n). - // - // The overall complexity appears to be comparable to many other MIR transform algorithms, and I - // don't expect that this function is creating a performance hot spot, but if this becomes an - // issue, there may be ways to optimize the `dominates` algorithm (as indicated by an - // existing `FIXME` comment in that code), or possibly ways to optimize it's usage here, perhaps - // by keeping track of results for visited `BasicCoverageBlock`s if they can be used to short - // circuit downstream `dominates` checks. - // - // For now, that kind of optimization seems unnecessarily complicated. for (bcb, _) in basic_coverage_blocks.iter_enumerated() { for &successor in &basic_coverage_blocks.successors[bcb] { if basic_coverage_blocks.dominates(successor, bcb) { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 14937912cc5..d27200419e2 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -344,7 +344,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { // before the dominated equal spans). When later comparing two spans in // order, the first will either dominate the second, or they will have no // dominator relationship. - self.basic_coverage_blocks.dominators().rank_partial_cmp(a.bcb, b.bcb) + self.basic_coverage_blocks.rank_partial_cmp(a.bcb, b.bcb) } } else { // Sort hi() in reverse order so shorter spans are attempted after longer spans. diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs index 1b3ac78fbc6..bf5722b3d00 100644 --- a/compiler/rustc_mir_transform/src/ctfe_limit.rs +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -47,7 +47,7 @@ fn has_back_edge( return false; } // Check if any of the dominators of the node are also the node's successor. - doms.dominators(node).any(|dom| node_data.terminator().successors().any(|succ| succ == dom)) + node_data.terminator().successors().any(|succ| doms.dominates(succ, node)) } fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) { diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 2b404efccc7..e8e4246b797 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -31,11 +31,11 @@ pub struct SsaLocals { /// We often encounter MIR bodies with 1 or 2 basic blocks. In those cases, it's unnecessary to /// actually compute dominators, we can just compare block indices because bb0 is always the first /// block, and in any body all other blocks are always dominated by bb0. -struct SmallDominators { - inner: Option<Dominators<BasicBlock>>, +struct SmallDominators<'a> { + inner: Option<&'a Dominators<BasicBlock>>, } -impl SmallDominators { +impl SmallDominators<'_> { fn dominates(&self, first: Location, second: Location) -> bool { if first.block == second.block { first.statement_index <= second.statement_index @@ -198,14 +198,14 @@ enum LocationExtended { Arg, } -struct SsaVisitor { - dominators: SmallDominators, +struct SsaVisitor<'a> { + dominators: SmallDominators<'a>, assignments: IndexVec<Local, Set1<LocationExtended>>, assignment_order: Vec<Local>, direct_uses: IndexVec<Local, u32>, } -impl<'tcx> Visitor<'tcx> for SsaVisitor { +impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> { fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) { match ctxt { PlaceContext::MutatingUse(MutatingUseContext::Projection) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 7b39cb0a068..65dfdf31e54 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -454,12 +454,14 @@ struct EmbargoVisitor<'tcx> { /// n::p::f() /// } macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>, + /// Preliminary pass for marking all underlying types of `impl Trait`s as reachable. + impl_trait_pass: bool, /// Has something changed in the level map? changed: bool, } struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> { - effective_vis: Option<EffectiveVisibility>, + effective_vis: EffectiveVisibility, item_def_id: LocalDefId, ev: &'a mut EmbargoVisitor<'tcx>, level: Level, @@ -474,7 +476,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { fn update( &mut self, def_id: LocalDefId, - inherited_effective_vis: Option<EffectiveVisibility>, + inherited_effective_vis: EffectiveVisibility, level: Level, ) { let nominal_vis = self.tcx.local_visibility(def_id); @@ -484,30 +486,27 @@ impl<'tcx> EmbargoVisitor<'tcx> { fn update_eff_vis( &mut self, def_id: LocalDefId, - inherited_effective_vis: Option<EffectiveVisibility>, + inherited_effective_vis: EffectiveVisibility, nominal_vis: Option<ty::Visibility>, level: Level, ) { - if let Some(inherited_effective_vis) = inherited_effective_vis { - let private_vis = - ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)); - if Some(private_vis) != nominal_vis { - self.changed |= self.effective_visibilities.update( - def_id, - nominal_vis, - || private_vis, - inherited_effective_vis, - level, - self.tcx, - ); - } + let private_vis = ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)); + if Some(private_vis) != nominal_vis { + self.changed |= self.effective_visibilities.update( + def_id, + nominal_vis, + || private_vis, + inherited_effective_vis, + level, + self.tcx, + ); } } fn reach( &mut self, def_id: LocalDefId, - effective_vis: Option<EffectiveVisibility>, + effective_vis: EffectiveVisibility, ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { ReachEverythingInTheInterfaceVisitor { effective_vis, @@ -520,7 +519,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { fn reach_through_impl_trait( &mut self, def_id: LocalDefId, - effective_vis: Option<EffectiveVisibility>, + effective_vis: EffectiveVisibility, ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { ReachEverythingInTheInterfaceVisitor { effective_vis, @@ -532,9 +531,13 @@ impl<'tcx> EmbargoVisitor<'tcx> { // We have to make sure that the items that macros might reference // are reachable, since they might be exported transitively. - fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &MacroDef) { + fn update_reachability_from_macro( + &mut self, + local_def_id: LocalDefId, + md: &MacroDef, + macro_ev: EffectiveVisibility, + ) { // Non-opaque macros cannot make other items more accessible than they already are. - let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); let attrs = self.tcx.hir().attrs(hir_id); if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque { @@ -554,8 +557,6 @@ impl<'tcx> EmbargoVisitor<'tcx> { // Since we are starting from an externally visible module, // all the parents in the loop below are also guaranteed to be modules. let mut module_def_id = macro_module_def_id; - let macro_ev = self.get(local_def_id); - assert!(macro_ev.is_some()); loop { let changed_reachability = self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev); @@ -572,7 +573,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { &mut self, module_def_id: LocalDefId, defining_mod: LocalDefId, - macro_ev: Option<EffectiveVisibility>, + macro_ev: EffectiveVisibility, ) -> bool { if self.macro_reachable.insert((module_def_id, defining_mod)) { self.update_macro_reachable_mod(module_def_id, defining_mod, macro_ev); @@ -586,7 +587,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { &mut self, module_def_id: LocalDefId, defining_mod: LocalDefId, - macro_ev: Option<EffectiveVisibility>, + macro_ev: EffectiveVisibility, ) { let module = self.tcx.hir().get_module(module_def_id).0; for item_id in module.item_ids { @@ -618,7 +619,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { def_kind: DefKind, vis: ty::Visibility, module: LocalDefId, - macro_ev: Option<EffectiveVisibility>, + macro_ev: EffectiveVisibility, ) { self.update(def_id, macro_ev, Level::Reachable); match def_kind { @@ -700,128 +701,53 @@ impl<'tcx> EmbargoVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { - type NestedFilter = nested_filter::All; - - /// We want to visit items in the context of their containing - /// module and so forth, so supply a crate for doing a deep walk. - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let item_ev = match item.kind { - hir::ItemKind::Impl { .. } => { - let impl_ev = Option::<EffectiveVisibility>::of_impl( - item.owner_id.def_id, - self.tcx, - &self.effective_visibilities, - ); - - self.update_eff_vis(item.owner_id.def_id, impl_ev, None, Level::Direct); - impl_ev - } - _ => self.get(item.owner_id.def_id), - }; - - // Update levels of nested things. - match item.kind { - hir::ItemKind::Enum(ref def, _) => { - for variant in def.variants { - self.update(variant.def_id, item_ev, Level::Reachable); - let variant_ev = self.get(variant.def_id); - if let Some(ctor_def_id) = variant.data.ctor_def_id() { - self.update(ctor_def_id, variant_ev, Level::Reachable); - } - for field in variant.data.fields() { - self.update(field.def_id, variant_ev, Level::Reachable); - } - } - } - hir::ItemKind::Impl(ref impl_) => { - for impl_item_ref in impl_.items { - let def_id = impl_item_ref.id.owner_id.def_id; - let nominal_vis = - impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id)); - self.update_eff_vis(def_id, item_ev, nominal_vis, Level::Direct); - } - } - hir::ItemKind::Trait(.., trait_item_refs) => { - for trait_item_ref in trait_item_refs { - self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable); - } - } - hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { - if let Some(ctor_def_id) = def.ctor_def_id() { - self.update(ctor_def_id, item_ev, Level::Reachable); - } - for field in def.fields() { - self.update(field.def_id, item_ev, Level::Reachable); - } - } - hir::ItemKind::Macro(ref macro_def, _) => { - self.update_reachability_from_macro(item.owner_id.def_id, macro_def); - } - hir::ItemKind::ForeignMod { items, .. } => { - for foreign_item in items { - self.update(foreign_item.id.owner_id.def_id, item_ev, Level::Reachable); - } - } - - hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::Use(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::GlobalAsm(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::ExternCrate(..) => {} + if self.impl_trait_pass + && let hir::ItemKind::OpaqueTy(ref opaque) = item.kind + && !opaque.in_trait { + // FIXME: This is some serious pessimization intended to workaround deficiencies + // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time + // reachable if they are returned via `impl Trait`, even from private functions. + let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public); + self.reach_through_impl_trait(item.owner_id.def_id, pub_ev) + .generics() + .predicates() + .ty(); + return; } - // Mark all items in interfaces of reachable items as reachable. + // Update levels of nested things and mark all items + // in interfaces of reachable items as reachable. + let item_ev = self.get(item.owner_id.def_id); match item.kind { - // The interface is empty. - hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {} - // All nested items are checked by `visit_item`. - hir::ItemKind::Mod(..) => {} - // Handled in `rustc_resolve`. - hir::ItemKind::Use(..) => {} - // The interface is empty. - hir::ItemKind::GlobalAsm(..) => {} - hir::ItemKind::OpaqueTy(ref opaque) => { - // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general) - // Since rustdoc never needs to do codegen and doesn't care about link-time reachability, - // mark this as unreachable. - // See https://github.com/rust-lang/rust/issues/75100 - if !opaque.in_trait && !self.tcx.sess.opts.actually_rustdoc { - // FIXME: This is some serious pessimization intended to workaround deficiencies - // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time - // reachable if they are returned via `impl Trait`, even from private functions. - let exist_ev = Some(EffectiveVisibility::from_vis(ty::Visibility::Public)); - self.reach_through_impl_trait(item.owner_id.def_id, exist_ev) - .generics() - .predicates() - .ty(); + // The interface is empty, and no nested items. + hir::ItemKind::Use(..) + | hir::ItemKind::ExternCrate(..) + | hir::ItemKind::GlobalAsm(..) => {} + // The interface is empty, and all nested items are processed by `visit_item`. + hir::ItemKind::Mod(..) | hir::ItemKind::OpaqueTy(..) => {} + hir::ItemKind::Macro(ref macro_def, _) => { + if let Some(item_ev) = item_ev { + self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev); } } - // Visit everything. hir::ItemKind::Const(..) | hir::ItemKind::Static(..) | hir::ItemKind::Fn(..) | hir::ItemKind::TyAlias(..) => { - if item_ev.is_some() { + if let Some(item_ev) = item_ev { self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty(); } } hir::ItemKind::Trait(.., trait_item_refs) => { - if item_ev.is_some() { + if let Some(item_ev) = item_ev { self.reach(item.owner_id.def_id, item_ev).generics().predicates(); for trait_item_ref in trait_item_refs { + self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable); + let tcx = self.tcx; let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev); - reach.generics().predicates(); if trait_item_ref.kind == AssocItemKind::Type @@ -835,13 +761,18 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } hir::ItemKind::TraitAlias(..) => { - if item_ev.is_some() { + if let Some(item_ev) = item_ev { self.reach(item.owner_id.def_id, item_ev).generics().predicates(); } } - // Visit everything except for private impl items. hir::ItemKind::Impl(ref impl_) => { - if item_ev.is_some() { + if let Some(item_ev) = Option::<EffectiveVisibility>::of_impl( + item.owner_id.def_id, + self.tcx, + &self.effective_visibilities, + ) { + self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct); + self.reach(item.owner_id.def_id, item_ev) .generics() .predicates() @@ -849,27 +780,32 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { .trait_ref(); for impl_item_ref in impl_.items { - let impl_item_ev = self.get(impl_item_ref.id.owner_id.def_id); + let def_id = impl_item_ref.id.owner_id.def_id; + let nominal_vis = + impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id)); + self.update_eff_vis(def_id, item_ev, nominal_vis, Level::Direct); - if impl_item_ev.is_some() { - self.reach(impl_item_ref.id.owner_id.def_id, impl_item_ev) - .generics() - .predicates() - .ty(); + if let Some(impl_item_ev) = self.get(def_id) { + self.reach(def_id, impl_item_ev).generics().predicates().ty(); } } } } - - // Visit everything, but enum variants have their own levels. hir::ItemKind::Enum(ref def, _) => { - if item_ev.is_some() { + if let Some(item_ev) = item_ev { self.reach(item.owner_id.def_id, item_ev).generics().predicates(); } for variant in def.variants { - let variant_ev = self.get(variant.def_id); - if variant_ev.is_some() { + if let Some(item_ev) = item_ev { + self.update(variant.def_id, item_ev, Level::Reachable); + } + + if let Some(variant_ev) = self.get(variant.def_id) { + if let Some(ctor_def_id) = variant.data.ctor_def_id() { + self.update(ctor_def_id, variant_ev, Level::Reachable); + } for field in variant.data.fields() { + self.update(field.def_id, variant_ev, Level::Reachable); self.reach(field.def_id, variant_ev).ty(); } // Corner case: if the variant is reachable, but its @@ -877,18 +813,15 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { self.reach(item.owner_id.def_id, variant_ev).ty(); } if let Some(ctor_def_id) = variant.data.ctor_def_id() { - let ctor_ev = self.get(ctor_def_id); - if ctor_ev.is_some() { + if let Some(ctor_ev) = self.get(ctor_def_id) { self.reach(item.owner_id.def_id, ctor_ev).ty(); } } } } - // Visit everything, but foreign items have their own levels. hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - let foreign_item_ev = self.get(foreign_item.id.owner_id.def_id); - if foreign_item_ev.is_some() { + if let Some(foreign_item_ev) = self.get(foreign_item.id.owner_id.def_id) { self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev) .generics() .predicates() @@ -896,34 +829,26 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - // Visit everything except for private fields. hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { - if item_ev.is_some() { + if let Some(item_ev) = item_ev { self.reach(item.owner_id.def_id, item_ev).generics().predicates(); for field in struct_def.fields() { - let field_ev = self.get(field.def_id); - if field_ev.is_some() { + self.update(field.def_id, item_ev, Level::Reachable); + if let Some(field_ev) = self.get(field.def_id) { self.reach(field.def_id, field_ev).ty(); } } } if let Some(ctor_def_id) = struct_def.ctor_def_id() { - let ctor_ev = self.get(ctor_def_id); - if ctor_ev.is_some() { + if let Some(item_ev) = item_ev { + self.update(ctor_def_id, item_ev, Level::Reachable); + } + if let Some(ctor_ev) = self.get(ctor_def_id) { self.reach(item.owner_id.def_id, ctor_ev).ty(); } } } } - - intravisit::walk_item(self, item); - } - - fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { - // Blocks can have public items, for example impls, but they always - // start as completely private regardless of publicity of a function, - // constant, type, field, etc., in which this block resides. - intravisit::walk_block(self, b); } } @@ -2205,12 +2130,24 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { tcx, effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(), macro_reachable: Default::default(), + // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and + // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't + // care about link-time reachability, keep them unreachable (issue #75100). + impl_trait_pass: !tcx.sess.opts.actually_rustdoc, changed: false, }; visitor.effective_visibilities.check_invariants(tcx, true); + if visitor.impl_trait_pass { + // Underlying types of `impl Trait`s are marked as reachable unconditionally, + // so this pass doesn't need to be a part of the fixed point iteration below. + tcx.hir().visit_all_item_likes_in_crate(&mut visitor); + visitor.impl_trait_pass = false; + visitor.changed = false; + } + loop { - tcx.hir().walk_toplevel_module(&mut visitor); + tcx.hir().visit_all_item_likes_in_crate(&mut visitor); if visitor.changed { visitor.changed = false; } else { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 08b73ebb694..b3d0e4ba258 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -873,6 +873,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let msg = "macro-expanded `extern crate` items cannot \ shadow names passed with `--extern`"; self.r.tcx.sess.span_err(item.span, msg); + // `return` is intended to discard this binding because it's an + // unregistered ambiguity error which would result in a panic + // caused by inconsistency `path_res` + // more details: https://github.com/rust-lang/rust/pull/111761 + return; } } let entry = self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a1077615d95..e0611907613 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -17,7 +17,7 @@ use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg}; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; +use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; @@ -4287,12 +4287,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } } - fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> bool { + fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> { // FIXME: This caching may be incorrect in case of multiple `macro_rules` // items with the same name in the same module. // Also hygiene is not considered. let mut doc_link_resolutions = std::mem::take(&mut self.r.doc_link_resolutions); - let res = doc_link_resolutions + let res = *doc_link_resolutions .entry(self.parent_scope.module.nearest_parent_mod().expect_local()) .or_default() .entry((Symbol::intern(path_str), ns)) @@ -4307,8 +4307,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { return None; } res - }) - .is_some(); + }); self.r.doc_link_resolutions = doc_link_resolutions; res } @@ -4343,8 +4342,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let mut any_resolved = false; let mut need_assoc = false; for ns in [TypeNS, ValueNS, MacroNS] { - if self.resolve_and_cache_rustdoc_path(&path_str, ns) { - any_resolved = true; + if let Some(res) = self.resolve_and_cache_rustdoc_path(&path_str, ns) { + // Rustdoc ignores tool attribute resolutions and attempts + // to resolve their prefixes for diagnostics. + any_resolved = !matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Tool)); } else if ns != MacroNS { need_assoc = true; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3cdc3f0ecf8..1e31a0ff278 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -106,7 +106,7 @@ impl Determinacy { /// A specific scope in which a name can be looked up. /// This enum is currently used only for early resolution (imports and macros), /// but not for late resolution yet. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum Scope<'a> { DeriveHelpers(LocalExpnId), DeriveHelpersCompat, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index a3f262905c7..254ede4e6a0 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -220,7 +220,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { match *ty.kind() { // Print all nominal types as paths (unlike `pretty_print_type`). ty::FnDef(def_id, substs) - | ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) | ty::Closure(def_id, substs) | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), @@ -241,6 +241,8 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { Ok(self) } + ty::Alias(ty::Inherent, _) => panic!("unexpected inherent projection"), + _ => self.pretty_print_type(ty), } } diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 51d508a580b..da8a16dee8a 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -272,12 +272,11 @@ fn encode_region<'tcx>( s.push('E'); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReErased => { + RegionKind::ReEarlyBound(..) | RegionKind::ReErased => { s.push_str("u6region"); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReEarlyBound(..) - | RegionKind::ReFree(..) + RegionKind::ReFree(..) | RegionKind::ReStatic | RegionKind::ReError(_) | RegionKind::ReVar(..) @@ -704,14 +703,15 @@ fn transform_predicates<'tcx>( ) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> { let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates .iter() - .map(|predicate| match predicate.skip_binder() { + .filter_map(|predicate| match predicate.skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => { let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id); - ty::Binder::dummy(ty::ExistentialPredicate::Trait( + Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait( ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), - )) + ))) } - _ => predicate, + ty::ExistentialPredicate::Projection(..) => None, + ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), }) .collect(); tcx.mk_poly_existential_predicates(&predicates) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 2235524129e..4cccc639892 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -433,7 +433,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { // Mangle all nominal types as paths. ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs) | ty::FnDef(def_id, substs) - | ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) | ty::Closure(def_id, substs) | ty::Generator(def_id, substs, _) => { self = self.print_def_path(def_id, substs)?; @@ -482,6 +482,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { self = r.print(self)?; } + ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"), ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"), } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index dcfa33ae842..644bfd33970 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -177,14 +177,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - if goal.predicate.self_ty().has_non_region_infer() { + // The regions of a type don't affect the size of the type + let tcx = ecx.tcx(); + // We should erase regions from both the param-env and type, since both + // may have infer regions. Specifically, after canonicalizing and instantiating, + // early bound regions turn into region vars in both the new and old solver. + let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty())); + // But if there are inference variables, we have to wait until it's resolved. + if key.has_non_region_infer() { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } - let tcx = ecx.tcx(); - let self_ty = tcx.erase_regions(goal.predicate.self_ty()); - - if let Ok(layout) = tcx.layout_of(goal.param_env.and(self_ty)) + if let Ok(layout) = tcx.layout_of(key) && layout.layout.is_pointer_like(&tcx.data_layout) { // FIXME: We could make this faster by making a no-constraints response diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f5f2fe54217..dc43a3d154a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -885,7 +885,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return; } - if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) { + if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) { err.emit(); return; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index ea17f23434b..83511e898f7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -30,9 +30,9 @@ use rustc_middle::hir::map; use rustc_middle::ty::error::TypeError::{self, Sorts}; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, - GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts, - IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, TypeckResults, + GeneratorDiagnosticData, GeneratorInteriorTypeCause, InferTy, InternalSubsts, IsSuggestable, + ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, TypeckResults, }; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -261,7 +261,6 @@ pub trait TypeErrCtxtExt<'tcx> { fn suggest_impl_trait( &self, err: &mut Diagnostic, - span: Span, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool; @@ -1792,215 +1791,66 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn suggest_impl_trait( &self, err: &mut Diagnostic, - span: Span, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { - match obligation.cause.code().peel_derives() { - // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. - ObligationCauseCode::SizedReturnType => {} - _ => return false, - } - - let hir = self.tcx.hir(); - let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id); - let node = hir.find_by_def_id(obligation.cause.body_id); - let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(sig, _, body_id), - .. - })) = node - else { + let ObligationCauseCode::SizedReturnType = obligation.cause.code() else { return false; }; - let body = hir.body(*body_id); - let trait_pred = self.resolve_vars_if_possible(trait_pred); - let ty = trait_pred.skip_binder().self_ty(); - let is_object_safe = match ty.kind() { - ty::Dynamic(predicates, _, ty::Dyn) => { - // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. - predicates - .principal_def_id() - .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id)) - } - // We only want to suggest `impl Trait` to `dyn Trait`s. - // For example, `fn foo() -> str` needs to be filtered out. - _ => return false, - }; - - let hir::FnRetTy::Return(ret_ty) = sig.decl.output else { + let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else { return false; }; - // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for - // cases like `fn foo() -> (dyn Trait, i32) {}`. - // Recursively look for `TraitObject` types and if there's only one, use that span to - // suggest `impl Trait`. - - // Visit to make sure there's a single `return` type to suggest `impl Trait`, - // otherwise suggest using `Box<dyn Trait>` or an enum. - let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(&body); - - let typeck_results = self.typeck_results.as_ref().unwrap(); - let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; }; - - let ret_types = visitor - .returns - .iter() - .filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?))) - .map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty))); - let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold( - (None, true, true), - |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool), - (_, ty)| { - let ty = self.resolve_vars_if_possible(ty); - same &= - !matches!(ty.kind(), ty::Error(_)) - && last_ty.map_or(true, |last_ty| { - // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes - // *after* in the dependency graph. - match (ty.kind(), last_ty.kind()) { - (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_))) - | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_))) - | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_))) - | ( - Infer(InferTy::FreshFloatTy(_)), - Infer(InferTy::FreshFloatTy(_)), - ) => true, - _ => ty == last_ty, - } - }); - (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never)) - }, - ); - let mut spans_and_needs_box = vec![]; - - match liberated_sig.output().kind() { - ty::Dynamic(predicates, _, ty::Dyn) => { - let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id); - let param_env = ty::ParamEnv::empty(); - - if !only_never_return { - for (expr_span, return_ty) in ret_types { - let self_ty_satisfies_dyn_predicates = |self_ty| { - predicates.iter().all(|predicate| { - let pred = predicate.with_self_ty(self.tcx, self_ty); - let obl = Obligation::new(self.tcx, cause.clone(), param_env, pred); - self.predicate_may_hold(&obl) - }) - }; - - if let ty::Adt(def, substs) = return_ty.kind() - && def.is_box() - && self_ty_satisfies_dyn_predicates(substs.type_at(0)) - { - spans_and_needs_box.push((expr_span, false)); - } else if self_ty_satisfies_dyn_predicates(return_ty) { - spans_and_needs_box.push((expr_span, true)); - } else { - return false; - } - } - } - } - _ => return false, - }; - - let sm = self.tcx.sess.source_map(); - if !ret_ty.span.overlaps(span) { - return false; - } - let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind { - if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) { - snippet - } else { - return false; - } - } else { - // Substitute the type, so we can print a fixup given `type Alias = dyn Trait` - let name = liberated_sig.output().to_string(); - let name = - name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name); - if !name.starts_with("dyn ") { - return false; - } - name.to_owned() - }; - err.code(error_code!(E0746)); err.set_primary_message("return type cannot have an unboxed trait object"); err.children.clear(); - let impl_trait_msg = "for information on `impl Trait`, see \ - <https://doc.rust-lang.org/book/ch10-02-traits.html\ - #returning-types-that-implement-traits>"; - let trait_obj_msg = "for information on trait objects, see \ - <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\ - #using-trait-objects-that-allow-for-values-of-different-types>"; - - let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn"); - let trait_obj = if has_dyn { &snippet[4..] } else { &snippet }; - if only_never_return { - // No return paths, probably using `panic!()` or similar. - // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`. - suggest_trait_object_return_type_alternatives( - err, - ret_ty.span, - trait_obj, - is_object_safe, - ); - } else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) { - // Suggest `-> impl Trait`. + + let span = obligation.cause.span; + if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) + && snip.starts_with("dyn ") + { err.span_suggestion( - ret_ty.span, - format!( - "use `impl {1}` as the return type, as all return paths are of type `{}`, \ - which implements `{1}`", - last_ty, trait_obj, - ), - format!("impl {}", trait_obj), - Applicability::MachineApplicable, + span.with_hi(span.lo() + BytePos(4)), + "return an `impl Trait` instead of a `dyn Trait`, \ + if all returned values are the same type", + "impl ", + Applicability::MaybeIncorrect, ); - err.note(impl_trait_msg); - } else { - if is_object_safe { - // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`. - err.multipart_suggestion( - "return a boxed trait object instead", - vec![ - (ret_ty.span.shrink_to_lo(), "Box<".to_string()), - (span.shrink_to_hi(), ">".to_string()), - ], - Applicability::MaybeIncorrect, - ); - for (span, needs_box) in spans_and_needs_box { - if needs_box { - err.multipart_suggestion( - "... and box this value", - vec![ - (span.shrink_to_lo(), "Box::new(".to_string()), - (span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } - } + } + + let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id)); + + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(&body); + + let mut sugg = + vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())]; + sugg.extend(visitor.returns.into_iter().flat_map(|expr| { + let span = expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span); + if !span.can_be_used_for_suggestions() { + vec![] + } else if let hir::ExprKind::Call(path, ..) = expr.kind + && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, method)) = path.kind + && method.ident.name == sym::new + && let hir::TyKind::Path(hir::QPath::Resolved(.., box_path)) = ty.kind + && box_path.res.opt_def_id().is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box()) + { + // Don't box `Box::new` + vec![] } else { - // This is currently not possible to trigger because E0038 takes precedence, but - // leave it in for completeness in case anything changes in an earlier stage. - err.note(format!( - "if trait `{}` were object-safe, you could return a trait object", - trait_obj, - )); + vec![ + (span.shrink_to_lo(), "Box::new(".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ] } - err.note(trait_obj_msg); - err.note(format!( - "if all the returned values were of the same type you could use `impl {}` as the \ - return type", - trait_obj, - )); - err.note(impl_trait_msg); - err.note("you can create a new `enum` with a variant for each returned type"); - } + })); + + err.multipart_suggestion( + "box the return type, and wrap all of the returned values in `Box::new`", + sugg, + Applicability::MaybeIncorrect, + ); + true } @@ -4139,37 +3989,6 @@ impl NextTypeParamName for &[hir::GenericParam<'_>] { } } -fn suggest_trait_object_return_type_alternatives( - err: &mut Diagnostic, - ret_ty: Span, - trait_obj: &str, - is_object_safe: bool, -) { - err.span_suggestion( - ret_ty, - format!( - "use `impl {}` as the return type if all return paths have the same type but you \ - want to expose only the trait in the signature", - trait_obj, - ), - format!("impl {}", trait_obj), - Applicability::MaybeIncorrect, - ); - if is_object_safe { - err.multipart_suggestion( - format!( - "use a boxed trait object if all return paths implement trait `{}`", - trait_obj, - ), - vec![ - (ret_ty.shrink_to_lo(), "Box<".to_string()), - (ret_ty.shrink_to_hi(), ">".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } -} - /// Collect the spans that we see the generic param `param_did` struct ReplaceImplTraitVisitor<'a> { ty_spans: &'a mut Vec<Span>, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 1f8e756043d..3d6c1d9e2b0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -1,32 +1,31 @@ use crate::infer::canonical::query_response; -use crate::infer::{InferCtxt, InferOk}; +use crate::infer::InferCtxt; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; use crate::traits::ObligationCtxt; use rustc_infer::infer::region_constraints::RegionConstraintData; +use rustc_middle::traits::query::NoSolution; use rustc_span::source_map::DUMMY_SP; use std::fmt; -pub struct CustomTypeOp<F, G> { +pub struct CustomTypeOp<F> { closure: F, - description: G, + description: &'static str, } -impl<F, G> CustomTypeOp<F, G> { - pub fn new<'tcx, R>(closure: F, description: G) -> Self +impl<F> CustomTypeOp<F> { + pub fn new<'tcx, R>(closure: F, description: &'static str) -> Self where - F: FnOnce(&InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>, - G: Fn() -> String, + F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>, { CustomTypeOp { closure, description } } } -impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G> +impl<'tcx, F, R: fmt::Debug> super::TypeOp<'tcx> for CustomTypeOp<F> where - F: for<'a, 'cx> FnOnce(&'a InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>, - G: Fn() -> String, + F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>, { type Output = R; /// We can't do any custom error reporting for `CustomTypeOp`, so @@ -41,16 +40,13 @@ where info!("fully_perform({:?})", self); } - Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0) + Ok(scrape_region_constraints(infcx, self.closure)?.0) } } -impl<F, G> fmt::Debug for CustomTypeOp<F, G> -where - G: Fn() -> String, -{ +impl<F> fmt::Debug for CustomTypeOp<F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", (self.description)()) + self.description.fmt(f) } } @@ -58,7 +54,7 @@ where /// constraints that result, creating query-region-constraints. pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx: &InferCtxt<'tcx>, - op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, + op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>, ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { // During NLL, we expect that nobody will register region // obligations **except** as part of a custom type op (and, at the @@ -72,16 +68,20 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( pre_obligations, ); - let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligations(obligations); - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.tcx.sess.diagnostic().delay_span_bug( - DUMMY_SP, - format!("errors selecting obligation during MIR typeck: {:?}", errors), - ); - } + let value = infcx.commit_if_ok(|_| { + let ocx = ObligationCtxt::new_in_snapshot(infcx); + let value = op(&ocx)?; + let errors = ocx.select_all_or_error(); + if errors.is_empty() { + Ok(value) + } else { + infcx.tcx.sess.delay_span_bug( + DUMMY_SP, + format!("errors selecting obligation during MIR typeck: {:?}", errors), + ); + Err(NoSolution) + } + })?; let region_obligations = infcx.take_registered_region_obligations(); let region_constraint_data = infcx.take_and_reset_region_constraints(); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index aa230936903..8bc82b9f549 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -967,16 +967,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // The regions of a type don't affect the size of the type let tcx = self.tcx(); - let self_ty = - tcx.erase_regions(tcx.erase_late_bound_regions(obligation.predicate.self_ty())); - + let self_ty = tcx.erase_late_bound_regions(obligation.predicate.self_ty()); + // We should erase regions from both the param-env and type, since both + // may have infer regions. Specifically, after canonicalizing and instantiating, + // early bound regions turn into region vars in both the new and old solver. + let key = tcx.erase_regions(obligation.param_env.and(self_ty)); // But if there are inference variables, we have to wait until it's resolved. - if self_ty.has_non_region_infer() { + if key.has_non_region_infer() { candidates.ambiguous = true; return; } - if let Ok(layout) = tcx.layout_of(obligation.param_env.and(self_ty)) + if let Ok(layout) = tcx.layout_of(key) && layout.layout.is_pointer_like(&tcx.data_layout) { candidates.vec.push(BuiltinCandidate { has_nested: false }); |
