Implement MIR const trait stability checks
This commit is contained in:
parent
0df0662ee0
commit
4aaf467e26
9 changed files with 232 additions and 120 deletions
|
@ -403,7 +403,7 @@ const_eval_uninhabited_enum_variant_read =
|
||||||
const_eval_uninhabited_enum_variant_written =
|
const_eval_uninhabited_enum_variant_written =
|
||||||
writing discriminant of an uninhabited enum variant
|
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]`
|
.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
|
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)
|
.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_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_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_eval_unstable_in_stable_exposed =
|
||||||
const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
|
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
|
.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_attr_parsing::{ConstStability, StabilityLevel};
|
||||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||||
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{self as hir, LangItem};
|
use rustc_hir::{self as hir, LangItem};
|
||||||
use rustc_index::bit_set::DenseBitSet;
|
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::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
||||||
use super::resolver::FlowSensitiveAnalysis;
|
use super::resolver::FlowSensitiveAnalysis;
|
||||||
use super::{ConstCx, Qualif};
|
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;
|
use crate::errors;
|
||||||
|
|
||||||
type QualifResults<'mir, 'tcx, Q> =
|
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))
|
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> {
|
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
|
@ -716,8 +799,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
span: *fn_span,
|
span: *fn_span,
|
||||||
call_source,
|
call_source,
|
||||||
});
|
});
|
||||||
// FIXME(const_trait_impl): do a more fine-grained check whether this
|
self.check_callee_stability(trait_did);
|
||||||
// particular trait can be const-stably called.
|
|
||||||
} else {
|
} else {
|
||||||
// Not even a const trait.
|
// Not even a const trait.
|
||||||
self.check_op(ops::FnCallNonConst {
|
self.check_op(ops::FnCallNonConst {
|
||||||
|
@ -793,7 +875,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
// fallback body is safe to expose on stable.
|
// fallback body is safe to expose on stable.
|
||||||
let is_const_stable = intrinsic.const_stable
|
let is_const_stable = intrinsic.const_stable
|
||||||
|| (!intrinsic.must_be_overridden
|
|| (!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) {
|
match tcx.lookup_const_stability(callee) {
|
||||||
None => {
|
None => {
|
||||||
// This doesn't need a separate const-stability check -- const-stability equals
|
// This doesn't need a separate const-stability check -- const-stability equals
|
||||||
|
@ -842,83 +924,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, stability for regular function calls -- this is the big one.
|
// Finally, stability for regular function calls -- this is the big one.
|
||||||
match tcx.lookup_const_stability(callee) {
|
self.check_callee_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(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forbid all `Drop` terminators unless the place being dropped is a local with no
|
// 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.const_kind == Some(hir::ConstContext::ConstFn)
|
||||||
&& (self.tcx.features().staged_api()
|
&& (self.tcx.features().staged_api()
|
||||||
|| self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked)
|
|| 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 {
|
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)
|
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".
|
/// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable".
|
||||||
///
|
|
||||||
/// Panics if the given `DefId` does not refer to a `const fn`.
|
|
||||||
///
|
///
|
||||||
/// This is relevant within a `staged_api` crate. Unlike with normal features, the use of unstable
|
/// 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
|
/// 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
|
/// 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
|
/// 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.
|
/// 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 {
|
pub fn is_fn_or_trait_safe_to_expose_on_stable(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));
|
|
||||||
|
|
||||||
match tcx.lookup_const_stability(def_id) {
|
match tcx.lookup_const_stability(def_id) {
|
||||||
None => {
|
None => {
|
||||||
// In a `staged_api` crate, we do enforce recursive const stability for all unmarked
|
// 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
|
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)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct FnCallUnstable {
|
pub(crate) struct CallUnstable {
|
||||||
pub def_id: DefId,
|
pub def_id: DefId,
|
||||||
pub feature: Symbol,
|
pub feature: Symbol,
|
||||||
/// If this is true, then the feature is enabled, but we need to still check if it is safe to
|
/// 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 feature_enabled: bool,
|
||||||
pub safe_to_expose_on_stable: bool,
|
pub safe_to_expose_on_stable: bool,
|
||||||
pub suggestion_span: Option<Span>,
|
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 {
|
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||||
Status::Unstable {
|
Status::Unstable {
|
||||||
gate: self.feature,
|
gate: self.feature,
|
||||||
gate_already_checked: self.feature_enabled,
|
gate_already_checked: self.feature_enabled,
|
||||||
safe_to_expose_on_stable: self.safe_to_expose_on_stable,
|
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> {
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||||
assert!(!self.feature_enabled);
|
assert!(!self.feature_enabled);
|
||||||
let mut err = ccx.dcx().create_err(errors::UnstableConstFn {
|
let mut err = if self.is_function_call {
|
||||||
span,
|
ccx.dcx().create_err(errors::UnstableConstFn {
|
||||||
def_path: ccx.tcx.def_path_str(self.def_id),
|
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
|
// FIXME: make this translatable
|
||||||
let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature);
|
let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature);
|
||||||
#[allow(rustc::untranslatable_diagnostic)]
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
|
@ -121,6 +121,14 @@ pub(crate) struct UnstableConstFn {
|
||||||
pub def_path: String,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(const_eval_unstable_intrinsic)]
|
#[diag(const_eval_unstable_intrinsic)]
|
||||||
pub(crate) struct UnstableIntrinsic {
|
pub(crate) struct UnstableIntrinsic {
|
||||||
|
@ -139,9 +147,9 @@ pub(crate) struct UnstableIntrinsic {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(const_eval_unmarked_const_fn_exposed)]
|
#[diag(const_eval_unmarked_const_item_exposed)]
|
||||||
#[help]
|
#[help]
|
||||||
pub(crate) struct UnmarkedConstFnExposed {
|
pub(crate) struct UnmarkedConstItemExposed {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub def_path: String,
|
pub def_path: String,
|
||||||
|
|
|
@ -11,6 +11,7 @@ fn non_const_context() {
|
||||||
const fn stable_const_context() {
|
const fn stable_const_context() {
|
||||||
Unstable::func();
|
Unstable::func();
|
||||||
//~^ ERROR cannot call conditionally-const associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
|
//~^ 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() {}
|
fn main() {}
|
||||||
|
|
|
@ -9,6 +9,17 @@ LL | Unstable::func();
|
||||||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
= 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
|
= 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`.
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
|
|
@ -22,7 +22,7 @@ impl const MyTrait for Foo {
|
||||||
fn func() {}
|
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>() {
|
const fn conditionally_const<T: ~const MyTrait>() {
|
||||||
T::func();
|
T::func();
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,13 @@ fn non_const_context() {
|
||||||
const fn const_context() {
|
const fn const_context() {
|
||||||
Unstable::func();
|
Unstable::func();
|
||||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||||
|
//~| ERROR cannot use `#[feature(unstable)]`
|
||||||
Foo::func();
|
Foo::func();
|
||||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||||
|
//~| ERROR cannot use `#[feature(unstable)]`
|
||||||
Unstable2::func();
|
Unstable2::func();
|
||||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||||
|
//~| ERROR cannot use `#[feature(unstable)]`
|
||||||
conditionally_const::<Foo>();
|
conditionally_const::<Foo>();
|
||||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||||
}
|
}
|
||||||
|
@ -59,8 +62,10 @@ pub const fn const_context_not_const_stable() {
|
||||||
const fn stable_const_context() {
|
const fn stable_const_context() {
|
||||||
Unstable::func();
|
Unstable::func();
|
||||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||||
|
//~| ERROR cannot use `#[feature(unstable)]`
|
||||||
Foo::func();
|
Foo::func();
|
||||||
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
|
||||||
|
//~| ERROR cannot use `#[feature(unstable)]`
|
||||||
const_context_not_const_stable();
|
const_context_not_const_stable();
|
||||||
//~^ ERROR cannot use `#[feature(local_feature)]`
|
//~^ ERROR cannot use `#[feature(local_feature)]`
|
||||||
conditionally_const::<Foo>();
|
conditionally_const::<Foo>();
|
||||||
|
|
|
@ -15,8 +15,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||||
LL | const fn const_context() {
|
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)]`
|
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();
|
LL | Foo::func();
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
@ -32,8 +49,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||||
LL | const fn const_context() {
|
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)]`
|
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();
|
LL | Unstable2::func();
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
@ -49,9 +83,26 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||||
LL | const fn const_context() {
|
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
|
--> $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>();
|
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)]`
|
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();
|
LL | Unstable::func();
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
@ -83,8 +134,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||||
LL | const fn stable_const_context() {
|
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)]`
|
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();
|
LL | Foo::func();
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
@ -100,8 +168,25 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||||
LL | const fn stable_const_context() {
|
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)]`
|
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();
|
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)]`
|
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>();
|
LL | conditionally_const::<Foo>();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -135,5 +220,5 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
|
||||||
LL | const fn stable_const_context() {
|
LL | const fn stable_const_context() {
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
error: aborting due to 13 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue