Auto merge of #142483 - workingjubilee:rollup-8qnhueh, r=workingjubilee

Rollup of 16 pull requests

Successful merges:

 - rust-lang/rust#140969 (Allow initializing logger with additional tracing Layer)
 - rust-lang/rust#141352 (builtin dyn impl no guide inference)
 - rust-lang/rust#142046 (add Vec::peek_mut)
 - rust-lang/rust#142273 (tests: Minicore `extern "gpu-kernel"` feature test)
 - rust-lang/rust#142302 (Rework how the disallowed qualifier in function type diagnostics are generated)
 - rust-lang/rust#142405 (Don't hardcode the intrinsic return types twice in the compiler)
 - rust-lang/rust#142434 ( Pre-install JS dependencies in tidy Dockerfile)
 - rust-lang/rust#142439 (doc: mention that intrinsics should not be called in user code)
 - rust-lang/rust#142441 (Delay replacing escaping bound vars in `FindParamInClause`)
 - rust-lang/rust#142449 (Require generic params for const generic params)
 - rust-lang/rust#142452 (Remove "intermittent" wording from `ReadDir`)
 - rust-lang/rust#142459 (Remove output helper bootstrap)
 - rust-lang/rust#142460 (cleanup search graph impl)
 - rust-lang/rust#142461 (compiletest: Clarify that `--no-capture` is needed with `--verbose`)
 - rust-lang/rust#142475 (Add platform support docs & maintainers for *-windows-msvc)
 - rust-lang/rust#142480 (tests: Convert two handwritten minicores to add-core-stubs)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-06-14 04:58:22 +00:00
commit 64033a4ee5
71 changed files with 1267 additions and 613 deletions

View file

@ -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",

View file

@ -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<FOO<impl Trait>>` 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<FOO<impl Trait>>` support
ImplTraitContext::Disallowed(ImplTraitPosition::Path),

View file

@ -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))?;

View file

@ -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<F, T>(
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() {

View file

@ -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<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> {
type Result = ControlFlow<ErrorGuaranteed>;
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
&mut self,
binder: &ty::Binder<'tcx, T>,
) -> Self::Result {

View file

@ -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<DefId, ty::Variance>,
OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>,
{
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&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() {

View file

@ -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<F, T>(
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()

View file

@ -163,6 +163,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> 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)
}

View file

@ -933,7 +933,9 @@ impl Placeholder<BoundVar> {
pub type PlaceholderRegion = Placeholder<BoundRegion>;
impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion {
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> 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<BoundTy>;
impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType {
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> 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<BoundVar>;
impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst {
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> 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 }
}
}

View file

@ -148,6 +148,10 @@ impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> 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
}

View file

@ -66,7 +66,7 @@ impl<'tcx> TyCtxt<'tcx> {
{
type Result = ControlFlow<()>;
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
&mut self,
t: &Binder<'tcx, T>,
) -> Self::Result {
@ -168,7 +168,7 @@ impl LateBoundRegionsCollector {
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
self.current_index.shift_in(1);
t.super_visit_with(self);
self.current_index.shift_out(1);

View file

@ -435,13 +435,13 @@ impl<'a, D: SolverDelegate<Interner = I>, 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<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> 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<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> 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:?}"),
},

View file

@ -12,5 +12,6 @@
pub mod canonicalizer;
pub mod coherence;
pub mod delegate;
pub mod placeholder;
pub mod resolve;
pub mod solve;

View file

@ -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 = <Infcx as InferCtxtLike>::Interner>
where
Infcx: InferCtxtLike<Interner = I>,
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<I::PlaceholderRegion, I::BoundRegion>,
mapped_types: IndexMap<I::PlaceholderTy, I::BoundTy>,
mapped_consts: IndexMap<I::PlaceholderConst, I::BoundConst>,
// 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<Option<ty::UniverseIndex>>,
}
impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I>
where
Infcx: InferCtxtLike<Interner = I>,
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<T: TypeFoldable<I>>(
infcx: &'a Infcx,
universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
value: T,
) -> (
T,
IndexMap<I::PlaceholderRegion, I::BoundRegion>,
IndexMap<I::PlaceholderTy, I::BoundTy>,
IndexMap<I::PlaceholderConst, I::BoundConst>,
) {
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<Infcx, I> TypeFolder<I> for BoundVarReplacer<'_, Infcx, I>
where
Infcx: InferCtxtLike<Interner = I>,
I: Interner,
{
fn cx(&self) -> I {
self.infcx.cx()
}
fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, 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: 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 }
}
}

View file

@ -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<Interner = I>, I: Interner> {
ecx: &'a mut EvalCtxt<'b, D>,
param_env: I::ParamEnv,
universes: Vec<Option<ty::UniverseIndex>>,
}
impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I>
@ -1034,31 +1039,42 @@ where
{
type Result = ControlFlow<Result<(), NoSolution>>;
fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
self.ecx.enter_forall(t.clone(), |ecx, v| {
v.visit_with(&mut FindParamInClause { ecx, param_env: self.param_env })
})
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> 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")
}
}
}

View file

@ -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<Certainty, NoSolution> {
self.delegate.is_transmutable(dst, src, assume)
}
pub(super) fn replace_bound_vars<T: TypeFoldable<I>>(
&self,
t: T,
universes: &mut Vec<Option<ty::UniverseIndex>>,
) -> T {
BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0
}
}
/// Eagerly replace aliases with inference variables, emitting `AliasRelate`

View file

@ -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 ->

View file

@ -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,
}

View file

@ -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<P<FnContract>>, Option<P<Block>>)> {
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,
}

View file

@ -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:
// `<constness> <coroutine_kind> <safety> <extern> 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 })))
}

View file

@ -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<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
self.outer_index.shift_in(1);
t.super_visit_with(self);
self.outer_index.shift_out(1);

View file

@ -1919,12 +1919,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// impl `impl<T: ?Sized> 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,
}

View file

@ -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<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
// 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<Option<ty::UniverseIndex>>,
}
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<T: TypeFoldable<TyCtxt<'tcx>>>(
infcx: &'a InferCtxt<'tcx>,
universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
value: T,
) -> (
T,
FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
) {
let mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion> =
FxIndexMap::default();
let mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy> = FxIndexMap::default();
let mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar> = 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<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
fn cx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
&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<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundVar>,
universe_indices: &'a [Option<ty::UniverseIndex>],
current_index: ty::DebruijnIndex,
}
@ -373,7 +228,7 @@ impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundVar>,
universe_indices: &'a [Option<ty::UniverseIndex>],
value: T,
) -> T {

View file

@ -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<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, binder: &ty::Binder<'tcx, T>) {
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, binder: &ty::Binder<'tcx, T>) {
self.depth.shift_in(1);
binder.super_visit_with(self);
self.depth.shift_out(1);

View file

@ -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 }

View file

@ -128,7 +128,7 @@ impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Binder<I, T> {
}
}
impl<I: Interner, T: TypeFoldable<I>> TypeVisitable<I> for Binder<I, T> {
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Binder<I, T> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
visitor.visit_binder(self)
}
@ -147,7 +147,7 @@ impl<I: Interner, T: TypeFoldable<I>> TypeSuperFoldable<I> for Binder<I, T> {
}
}
impl<I: Interner, T: TypeFoldable<I>> TypeSuperVisitable<I> for Binder<I, T> {
impl<I: Interner, T: TypeVisitable<I>> TypeSuperVisitable<I> for Binder<I, T> {
fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
self.as_ref().skip_binder().visit_with(visitor)
}
@ -292,7 +292,7 @@ impl<I: Interner> ValidateBoundVars<I> {
impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
type Result = ControlFlow<()>;
fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result {
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result {
self.binder_index.shift_in(1);
let result = t.super_visit_with(self);
self.binder_index.shift_out(1);

View file

@ -228,6 +228,8 @@ pub trait Region<I: Interner<Region = Self>>:
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<I: Interner<Const = Self>>:
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<I>) -> Self;
fn new_expr(interner: I, expr: I::ExprConst) -> Self;
@ -524,13 +528,14 @@ pub trait Clauses<I: Interner<Clauses = Self>>:
}
/// Common capabilities of placeholder kinds
pub trait PlaceholderLike: Copy + Debug + Hash + Eq {
pub trait PlaceholderLike<I: Interner>: Copy + Debug + Hash + Eq {
fn universe(self) -> ty::UniverseIndex;
fn var(self) -> ty::BoundVar;
type Bound: BoundVarLike<I>;
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<I: Interner> {
pub trait BoundVarLike<I: Interner>: 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;
}

View file

@ -103,9 +103,9 @@ pub trait Interner:
type Ty: Ty<Self>;
type Tys: Tys<Self>;
type FnInputTys: Copy + Debug + Hash + Eq + SliceLike<Item = Self::Ty> + TypeVisitable<Self>;
type ParamTy: Copy + Debug + Hash + Eq + ParamLike;
type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
type PlaceholderTy: PlaceholderLike;
type ParamTy: ParamLike;
type BoundTy: BoundVarLike<Self>;
type PlaceholderTy: PlaceholderLike<Self, Bound = Self::BoundTy>;
// Things stored inside of tys
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
@ -131,19 +131,19 @@ pub trait Interner:
// Kinds of consts
type Const: Const<Self>;
type PlaceholderConst: PlaceholderLike;
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
type BoundConst: BoundVarLike<Self>;
type PlaceholderConst: PlaceholderLike<Self, Bound = Self::BoundConst>;
type ValueConst: ValueConst<Self>;
type ExprConst: ExprConst<Self>;
type ValTree: Copy + Debug + Hash + Eq;
// Kinds of regions
type Region: Region<Self>;
type EarlyParamRegion: Copy + Debug + Hash + Eq + ParamLike;
type EarlyParamRegion: ParamLike;
type LateParamRegion: Copy + Debug + Hash + Eq;
type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
type PlaceholderRegion: PlaceholderLike;
type BoundRegion: BoundVarLike<Self>;
type PlaceholderRegion: PlaceholderLike<Self, Bound = Self::BoundRegion>;
// Predicates
type ParamEnv: ParamEnv<Self>;

View file

@ -4,7 +4,7 @@ use super::{AvailableDepth, Cx, NestedGoals};
use crate::data_structures::HashMap;
struct Success<X: Cx> {
additional_depth: usize,
required_depth: usize,
nested_goals: NestedGoals<X>,
result: X::Tracked<X::Result>,
}
@ -28,7 +28,7 @@ struct CacheEntry<X: Cx> {
#[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<X>,
}
@ -47,7 +47,7 @@ impl<X: Cx> GlobalCache<X> {
origin_result: X::Result,
dep_node: X::DepNodeIndex,
additional_depth: usize,
required_depth: usize,
encountered_overflow: bool,
nested_goals: NestedGoals<X>,
) {
@ -55,13 +55,13 @@ impl<X: Cx> GlobalCache<X> {
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<X: Cx> GlobalCache<X> {
mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool,
) -> Option<CacheData<'a, X>> {
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<X: Cx> GlobalCache<X> {
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,
});

View file

@ -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<D: Delegate>(
root_depth: AvailableDepth,
stack: &IndexVec<StackDepth, StackEntry<D::Cx>>,
stack: &Stack<D::Cx>,
) -> Option<AvailableDepth> {
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<X: Cx> NestedGoals<X> {
}
}
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<X: Cx> {
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<UsageKind>,
/// The nested goals of this goal, see the doc comment of the type.
nested_goals: NestedGoals<X>,
/// Starts out as `None` and gets set when rerunning this
/// goal in case we encounter a cycle.
provisional_result: Option<X::Result>,
}
/// 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<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
/// The stack of goals currently being computed.
///
/// An element is *deeper* in the stack if its index is *lower*.
stack: IndexVec<StackDepth, StackEntry<X>>,
stack: Stack<X>,
/// 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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
/// 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<StackDepth, StackEntry<X>>,
stack: &mut Stack<X>,
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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
/// 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<StackDepth, StackEntry<X>>,
stack: &Stack<X>,
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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
// 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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
// 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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
// 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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
/// 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<StackDepth, StackEntry<X>>,
stack: &Stack<X>,
step_kind_from_parent: PathKind,
provisional_cache: &HashMap<X::Input, Vec<ProvisionalCacheEntry<X>>>,
nested_goals: &NestedGoals<X>,
@ -991,7 +940,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
available_depth: AvailableDepth,
) -> Option<X::Result> {
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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
)
})?;
// 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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
input: X::Input,
step_kind_from_parent: PathKind,
) -> Option<X::Result> {
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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
// 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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
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<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
fn insert_global_cache(
&mut self,
cx: X,
input: X::Input,
final_entry: StackEntry<X>,
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,
)

View file

@ -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<X: Cx> {
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<UsageKind>,
/// The nested goals of this goal, see the doc comment of the type.
pub nested_goals: NestedGoals<X>,
/// Starts out as `None` and gets set when rerunning this
/// goal in case we encounter a cycle.
pub provisional_result: Option<X::Result>,
}
#[derive_where(Default; X: Cx)]
pub(super) struct Stack<X: Cx> {
entries: IndexVec<StackDepth, StackEntry<X>>,
}
impl<X: Cx> Stack<X> {
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<StackDepth> {
self.entries.last_index()
}
pub(super) fn last(&self) -> Option<&StackEntry<X>> {
self.entries.raw.last()
}
pub(super) fn last_mut(&mut self) -> Option<&mut StackEntry<X>> {
self.entries.raw.last_mut()
}
pub(super) fn next_index(&self) -> StackDepth {
self.entries.next_index()
}
pub(super) fn push(&mut self, entry: StackEntry<X>) -> StackDepth {
self.entries.push(entry)
}
pub(super) fn pop(&mut self) -> StackEntry<X> {
self.entries.pop().unwrap()
}
pub(super) fn cycle_step_kinds(&self, head: StackDepth) -> impl Iterator<Item = PathKind> {
self.entries.raw[head.index() + 1..].iter().map(|entry| entry.step_kind_from_parent)
}
pub(super) fn iter(&self) -> impl Iterator<Item = &StackEntry<X>> {
self.entries.iter()
}
pub(super) fn find(&self, input: X::Input) -> Option<StackDepth> {
self.entries.iter_enumerated().find(|(_, e)| e.input == input).map(|(idx, _)| idx)
}
}
impl<X: Cx> Index<StackDepth> for Stack<X> {
type Output = StackEntry<X>;
fn index(&self, index: StackDepth) -> &StackEntry<X> {
&self.entries[index]
}
}
impl<X: Cx> IndexMut<StackDepth> for Stack<X> {
fn index_mut(&mut self, index: StackDepth) -> &mut Self::Output {
&mut self.entries[index]
}
}

View file

@ -342,7 +342,7 @@ struct HasRegionsBoundAt {
// FIXME: Could be optimized to not walk into components with no escaping bound vars.
impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt {
type Result = ControlFlow<()>;
fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
self.binder.shift_in(1);
t.super_visit_with(self)?;
self.binder.shift_out(1);

View file

@ -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<I: Interner>: Sized {
#[cfg(not(feature = "nightly"))]
type Result: VisitorResult;
fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
t.super_visit_with(self)
}
@ -401,7 +401,7 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
type Result = ControlFlow<FoundFlags>;
fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> 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<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
type Result = ControlFlow<FoundEscapingVars>;
fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
self.outer_index.shift_in(1);
let result = t.super_visit_with(self);
self.outer_index.shift_out(1);

View file

@ -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<T> Vec<T> {
pub unsafe fn from_parts(ptr: NonNull<T>, 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<'_, T>> {
PeekMut::new(self)
}
}
impl<T, A: Allocator> Vec<T, A> {

View file

@ -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<T>,
}
#[unstable(feature = "vec_peek_mut", issue = "122742")]
impl<T: fmt::Debug> 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<T>) -> Option<Self> {
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) }
}
}

View file

@ -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)]

View file

@ -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!

View file

@ -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 <https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_transform/src/lower_intrinsics.rs>.
//! The remaining intrinsics are implemented for the LLVM backend in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs>

View file

@ -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);

View file

@ -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<String> = 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<String> = 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.

View file

@ -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<PathBuf> = 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()
})
}

View file

@ -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.

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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.

View file

@ -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<B>(
ControlFlow::Continue(())
}
}
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
self.index += 1;
let res = t.super_visit_with(self);
self.index -= 1;

View file

@ -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);
}
}

View file

@ -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() {

View file

@ -1,6 +0,0 @@
//@ known-bug: #137188
#![feature(min_generic_const_args)]
trait Trait {}
impl Trait for [(); N] {}
fn N<T>() {}
pub fn main() {}

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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;
}

View file

@ -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() {}

View file

@ -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<PeekMut<'_, i32>>, ())`
| - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<std::collections::binary_heap::PeekMut<'_, i32>>, ())`
|
= 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)

View file

@ -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<PeekMut<'_, i32>>`
| - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<std::collections::binary_heap::PeekMut<'_, i32>>`
error: aborting due to 1 previous error

View file

@ -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<T>() {}
pub fn main() {}

View file

@ -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<T>() {}
| ^ -
help: add missing generic argument
|
LL | impl Trait for [(); N<T>] {}
| +++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0107`.

View file

@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.

View file

@ -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(_: ());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.

View file

@ -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

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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

View file

@ -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
}

View file

@ -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`.

View file

@ -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

View file

@ -0,0 +1,16 @@
error[E0283]: type annotations needed
--> $DIR/no-incomplete-inference.rs:16:5
|
LL | impls_equals::<dyn Equals<u32>, _>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_equals`
|
= note: cannot satisfy `dyn Equals<u32>: Equals<_>`
note: required by a bound in `impls_equals`
--> $DIR/no-incomplete-inference.rs:13:20
|
LL | fn impls_equals<T: Equals<U> + ?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`.

View file

@ -0,0 +1,16 @@
error[E0283]: type annotations needed
--> $DIR/no-incomplete-inference.rs:16:5
|
LL | impls_equals::<dyn Equals<u32>, _>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_equals`
|
= note: cannot satisfy `dyn Equals<u32>: Equals<_>`
note: required by a bound in `impls_equals`
--> $DIR/no-incomplete-inference.rs:13:20
|
LL | fn impls_equals<T: Equals<U> + ?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`.

View file

@ -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<T: ?Sized> {}
impl<T: ?Sized> Equals<T> for T {}
fn impls_equals<T: Equals<U> + ?Sized, U: ?Sized>() {}
fn main() {
impls_equals::<dyn Equals<u32>, _>();
//~^ ERROR type annotations needed
}