Auto merge of #136203 - matthiaskrgr:rollup-1k0f44l, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #135869 (Make docs for AtomicUsize::from_mut platform-independent) - #135892 (-Znext-solver: "normalize" signature before checking it mentions self in `deduce_closure_signature`) - #136055 (Implement MIR const trait stability checks) - #136066 (Pass spans to `perform_locally_in_new_solver`) - #136071 ([Clippy] Add vec_reserve & vecdeque_reserve diagnostic items) - #136124 (Arbitrary self types v2: explain test.) - #136149 (Flip the `rustc-rayon`/`indexmap` dependency order) - #136173 (Update comments and sort target_arch in c_char_definition) - #136178 (Update username in build helper example) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
bf1b174e7d
37 changed files with 561 additions and 167 deletions
|
@ -1859,7 +1859,6 @@ checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
|||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
"rustc-rayon",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
@ -3240,11 +3239,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-rayon"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb81aadc8837ca6ecebe0fe1353f15df83b3b3cc2cf7a8afd571bc22aa121710"
|
||||
checksum = "2cd9fb077db982d7ceb42a90471e5a69a990b58f71e06f0d8340bb2cf35eb751"
|
||||
dependencies = [
|
||||
"either",
|
||||
"indexmap",
|
||||
"rustc-rayon-core",
|
||||
]
|
||||
|
||||
|
|
|
@ -310,7 +310,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
|||
let (infcx, key, _) =
|
||||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
|
||||
type_op_ascribe_user_type_with_span(&ocx, key, cause.span).ok()?;
|
||||
let diag = try_extract_error_from_fulfill_cx(
|
||||
&ocx,
|
||||
mbcx.mir_def_id(),
|
||||
|
|
|
@ -403,7 +403,7 @@ const_eval_uninhabited_enum_variant_read =
|
|||
const_eval_uninhabited_enum_variant_written =
|
||||
writing discriminant of an uninhabited enum variant
|
||||
|
||||
const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
|
||||
const_eval_unmarked_const_item_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
|
||||
.help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
|
||||
const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable
|
||||
.help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)
|
||||
|
@ -414,6 +414,7 @@ const_eval_unreachable_unwind =
|
|||
|
||||
const_eval_unsized_local = unsized locals are not supported
|
||||
const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
|
||||
const_eval_unstable_const_trait = `{$def_path}` is not yet stable as a const trait
|
||||
const_eval_unstable_in_stable_exposed =
|
||||
const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
|
||||
.is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::ops::Deref;
|
|||
|
||||
use rustc_attr_parsing::{ConstStability, StabilityLevel};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
|
@ -29,7 +30,7 @@ use super::ops::{self, NonConstOp, Status};
|
|||
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
||||
use super::resolver::FlowSensitiveAnalysis;
|
||||
use super::{ConstCx, Qualif};
|
||||
use crate::check_consts::is_safe_to_expose_on_stable_const_fn;
|
||||
use crate::check_consts::is_fn_or_trait_safe_to_expose_on_stable;
|
||||
use crate::errors;
|
||||
|
||||
type QualifResults<'mir, 'tcx, Q> =
|
||||
|
@ -470,6 +471,88 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
self.tcx.crate_level_attribute_injection_span(self.tcx.local_def_id_to_hir_id(id))
|
||||
})
|
||||
}
|
||||
|
||||
/// Check the const stability of the given item (fn or trait).
|
||||
fn check_callee_stability(&mut self, def_id: DefId) {
|
||||
match self.tcx.lookup_const_stability(def_id) {
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
|
||||
// All good.
|
||||
}
|
||||
None => {
|
||||
// This doesn't need a separate const-stability check -- const-stability equals
|
||||
// regular stability, and regular stability is checked separately.
|
||||
// However, we *do* have to worry about *recursive* const stability.
|
||||
if self.enforce_recursive_const_stability()
|
||||
&& !is_fn_or_trait_safe_to_expose_on_stable(self.tcx, def_id)
|
||||
{
|
||||
self.dcx().emit_err(errors::UnmarkedConstItemExposed {
|
||||
span: self.span,
|
||||
def_path: self.tcx.def_path_str(def_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(ConstStability {
|
||||
level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
|
||||
feature,
|
||||
..
|
||||
}) => {
|
||||
// An unstable const fn/trait with a feature gate.
|
||||
let callee_safe_to_expose_on_stable =
|
||||
is_fn_or_trait_safe_to_expose_on_stable(self.tcx, def_id);
|
||||
|
||||
// We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
|
||||
// the callee is safe to expose, to avoid bypassing recursive stability.
|
||||
// This is not ideal since it means the user sees an error, not the macro
|
||||
// author, but that's also the case if one forgets to set
|
||||
// `#[allow_internal_unstable]` in the first place. Note that this cannot be
|
||||
// integrated in the check below since we want to enforce
|
||||
// `callee_safe_to_expose_on_stable` even if
|
||||
// `!self.enforce_recursive_const_stability()`.
|
||||
if (self.span.allows_unstable(feature)
|
||||
|| implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
|
||||
&& callee_safe_to_expose_on_stable
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't use `check_op` to check whether the feature is enabled because
|
||||
// the logic is a bit different than elsewhere: local functions don't need
|
||||
// the feature gate, and there might be an "implied" gate that also suffices
|
||||
// to allow this.
|
||||
let feature_enabled = def_id.is_local()
|
||||
|| self.tcx.features().enabled(feature)
|
||||
|| implied_feature.is_some_and(|f| self.tcx.features().enabled(f))
|
||||
|| {
|
||||
// When we're compiling the compiler itself we may pull in
|
||||
// crates from crates.io, but those crates may depend on other
|
||||
// crates also pulled in from crates.io. We want to ideally be
|
||||
// able to compile everything without requiring upstream
|
||||
// modifications, so in the case that this looks like a
|
||||
// `rustc_private` crate (e.g., a compiler crate) and we also have
|
||||
// the `-Z force-unstable-if-unmarked` flag present (we're
|
||||
// compiling a compiler crate), then let this missing feature
|
||||
// annotation slide.
|
||||
// This matches what we do in `eval_stability_allow_unstable` for
|
||||
// regular stability.
|
||||
feature == sym::rustc_private
|
||||
&& issue == NonZero::new(27812)
|
||||
&& self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
|
||||
};
|
||||
// Even if the feature is enabled, we still need check_op to double-check
|
||||
// this if the callee is not safe to expose on stable.
|
||||
if !feature_enabled || !callee_safe_to_expose_on_stable {
|
||||
self.check_op(ops::CallUnstable {
|
||||
def_id,
|
||||
feature,
|
||||
feature_enabled,
|
||||
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
|
||||
suggestion_span: self.crate_inject_span(),
|
||||
is_function_call: self.tcx.def_kind(def_id) != DefKind::Trait,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
|
@ -733,8 +816,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
span: *fn_span,
|
||||
call_source,
|
||||
});
|
||||
// FIXME(const_trait_impl): do a more fine-grained check whether this
|
||||
// particular trait can be const-stably called.
|
||||
self.check_callee_stability(trait_did);
|
||||
} else {
|
||||
// Not even a const trait.
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
|
@ -810,7 +892,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// fallback body is safe to expose on stable.
|
||||
let is_const_stable = intrinsic.const_stable
|
||||
|| (!intrinsic.must_be_overridden
|
||||
&& is_safe_to_expose_on_stable_const_fn(tcx, callee));
|
||||
&& is_fn_or_trait_safe_to_expose_on_stable(tcx, callee));
|
||||
match tcx.lookup_const_stability(callee) {
|
||||
None => {
|
||||
// This doesn't need a separate const-stability check -- const-stability equals
|
||||
|
@ -859,83 +941,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
|
||||
// Finally, stability for regular function calls -- this is the big one.
|
||||
match tcx.lookup_const_stability(callee) {
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
|
||||
// All good.
|
||||
}
|
||||
None => {
|
||||
// This doesn't need a separate const-stability check -- const-stability equals
|
||||
// regular stability, and regular stability is checked separately.
|
||||
// However, we *do* have to worry about *recursive* const stability.
|
||||
if self.enforce_recursive_const_stability()
|
||||
&& !is_safe_to_expose_on_stable_const_fn(tcx, callee)
|
||||
{
|
||||
self.dcx().emit_err(errors::UnmarkedConstFnExposed {
|
||||
span: self.span,
|
||||
def_path: self.tcx.def_path_str(callee),
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(ConstStability {
|
||||
level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
|
||||
feature,
|
||||
..
|
||||
}) => {
|
||||
// An unstable const fn with a feature gate.
|
||||
let callee_safe_to_expose_on_stable =
|
||||
is_safe_to_expose_on_stable_const_fn(tcx, callee);
|
||||
|
||||
// We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
|
||||
// the callee is safe to expose, to avoid bypassing recursive stability.
|
||||
// This is not ideal since it means the user sees an error, not the macro
|
||||
// author, but that's also the case if one forgets to set
|
||||
// `#[allow_internal_unstable]` in the first place. Note that this cannot be
|
||||
// integrated in the check below since we want to enforce
|
||||
// `callee_safe_to_expose_on_stable` even if
|
||||
// `!self.enforce_recursive_const_stability()`.
|
||||
if (self.span.allows_unstable(feature)
|
||||
|| implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
|
||||
&& callee_safe_to_expose_on_stable
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't use `check_op` to check whether the feature is enabled because
|
||||
// the logic is a bit different than elsewhere: local functions don't need
|
||||
// the feature gate, and there might be an "implied" gate that also suffices
|
||||
// to allow this.
|
||||
let feature_enabled = callee.is_local()
|
||||
|| tcx.features().enabled(feature)
|
||||
|| implied_feature.is_some_and(|f| tcx.features().enabled(f))
|
||||
|| {
|
||||
// When we're compiling the compiler itself we may pull in
|
||||
// crates from crates.io, but those crates may depend on other
|
||||
// crates also pulled in from crates.io. We want to ideally be
|
||||
// able to compile everything without requiring upstream
|
||||
// modifications, so in the case that this looks like a
|
||||
// `rustc_private` crate (e.g., a compiler crate) and we also have
|
||||
// the `-Z force-unstable-if-unmarked` flag present (we're
|
||||
// compiling a compiler crate), then let this missing feature
|
||||
// annotation slide.
|
||||
// This matches what we do in `eval_stability_allow_unstable` for
|
||||
// regular stability.
|
||||
feature == sym::rustc_private
|
||||
&& issue == NonZero::new(27812)
|
||||
&& tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
|
||||
};
|
||||
// Even if the feature is enabled, we still need check_op to double-check
|
||||
// this if the callee is not safe to expose on stable.
|
||||
if !feature_enabled || !callee_safe_to_expose_on_stable {
|
||||
self.check_op(ops::FnCallUnstable {
|
||||
def_id: callee,
|
||||
feature,
|
||||
feature_enabled,
|
||||
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
|
||||
suggestion_span: self.crate_inject_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
self.check_callee_stability(callee);
|
||||
}
|
||||
|
||||
// Forbid all `Drop` terminators unless the place being dropped is a local with no
|
||||
|
|
|
@ -56,7 +56,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
|
|||
self.const_kind == Some(hir::ConstContext::ConstFn)
|
||||
&& (self.tcx.features().staged_api()
|
||||
|| self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked)
|
||||
&& is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id())
|
||||
&& is_fn_or_trait_safe_to_expose_on_stable(self.tcx, self.def_id().to_def_id())
|
||||
}
|
||||
|
||||
fn is_async(&self) -> bool {
|
||||
|
@ -84,28 +84,14 @@ pub fn rustc_allow_const_fn_unstable(
|
|||
attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate)
|
||||
}
|
||||
|
||||
/// Returns `true` if the given `const fn` is "safe to expose on stable".
|
||||
///
|
||||
/// Panics if the given `DefId` does not refer to a `const fn`.
|
||||
/// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable".
|
||||
///
|
||||
/// This is relevant within a `staged_api` crate. Unlike with normal features, the use of unstable
|
||||
/// const features *recursively* taints the functions that use them. This is to avoid accidentally
|
||||
/// exposing e.g. the implementation of an unstable const intrinsic on stable. So we partition the
|
||||
/// world into two functions: those that are safe to expose on stable (and hence may not use
|
||||
/// unstable features, not even recursively), and those that are not.
|
||||
pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
// A default body in a `#[const_trait]` is not const-stable because const trait fns currently
|
||||
// cannot be const-stable. These functions can't be called from anything stable, so we shouldn't
|
||||
// restrict them to only call const-stable functions.
|
||||
if tcx.is_const_default_method(def_id) {
|
||||
// FIXME(const_trait_impl): we have to eventually allow some of these if these things can ever be stable.
|
||||
// They should probably behave like regular `const fn` for that...
|
||||
return false;
|
||||
}
|
||||
|
||||
// Const-stability is only relevant for `const fn`.
|
||||
assert!(tcx.is_const_fn(def_id));
|
||||
|
||||
pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
match tcx.lookup_const_stability(def_id) {
|
||||
None => {
|
||||
// In a `staged_api` crate, we do enforce recursive const stability for all unmarked
|
||||
|
|
|
@ -377,11 +377,11 @@ fn build_error_for_const_call<'tcx>(
|
|||
err
|
||||
}
|
||||
|
||||
/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
|
||||
/// A call to an `#[unstable]` const fn, `#[rustc_const_unstable]` function or trait.
|
||||
///
|
||||
/// Contains the name of the feature that would allow the use of this function.
|
||||
/// Contains the name of the feature that would allow the use of this function/trait.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FnCallUnstable {
|
||||
pub(crate) struct CallUnstable {
|
||||
pub def_id: DefId,
|
||||
pub feature: Symbol,
|
||||
/// If this is true, then the feature is enabled, but we need to still check if it is safe to
|
||||
|
@ -389,24 +389,33 @@ pub(crate) struct FnCallUnstable {
|
|||
pub feature_enabled: bool,
|
||||
pub safe_to_expose_on_stable: bool,
|
||||
pub suggestion_span: Option<Span>,
|
||||
/// true if `def_id` is the function we are calling, false if `def_id` is an unstable trait.
|
||||
pub is_function_call: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
||||
impl<'tcx> NonConstOp<'tcx> for CallUnstable {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable {
|
||||
gate: self.feature,
|
||||
gate_already_checked: self.feature_enabled,
|
||||
safe_to_expose_on_stable: self.safe_to_expose_on_stable,
|
||||
is_function_call: true,
|
||||
is_function_call: self.is_function_call,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
assert!(!self.feature_enabled);
|
||||
let mut err = ccx.dcx().create_err(errors::UnstableConstFn {
|
||||
span,
|
||||
def_path: ccx.tcx.def_path_str(self.def_id),
|
||||
});
|
||||
let mut err = if self.is_function_call {
|
||||
ccx.dcx().create_err(errors::UnstableConstFn {
|
||||
span,
|
||||
def_path: ccx.tcx.def_path_str(self.def_id),
|
||||
})
|
||||
} else {
|
||||
ccx.dcx().create_err(errors::UnstableConstTrait {
|
||||
span,
|
||||
def_path: ccx.tcx.def_path_str(self.def_id),
|
||||
})
|
||||
};
|
||||
// FIXME: make this translatable
|
||||
let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature);
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
|
|
|
@ -121,6 +121,14 @@ pub(crate) struct UnstableConstFn {
|
|||
pub def_path: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unstable_const_trait)]
|
||||
pub(crate) struct UnstableConstTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def_path: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unstable_intrinsic)]
|
||||
pub(crate) struct UnstableIntrinsic {
|
||||
|
@ -139,9 +147,9 @@ pub(crate) struct UnstableIntrinsic {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unmarked_const_fn_exposed)]
|
||||
#[diag(const_eval_unmarked_const_item_exposed)]
|
||||
#[help]
|
||||
pub(crate) struct UnmarkedConstFnExposed {
|
||||
pub(crate) struct UnmarkedConstItemExposed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def_path: String,
|
||||
|
|
|
@ -10,11 +10,11 @@ bitflags = "2.4.1"
|
|||
either = "1.0"
|
||||
elsa = "=1.7.1"
|
||||
ena = "0.14.3"
|
||||
indexmap = { version = "2.4.0", features = ["rustc-rayon"] }
|
||||
indexmap = "2.4.0"
|
||||
jobserver_crate = { version = "0.1.28", package = "jobserver" }
|
||||
measureme = "11"
|
||||
rustc-hash = "2.0.0"
|
||||
rustc-rayon = "0.5.0"
|
||||
rustc-rayon = { version = "0.5.1", features = ["indexmap"] }
|
||||
rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
rustc_graphviz = { path = "../rustc_graphviz" }
|
||||
|
|
|
@ -296,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
/// Given the expected type, figures out what it can about this closure we
|
||||
/// are about to type check:
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
fn deduce_closure_signature(
|
||||
&self,
|
||||
expected_ty: Ty<'tcx>,
|
||||
|
@ -378,6 +378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
bound_predicate.rebind(proj_predicate),
|
||||
),
|
||||
);
|
||||
|
||||
// Make sure that we didn't infer a signature that mentions itself.
|
||||
// This can happen when we elaborate certain supertrait bounds that
|
||||
// mention projections containing the `Self` type. See #105401.
|
||||
|
@ -395,8 +396,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
|
||||
expected_sig = inferred_sig;
|
||||
|
||||
// Don't infer a closure signature from a goal that names the closure type as this will
|
||||
// (almost always) lead to occurs check errors later in type checking.
|
||||
if self.next_trait_solver()
|
||||
&& let Some(inferred_sig) = inferred_sig
|
||||
{
|
||||
// In the new solver it is difficult to explicitly normalize the inferred signature as we
|
||||
// would have to manually handle universes and rewriting bound vars and placeholders back
|
||||
// and forth.
|
||||
//
|
||||
// Instead we take advantage of the fact that we relating an inference variable with an alias
|
||||
// will only instantiate the variable if the alias is rigid(*not quite). Concretely we:
|
||||
// - Create some new variable `?sig`
|
||||
// - Equate `?sig` with the unnormalized signature, e.g. `fn(<Foo<?x> as Trait>::Assoc)`
|
||||
// - Depending on whether `<Foo<?x> as Trait>::Assoc` is rigid, ambiguous or normalizeable,
|
||||
// we will either wind up with `?sig=<Foo<?x> as Trait>::Assoc/?y/ConcreteTy` respectively.
|
||||
//
|
||||
// *: In cases where there are ambiguous aliases in the signature that make use of bound vars
|
||||
// they will wind up present in `?sig` even though they are non-rigid.
|
||||
//
|
||||
// This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty`
|
||||
// even though the normalized form may not name `expected_ty`. However, this matches the existing
|
||||
// behaviour of the old solver and would be technically a breaking change to fix.
|
||||
let generalized_fnptr_sig = self.next_ty_var(span);
|
||||
let inferred_fnptr_sig = Ty::new_fn_ptr(self.tcx, inferred_sig.sig);
|
||||
self.demand_eqtype(span, inferred_fnptr_sig, generalized_fnptr_sig);
|
||||
|
||||
let resolved_sig = self.resolve_vars_if_possible(generalized_fnptr_sig);
|
||||
|
||||
if resolved_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
|
||||
expected_sig = Some(ExpectedSig {
|
||||
cause_span: inferred_sig.cause_span,
|
||||
sig: resolved_sig.fn_sig(self.tcx),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
|
||||
expected_sig = inferred_sig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use rustc_span::Span;
|
|||
use rustc_trait_selection::solve::inspect::{
|
||||
InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor,
|
||||
};
|
||||
use rustc_type_ir::solve::GoalSource;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::FnCtxt;
|
||||
|
@ -119,7 +120,21 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
|
|||
fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
|
||||
let tcx = self.fcx.tcx;
|
||||
let goal = inspect_goal.goal();
|
||||
if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) {
|
||||
if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty)
|
||||
// We do not push the instantiated forms of goals as it would cause any
|
||||
// aliases referencing bound vars to go from having escaping bound vars to
|
||||
// being able to be normalized to an inference variable.
|
||||
//
|
||||
// This is mostly just a hack as arbitrary nested goals could still contain
|
||||
// such aliases while having a different `GoalSource`. Closure signature inference
|
||||
// however can't really handle *every* higher ranked `Fn` goal also being present
|
||||
// in the form of `?c: Fn<(<?x as Trait<'!a>>::Assoc)`.
|
||||
//
|
||||
// This also just better matches the behaviour of the old solver where we do not
|
||||
// encounter instantiated forms of goals, only nested goals that referred to bound
|
||||
// vars from instantiated goals.
|
||||
&& !matches!(inspect_goal.source(), GoalSource::InstantiateHigherRanked)
|
||||
{
|
||||
self.obligations_for_self_ty.push(traits::Obligation::new(
|
||||
tcx,
|
||||
self.root_cause.clone(),
|
||||
|
|
|
@ -2184,8 +2184,10 @@ symbols! {
|
|||
vec_macro,
|
||||
vec_new,
|
||||
vec_pop,
|
||||
vec_reserve,
|
||||
vec_with_capacity,
|
||||
vecdeque_iter,
|
||||
vecdeque_reserve,
|
||||
vector,
|
||||
version,
|
||||
vfp2,
|
||||
|
|
|
@ -90,6 +90,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
pub fn compute_dropck_outlives_inner<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
|
||||
span: Span,
|
||||
) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
|
||||
let tcx = ocx.infcx.tcx;
|
||||
let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal;
|
||||
|
@ -135,7 +136,7 @@ pub fn compute_dropck_outlives_inner<'tcx>(
|
|||
// Set used to detect infinite recursion.
|
||||
let mut ty_set = FxHashSet::default();
|
||||
|
||||
let cause = ObligationCause::dummy();
|
||||
let cause = ObligationCause::dummy_with_span(span);
|
||||
let mut constraints = DropckConstraint::empty();
|
||||
while let Some((ty, depth)) = ty_stack.pop() {
|
||||
debug!(
|
||||
|
|
|
@ -30,8 +30,9 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
type_op_ascribe_user_type_with_span(ocx, key, None)
|
||||
type_op_ascribe_user_type_with_span(ocx, key, span)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,11 +42,10 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
|
|||
pub fn type_op_ascribe_user_type_with_span<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
|
||||
span: Option<Span>,
|
||||
span: Span,
|
||||
) -> Result<(), NoSolution> {
|
||||
let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
|
||||
debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
|
||||
let span = span.unwrap_or(DUMMY_SP);
|
||||
match user_ty.kind {
|
||||
UserTypeKind::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
|
||||
UserTypeKind::TypeOf(def_id, user_args) => {
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
|
|||
use rustc_middle::infer::canonical::CanonicalQueryResponse;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_type_ir::outlives::{Component, push_outlives_components};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
@ -45,11 +45,12 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
if ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
|
||||
compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty)
|
||||
compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty, span)
|
||||
} else {
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty)
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,13 +59,14 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
|
|||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
|
||||
let normalize_op = |ty| -> Result<_, NoSolution> {
|
||||
// We must normalize the type so we can compute the right outlives components.
|
||||
// for example, if we have some constrained param type like `T: Trait<Out = U>`,
|
||||
// and we know that `&'a T::Out` is WF, then we want to imply `U: 'a`.
|
||||
let ty = ocx
|
||||
.deeply_normalize(&ObligationCause::dummy(), param_env, ty)
|
||||
.deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty)
|
||||
.map_err(|_| NoSolution)?;
|
||||
if !ocx.select_all_or_error().is_empty() {
|
||||
return Err(NoSolution);
|
||||
|
@ -142,6 +144,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
|||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
|
||||
let tcx = ocx.infcx.tcx;
|
||||
|
||||
|
@ -171,8 +174,8 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
|||
// FIXME(@lcnr): It's not really "always fine", having fewer implied
|
||||
// bounds can be backward incompatible, e.g. #101951 was caused by
|
||||
// us not dealing with inference vars in `TypeOutlives` predicates.
|
||||
let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
|
||||
.unwrap_or_default();
|
||||
let obligations =
|
||||
wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, span).unwrap_or_default();
|
||||
|
||||
for obligation in obligations {
|
||||
debug!(?obligation);
|
||||
|
@ -255,7 +258,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
|||
// Need to manually normalize in the new solver as `wf::obligations` does not.
|
||||
if ocx.infcx.next_trait_solver() {
|
||||
ty_a = ocx
|
||||
.deeply_normalize(&ObligationCause::dummy(), param_env, ty_a)
|
||||
.deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty_a)
|
||||
.map_err(|_| NoSolution)?;
|
||||
}
|
||||
let mut components = smallvec![];
|
||||
|
|
|
@ -92,6 +92,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution>;
|
||||
|
||||
fn fully_perform_into(
|
||||
|
@ -152,7 +153,7 @@ where
|
|||
if infcx.next_trait_solver() {
|
||||
return Ok(scrape_region_constraints(
|
||||
infcx,
|
||||
|ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self),
|
||||
|ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span),
|
||||
"query type op",
|
||||
span,
|
||||
)?
|
||||
|
|
|
@ -5,6 +5,7 @@ use rustc_middle::traits::query::NoSolution;
|
|||
pub use rustc_middle::traits::query::type_op::Normalize;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
@ -29,9 +30,10 @@ where
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
// FIXME(-Znext-solver): shouldn't be using old normalizer
|
||||
Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value))
|
||||
Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
|
||||
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
@ -28,7 +29,8 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
compute_dropck_outlives_inner(ocx, key.param_env.and(key.value))
|
||||
compute_dropck_outlives_inner(ocx, key.param_env.and(key.value), span)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use rustc_middle::traits::ObligationCause;
|
|||
use rustc_middle::traits::query::NoSolution;
|
||||
pub use rustc_middle::traits::query::type_op::ProvePredicate;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
@ -57,10 +58,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
|
|||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
span: Span,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
ocx.register_obligation(Obligation::new(
|
||||
ocx.infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
ObligationCause::dummy_with_span(span),
|
||||
key.param_env,
|
||||
key.value.predicate,
|
||||
));
|
||||
|
|
|
@ -6,6 +6,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
|
||||
use rustc_middle::ty::{self, GenericArgs, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::dropck_outlives::{
|
||||
compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner,
|
||||
|
@ -24,7 +25,7 @@ fn dropck_outlives<'tcx>(
|
|||
debug!("dropck_outlives(goal={:#?})", canonical_goal);
|
||||
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| {
|
||||
compute_dropck_outlives_inner(ocx, goal)
|
||||
compute_dropck_outlives_inner(ocx, goal, DUMMY_SP)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use rustc_infer::traits::query::OutlivesBound;
|
|||
use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{
|
||||
compute_implied_outlives_bounds_compat_inner, compute_implied_outlives_bounds_inner,
|
||||
|
@ -28,7 +29,7 @@ fn implied_outlives_bounds_compat<'tcx>(
|
|||
> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
|
||||
let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts();
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty)
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty, DUMMY_SP)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -41,6 +42,6 @@ fn implied_outlives_bounds<'tcx>(
|
|||
> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
|
||||
let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts();
|
||||
compute_implied_outlives_bounds_inner(ocx, param_env, ty)
|
||||
compute_implied_outlives_bounds_inner(ocx, param_env, ty, DUMMY_SP)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use rustc_infer::infer::canonical::{Canonical, CanonicalQueryInput, QueryRespons
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::{Clause, FnSig, ParamEnvAnd, PolyFnSig, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
|
||||
AscribeUserType, type_op_ascribe_user_type_with_span,
|
||||
|
@ -30,7 +31,7 @@ fn type_op_ascribe_user_type<'tcx>(
|
|||
canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
|
||||
type_op_ascribe_user_type_with_span(ocx, key, None)
|
||||
type_op_ascribe_user_type_with_span(ocx, key, DUMMY_SP)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -823,6 +823,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
|
|||
/// assert!(buf.capacity() >= 11);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_reserve")]
|
||||
#[track_caller]
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
let new_cap = self.len.checked_add(additional).expect("capacity overflow");
|
||||
|
|
|
@ -1267,6 +1267,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[track_caller]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")]
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
self.buf.reserve(self.len, additional);
|
||||
}
|
||||
|
|
|
@ -116,7 +116,6 @@ mod c_char_definition {
|
|||
// Section 2.1 "Basic Types" in MSP430 Embedded Application Binary
|
||||
// Interface says "The char type is unsigned by default".
|
||||
// https://www.ti.com/lit/an/slaa534a/slaa534a.pdf
|
||||
// Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945).
|
||||
// powerpc/powerpc64:
|
||||
// - PPC32 SysV: "Table 3-1 Scalar Types" in System V Application Binary Interface PowerPC
|
||||
// Processor Supplement says ANSI C char is unsigned byte
|
||||
|
@ -139,8 +138,10 @@ mod c_char_definition {
|
|||
// https://github.com/IBM/s390x-abi/releases/tag/v1.6.1
|
||||
// - z/OS: XL C/C++ Language Reference says: "By default, char behaves like an unsigned char."
|
||||
// https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-character-types
|
||||
// Xtensa:
|
||||
// - "The char type is unsigned by default for Xtensa processors."
|
||||
// xtensa:
|
||||
// Section 2.17.1 "Data Types and Alignment" of Xtensa LX Microprocessor Overview handbook
|
||||
// says "`char` type is unsigned by default".
|
||||
// https://loboris.eu/ESP32/Xtensa_lx%20Overview%20handbook.pdf
|
||||
//
|
||||
// On the following operating systems, c_char is signed by default, regardless of architecture.
|
||||
// Darwin (macOS, iOS, etc.):
|
||||
|
@ -150,11 +151,12 @@ mod c_char_definition {
|
|||
// Windows MSVC C++ Language Reference says "Microsoft-specific: Variables of type char
|
||||
// are promoted to int as if from type signed char by default, unless the /J compilation
|
||||
// option is used."
|
||||
// https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types)
|
||||
// L4RE:
|
||||
// https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types
|
||||
// L4Re:
|
||||
// The kernel builds with -funsigned-char on all targets (but useserspace follows the
|
||||
// architecture defaults). As we only have a target for userspace apps so there are no
|
||||
// special cases for L4RE below.
|
||||
// special cases for L4Re below.
|
||||
// https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240
|
||||
if #[cfg(all(
|
||||
not(windows),
|
||||
not(target_vendor = "apple"),
|
||||
|
@ -166,8 +168,8 @@ mod c_char_definition {
|
|||
target_arch = "msp430",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "riscv64",
|
||||
target_arch = "riscv32",
|
||||
target_arch = "riscv64",
|
||||
target_arch = "s390x",
|
||||
target_arch = "xtensa",
|
||||
)
|
||||
|
|
|
@ -2547,7 +2547,7 @@ macro_rules! atomic_int {
|
|||
$int_type,
|
||||
no = [
|
||||
"**Note:** This function is only available on targets where `",
|
||||
stringify!($int_type), "` has an alignment of ", $align, " bytes."
|
||||
stringify!($atomic_type), "` has the same alignment as `", stringify!($int_type), "`."
|
||||
],
|
||||
}]
|
||||
///
|
||||
|
|
|
@ -30,8 +30,8 @@ pub fn output_result(cmd: &mut Command) -> Result<String, String> {
|
|||
/// Finds the remote for rust-lang/rust.
|
||||
/// For example for these remotes it will return `upstream`.
|
||||
/// ```text
|
||||
/// origin https://github.com/Nilstrieb/rust.git (fetch)
|
||||
/// origin https://github.com/Nilstrieb/rust.git (push)
|
||||
/// origin https://github.com/pietroalbani/rust.git (fetch)
|
||||
/// origin https://github.com/pietroalbani/rust.git (push)
|
||||
/// upstream https://github.com/rust-lang/rust (fetch)
|
||||
/// upstream https://github.com/rust-lang/rust (push)
|
||||
/// ```
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
//@ check-pass
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
trait FnOnceForGenericRef<T>: FnOnce(&T) -> Self::FnOutput {
|
||||
type FnOutput;
|
||||
|
@ -16,10 +19,7 @@ struct Data<T, D: FnOnceForGenericRef<T>> {
|
|||
impl<T, D: FnOnceForGenericRef<T>> Data<T, D> {
|
||||
fn new(value: T, f: D) -> Self {
|
||||
let output = f(&value);
|
||||
Self {
|
||||
value: Some(value),
|
||||
output: Some(output),
|
||||
}
|
||||
Self { value: Some(value), output: Some(output) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
//@ check-pass
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
pub trait Fn0: Fn(i32) -> Self::Out {
|
||||
type Out;
|
||||
|
|
|
@ -9,4 +9,5 @@ fn main() {
|
|||
let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
|
||||
//[current]~^ ERROR type mismatch in closure arguments
|
||||
//[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
|
||||
//[next]~| ERROR expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found
|
||||
}
|
||||
|
|
|
@ -13,12 +13,26 @@ note: required by a bound in `find`
|
|||
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
||||
|
||||
error[E0271]: expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
|
||||
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:33
|
||||
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24
|
||||
|
|
||||
LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
|
||||
| ^^^^^^ expected `&&i32`, found integer
|
||||
| ^^^^ expected `&&i32`, found integer
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0277]: expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}`
|
||||
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:29
|
||||
|
|
||||
LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
|
||||
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `for<'a> FnMut(&'a <RangeInclusive<{integer}> as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}`
|
||||
= note: expected a closure with arguments `(&&&i32,)`
|
||||
found a closure with arguments `(&<RangeInclusive<{integer}> as Iterator>::Item,)`
|
||||
note: required by a bound in `find`
|
||||
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0277.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
|
|
|
@ -9,4 +9,5 @@ fn main() {
|
|||
let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
|
||||
//[current]~^ ERROR type mismatch in closure arguments
|
||||
//[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
|
||||
//[next]~| ERROR expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found
|
||||
}
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
//@ run-pass
|
||||
#![feature(arbitrary_self_types)]
|
||||
|
||||
// When probing for methods, we step forward through a chain of types. The first
|
||||
// few of those steps can be reached by jumping through the chain of Derefs or the
|
||||
// chain of Receivers. Later steps can only be reached by following the chain of
|
||||
// Receivers. For instance, supposing A and B implement both Receiver and Deref,
|
||||
// while C and D implement only Receiver:
|
||||
//
|
||||
// Type A<B<C<D<E>>>>
|
||||
//
|
||||
// Deref chain: A -> B -> C
|
||||
// Receiver chain: A -> B -> C -> D -> E
|
||||
//
|
||||
// We report bad type errors from the end of the chain. But at the end of which
|
||||
// chain? We never morph the type as far as E so the correct behavior is to
|
||||
// report errors from point C, i.e. the end of the Deref chain. This test case
|
||||
// ensures we do that.
|
||||
|
||||
struct MyNonNull<T>(*const T);
|
||||
|
||||
impl<T> std::ops::Receiver for MyNonNull<T> {
|
||||
|
@ -10,7 +26,13 @@ impl<T> std::ops::Receiver for MyNonNull<T> {
|
|||
#[allow(dead_code)]
|
||||
impl<T> MyNonNull<T> {
|
||||
fn foo<U>(&self) -> *const U {
|
||||
self.cast::<U>().bar()
|
||||
let mnn = self.cast::<U>();
|
||||
// The following method call is the point of this test.
|
||||
// If probe.rs reported errors from the last type discovered
|
||||
// in the Receiver chain, it would be sad here because U is just
|
||||
// a type variable. But this is a valid call so it ensures
|
||||
// probe.rs doesn't make that mistake.
|
||||
mnn.bar()
|
||||
}
|
||||
fn cast<U>(&self) -> MyNonNull<U> {
|
||||
MyNonNull(self.0 as *const U)
|
||||
|
|
|
@ -11,6 +11,7 @@ fn non_const_context() {
|
|||
const fn stable_const_context() {
|
||||
Unstable::func();
|
||||
//~^ ERROR cannot call conditionally-const associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
|
||||
//~| ERROR `staged_api::MyTrait` is not yet stable as a const trait
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -9,6 +9,17 @@ LL | Unstable::func();
|
|||
= help: add `#![feature(const_trait_impl)]` 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 1 previous error
|
||||
error: `staged_api::MyTrait` is not yet stable as a const trait
|
||||
--> $DIR/staged-api-user-crate.rs:12:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add `#![feature(unstable)]` to the crate attributes to enable
|
||||
|
|
||||
LL + #![feature(unstable)]
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
@ -22,7 +22,7 @@ impl const MyTrait for Foo {
|
|||
fn func() {}
|
||||
}
|
||||
|
||||
#[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||
#[rustc_allow_const_fn_unstable(const_trait_impl, unstable)]
|
||||
const fn conditionally_const<T: ~const MyTrait>() {
|
||||
T::func();
|
||||
}
|
||||
|
@ -37,10 +37,13 @@ fn non_const_context() {
|
|||
const fn const_context() {
|
||||
Unstable::func();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
//~| ERROR cannot use `#[feature(unstable)]`
|
||||
Foo::func();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
//~| ERROR cannot use `#[feature(unstable)]`
|
||||
Unstable2::func();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
//~| ERROR cannot use `#[feature(unstable)]`
|
||||
conditionally_const::<Foo>();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
}
|
||||
|
@ -59,8 +62,23 @@ pub const fn const_context_not_const_stable() {
|
|||
const fn stable_const_context() {
|
||||
Unstable::func();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
//~| ERROR cannot use `#[feature(unstable)]`
|
||||
Foo::func();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
//~| ERROR cannot use `#[feature(unstable)]`
|
||||
const_context_not_const_stable();
|
||||
//~^ ERROR cannot use `#[feature(local_feature)]`
|
||||
conditionally_const::<Foo>();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
}
|
||||
|
||||
const fn implicitly_stable_const_context() {
|
||||
Unstable::func();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
//~| ERROR cannot use `#[feature(unstable)]`
|
||||
Foo::func();
|
||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||
//~| ERROR cannot use `#[feature(unstable)]`
|
||||
const_context_not_const_stable();
|
||||
//~^ ERROR cannot use `#[feature(local_feature)]`
|
||||
conditionally_const::<Foo>();
|
||||
|
|
|
@ -15,8 +15,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
|||
LL | const fn const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
|
||||
--> $DIR/staged-api.rs:38:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(unstable)]
|
||||
LL | const fn const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:40:5
|
||||
--> $DIR/staged-api.rs:41:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
@ -32,8 +49,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
|||
LL | const fn const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
|
||||
--> $DIR/staged-api.rs:41:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(unstable)]
|
||||
LL | const fn const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:42:5
|
||||
--> $DIR/staged-api.rs:44:5
|
||||
|
|
||||
LL | Unstable2::func();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
@ -49,9 +83,26 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
|||
LL | const fn const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
|
||||
--> $DIR/staged-api.rs:44:5
|
||||
|
|
||||
LL | Unstable2::func();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(unstable)]
|
||||
LL | const fn const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:47:5
|
||||
|
|
||||
LL | conditionally_const::<Foo>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
|
@ -67,7 +118,7 @@ LL | const fn const_context() {
|
|||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:60:5
|
||||
--> $DIR/staged-api.rs:63:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
@ -83,8 +134,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
|||
LL | const fn stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
|
||||
--> $DIR/staged-api.rs:63:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn stable_const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(unstable)]
|
||||
LL | const fn stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:62:5
|
||||
--> $DIR/staged-api.rs:66:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
@ -100,8 +168,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
|||
LL | const fn stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
|
||||
--> $DIR/staged-api.rs:66:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn stable_const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(unstable)]
|
||||
LL | const fn stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
|
||||
--> $DIR/staged-api.rs:64:5
|
||||
--> $DIR/staged-api.rs:69:5
|
||||
|
|
||||
LL | const_context_not_const_stable();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -119,7 +204,7 @@ LL | const fn stable_const_context() {
|
|||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:66:5
|
||||
--> $DIR/staged-api.rs:71:5
|
||||
|
|
||||
LL | conditionally_const::<Foo>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -135,5 +220,108 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
|||
LL | const fn stable_const_context() {
|
||||
|
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:76:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
|
||||
--> $DIR/staged-api.rs:76:5
|
||||
|
|
||||
LL | Unstable::func();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(unstable)]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:79:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
|
||||
--> $DIR/staged-api.rs:79:5
|
||||
|
|
||||
LL | Foo::func();
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(unstable)]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
|
||||
--> $DIR/staged-api.rs:82:5
|
||||
|
|
||||
LL | const_context_not_const_stable();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
|
||||
help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(local_feature)]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
|
||||
--> $DIR/staged-api.rs:84:5
|
||||
|
|
||||
LL | conditionally_const::<Foo>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
|
|
||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
|
||||
LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||
LL | const fn implicitly_stable_const_context() {
|
||||
|
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
//@ check-pass
|
||||
//@ revisions: current next
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
// When type checking a closure expr we look at the list of unsolved goals
|
||||
// to determine if there are any bounds on the closure type to infer a signature from.
|
||||
//
|
||||
// We attempt to discard goals that name the closure type so as to avoid inferring the
|
||||
// closure type to something like `?x = closure(sig=fn(?x))`. This test checks that when
|
||||
// such a goal names the closure type inside of an ambiguous alias and there exists another
|
||||
// potential goal to infer the closure signature from, we do that.
|
||||
|
||||
trait Trait<'a> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<'a, F> Trait<'a> for F {
|
||||
type Assoc = u32;
|
||||
}
|
||||
|
||||
fn closure_typer1<F>(_: F)
|
||||
where
|
||||
F: Fn(u32) + for<'a> Fn(<F as Trait<'a>>::Assoc),
|
||||
{
|
||||
}
|
||||
|
||||
fn closure_typer2<F>(_: F)
|
||||
where
|
||||
F: for<'a> Fn(<F as Trait<'a>>::Assoc) + Fn(u32),
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Here we have some closure with a yet to be inferred type of `?c`. There are two goals
|
||||
// involving `?c` that can be used to determine the closure signature:
|
||||
// - `?c: for<'a> Fn<(<?c as Trait<'a>>::Assoc,), Output = ()>`
|
||||
// - `?c: Fn<(u32,), Output = ()>`
|
||||
//
|
||||
// If we were to infer the argument of the closure (`x` below) to `<?c as Trait<'a>>::Assoc`
|
||||
// then we would not be able to call `x.into()` as `x` is some unknown type. Instead we must
|
||||
// use the `?c: Fn(u32)` goal to infer a signature in order for this code to compile.
|
||||
//
|
||||
// As the algorithm for picking a goal to infer the signature from is dependent on the ordering
|
||||
// of pending goals in the type checker, we test both orderings of bounds to ensure we aren't
|
||||
// testing that we just *happen* to pick `?c: Fn(u32)`.
|
||||
closure_typer1(move |x| {
|
||||
let _: u32 = x.into();
|
||||
});
|
||||
closure_typer2(move |x| {
|
||||
let _: u32 = x.into();
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue