diff --git a/Cargo.lock b/Cargo.lock index 9c0978b92f73c..df2842bddb386 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4618,7 +4618,7 @@ dependencies = [ "derive-where", "ena", "indexmap", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "rustc_ast_ir", "rustc_data_structures", "rustc_index", diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4f0368bcb01b2..3b99a653417aa 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2147,7 +2147,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ty_id, &None, path, - ParamMode::Optional, + ParamMode::Explicit, AllowReturnTypeNotation::No, // FIXME(mgca): update for `fn foo() -> Bar>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), @@ -2219,7 +2219,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { expr.id, qself, path, - ParamMode::Optional, + ParamMode::Explicit, AllowReturnTypeNotation::No, // FIXME(mgca): update for `fn foo() -> Bar>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 754b2ba0d760c..96c39c7bb32ba 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -139,13 +139,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { let gid = GlobalId { instance, promoted: None }; - let ty = match intrinsic_name { - sym::variant_count => self.tcx.types.usize, - sym::needs_drop => self.tcx.types.bool, - sym::type_id => self.tcx.types.u128, - sym::type_name => Ty::new_static_str(self.tcx.tcx), - _ => bug!(), - }; + let ty = self + .tcx + .fn_sig(instance.def_id()) + .instantiate(self.tcx.tcx, instance.args) + .output() + .no_bound_vars() + .unwrap(); let val = self .ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?; let val = self.const_val_to_op(val, ty, Some(dest.layout))?; diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 54a331a490444..0cd9e36a92771 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1500,13 +1500,31 @@ pub fn init_rustc_env_logger(early_dcx: &EarlyDiagCtxt) { /// This allows tools to enable rust logging without having to magically match rustc's /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose -/// the values directly rather than having to set an environment variable. +/// the logger config directly rather than having to set an environment variable. pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) { if let Err(error) = rustc_log::init_logger(cfg) { early_dcx.early_fatal(error.to_string()); } } +/// This allows tools to enable rust logging without having to magically match rustc's +/// tracing crate version. In contrast to `init_rustc_env_logger`, it allows you to +/// choose the logger config directly rather than having to set an environment variable. +/// Moreover, in contrast to `init_logger`, it allows you to add a custom tracing layer +/// via `build_subscriber`, for example `|| Registry::default().with(custom_layer)`. +pub fn init_logger_with_additional_layer( + early_dcx: &EarlyDiagCtxt, + cfg: rustc_log::LoggerConfig, + build_subscriber: F, +) where + F: FnOnce() -> T, + T: rustc_log::BuildSubscriberRet, +{ + if let Err(error) = rustc_log::init_logger_with_additional_layer(cfg, build_subscriber) { + early_dcx.early_fatal(error.to_string()); + } +} + /// Install our usual `ctrlc` handler, which sets [`rustc_const_eval::CTRL_C_RECEIVED`]. /// Making this handler optional lets tools can install a different handler, if they wish. pub fn install_ctrlc_handler() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index bdc42c7a2d909..106420faa4c01 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; use rustc_middle::ty::{ - self as ty, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, Upcast, + self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + TypeVisitor, Upcast, }; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::traits; @@ -927,7 +927,7 @@ struct GenericParamAndBoundVarCollector<'a, 'tcx> { impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 'tcx> { type Result = ControlFlow; - fn visit_binder>>( + fn visit_binder>>( &mut self, binder: &ty::Binder<'tcx, T>, ) -> Self::Result { diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 8124d7f7c86a1..aa6f36a67f09a 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -15,8 +15,7 @@ use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, - TypeVisitor, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::FutureIncompatibilityReason; @@ -210,7 +209,7 @@ where VarFn: FnOnce() -> FxHashMap, OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>, { - fn visit_binder>>(&mut self, t: &ty::Binder<'tcx, T>) { + fn visit_binder>>(&mut self, t: &ty::Binder<'tcx, T>) { // When we get into a binder, we need to add its own bound vars to the scope. let mut added = vec![]; for arg in t.bound_vars() { diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 1bb502ca3d062..df648bbd48951 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -43,6 +43,7 @@ use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter}; use tracing_subscriber::fmt::FmtContext; use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields}; use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::{Layer, Registry}; /// The values of all the environment variables that matter for configuring a logger. /// Errors are explicitly preserved so that we can share error handling. @@ -72,6 +73,36 @@ impl LoggerConfig { /// Initialize the logger with the given values for the filter, coloring, and other options env variables. pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> { + init_logger_with_additional_layer(cfg, || Registry::default()) +} + +/// Trait alias for the complex return type of `build_subscriber` in +/// [init_logger_with_additional_layer]. A [Registry] with any composition of [tracing::Subscriber]s +/// (e.g. `Registry::default().with(custom_layer)`) should be compatible with this type. +/// Having an alias is also useful so rustc_driver_impl does not need to explicitly depend on +/// `tracing_subscriber`. +pub trait BuildSubscriberRet: + tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync +{ +} + +impl< + T: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync, +> BuildSubscriberRet for T +{ +} + +/// Initialize the logger with the given values for the filter, coloring, and other options env variables. +/// Additionally add a custom layer to collect logging and tracing events via `build_subscriber`, +/// for example: `|| Registry::default().with(custom_layer)`. +pub fn init_logger_with_additional_layer( + cfg: LoggerConfig, + build_subscriber: F, +) -> Result<(), Error> +where + F: FnOnce() -> T, + T: BuildSubscriberRet, +{ let filter = match cfg.filter { Ok(env) => EnvFilter::new(env), _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)), @@ -124,7 +155,7 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> { Err(_) => {} // no wraptree } - let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); + let subscriber = build_subscriber().with(layer.with_filter(filter)); match cfg.backtrace { Ok(backtrace_target) => { let fmt_layer = tracing_subscriber::fmt::layer() diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 455ac66041261..2fbaa2221a18b 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -163,6 +163,10 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_bound(tcx, debruijn, var) } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self { + Const::new_placeholder(tcx, placeholder) + } + fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self { Const::new_unevaluated(interner, uv) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dc3f2844e5ae8..0402d09882254 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -933,7 +933,9 @@ impl Placeholder { pub type PlaceholderRegion = Placeholder; -impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderRegion { + type Bound = BoundRegion; + fn universe(self) -> UniverseIndex { self.universe } @@ -946,14 +948,20 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion { Placeholder { universe: ui, ..self } } - fn new(ui: UniverseIndex, var: BoundVar) -> Self { + fn new(ui: UniverseIndex, bound: BoundRegion) -> Self { + Placeholder { universe: ui, bound } + } + + fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::Anon } } } } pub type PlaceholderType = Placeholder; -impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderType { + type Bound = BoundTy; + fn universe(self) -> UniverseIndex { self.universe } @@ -966,7 +974,11 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType { Placeholder { universe: ui, ..self } } - fn new(ui: UniverseIndex, var: BoundVar) -> Self { + fn new(ui: UniverseIndex, bound: BoundTy) -> Self { + Placeholder { universe: ui, bound } + } + + fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } } } } @@ -980,7 +992,9 @@ pub struct BoundConst<'tcx> { pub type PlaceholderConst = Placeholder; -impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst { +impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderConst { + type Bound = BoundVar; + fn universe(self) -> UniverseIndex { self.universe } @@ -993,7 +1007,11 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst { Placeholder { universe: ui, ..self } } - fn new(ui: UniverseIndex, var: BoundVar) -> Self { + fn new(ui: UniverseIndex, bound: BoundVar) -> Self { + Placeholder { universe: ui, bound } + } + + fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { Placeholder { universe: ui, bound: var } } } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 3e4f7a79d5394..cc25cd16567b1 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -148,6 +148,10 @@ impl<'tcx> rustc_type_ir::inherent::Region> for Region<'tcx> { Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }) } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self { + Region::new_placeholder(tcx, placeholder) + } + fn new_static(tcx: TyCtxt<'tcx>) -> Self { tcx.lifetimes.re_static } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index f804217459915..3853a804a920f 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -66,7 +66,7 @@ impl<'tcx> TyCtxt<'tcx> { { type Result = ControlFlow<()>; - fn visit_binder>>( + fn visit_binder>>( &mut self, t: &Binder<'tcx, T>, ) -> Self::Result { @@ -168,7 +168,7 @@ impl LateBoundRegionsCollector { } impl<'tcx> TypeVisitor> for LateBoundRegionsCollector { - fn visit_binder>>(&mut self, t: &Binder<'tcx, T>) { + fn visit_binder>>(&mut self, t: &Binder<'tcx, T>) { self.current_index.shift_in(1); t.super_visit_with(self); self.current_index.shift_out(1); diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index cea7753317863..47ed9e8724482 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -435,13 +435,13 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }, ty::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy( - PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), + PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()), ), CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), }, ty::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy( - PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), + PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()), ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {t:?}"), }, @@ -594,7 +594,7 @@ impl, I: Interner> TypeFolder for Canonicaliz }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst( - PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), + PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()), ), CanonicalizeMode::Response { .. } => { CanonicalVarKind::PlaceholderConst(placeholder) @@ -602,7 +602,7 @@ impl, I: Interner> TypeFolder for Canonicaliz }, ty::ConstKind::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst( - PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), + PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()), ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"), }, diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 92cdc28a37b4b..77f098e6f2649 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -12,5 +12,6 @@ pub mod canonicalizer; pub mod coherence; pub mod delegate; +pub mod placeholder; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs new file mode 100644 index 0000000000000..c88fb8defae7b --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -0,0 +1,158 @@ +use core::panic; + +use rustc_type_ir::data_structures::IndexMap; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{ + self as ty, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, +}; + +pub struct BoundVarReplacer<'a, Infcx, I = ::Interner> +where + Infcx: InferCtxtLike, + I: Interner, +{ + infcx: &'a Infcx, + // These three maps track the bound variable that were replaced by placeholders. It might be + // nice to remove these since we already have the `kind` in the placeholder; we really just need + // the `var` (but we *could* bring that into scope if we were to track them as we pass them). + mapped_regions: IndexMap, + mapped_types: IndexMap, + mapped_consts: IndexMap, + // The current depth relative to *this* folding, *not* the entire normalization. In other words, + // the depth of binders we've passed here. + current_index: ty::DebruijnIndex, + // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy: + // we don't actually create a universe until we see a bound var we have to replace. + universe_indices: &'a mut Vec>, +} + +impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that + /// use a binding level above `universe_indices.len()`, we fail. + pub fn replace_bound_vars>( + infcx: &'a Infcx, + universe_indices: &'a mut Vec>, + value: T, + ) -> ( + T, + IndexMap, + IndexMap, + IndexMap, + ) { + let mut replacer = BoundVarReplacer { + infcx, + mapped_regions: Default::default(), + mapped_types: Default::default(), + mapped_consts: Default::default(), + current_index: ty::INNERMOST, + universe_indices, + }; + + let value = value.fold_with(&mut replacer); + + (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) + } + + fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { + let infcx = self.infcx; + let index = + self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1; + let universe = self.universe_indices[index].unwrap_or_else(|| { + for i in self.universe_indices.iter_mut().take(index + 1) { + *i = i.or_else(|| Some(infcx.create_next_universe())) + } + self.universe_indices[index].unwrap() + }); + universe + } +} + +impl TypeFolder for BoundVarReplacer<'_, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn cx(&self) -> I { + self.infcx.cx() + } + + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: I::Region) -> I::Region { + match r.kind() { + ty::ReBound(debruijn, _) + if debruijn.as_usize() + >= self.current_index.as_usize() + self.universe_indices.len() => + { + panic!( + "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::ReBound(debruijn, br) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = PlaceholderLike::new(universe, br); + self.mapped_regions.insert(p, br); + Region::new_placeholder(self.cx(), p) + } + _ => r, + } + } + + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + match t.kind() { + ty::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + panic!( + "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = PlaceholderLike::new(universe, bound_ty); + self.mapped_types.insert(p, bound_ty); + Ty::new_placeholder(self.cx(), p) + } + _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), + _ => t, + } + } + + fn fold_const(&mut self, ct: I::Const) -> I::Const { + match ct.kind() { + ty::ConstKind::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + panic!( + "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = PlaceholderLike::new(universe, bound_const); + self.mapped_consts.insert(p, bound_const); + Const::new_placeholder(self.cx(), p) + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } +} diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 542e212e1bfb1..0c267feefbe6b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1014,7 +1014,11 @@ where return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)); } - match assumption.visit_with(&mut FindParamInClause { ecx: self, param_env }) { + match assumption.visit_with(&mut FindParamInClause { + ecx: self, + param_env, + universes: vec![], + }) { ControlFlow::Break(Err(NoSolution)) => Err(NoSolution), ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)), ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)), @@ -1025,6 +1029,7 @@ where struct FindParamInClause<'a, 'b, D: SolverDelegate, I: Interner> { ecx: &'a mut EvalCtxt<'b, D>, param_env: I::ParamEnv, + universes: Vec>, } impl TypeVisitor for FindParamInClause<'_, '_, D, I> @@ -1034,31 +1039,42 @@ where { type Result = ControlFlow>; - fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { - self.ecx.enter_forall(t.clone(), |ecx, v| { - v.visit_with(&mut FindParamInClause { ecx, param_env: self.param_env }) - }) + fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { + self.universes.push(None); + t.super_visit_with(self)?; + self.universes.pop(); + ControlFlow::Continue(()) } fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { + let ty = self.ecx.replace_bound_vars(ty, &mut self.universes); let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else { return ControlFlow::Break(Err(NoSolution)); }; - if let ty::Placeholder(_) = ty.kind() { - ControlFlow::Break(Ok(())) + if let ty::Placeholder(p) = ty.kind() { + if p.universe() == ty::UniverseIndex::ROOT { + ControlFlow::Break(Ok(())) + } else { + ControlFlow::Continue(()) + } } else { ty.super_visit_with(self) } } fn visit_const(&mut self, ct: I::Const) -> Self::Result { + let ct = self.ecx.replace_bound_vars(ct, &mut self.universes); let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else { return ControlFlow::Break(Err(NoSolution)); }; - if let ty::ConstKind::Placeholder(_) = ct.kind() { - ControlFlow::Break(Ok(())) + if let ty::ConstKind::Placeholder(p) = ct.kind() { + if p.universe() == ty::UniverseIndex::ROOT { + ControlFlow::Break(Ok(())) + } else { + ControlFlow::Continue(()) + } } else { ct.super_visit_with(self) } @@ -1066,10 +1082,17 @@ where fn visit_region(&mut self, r: I::Region) -> Self::Result { match self.ecx.eager_resolve_region(r).kind() { - ty::ReStatic | ty::ReError(_) => ControlFlow::Continue(()), - ty::ReVar(_) | ty::RePlaceholder(_) => ControlFlow::Break(Ok(())), - ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReBound(..) => { - unreachable!() + ty::ReStatic | ty::ReError(_) | ty::ReBound(..) => ControlFlow::Continue(()), + ty::RePlaceholder(p) => { + if p.universe() == ty::UniverseIndex::ROOT { + ControlFlow::Break(Ok(())) + } else { + ControlFlow::Continue(()) + } + } + ty::ReVar(_) => ControlFlow::Break(Ok(())), + ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) => { + unreachable!("unexpected region in param-env clause") } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 345ece20b7e53..7ead0a6d6b776 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -19,6 +19,7 @@ use tracing::{debug, instrument, trace}; use super::has_only_region_constraints; use crate::coherence; use crate::delegate::SolverDelegate; +use crate::placeholder::BoundVarReplacer; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ @@ -1232,6 +1233,14 @@ where ) -> Result { self.delegate.is_transmutable(dst, src, assume) } + + pub(super) fn replace_bound_vars>( + &self, + t: T, + universes: &mut Vec>, + ) -> T { + BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0 + } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1f221b4bf78c2..f6e0b08b14046 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -299,10 +299,12 @@ parse_float_literal_unsupported_base = {$base} float literal is not supported parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async` .label = `async` because of this .suggestion = remove the `async` qualifier + .note = allowed qualifiers are: `unsafe` and `extern` parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const` .label = `const` because of this .suggestion = remove the `const` qualifier + .note = allowed qualifiers are: `unsafe` and `extern` parse_fn_ptr_with_generics = function pointer types may not have generic parameters .suggestion = consider moving the lifetime {$arity -> diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 2dba568a258a2..0f0c5434800a5 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2938,22 +2938,22 @@ pub(crate) struct DynAfterMut { #[derive(Diagnostic)] #[diag(parse_fn_pointer_cannot_be_const)] +#[note] pub(crate) struct FnPointerCannotBeConst { #[primary_span] - pub span: Span, #[label] - pub qualifier: Span, + pub span: Span, #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub suggestion: Span, } #[derive(Diagnostic)] #[diag(parse_fn_pointer_cannot_be_async)] +#[note] pub(crate) struct FnPointerCannotBeAsync { #[primary_span] - pub span: Span, #[label] - pub qualifier: Span, + pub span: Span, #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub suggestion: Span, } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a325c2a57ab8e..658ed4bd41c40 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -23,7 +23,7 @@ use super::{ AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, Trailing, UsePreAttrPos, }; -use crate::errors::{self, MacroExpandsToAdtField}; +use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField}; use crate::{exp, fluent_generated as fluent}; impl<'a> Parser<'a> { @@ -2402,7 +2402,7 @@ impl<'a> Parser<'a> { case: Case, ) -> PResult<'a, (Ident, FnSig, Generics, Option>, Option>)> { let fn_span = self.token.span; - let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn` + let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` let decl = match self.parse_fn_decl( @@ -2658,16 +2658,37 @@ impl<'a> Parser<'a> { /// /// `vis` represents the visibility that was already parsed, if any. Use /// `Visibility::Inherited` when no visibility is known. + /// + /// If `parsing_mode` is `FrontMatterParsingMode::FunctionPtrType`, we error on `const` and `async` qualifiers, + /// which are not allowed in function pointer types. pub(super) fn parse_fn_front_matter( &mut self, orig_vis: &Visibility, case: Case, + parsing_mode: FrontMatterParsingMode, ) -> PResult<'a, FnHeader> { let sp_start = self.token.span; let constness = self.parse_constness(case); + if parsing_mode == FrontMatterParsingMode::FunctionPtrType + && let Const::Yes(const_span) = constness + { + self.dcx().emit_err(FnPointerCannotBeConst { + span: const_span, + suggestion: const_span.until(self.token.span), + }); + } let async_start_sp = self.token.span; let coroutine_kind = self.parse_coroutine_kind(case); + if parsing_mode == FrontMatterParsingMode::FunctionPtrType + && let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind + { + self.dcx().emit_err(FnPointerCannotBeAsync { + span: async_span, + suggestion: async_span.until(self.token.span), + }); + } + // FIXME(gen_blocks): emit a similar error for `gen fn()` let unsafe_start_sp = self.token.span; let safety = self.parse_safety(case); @@ -2703,6 +2724,11 @@ impl<'a> Parser<'a> { enum WrongKw { Duplicated(Span), Misplaced(Span), + /// `MisplacedDisallowedQualifier` is only used instead of `Misplaced`, + /// when the misplaced keyword is disallowed by the current `FrontMatterParsingMode`. + /// In this case, we avoid generating the suggestion to swap around the keywords, + /// as we already generated a suggestion to remove the keyword earlier. + MisplacedDisallowedQualifier, } // We may be able to recover @@ -2716,7 +2742,21 @@ impl<'a> Parser<'a> { Const::Yes(sp) => Some(WrongKw::Duplicated(sp)), Const::No => { recover_constness = Const::Yes(self.token.span); - Some(WrongKw::Misplaced(async_start_sp)) + match parsing_mode { + FrontMatterParsingMode::Function => { + Some(WrongKw::Misplaced(async_start_sp)) + } + FrontMatterParsingMode::FunctionPtrType => { + self.dcx().emit_err(FnPointerCannotBeConst { + span: self.token.span, + suggestion: self + .token + .span + .with_lo(self.prev_token.span.hi()), + }); + Some(WrongKw::MisplacedDisallowedQualifier) + } + } } } } else if self.check_keyword(exp!(Async)) { @@ -2742,7 +2782,21 @@ impl<'a> Parser<'a> { closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID, }); - Some(WrongKw::Misplaced(unsafe_start_sp)) + match parsing_mode { + FrontMatterParsingMode::Function => { + Some(WrongKw::Misplaced(async_start_sp)) + } + FrontMatterParsingMode::FunctionPtrType => { + self.dcx().emit_err(FnPointerCannotBeAsync { + span: self.token.span, + suggestion: self + .token + .span + .with_lo(self.prev_token.span.hi()), + }); + Some(WrongKw::MisplacedDisallowedQualifier) + } + } } } } else if self.check_keyword(exp!(Unsafe)) { @@ -2840,14 +2894,20 @@ impl<'a> Parser<'a> { // FIXME(gen_blocks): add keyword recovery logic for genness - if wrong_kw.is_some() + if let Some(wrong_kw) = wrong_kw && self.may_recover() && self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case)) { // Advance past the misplaced keyword and `fn` self.bump(); self.bump(); - err.emit(); + // When we recover from a `MisplacedDisallowedQualifier`, we already emitted an error for the disallowed qualifier + // So we don't emit another error that the qualifier is unexpected. + if matches!(wrong_kw, WrongKw::MisplacedDisallowedQualifier) { + err.cancel(); + } else { + err.emit(); + } return Ok(FnHeader { constness: recover_constness, safety: recover_safety, @@ -3194,3 +3254,12 @@ enum IsMacroRulesItem { Yes { has_bang: bool }, No, } + +#[derive(Copy, Clone, PartialEq, Eq)] +pub(super) enum FrontMatterParsingMode { + /// Parse the front matter of a function declaration + Function, + /// Parse the front matter of a function pointet type. + /// For function pointer types, the `const` and `async` keywords are not permitted. + FunctionPtrType, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 9ddfc179e9b84..620a34044d12e 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -15,10 +15,11 @@ use thin_vec::{ThinVec, thin_vec}; use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use crate::errors::{ self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, - FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg, - HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, - NestedCVariadicType, ReturnTypesUseThinArrow, + FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword, + LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, + ReturnTypesUseThinArrow, }; +use crate::parser::item::FrontMatterParsingMode; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; /// Signals whether parsing a type should allow `+`. @@ -669,62 +670,16 @@ impl<'a> Parser<'a> { tokens: None, }; let span_start = self.token.span; - let ast::FnHeader { ext, safety, constness, coroutine_kind } = - self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?; - let fn_start_lo = self.prev_token.span.lo(); + let ast::FnHeader { ext, safety, .. } = self.parse_fn_front_matter( + &inherited_vis, + Case::Sensitive, + FrontMatterParsingMode::FunctionPtrType, + )?; if self.may_recover() && self.token == TokenKind::Lt { self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?; } let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; - let whole_span = lo.to(self.prev_token.span); - - // Order/parsing of "front matter" follows: - // ` fn()` - // ^ ^ ^ ^ ^ - // | | | | fn_start_lo - // | | | ext_sp.lo - // | | safety_sp.lo - // | coroutine_sp.lo - // const_sp.lo - if let ast::Const::Yes(const_span) = constness { - let next_token_lo = if let Some( - ast::CoroutineKind::Async { span, .. } - | ast::CoroutineKind::Gen { span, .. } - | ast::CoroutineKind::AsyncGen { span, .. }, - ) = coroutine_kind - { - span.lo() - } else if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety { - span.lo() - } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext { - span.lo() - } else { - fn_start_lo - }; - let sugg_span = const_span.with_hi(next_token_lo); - self.dcx().emit_err(FnPointerCannotBeConst { - span: whole_span, - qualifier: const_span, - suggestion: sugg_span, - }); - } - if let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind { - let next_token_lo = if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety - { - span.lo() - } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext { - span.lo() - } else { - fn_start_lo - }; - let sugg_span = async_span.with_hi(next_token_lo); - self.dcx().emit_err(FnPointerCannotBeAsync { - span: whole_span, - qualifier: async_span, - suggestion: sugg_span, - }); - } - // FIXME(gen_blocks): emit a similar error for `gen fn()` + let decl_span = span_start.to(self.prev_token.span); Ok(TyKind::BareFn(P(BareFnTy { ext, safety, generic_params: params, decl, decl_span }))) } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index eb34cb10c68dd..a54eb80fedc25 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -9,7 +9,7 @@ use rustc_macros::extension; pub use rustc_middle::traits::query::NormalizationResult; use rustc_middle::ty::{ self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitableExt, TypeVisitor, TypingMode, + TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_span::DUMMY_SP; use tracing::{debug, info, instrument}; @@ -127,7 +127,7 @@ struct MaxEscapingBoundVarVisitor { } impl<'tcx> TypeVisitor> for MaxEscapingBoundVarVisitor { - fn visit_binder>>(&mut self, t: &ty::Binder<'tcx, T>) { + fn visit_binder>>(&mut self, t: &ty::Binder<'tcx, T>) { self.outer_index.shift_in(1); t.super_visit_with(self); self.outer_index.shift_out(1); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3a2f9e8ca179f..1b9b68fa980de 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1919,12 +1919,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // impl `impl Any for T { .. }`. This really shouldn't exist but is // necessary due to #57893. We again arbitrarily prefer the applicable candidate // with the lowest index. + // + // We do not want to use these impls to guide inference in case a user-written impl + // may also apply. let object_bound = candidates .iter() .filter_map(|c| if let ObjectCandidate(i) = c.candidate { Some(i) } else { None }) .try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) }); match object_bound { - Some(Some(index)) => return Some(ObjectCandidate(index)), + Some(Some(index)) => { + return if has_non_region_infer + && candidates.iter().any(|c| matches!(c.candidate, ImplCandidate(_))) + { + None + } else { + Some(ObjectCandidate(index)) + }; + } Some(None) => {} None => return None, } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 035fd38c48aad..0723aebd5d225 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, VecDeque}; +use std::collections::VecDeque; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::LangItem; @@ -9,6 +9,7 @@ use rustc_middle::bug; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; +pub use rustc_next_trait_solver::placeholder::BoundVarReplacer; use rustc_span::Span; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -212,158 +213,12 @@ pub fn with_replaced_escaping_bound_vars< } } -pub struct BoundVarReplacer<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, - // These three maps track the bound variable that were replaced by placeholders. It might be - // nice to remove these since we already have the `kind` in the placeholder; we really just need - // the `var` (but we *could* bring that into scope if we were to track them as we pass them). - mapped_regions: FxIndexMap, - mapped_types: FxIndexMap, - mapped_consts: BTreeMap, - // The current depth relative to *this* folding, *not* the entire normalization. In other words, - // the depth of binders we've passed here. - current_index: ty::DebruijnIndex, - // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy: - // we don't actually create a universe until we see a bound var we have to replace. - universe_indices: &'a mut Vec>, -} - -impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> { - /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that - /// use a binding level above `universe_indices.len()`, we fail. - pub fn replace_bound_vars>>( - infcx: &'a InferCtxt<'tcx>, - universe_indices: &'a mut Vec>, - value: T, - ) -> ( - T, - FxIndexMap, - FxIndexMap, - BTreeMap, - ) { - let mapped_regions: FxIndexMap = - FxIndexMap::default(); - let mapped_types: FxIndexMap = FxIndexMap::default(); - let mapped_consts: BTreeMap = BTreeMap::new(); - - let mut replacer = BoundVarReplacer { - infcx, - mapped_regions, - mapped_types, - mapped_consts, - current_index: ty::INNERMOST, - universe_indices, - }; - - let value = value.fold_with(&mut replacer); - - (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) - } - - fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { - let infcx = self.infcx; - let index = - self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1; - let universe = self.universe_indices[index].unwrap_or_else(|| { - for i in self.universe_indices.iter_mut().take(index + 1) { - *i = i.or_else(|| Some(infcx.create_next_universe())) - } - self.universe_indices[index].unwrap() - }); - universe - } -} - -impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_binder>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match r.kind() { - ty::ReBound(debruijn, _) - if debruijn.as_usize() - >= self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::ReBound(debruijn, br) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderRegion { universe, bound: br }; - self.mapped_regions.insert(p, br); - ty::Region::new_placeholder(self.infcx.tcx, p) - } - _ => r, - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match *t.kind() { - ty::Bound(debruijn, _) - if debruijn.as_usize() + 1 - > self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderType { universe, bound: bound_ty }; - self.mapped_types.insert(p, bound_ty); - Ty::new_placeholder(self.infcx.tcx, p) - } - _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), - _ => t, - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - match ct.kind() { - ty::ConstKind::Bound(debruijn, _) - if debruijn.as_usize() + 1 - > self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderConst { universe, bound: bound_const }; - self.mapped_consts.insert(p, bound_const); - ty::Const::new_placeholder(self.infcx.tcx, p) - } - _ => ct.super_fold_with(self), - } - } - - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } - } -} - /// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. pub struct PlaceholderReplacer<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap, mapped_types: FxIndexMap, - mapped_consts: BTreeMap, + mapped_consts: FxIndexMap, universe_indices: &'a [Option], current_index: ty::DebruijnIndex, } @@ -373,7 +228,7 @@ impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap, mapped_types: FxIndexMap, - mapped_consts: BTreeMap, + mapped_consts: FxIndexMap, universe_indices: &'a [Option], value: T, ) -> T { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 79ac622df32aa..11becea998c84 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -7,8 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, - fold_regions, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, fold_regions, }; use rustc_span::DUMMY_SP; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; @@ -186,7 +185,7 @@ struct ImplTraitInTraitFinder<'a, 'tcx> { } impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { - fn visit_binder>>(&mut self, binder: &ty::Binder<'tcx, T>) { + fn visit_binder>>(&mut self, binder: &ty::Binder<'tcx, T>) { self.depth.shift_in(1); binder.super_visit_with(self); self.depth.shift_out(1); diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 83d3d78298e60..4bd7bfe79befe 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -9,7 +9,7 @@ bitflags = "2.4.1" derive-where = "1.2.7" ena = "0.14.3" indexmap = "2.0.0" -rustc-hash = "1.1.0" +rustc-hash = "2.0.0" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 55c0a3bba9f2b..927a2ce84ea73 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -128,7 +128,7 @@ impl> TypeFoldable for Binder { } } -impl> TypeVisitable for Binder { +impl> TypeVisitable for Binder { fn visit_with>(&self, visitor: &mut V) -> V::Result { visitor.visit_binder(self) } @@ -147,7 +147,7 @@ impl> TypeSuperFoldable for Binder { } } -impl> TypeSuperVisitable for Binder { +impl> TypeSuperVisitable for Binder { fn super_visit_with>(&self, visitor: &mut V) -> V::Result { self.as_ref().skip_binder().visit_with(visitor) } @@ -292,7 +292,7 @@ impl ValidateBoundVars { impl TypeVisitor for ValidateBoundVars { type Result = ControlFlow<()>; - fn visit_binder>(&mut self, t: &Binder) -> Self::Result { + fn visit_binder>(&mut self, t: &Binder) -> Self::Result { self.binder_index.shift_in(1); let result = t.super_visit_with(self); self.binder_index.shift_out(1); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index fa88bcb891a9c..436ab9f80b6a1 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -228,6 +228,8 @@ pub trait Region>: fn new_static(interner: I) -> Self; + fn new_placeholder(interner: I, var: I::PlaceholderRegion) -> Self; + fn is_bound(self) -> bool { matches!(self.kind(), ty::ReBound(..)) } @@ -254,6 +256,8 @@ pub trait Const>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; + fn new_placeholder(interner: I, param: I::PlaceholderConst) -> Self; + fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst) -> Self; fn new_expr(interner: I, expr: I::ExprConst) -> Self; @@ -524,13 +528,14 @@ pub trait Clauses>: } /// Common capabilities of placeholder kinds -pub trait PlaceholderLike: Copy + Debug + Hash + Eq { +pub trait PlaceholderLike: Copy + Debug + Hash + Eq { fn universe(self) -> ty::UniverseIndex; fn var(self) -> ty::BoundVar; + type Bound: BoundVarLike; + fn new(ui: ty::UniverseIndex, bound: Self::Bound) -> Self; + fn new_anon(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self; fn with_updated_universe(self, ui: ty::UniverseIndex) -> Self; - - fn new(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self; } pub trait IntoKind { @@ -539,13 +544,13 @@ pub trait IntoKind { fn kind(self) -> Self::Kind; } -pub trait BoundVarLike { +pub trait BoundVarLike: Copy + Debug + Hash + Eq { fn var(self) -> ty::BoundVar; fn assert_eq(self, var: I::BoundVarKind); } -pub trait ParamLike { +pub trait ParamLike: Copy + Debug + Hash + Eq { fn index(self) -> u32; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index cc0925b2c32a4..033d2579678ca 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -103,9 +103,9 @@ pub trait Interner: type Ty: Ty; type Tys: Tys; type FnInputTys: Copy + Debug + Hash + Eq + SliceLike + TypeVisitable; - type ParamTy: Copy + Debug + Hash + Eq + ParamLike; - type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike; - type PlaceholderTy: PlaceholderLike; + type ParamTy: ParamLike; + type BoundTy: BoundVarLike; + type PlaceholderTy: PlaceholderLike; // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; @@ -131,19 +131,19 @@ pub trait Interner: // Kinds of consts type Const: Const; - type PlaceholderConst: PlaceholderLike; type ParamConst: Copy + Debug + Hash + Eq + ParamLike; - type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike; + type BoundConst: BoundVarLike; + type PlaceholderConst: PlaceholderLike; type ValueConst: ValueConst; type ExprConst: ExprConst; type ValTree: Copy + Debug + Hash + Eq; // Kinds of regions type Region: Region; - type EarlyParamRegion: Copy + Debug + Hash + Eq + ParamLike; + type EarlyParamRegion: ParamLike; type LateParamRegion: Copy + Debug + Hash + Eq; - type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike; - type PlaceholderRegion: PlaceholderLike; + type BoundRegion: BoundVarLike; + type PlaceholderRegion: PlaceholderLike; // Predicates type ParamEnv: ParamEnv; diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index 0ce927b58bb38..a2442660259dc 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -4,7 +4,7 @@ use super::{AvailableDepth, Cx, NestedGoals}; use crate::data_structures::HashMap; struct Success { - additional_depth: usize, + required_depth: usize, nested_goals: NestedGoals, result: X::Tracked, } @@ -28,7 +28,7 @@ struct CacheEntry { #[derive_where(Debug; X: Cx)] pub(super) struct CacheData<'a, X: Cx> { pub(super) result: X::Result, - pub(super) additional_depth: usize, + pub(super) required_depth: usize, pub(super) encountered_overflow: bool, pub(super) nested_goals: &'a NestedGoals, } @@ -47,7 +47,7 @@ impl GlobalCache { origin_result: X::Result, dep_node: X::DepNodeIndex, - additional_depth: usize, + required_depth: usize, encountered_overflow: bool, nested_goals: NestedGoals, ) { @@ -55,13 +55,13 @@ impl GlobalCache { let entry = self.map.entry(input).or_default(); if encountered_overflow { let with_overflow = WithOverflow { nested_goals, result }; - let prev = entry.with_overflow.insert(additional_depth, with_overflow); + let prev = entry.with_overflow.insert(required_depth, with_overflow); if let Some(prev) = &prev { assert!(cx.evaluation_is_concurrent()); assert_eq!(cx.get_tracked(&prev.result), origin_result); } } else { - let prev = entry.success.replace(Success { additional_depth, nested_goals, result }); + let prev = entry.success.replace(Success { required_depth, nested_goals, result }); if let Some(prev) = &prev { assert!(cx.evaluation_is_concurrent()); assert_eq!(cx.get_tracked(&prev.result), origin_result); @@ -81,13 +81,13 @@ impl GlobalCache { mut candidate_is_applicable: impl FnMut(&NestedGoals) -> bool, ) -> Option> { let entry = self.map.get(&input)?; - if let Some(Success { additional_depth, ref nested_goals, ref result }) = entry.success { - if available_depth.cache_entry_is_applicable(additional_depth) + if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success { + if available_depth.cache_entry_is_applicable(required_depth) && candidate_is_applicable(nested_goals) { return Some(CacheData { result: cx.get_tracked(&result), - additional_depth, + required_depth, encountered_overflow: false, nested_goals, }); @@ -101,7 +101,7 @@ impl GlobalCache { if candidate_is_applicable(nested_goals) { return Some(CacheData { result: cx.get_tracked(result), - additional_depth, + required_depth: additional_depth, encountered_overflow: true, nested_goals, }); diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 1acd5d5c2af4b..f0eb96b47b108 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -19,13 +19,14 @@ use std::hash::Hash; use std::marker::PhantomData; use derive_where::derive_where; -use rustc_index::{Idx, IndexVec}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use tracing::debug; use crate::data_structures::HashMap; +mod stack; +use stack::{Stack, StackDepth, StackEntry}; mod global_cache; use global_cache::CacheData; pub use global_cache::GlobalCache; @@ -225,9 +226,9 @@ impl AvailableDepth { /// in case there is exponential blowup. fn allowed_depth_for_nested( root_depth: AvailableDepth, - stack: &IndexVec>, + stack: &Stack, ) -> Option { - if let Some(last) = stack.raw.last() { + if let Some(last) = stack.last() { if last.available_depth.0 == 0 { return None; } @@ -433,50 +434,6 @@ impl NestedGoals { } } -rustc_index::newtype_index! { - #[orderable] - #[gate_rustc_only] - pub struct StackDepth {} -} - -/// Stack entries of the evaluation stack. Its fields tend to be lazily -/// when popping a child goal or completely immutable. -#[derive_where(Debug; X: Cx)] -struct StackEntry { - input: X::Input, - - /// Whether proving this goal is a coinductive step. - /// - /// This is used when encountering a trait solver cycle to - /// decide whether the initial provisional result of the cycle. - step_kind_from_parent: PathKind, - - /// The available depth of a given goal, immutable. - available_depth: AvailableDepth, - - /// The maximum depth reached by this stack entry, only up-to date - /// for the top of the stack and lazily updated for the rest. - reached_depth: StackDepth, - - /// All cycle heads this goal depends on. Lazily updated and only - /// up-to date for the top of the stack. - heads: CycleHeads, - - /// Whether evaluating this goal encountered overflow. Lazily updated. - encountered_overflow: bool, - - /// Whether this goal has been used as the root of a cycle. This gets - /// eagerly updated when encountering a cycle. - has_been_used: Option, - - /// The nested goals of this goal, see the doc comment of the type. - nested_goals: NestedGoals, - - /// Starts out as `None` and gets set when rerunning this - /// goal in case we encounter a cycle. - provisional_result: Option, -} - /// A provisional result of an already computed goals which depends on other /// goals still on the stack. #[derive_where(Debug; X: Cx)] @@ -498,7 +455,7 @@ pub struct SearchGraph, X: Cx = ::Cx> { /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. - stack: IndexVec>, + stack: Stack, /// The provisional cache contains entries for already computed goals which /// still depend on goals higher-up in the stack. We don't move them to the /// global cache and track them locally instead. A provisional cache entry @@ -537,16 +494,16 @@ impl, X: Cx> SearchGraph { /// and using existing global cache entries to make sure they /// have the same impact on the remaining evaluation. fn update_parent_goal( - stack: &mut IndexVec>, + stack: &mut Stack, step_kind_from_parent: PathKind, - reached_depth: StackDepth, + required_depth_for_nested: usize, heads: &CycleHeads, encountered_overflow: bool, context: UpdateParentGoalCtxt<'_, X>, ) { if let Some(parent_index) = stack.last_index() { let parent = &mut stack[parent_index]; - parent.reached_depth = parent.reached_depth.max(reached_depth); + parent.required_depth = parent.required_depth.max(required_depth_for_nested + 1); parent.encountered_overflow |= encountered_overflow; parent.heads.extend_from_child(parent_index, step_kind_from_parent, heads); @@ -588,13 +545,11 @@ impl, X: Cx> SearchGraph { /// the stack which completes the cycle. This given an inductive step AB which then cycles /// coinductively with A, we need to treat this cycle as coinductive. fn cycle_path_kind( - stack: &IndexVec>, + stack: &Stack, step_kind_to_head: PathKind, head: StackDepth, ) -> PathKind { - stack.raw[head.index() + 1..] - .iter() - .fold(step_kind_to_head, |curr, entry| curr.extend(entry.step_kind_from_parent)) + stack.cycle_step_kinds(head).fold(step_kind_to_head, |curr, step| curr.extend(step)) } /// Probably the most involved method of the whole solver. @@ -656,20 +611,18 @@ impl, X: Cx> SearchGraph { return result; } - // Unfortunate, it looks like we actually have to compute this goalrar. - let depth = self.stack.next_index(); - let entry = StackEntry { + // Unfortunate, it looks like we actually have to compute this goal. + self.stack.push(StackEntry { input, step_kind_from_parent, available_depth, - reached_depth: depth, + required_depth: 0, heads: Default::default(), encountered_overflow: false, has_been_used: None, nested_goals: Default::default(), provisional_result: None, - }; - assert_eq!(self.stack.push(entry), depth); + }); // This is for global caching, so we properly track query dependencies. // Everything that affects the `result` should be performed within this @@ -686,7 +639,7 @@ impl, X: Cx> SearchGraph { Self::update_parent_goal( &mut self.stack, final_entry.step_kind_from_parent, - final_entry.reached_depth, + final_entry.required_depth, &final_entry.heads, final_entry.encountered_overflow, UpdateParentGoalCtxt::Ordinary(&final_entry.nested_goals), @@ -700,7 +653,7 @@ impl, X: Cx> SearchGraph { // the global cache. assert_eq!(result, expected, "input={input:?}"); } else if D::inspect_is_noop(inspect) { - self.insert_global_cache(cx, input, final_entry, result, dep_node) + self.insert_global_cache(cx, final_entry, result, dep_node) } } else if D::ENABLE_PROVISIONAL_CACHE { debug_assert!(validate_cache.is_none(), "unexpected non-root: {input:?}"); @@ -728,7 +681,7 @@ impl, X: Cx> SearchGraph { input: X::Input, inspect: &mut D::ProofTreeBuilder, ) -> X::Result { - if let Some(last) = self.stack.raw.last_mut() { + if let Some(last) = self.stack.last_mut() { last.encountered_overflow = true; // If computing a goal `B` depends on another goal `A` and // `A` has a nested goal which overflows, then computing `B` @@ -859,7 +812,7 @@ impl, X: Cx> SearchGraph { // apply provisional cache entries which encountered overflow once the // current goal is already part of the same cycle. This check could be // improved but seems to be good enough for now. - let last = self.stack.raw.last().unwrap(); + let last = self.stack.last().unwrap(); if last.heads.opt_lowest_cycle_head().is_none_or(|lowest| lowest > head) { continue; } @@ -868,14 +821,10 @@ impl, X: Cx> SearchGraph { // A provisional cache entry is only valid if the current path from its // highest cycle head to the goal is the same. if path_from_head == Self::cycle_path_kind(&self.stack, step_kind_from_parent, head) { - // While we don't have to track the full depth of the provisional cache entry, - // we do have to increment the required depth by one as we'd have already failed - // with overflow otherwise - let next_index = self.stack.next_index(); Self::update_parent_goal( &mut self.stack, step_kind_from_parent, - next_index, + 0, heads, encountered_overflow, UpdateParentGoalCtxt::ProvisionalCacheHit, @@ -893,7 +842,7 @@ impl, X: Cx> SearchGraph { /// evaluating this entry would not have ended up depending on either a goal /// already on the stack or a provisional cache entry. fn candidate_is_applicable( - stack: &IndexVec>, + stack: &Stack, step_kind_from_parent: PathKind, provisional_cache: &HashMap>>, nested_goals: &NestedGoals, @@ -991,7 +940,7 @@ impl, X: Cx> SearchGraph { available_depth: AvailableDepth, ) -> Option { cx.with_global_cache(|cache| { - let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache + let CacheData { result, required_depth, encountered_overflow, nested_goals } = cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( &self.stack, @@ -1001,23 +950,19 @@ impl, X: Cx> SearchGraph { ) })?; - // Update the reached depth of the current goal to make sure - // its state is the same regardless of whether we've used the - // global cache or not. - let reached_depth = self.stack.next_index().plus(additional_depth); // We don't move cycle participants to the global cache, so the // cycle heads are always empty. let heads = Default::default(); Self::update_parent_goal( &mut self.stack, step_kind_from_parent, - reached_depth, + required_depth, &heads, encountered_overflow, UpdateParentGoalCtxt::Ordinary(nested_goals), ); - debug!(?additional_depth, "global cache hit"); + debug!(?required_depth, "global cache hit"); Some(result) }) } @@ -1028,7 +973,7 @@ impl, X: Cx> SearchGraph { input: X::Input, step_kind_from_parent: PathKind, ) -> Option { - let (head, _stack_entry) = self.stack.iter_enumerated().find(|(_, e)| e.input == input)?; + let head = self.stack.find(input)?; // We have a nested goal which directly relies on a goal deeper in the stack. // // We start by tagging all cycle participants, as that's necessary for caching. @@ -1043,10 +988,9 @@ impl, X: Cx> SearchGraph { // Subtle: when encountering a cyclic goal, we still first checked for overflow, // so we have to update the reached depth. - let next_index = self.stack.next_index(); let last_index = self.stack.last_index().unwrap(); let last = &mut self.stack[last_index]; - last.reached_depth = last.reached_depth.max(next_index); + last.required_depth = last.required_depth.max(1); last.nested_goals.insert(input, step_kind_from_parent.into()); last.nested_goals.insert(last.input, PathsToNested::EMPTY); @@ -1095,7 +1039,7 @@ impl, X: Cx> SearchGraph { let mut i = 0; loop { let result = evaluate_goal(self, inspect); - let stack_entry = self.stack.pop().unwrap(); + let stack_entry = self.stack.pop(); debug_assert_eq!(stack_entry.input, input); // If the current goal is not the root of a cycle, we are done. @@ -1176,20 +1120,18 @@ impl, X: Cx> SearchGraph { fn insert_global_cache( &mut self, cx: X, - input: X::Input, final_entry: StackEntry, result: X::Result, dep_node: X::DepNodeIndex, ) { - let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len(); debug!(?final_entry, ?result, "insert global cache"); cx.with_global_cache(|cache| { cache.insert( cx, - input, + final_entry.input, result, dep_node, - additional_depth, + final_entry.required_depth, final_entry.encountered_overflow, final_entry.nested_goals, ) diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs new file mode 100644 index 0000000000000..8bb247bf0554d --- /dev/null +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -0,0 +1,113 @@ +use std::ops::{Index, IndexMut}; + +use derive_where::derive_where; +use rustc_index::IndexVec; + +use super::{AvailableDepth, Cx, CycleHeads, NestedGoals, PathKind, UsageKind}; + +rustc_index::newtype_index! { + #[orderable] + #[gate_rustc_only] + pub(super) struct StackDepth {} +} + +/// Stack entries of the evaluation stack. Its fields tend to be lazily +/// when popping a child goal or completely immutable. +#[derive_where(Debug; X: Cx)] +pub(super) struct StackEntry { + pub input: X::Input, + + /// Whether proving this goal is a coinductive step. + /// + /// This is used when encountering a trait solver cycle to + /// decide whether the initial provisional result of the cycle. + pub step_kind_from_parent: PathKind, + + /// The available depth of a given goal, immutable. + pub available_depth: AvailableDepth, + + /// The maximum depth required while evaluating this goal. + pub required_depth: usize, + + /// All cycle heads this goal depends on. Lazily updated and only + /// up-to date for the top of the stack. + pub heads: CycleHeads, + + /// Whether evaluating this goal encountered overflow. Lazily updated. + pub encountered_overflow: bool, + + /// Whether this goal has been used as the root of a cycle. This gets + /// eagerly updated when encountering a cycle. + pub has_been_used: Option, + + /// The nested goals of this goal, see the doc comment of the type. + pub nested_goals: NestedGoals, + + /// Starts out as `None` and gets set when rerunning this + /// goal in case we encounter a cycle. + pub provisional_result: Option, +} + +#[derive_where(Default; X: Cx)] +pub(super) struct Stack { + entries: IndexVec>, +} + +impl Stack { + pub(super) fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + pub(super) fn len(&self) -> usize { + self.entries.len() + } + + pub(super) fn last_index(&self) -> Option { + self.entries.last_index() + } + + pub(super) fn last(&self) -> Option<&StackEntry> { + self.entries.raw.last() + } + + pub(super) fn last_mut(&mut self) -> Option<&mut StackEntry> { + self.entries.raw.last_mut() + } + + pub(super) fn next_index(&self) -> StackDepth { + self.entries.next_index() + } + + pub(super) fn push(&mut self, entry: StackEntry) -> StackDepth { + self.entries.push(entry) + } + + pub(super) fn pop(&mut self) -> StackEntry { + self.entries.pop().unwrap() + } + + pub(super) fn cycle_step_kinds(&self, head: StackDepth) -> impl Iterator { + self.entries.raw[head.index() + 1..].iter().map(|entry| entry.step_kind_from_parent) + } + + pub(super) fn iter(&self) -> impl Iterator> { + self.entries.iter() + } + + pub(super) fn find(&self, input: X::Input) -> Option { + self.entries.iter_enumerated().find(|(_, e)| e.input == input).map(|(idx, _)| idx) + } +} + +impl Index for Stack { + type Output = StackEntry; + fn index(&self, index: StackDepth) -> &StackEntry { + &self.entries[index] + } +} + +impl IndexMut for Stack { + fn index_mut(&mut self, index: StackDepth) -> &mut Self::Output { + &mut self.entries[index] + } +} diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 8ba985d2d1931..d1ca9bdb7fbd1 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -342,7 +342,7 @@ struct HasRegionsBoundAt { // FIXME: Could be optimized to not walk into components with no escaping bound vars. impl TypeVisitor for HasRegionsBoundAt { type Result = ControlFlow<()>; - fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { + fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { self.binder.shift_in(1); t.super_visit_with(self)?; self.binder.shift_out(1); diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index fc3864dd5ae6e..a96ac97f785d4 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -52,7 +52,7 @@ use smallvec::SmallVec; use thin_vec::ThinVec; use crate::inherent::*; -use crate::{self as ty, Interner, TypeFlags, TypeFoldable}; +use crate::{self as ty, Interner, TypeFlags}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. @@ -94,7 +94,7 @@ pub trait TypeVisitor: Sized { #[cfg(not(feature = "nightly"))] type Result: VisitorResult; - fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { + fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { t.super_visit_with(self) } @@ -401,7 +401,7 @@ impl std::fmt::Debug for HasTypeFlagsVisitor { impl TypeVisitor for HasTypeFlagsVisitor { type Result = ControlFlow; - fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { + fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { // If we're looking for the HAS_BINDER_VARS flag, check if the // binder has vars. This won't be present in the binder's bound // value, so we need to check here too. @@ -510,7 +510,7 @@ struct HasEscapingVarsVisitor { impl TypeVisitor for HasEscapingVarsVisitor { type Result = ControlFlow; - fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { + fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ce7321544b6b9..5bd82560da7ed 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -109,6 +109,11 @@ mod in_place_collect; mod partial_eq; +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub use self::peek_mut::PeekMut; + +mod peek_mut; + #[cfg(not(no_global_oom_handling))] use self::spec_from_elem::SpecFromElem; @@ -729,6 +734,33 @@ impl Vec { pub unsafe fn from_parts(ptr: NonNull, length: usize, capacity: usize) -> Self { unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } + + /// Returns a mutable reference to the last item in the vector, or + /// `None` if it is empty. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(vec_peek_mut)] + /// let mut vec = Vec::new(); + /// assert!(vec.peek_mut().is_none()); + /// + /// vec.push(1); + /// vec.push(5); + /// vec.push(2); + /// assert_eq!(vec.last(), Some(&2)); + /// if let Some(mut val) = vec.peek_mut() { + /// *val = 0; + /// } + /// assert_eq!(vec.last(), Some(&0)); + /// ``` + #[inline] + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn peek_mut(&mut self) -> Option> { + PeekMut::new(self) + } } impl Vec { diff --git a/library/alloc/src/vec/peek_mut.rs b/library/alloc/src/vec/peek_mut.rs new file mode 100644 index 0000000000000..c0dd941ed3933 --- /dev/null +++ b/library/alloc/src/vec/peek_mut.rs @@ -0,0 +1,55 @@ +use core::ops::{Deref, DerefMut}; + +use super::Vec; +use crate::fmt; + +/// Structure wrapping a mutable reference to the last item in a +/// `Vec`. +/// +/// This `struct` is created by the [`peek_mut`] method on [`Vec`]. See +/// its documentation for more. +/// +/// [`peek_mut`]: Vec::peek_mut +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub struct PeekMut<'a, T> { + vec: &'a mut Vec, +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl fmt::Debug for PeekMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PeekMut").field(self.deref()).finish() + } +} + +impl<'a, T> PeekMut<'a, T> { + pub(crate) fn new(vec: &'a mut Vec) -> Option { + if vec.is_empty() { None } else { Some(Self { vec }) } + } + + /// Removes the peeked value from the vector and returns it. + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn pop(self) -> T { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.pop().unwrap_unchecked() } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> Deref for PeekMut<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked(self.vec.len() - 1) } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> DerefMut for PeekMut<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + let idx = self.vec.len() - 1; + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked_mut(idx) } + } +} diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 38309585fad61..a41162ecd51a0 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -40,6 +40,7 @@ #![feature(vec_deque_truncate_front)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] +#![feature(vec_peek_mut)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index f430d979fa848..51b49b8edb3f0 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2698,6 +2698,23 @@ fn test_pop_if_mutates() { assert_eq!(v, [2]); } +#[test] +fn test_peek_mut() { + let mut vec = Vec::new(); + assert!(vec.peek_mut().is_none()); + vec.push(1); + vec.push(2); + if let Some(mut p) = vec.peek_mut() { + assert_eq!(*p, 2); + *p = 0; + assert_eq!(*p, 0); + p.pop(); + assert_eq!(vec.len(), 1); + } else { + unreachable!() + } +} + /// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments /// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but /// `vec.insert(usize::MAX, val)` once slipped by! diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 7ba48cc72683c..e0e80fc9b413b 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1,5 +1,9 @@ //! Compiler intrinsics. //! +//! The functions in this module are implementation details of `core` and should +//! not be used outside of the standard library. We generally provide access to +//! intrinsics via stable wrapper functions. Use these instead. +//! //! These are the imports making intrinsics available to Rust code. The actual implementations live in the compiler. //! Some of these intrinsics are lowered to MIR in . //! The remaining intrinsics are implemented for the LLVM backend in diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 6cbf8301e01b9..0cd794fd3efbb 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -153,9 +153,8 @@ pub struct Metadata(fs_imp::FileAttr); /// dependent. /// /// # Errors -/// -/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent -/// IO error during iteration. +/// This [`io::Result`] will be an [`Err`] if an error occurred while fetching +/// the next entry from the OS. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct ReadDir(fs_imp::ReadDir); diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index ef776e2194365..493f73b21fe15 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -200,12 +200,14 @@ than building it. .map(|p| cmd_finder.must_have(p)) .or_else(|| cmd_finder.maybe_have("reuse")); - let stage0_supported_target_list: HashSet = crate::utils::helpers::output( - command(&build.config.initial_rustc).args(["--print", "target-list"]).as_command_mut(), - ) - .lines() - .map(|s| s.to_string()) - .collect(); + let stage0_supported_target_list: HashSet = command(&build.config.initial_rustc) + .args(["--print", "target-list"]) + .run_always() + .run_capture_stdout(&build) + .stdout() + .lines() + .map(|s| s.to_string()) + .collect(); // Compiler tools like `cc` and `ar` are not configured for cross-targets on certain subcommands // because they are not needed. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 25e59bfe3a889..7254c653a2dba 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -21,7 +21,6 @@ use std::cell::{Cell, RefCell}; use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::Display; use std::path::{Path, PathBuf}; -use std::process::Command; use std::sync::OnceLock; use std::time::SystemTime; use std::{env, fs, io, str}; @@ -39,7 +38,7 @@ use crate::core::builder::Kind; use crate::core::config::{DryRun, LldMode, LlvmLibunwind, TargetSelection, flags}; use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command}; use crate::utils::helpers::{ - self, dir_is_empty, exe, libdir, output, set_file_times, split_debuginfo, symlink_dir, + self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo, symlink_dir, }; mod core; @@ -376,10 +375,13 @@ impl Build { let in_tree_llvm_info = config.in_tree_llvm_info.clone(); let in_tree_gcc_info = config.in_tree_gcc_info.clone(); - let initial_target_libdir = - output(Command::new(&config.initial_rustc).args(["--print", "target-libdir"])) - .trim() - .to_owned(); + let initial_target_libdir = command(&config.initial_rustc) + .run_always() + .args(["--print", "target-libdir"]) + .run_capture_stdout(&config) + .stdout() + .trim() + .to_owned(); let initial_target_dir = Path::new(&initial_target_libdir) .parent() @@ -479,8 +481,11 @@ impl Build { // If local-rust is the same major.minor as the current version, then force a // local-rebuild - let local_version_verbose = - output(Command::new(&build.initial_rustc).arg("--version").arg("--verbose")); + let local_version_verbose = command(&build.initial_rustc) + .run_always() + .args(["--version", "--verbose"]) + .run_capture_stdout(&build) + .stdout(); let local_release = local_version_verbose .lines() .filter_map(|x| x.strip_prefix("release:")) @@ -941,9 +946,14 @@ impl Build { fn rustc_snapshot_sysroot(&self) -> &Path { static SYSROOT_CACHE: OnceLock = OnceLock::new(); SYSROOT_CACHE.get_or_init(|| { - let mut rustc = Command::new(&self.initial_rustc); - rustc.args(["--print", "sysroot"]); - output(&mut rustc).trim().into() + command(&self.initial_rustc) + .run_always() + .args(["--print", "sysroot"]) + .run_capture_stdout(self) + .stdout() + .trim() + .to_owned() + .into() }) } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index f2c3e8c0df464..3e04e04684466 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -300,25 +300,6 @@ pub fn make(host: &str) -> PathBuf { } } -#[track_caller] -pub fn output(cmd: &mut Command) -> String { - #[cfg(feature = "tracing")] - let _run_span = crate::trace_cmd!(cmd); - - let output = match cmd.stderr(Stdio::inherit()).output() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), - }; - if !output.status.success() { - panic!( - "command did not execute successfully: {:?}\n\ - expected success, got: {}", - cmd, output.status - ); - } - String::from_utf8(output.stdout).unwrap() -} - /// Spawn a process and return a closure that will wait for the process /// to finish and then return its output. This allows the spawned process /// to do work without immediately blocking bootstrap. diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index 006a697af2126..8d2c5e004e479 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile @@ -41,7 +41,9 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/ +RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)' + # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. -ENV SCRIPT TIDY_PRINT_DIFF=1 npm install eslint@$(head -n 1 /tmp/eslint.version) && \ - python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp +ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \ + src/tools/tidy tidyselftest --extra-checks=py,cpp diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index a3939e5a5c451..201a550307972 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -113,6 +113,7 @@ - [\*-unknown-openbsd](platform-support/openbsd.md) - [\*-unknown-redox](platform-support/redox.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) + - [\*-unknown-windows-msvc](platform-support/windows-msvc.md) - [\*-uwp-windows-msvc](platform-support/uwp-windows-msvc.md) - [\*-wrs-vxworks](platform-support/vxworks.md) - [wasm32-wasip1](platform-support/wasm32-wasip1.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 559e4867bbb10..3cab57df75a82 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -34,11 +34,11 @@ target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+) -`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] +[`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+) -`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+) +[`x86_64-pc-windows-msvc`](platform-support/windows-msvc.md) | 64-bit MSVC (Windows 10+, Windows Server 2016+) `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue]. @@ -88,7 +88,7 @@ so Rustup may install the documentation for a similar tier 1 target instead. target | notes -------|------- -`aarch64-pc-windows-msvc` | ARM64 Windows MSVC +[`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17) diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md new file mode 100644 index 0000000000000..71dc4ddc2e65c --- /dev/null +++ b/src/doc/rustc/src/platform-support/windows-msvc.md @@ -0,0 +1,69 @@ +# `*-pc-windows-msvc` + +Windows MSVC targets. + +**Tier 1 with host tools:** + +- `i686-pc-windows-msvc`: Windows on 32-bit x86. +- `x86_64-pc-windows-msvc`: Windows on 64-bit x86. + +**Tier 2 with host tools:** + +- `aarch64-pc-windows-msvc`: Windows on ARM64. + +## Target maintainers + +[@ChrisDenton](https://github.com/ChrisDenton) +[@dpaoliello](https://github.com/dpaoliello) +[@lambdageek](https://github.com/lambdageek) +[@sivadeilra](https://github.com/sivadeilra) +[@wesleywiser](https://github.com/wesleywiser) + +## Requirements + +### OS version + +Windows 10 or higher is required for client installs, Windows Server 2016 or higher is required for server installs. + +### Host tooling + +The minimum supported Visual Studio version is 2017 but this support is not actively tested in CI. +It is **highly** recommended to use the latest version of VS (currently VS 2022). + +### Platform details + +These targets fully implement the Rust standard library. + +The `extern "C"` calling convention conforms to Microsoft's default calling convention for the given architecture: [`__cdecl`] on `i686`, [`x64`] on `x86_64` and [`ARM64`] on `aarch64`. + +The `*-windows-msvc` targets produce PE/COFF binaries with CodeView debuginfo, the native formats used on Windows. + +[`__cdecl`]: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +[`x64`]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170 +[`ARM64`]: https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170 + +## Building Rust programs + +These targets are distributed via `rustup` and can be installed via `rustup component add [--toolchain {name}] {target}`. + +For example, adding the 32-bit x86 target to the `nightly` toolchain: + +```text +rustup component add --toolchain nightly i686-pc-windows-msvc +``` + +or adding the ARM64 target to the active toolchain: + +```text +rustup component add aarch64-pc-windows-msvc +``` + +## Testing + +There are no special requirements for testing and running this target. + +## Cross-compilation toolchains and C code + +Architectural cross-compilation from one Windows host to a different Windows platform is natively supported by the MSVC toolchain provided the appropriate components are selected when using the VS Installer. + +Cross-compilation from a non-Windows host to a `*-windows-msvc` target _may_ be possible but is not supported. diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 1f0a0f2b02ac0..32a992ccc2d7b 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, - GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, + GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; @@ -853,7 +853,7 @@ pub fn for_each_top_level_late_bound_region( ControlFlow::Continue(()) } } - fn visit_binder>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result { + fn visit_binder>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result { self.index += 1; let res = t.super_visit_with(self); self.index -= 1; diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 81f5679aead77..202582bea8c13 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -29,6 +29,7 @@ fn path_div() -> &'static str { pub fn logv(config: &Config, s: String) { debug!("{}", s); if config.verbose { + // Note: `./x test ... --verbose --no-capture` is needed to see this print. println!("{}", s); } } diff --git a/tests/codegen/retpoline.rs b/tests/codegen/retpoline.rs index 30fdd9c2db2c0..915c2c3d7978e 100644 --- a/tests/codegen/retpoline.rs +++ b/tests/codegen/retpoline.rs @@ -3,18 +3,16 @@ // `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls` // target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set. +//@ add-core-stubs //@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk //@ needs-llvm-components: x86 //@ compile-flags: --target x86_64-unknown-linux-gnu //@ [enabled_retpoline] compile-flags: -Zretpoline //@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk - #![crate_type = "lib"] -#![feature(no_core, lang_items)] +#![feature(no_core)] #![no_core] - -#[lang = "sized"] -trait Sized {} +extern crate minicore; #[no_mangle] pub fn foo() { diff --git a/tests/crashes/137188.rs b/tests/crashes/137188.rs deleted file mode 100644 index fdd098d300f4c..0000000000000 --- a/tests/crashes/137188.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #137188 -#![feature(min_generic_const_args)] -trait Trait {} -impl Trait for [(); N] {} -fn N() {} -pub fn main() {} diff --git a/tests/crashes/138166.rs b/tests/crashes/138166.rs deleted file mode 100644 index 98003bd6dae77..0000000000000 --- a/tests/crashes/138166.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #138166 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -struct a(Box<[u8; Box::b]>); -impl a { - fn c(self) { self.0.d() } -} -fn main() {} diff --git a/tests/crashes/138240.rs b/tests/crashes/138240.rs deleted file mode 100644 index 6ffb7868bd5d8..0000000000000 --- a/tests/crashes/138240.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #138240 -//@edition:2024 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -async fn _CF() -> Box<[u8; Box::b]> { - Box::new(true) -} - -fn main() {} diff --git a/tests/crashes/138266.rs b/tests/crashes/138266.rs deleted file mode 100644 index 9a4de9abcff5c..0000000000000 --- a/tests/crashes/138266.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #138266 -//@compile-flags: --crate-type=lib -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -pub fn f(mut x: [u8; Box::b]) { - x[72] = 1; -} diff --git a/tests/crashes/138359.rs b/tests/crashes/138359.rs deleted file mode 100644 index d4376d536eecc..0000000000000 --- a/tests/crashes/138359.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #138359 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -struct a(Box<[u8; Box::b]>); -impl a { - fn c(self) { self.0.da } -} -fn main() {} diff --git a/tests/ui/borrowck/issue-47646.stderr b/tests/ui/borrowck/issue-47646.stderr index 85adfc03d1070..cfe6f3f399388 100644 --- a/tests/ui/borrowck/issue-47646.stderr +++ b/tests/ui/borrowck/issue-47646.stderr @@ -11,7 +11,7 @@ LL | println!("{:?}", heap); | ^^^^ immutable borrow occurs here ... LL | }; - | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option>, ())` + | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option>, ())` | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/borrowck/issue-85581.stderr b/tests/ui/borrowck/issue-85581.stderr index 80f1f4cb50919..5fd457eb8dd45 100644 --- a/tests/ui/borrowck/issue-85581.stderr +++ b/tests/ui/borrowck/issue-85581.stderr @@ -10,7 +10,7 @@ LL | Some(_) => { heap.pop(); }, | ^^^^ second mutable borrow occurs here ... LL | } - | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option>` + | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option>` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/missing_generic_params.rs b/tests/ui/const-generics/mgca/missing_generic_params.rs new file mode 100644 index 0000000000000..ab1db3364ec3e --- /dev/null +++ b/tests/ui/const-generics/mgca/missing_generic_params.rs @@ -0,0 +1,16 @@ +// This used to ICE: #137188 +// The missing parameter list on `N` was set to +// "infer from use site" in ast lowering, which +// caused later code to not emit a missing generic +// param error. The missing param was then attempted +// to be inferred, but inference of generic params +// is only possible within bodies. So a delayed +// bug was generated with no error ever reported. + +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] +trait Trait {} +impl Trait for [(); N] {} +//~^ ERROR: missing generics for function `N` +fn N() {} +pub fn main() {} diff --git a/tests/ui/const-generics/mgca/missing_generic_params.stderr b/tests/ui/const-generics/mgca/missing_generic_params.stderr new file mode 100644 index 0000000000000..78010c756212c --- /dev/null +++ b/tests/ui/const-generics/mgca/missing_generic_params.stderr @@ -0,0 +1,19 @@ +error[E0107]: missing generics for function `N` + --> $DIR/missing_generic_params.rs:13:21 + | +LL | impl Trait for [(); N] {} + | ^ expected 1 generic argument + | +note: function defined here, with 1 generic parameter: `T` + --> $DIR/missing_generic_params.rs:15:4 + | +LL | fn N() {} + | ^ - +help: add missing generic argument + | +LL | impl Trait for [(); N] {} + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr new file mode 100644 index 0000000000000..fca32c5c1e6fc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr @@ -0,0 +1,73 @@ +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8 + | +LL | extern "gpu-kernel" fn f1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12 + | +LL | extern "gpu-kernel" fn m1(_: ()); + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 + | +LL | extern "gpu-kernel" fn dm1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 + | +LL | extern "gpu-kernel" fn m1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 + | +LL | extern "gpu-kernel" fn im1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 + | +LL | type A1 = extern "gpu-kernel" fn(_: ()); + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8 + | +LL | extern "gpu-kernel" {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr similarity index 88% rename from tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr rename to tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr index aa9c67f0151fc..cc81289f6b788 100644 --- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr @@ -1,5 +1,5 @@ error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:11:8 + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8 | LL | extern "gpu-kernel" fn f1(_: ()) {} | ^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | extern "gpu-kernel" fn f1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:16:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12 | LL | extern "gpu-kernel" fn m1(_: ()); | ^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | extern "gpu-kernel" fn m1(_: ()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:18:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 | LL | extern "gpu-kernel" fn dm1(_: ()) {} | ^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | extern "gpu-kernel" fn dm1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:26:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 | LL | extern "gpu-kernel" fn m1(_: ()) {} | ^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | extern "gpu-kernel" fn m1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 | LL | extern "gpu-kernel" fn im1(_: ()) {} | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | extern "gpu-kernel" fn im1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:18 + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | type A1 = extern "gpu-kernel" fn(_: ()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:8 + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8 | LL | extern "gpu-kernel" {} | ^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | extern "gpu-kernel" {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: the calling convention "gpu-kernel" is not supported on this target - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:11 + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,31 +79,31 @@ LL | type A1 = extern "gpu-kernel" fn(_: ()); = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:1 + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:1 | LL | extern "gpu-kernel" {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:11:1 + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:1 | LL | extern "gpu-kernel" fn f1(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:18:5 + --> $DIR/feature-gate-abi_gpu_kernel.rs:23:5 | LL | extern "gpu-kernel" fn dm1(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:26:5 + --> $DIR/feature-gate-abi_gpu_kernel.rs:31:5 | LL | extern "gpu-kernel" fn m1(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:32:5 + --> $DIR/feature-gate-abi_gpu_kernel.rs:37:5 | LL | extern "gpu-kernel" fn im1(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +114,7 @@ Some errors have detailed explanations: E0570, E0658. For more information about an error, try `rustc --explain E0570`. Future incompatibility report: Future breakage diagnostic: warning: the calling convention "gpu-kernel" is not supported on this target - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:11 + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr new file mode 100644 index 0000000000000..fca32c5c1e6fc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr @@ -0,0 +1,73 @@ +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8 + | +LL | extern "gpu-kernel" fn f1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12 + | +LL | extern "gpu-kernel" fn m1(_: ()); + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 + | +LL | extern "gpu-kernel" fn dm1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 + | +LL | extern "gpu-kernel" fn m1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 + | +LL | extern "gpu-kernel" fn im1(_: ()) {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 + | +LL | type A1 = extern "gpu-kernel" fn(_: ()); + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8 + | +LL | extern "gpu-kernel" {} + | ^^^^^^^^^^^^ + | + = note: see issue #135467 for more information + = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs index d9027b417b4d9..7b1ee681dd7ef 100644 --- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs @@ -1,5 +1,10 @@ +//@ revisions: HOST AMDGPU NVPTX //@ add-core-stubs //@ compile-flags: --crate-type=rlib +//@[AMDGPU] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx1100 +//@[AMDGPU] needs-llvm-components: amdgpu +//@[NVPTX] compile-flags: --target nvptx64-nvidia-cuda +//@[NVPTX] needs-llvm-components: nvptx #![feature(no_core, lang_items)] #![no_core] @@ -9,14 +14,14 @@ use minicore::*; // Functions extern "gpu-kernel" fn f1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change -//~^ ERROR is not a supported ABI +//[HOST]~^ ERROR is not a supported ABI // Methods in trait definition trait Tr { extern "gpu-kernel" fn m1(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change extern "gpu-kernel" fn dm1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change - //~^ ERROR is not a supported ABI + //[HOST]~^ ERROR is not a supported ABI } struct S; @@ -24,20 +29,20 @@ struct S; // Methods in trait impl impl Tr for S { extern "gpu-kernel" fn m1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change - //~^ ERROR is not a supported ABI + //[HOST]~^ ERROR is not a supported ABI } // Methods in inherent impl impl S { extern "gpu-kernel" fn im1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change - //~^ ERROR is not a supported ABI + //[HOST]~^ ERROR is not a supported ABI } // Function pointer types type A1 = extern "gpu-kernel" fn(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change -//~^ WARN the calling convention "gpu-kernel" is not supported on this target -//~^^ WARN this was previously accepted by the compiler but is being phased out +//[HOST]~^ WARNING the calling convention "gpu-kernel" is not supported on this target [unsupported_fn_ptr_calling_conventions] +//[HOST]~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! // Foreign modules extern "gpu-kernel" {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change -//~^ ERROR is not a supported ABI +//[HOST]~^ ERROR is not a supported ABI diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.fixed b/tests/ui/parser/bad-fn-ptr-qualifier.fixed index 8a97a2f09ccab..e9b87a72aab41 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.fixed +++ b/tests/ui/parser/bad-fn-ptr-qualifier.fixed @@ -23,4 +23,12 @@ pub type FTT6 = for<'a> unsafe extern "C" fn(); //~^ ERROR an `fn` pointer type cannot be `const` //~| ERROR an `fn` pointer type cannot be `async` +// Tests with qualifiers in the wrong order +pub type W1 = unsafe fn(); +//~^ ERROR an `fn` pointer type cannot be `const` +pub type W2 = unsafe fn(); +//~^ ERROR an `fn` pointer type cannot be `async` +pub type W3 = for<'a> unsafe fn(); +//~^ ERROR an `fn` pointer type cannot be `const` + fn main() {} diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.rs b/tests/ui/parser/bad-fn-ptr-qualifier.rs index f2611c93b1763..f110375509c66 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.rs +++ b/tests/ui/parser/bad-fn-ptr-qualifier.rs @@ -23,4 +23,12 @@ pub type FTT6 = for<'a> const async unsafe extern "C" fn(); //~^ ERROR an `fn` pointer type cannot be `const` //~| ERROR an `fn` pointer type cannot be `async` +// Tests with qualifiers in the wrong order +pub type W1 = unsafe const fn(); +//~^ ERROR an `fn` pointer type cannot be `const` +pub type W2 = unsafe async fn(); +//~^ ERROR an `fn` pointer type cannot be `async` +pub type W3 = for<'a> unsafe const fn(); +//~^ ERROR an `fn` pointer type cannot be `const` + fn main() {} diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr index b9d2625d9f4be..f3fbbf67159d1 100644 --- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr +++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr @@ -2,10 +2,9 @@ error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:5:15 | LL | pub type T0 = const fn(); - | -----^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type T0 = const fn(); @@ -16,10 +15,9 @@ error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:6:15 | LL | pub type T1 = const extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type T1 = const extern "C" fn(); @@ -30,10 +28,9 @@ error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:7:15 | LL | pub type T2 = const unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type T2 = const unsafe extern "C" fn(); @@ -44,10 +41,9 @@ error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:8:15 | LL | pub type T3 = async fn(); - | -----^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type T3 = async fn(); @@ -58,10 +54,9 @@ error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:9:15 | LL | pub type T4 = async extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type T4 = async extern "C" fn(); @@ -72,10 +67,9 @@ error: an `fn` pointer type cannot be `async` --> $DIR/bad-fn-ptr-qualifier.rs:10:15 | LL | pub type T5 = async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type T5 = async unsafe extern "C" fn(); @@ -86,10 +80,9 @@ error: an `fn` pointer type cannot be `const` --> $DIR/bad-fn-ptr-qualifier.rs:11:15 | LL | pub type T6 = const async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type T6 = const async unsafe extern "C" fn(); @@ -97,13 +90,12 @@ LL + pub type T6 = async unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:11:15 + --> $DIR/bad-fn-ptr-qualifier.rs:11:21 | LL | pub type T6 = const async unsafe extern "C" fn(); - | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type T6 = const async unsafe extern "C" fn(); @@ -111,13 +103,12 @@ LL + pub type T6 = const unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:15:17 + --> $DIR/bad-fn-ptr-qualifier.rs:15:25 | LL | pub type FTT0 = for<'a> const fn(); - | ^^^^^^^^-----^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type FTT0 = for<'a> const fn(); @@ -125,13 +116,12 @@ LL + pub type FTT0 = for<'a> fn(); | error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:16:17 + --> $DIR/bad-fn-ptr-qualifier.rs:16:25 | LL | pub type FTT1 = for<'a> const extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type FTT1 = for<'a> const extern "C" fn(); @@ -139,13 +129,12 @@ LL + pub type FTT1 = for<'a> extern "C" fn(); | error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:17:17 + --> $DIR/bad-fn-ptr-qualifier.rs:17:25 | LL | pub type FTT2 = for<'a> const unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type FTT2 = for<'a> const unsafe extern "C" fn(); @@ -153,13 +142,12 @@ LL + pub type FTT2 = for<'a> unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:18:17 + --> $DIR/bad-fn-ptr-qualifier.rs:18:25 | LL | pub type FTT3 = for<'a> async fn(); - | ^^^^^^^^-----^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type FTT3 = for<'a> async fn(); @@ -167,13 +155,12 @@ LL + pub type FTT3 = for<'a> fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:19:17 + --> $DIR/bad-fn-ptr-qualifier.rs:19:25 | LL | pub type FTT4 = for<'a> async extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type FTT4 = for<'a> async extern "C" fn(); @@ -181,13 +168,12 @@ LL + pub type FTT4 = for<'a> extern "C" fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:20:17 + --> $DIR/bad-fn-ptr-qualifier.rs:20:25 | LL | pub type FTT5 = for<'a> async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type FTT5 = for<'a> async unsafe extern "C" fn(); @@ -195,13 +181,12 @@ LL + pub type FTT5 = for<'a> unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:22:17 + --> $DIR/bad-fn-ptr-qualifier.rs:22:25 | LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); @@ -209,18 +194,56 @@ LL + pub type FTT6 = for<'a> async unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:22:17 + --> $DIR/bad-fn-ptr-qualifier.rs:22:31 | LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn(); LL + pub type FTT6 = for<'a> const unsafe extern "C" fn(); | -error: aborting due to 16 previous errors +error: an `fn` pointer type cannot be `const` + --> $DIR/bad-fn-ptr-qualifier.rs:27:22 + | +LL | pub type W1 = unsafe const fn(); + | ^^^^^ `const` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `const` qualifier + | +LL - pub type W1 = unsafe const fn(); +LL + pub type W1 = unsafe fn(); + | + +error: an `fn` pointer type cannot be `async` + --> $DIR/bad-fn-ptr-qualifier.rs:29:22 + | +LL | pub type W2 = unsafe async fn(); + | ^^^^^ `async` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `async` qualifier + | +LL - pub type W2 = unsafe async fn(); +LL + pub type W2 = unsafe fn(); + | + +error: an `fn` pointer type cannot be `const` + --> $DIR/bad-fn-ptr-qualifier.rs:31:30 + | +LL | pub type W3 = for<'a> unsafe const fn(); + | ^^^^^ `const` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `const` qualifier + | +LL - pub type W3 = for<'a> unsafe const fn(); +LL + pub type W3 = for<'a> unsafe fn(); + | + +error: aborting due to 19 previous errors diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs index 45d753495999b..a74b618c282cd 100644 --- a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs +++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs @@ -20,6 +20,14 @@ type FT6 = for<'a> const async unsafe extern "C" fn(); //~^ ERROR an `fn` pointer type cannot be `const` //~| ERROR an `fn` pointer type cannot be `async` +// Tests with qualifiers in the wrong order +type W1 = unsafe const fn(); +//~^ ERROR an `fn` pointer type cannot be `const` +type W2 = unsafe async fn(); +//~^ ERROR an `fn` pointer type cannot be `async` +type W3 = for<'a> unsafe const fn(); +//~^ ERROR an `fn` pointer type cannot be `const` + fn main() { let _recovery_witness: () = 0; //~ ERROR mismatched types } diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr index 4e5927914ccb5..3700bee6e1544 100644 --- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr +++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr @@ -2,10 +2,9 @@ error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:3:11 | LL | type T0 = const fn(); - | -----^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type T0 = const fn(); @@ -16,10 +15,9 @@ error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:4:11 | LL | type T1 = const extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type T1 = const extern "C" fn(); @@ -30,10 +28,9 @@ error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:5:11 | LL | type T2 = const unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type T2 = const unsafe extern "C" fn(); @@ -44,10 +41,9 @@ error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:6:11 | LL | type T3 = async fn(); - | -----^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type T3 = async fn(); @@ -58,10 +54,9 @@ error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:7:11 | LL | type T4 = async extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type T4 = async extern "C" fn(); @@ -72,10 +67,9 @@ error: an `fn` pointer type cannot be `async` --> $DIR/recover-const-async-fn-ptr.rs:8:11 | LL | type T5 = async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type T5 = async unsafe extern "C" fn(); @@ -86,10 +80,9 @@ error: an `fn` pointer type cannot be `const` --> $DIR/recover-const-async-fn-ptr.rs:9:11 | LL | type T6 = const async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type T6 = const async unsafe extern "C" fn(); @@ -97,13 +90,12 @@ LL + type T6 = async unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:9:11 + --> $DIR/recover-const-async-fn-ptr.rs:9:17 | LL | type T6 = const async unsafe extern "C" fn(); - | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type T6 = const async unsafe extern "C" fn(); @@ -111,13 +103,12 @@ LL + type T6 = const unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:13:12 + --> $DIR/recover-const-async-fn-ptr.rs:13:20 | LL | type FT0 = for<'a> const fn(); - | ^^^^^^^^-----^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type FT0 = for<'a> const fn(); @@ -125,13 +116,12 @@ LL + type FT0 = for<'a> fn(); | error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:14:12 + --> $DIR/recover-const-async-fn-ptr.rs:14:20 | LL | type FT1 = for<'a> const extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type FT1 = for<'a> const extern "C" fn(); @@ -139,13 +129,12 @@ LL + type FT1 = for<'a> extern "C" fn(); | error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:15:12 + --> $DIR/recover-const-async-fn-ptr.rs:15:20 | LL | type FT2 = for<'a> const unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type FT2 = for<'a> const unsafe extern "C" fn(); @@ -153,13 +142,12 @@ LL + type FT2 = for<'a> unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:16:12 + --> $DIR/recover-const-async-fn-ptr.rs:16:20 | LL | type FT3 = for<'a> async fn(); - | ^^^^^^^^-----^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type FT3 = for<'a> async fn(); @@ -167,13 +155,12 @@ LL + type FT3 = for<'a> fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:17:12 + --> $DIR/recover-const-async-fn-ptr.rs:17:20 | LL | type FT4 = for<'a> async extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type FT4 = for<'a> async extern "C" fn(); @@ -181,13 +168,12 @@ LL + type FT4 = for<'a> extern "C" fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:18:12 + --> $DIR/recover-const-async-fn-ptr.rs:18:20 | LL | type FT5 = for<'a> async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type FT5 = for<'a> async unsafe extern "C" fn(); @@ -195,13 +181,12 @@ LL + type FT5 = for<'a> unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:19:12 + --> $DIR/recover-const-async-fn-ptr.rs:19:20 | LL | type FT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this + | ^^^^^ `const` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `const` qualifier | LL - type FT6 = for<'a> const async unsafe extern "C" fn(); @@ -209,27 +194,65 @@ LL + type FT6 = for<'a> async unsafe extern "C" fn(); | error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:19:12 + --> $DIR/recover-const-async-fn-ptr.rs:19:26 | LL | type FT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this + | ^^^^^ `async` because of this | + = note: allowed qualifiers are: `unsafe` and `extern` help: remove the `async` qualifier | LL - type FT6 = for<'a> const async unsafe extern "C" fn(); LL + type FT6 = for<'a> const unsafe extern "C" fn(); | +error: an `fn` pointer type cannot be `const` + --> $DIR/recover-const-async-fn-ptr.rs:24:18 + | +LL | type W1 = unsafe const fn(); + | ^^^^^ `const` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `const` qualifier + | +LL - type W1 = unsafe const fn(); +LL + type W1 = unsafe fn(); + | + +error: an `fn` pointer type cannot be `async` + --> $DIR/recover-const-async-fn-ptr.rs:26:18 + | +LL | type W2 = unsafe async fn(); + | ^^^^^ `async` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `async` qualifier + | +LL - type W2 = unsafe async fn(); +LL + type W2 = unsafe fn(); + | + +error: an `fn` pointer type cannot be `const` + --> $DIR/recover-const-async-fn-ptr.rs:28:26 + | +LL | type W3 = for<'a> unsafe const fn(); + | ^^^^^ `const` because of this + | + = note: allowed qualifiers are: `unsafe` and `extern` +help: remove the `const` qualifier + | +LL - type W3 = for<'a> unsafe const fn(); +LL + type W3 = for<'a> unsafe fn(); + | + error[E0308]: mismatched types - --> $DIR/recover-const-async-fn-ptr.rs:24:33 + --> $DIR/recover-const-async-fn-ptr.rs:32:33 | LL | let _recovery_witness: () = 0; | -- ^ expected `()`, found integer | | | expected due to this -error: aborting due to 17 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs index 3e614a4236c03..de3c44c3ed0eb 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.rs +++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs @@ -1,3 +1,4 @@ +//@ add-core-stubs //@ revisions: by_flag by_feature1 by_feature2 by_feature3 //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib //@ needs-llvm-components: x86 @@ -11,12 +12,9 @@ //@ [by_feature1]build-pass //@ [by_feature2]build-pass //@ [by_feature3]build-pass -#![feature(no_core, lang_items)] -#![no_std] +#![feature(no_core)] #![no_core] - -#[lang = "sized"] -pub trait Sized {} +extern crate minicore; //[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead //[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead diff --git a/tests/ui/traits/object/no-incomplete-inference.current.stderr b/tests/ui/traits/object/no-incomplete-inference.current.stderr new file mode 100644 index 0000000000000..3c6b811a49e46 --- /dev/null +++ b/tests/ui/traits/object/no-incomplete-inference.current.stderr @@ -0,0 +1,16 @@ +error[E0283]: type annotations needed + --> $DIR/no-incomplete-inference.rs:16:5 + | +LL | impls_equals::, _>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_equals` + | + = note: cannot satisfy `dyn Equals: Equals<_>` +note: required by a bound in `impls_equals` + --> $DIR/no-incomplete-inference.rs:13:20 + | +LL | fn impls_equals + ?Sized, U: ?Sized>() {} + | ^^^^^^^^^ required by this bound in `impls_equals` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/object/no-incomplete-inference.next.stderr b/tests/ui/traits/object/no-incomplete-inference.next.stderr new file mode 100644 index 0000000000000..3c6b811a49e46 --- /dev/null +++ b/tests/ui/traits/object/no-incomplete-inference.next.stderr @@ -0,0 +1,16 @@ +error[E0283]: type annotations needed + --> $DIR/no-incomplete-inference.rs:16:5 + | +LL | impls_equals::, _>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_equals` + | + = note: cannot satisfy `dyn Equals: Equals<_>` +note: required by a bound in `impls_equals` + --> $DIR/no-incomplete-inference.rs:13:20 + | +LL | fn impls_equals + ?Sized, U: ?Sized>() {} + | ^^^^^^^^^ required by this bound in `impls_equals` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/object/no-incomplete-inference.rs b/tests/ui/traits/object/no-incomplete-inference.rs new file mode 100644 index 0000000000000..9ed8dd6c0b100 --- /dev/null +++ b/tests/ui/traits/object/no-incomplete-inference.rs @@ -0,0 +1,18 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + + +// Make sure that having an applicable user-written +// and builtin impl is ambiguous. + +trait Equals {} + +impl Equals for T {} + +fn impls_equals + ?Sized, U: ?Sized>() {} + +fn main() { + impls_equals::, _>(); + //~^ ERROR type annotations needed +}