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:
commit
64033a4ee5
71 changed files with 1267 additions and 613 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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))?;
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:?}"),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -12,5 +12,6 @@
|
|||
pub mod canonicalizer;
|
||||
pub mod coherence;
|
||||
pub mod delegate;
|
||||
pub mod placeholder;
|
||||
pub mod resolve;
|
||||
pub mod solve;
|
||||
|
|
|
|||
158
compiler/rustc_next_trait_solver/src/placeholder.rs
Normal file
158
compiler/rustc_next_trait_solver/src/placeholder.rs
Normal 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 }
|
||||
}
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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 ->
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 })))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
113
compiler/rustc_type_ir/src/search_graph/stack.rs
Normal file
113
compiler/rustc_type_ir/src/search_graph/stack.rs
Normal 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]
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
55
library/alloc/src/vec/peek_mut.rs
Normal file
55
library/alloc/src/vec/peek_mut.rs
Normal 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) }
|
||||
}
|
||||
}
|
||||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
69
src/doc/rustc/src/platform-support/windows-msvc.md
Normal file
69
src/doc/rustc/src/platform-support/windows-msvc.md
Normal 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.
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
//@ known-bug: #137188
|
||||
#![feature(min_generic_const_args)]
|
||||
trait Trait {}
|
||||
impl Trait for [(); N] {}
|
||||
fn N<T>() {}
|
||||
pub fn main() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
16
tests/ui/const-generics/mgca/missing_generic_params.rs
Normal file
16
tests/ui/const-generics/mgca/missing_generic_params.rs
Normal 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() {}
|
||||
19
tests/ui/const-generics/mgca/missing_generic_params.stderr
Normal file
19
tests/ui/const-generics/mgca/missing_generic_params.stderr
Normal 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`.
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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(_: ());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
16
tests/ui/traits/object/no-incomplete-inference.next.stderr
Normal file
16
tests/ui/traits/object/no-incomplete-inference.next.stderr
Normal 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`.
|
||||
18
tests/ui/traits/object/no-incomplete-inference.rs
Normal file
18
tests/ui/traits/object/no-incomplete-inference.rs
Normal 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue