mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
ensure that all publicly reachable const fn have const stability info
This commit is contained in:
parent
686eeb83e9
commit
e96808162a
@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::{RustcVersion, Session};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::symbol::{Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
||||
use crate::fluent_generated;
|
||||
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||
@ -92,9 +92,7 @@ impl Stability {
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct ConstStability {
|
||||
pub level: StabilityLevel,
|
||||
/// This can be `None` for functions that do not have an explicit const feature.
|
||||
/// We still track them for recursive const stability checks.
|
||||
pub feature: Option<Symbol>,
|
||||
pub feature: Symbol,
|
||||
/// This is true iff the `const_stable_indirect` attribute is present.
|
||||
pub const_stable_indirect: bool,
|
||||
/// whether the function has a `#[rustc_promotable]` attribute
|
||||
@ -272,22 +270,19 @@ pub fn find_stability(
|
||||
|
||||
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
|
||||
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
|
||||
///
|
||||
/// `is_const_fn` indicates whether this is a function marked as `const`.
|
||||
pub fn find_const_stability(
|
||||
sess: &Session,
|
||||
attrs: &[Attribute],
|
||||
item_sp: Span,
|
||||
is_const_fn: bool,
|
||||
) -> Option<(ConstStability, Span)> {
|
||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||
let mut promotable = false;
|
||||
let mut const_stable_indirect = None;
|
||||
let mut const_stable_indirect = false;
|
||||
|
||||
for attr in attrs {
|
||||
match attr.name_or_empty() {
|
||||
sym::rustc_promotable => promotable = true,
|
||||
sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
|
||||
sym::rustc_const_stable_indirect => const_stable_indirect = true,
|
||||
sym::rustc_const_unstable => {
|
||||
if const_stab.is_some() {
|
||||
sess.dcx()
|
||||
@ -299,7 +294,7 @@ pub fn find_const_stability(
|
||||
const_stab = Some((
|
||||
ConstStability {
|
||||
level,
|
||||
feature: Some(feature),
|
||||
feature,
|
||||
const_stable_indirect: false,
|
||||
promotable: false,
|
||||
},
|
||||
@ -317,7 +312,7 @@ pub fn find_const_stability(
|
||||
const_stab = Some((
|
||||
ConstStability {
|
||||
level,
|
||||
feature: Some(feature),
|
||||
feature,
|
||||
const_stable_indirect: false,
|
||||
promotable: false,
|
||||
},
|
||||
@ -340,7 +335,7 @@ pub fn find_const_stability(
|
||||
}
|
||||
}
|
||||
}
|
||||
if const_stable_indirect.is_some() {
|
||||
if const_stable_indirect {
|
||||
match &mut const_stab {
|
||||
Some((stab, _)) => {
|
||||
if stab.is_const_unstable() {
|
||||
@ -351,32 +346,13 @@ pub fn find_const_stability(
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => {
|
||||
// This function has no const stability attribute, but has `const_stable_indirect`.
|
||||
// We ignore that; unmarked functions are subject to recursive const stability
|
||||
// checks by default so we do carry out the user's intent.
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
|
||||
// fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
|
||||
// stability checks for them. We need to do this because the default for whether an unmarked
|
||||
// function enforces recursive stability differs between staged-api crates and force-unmarked
|
||||
// crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
|
||||
// enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
|
||||
// assume the function does not have recursive stability. All functions that *do* have recursive
|
||||
// stability must explicitly record this, and so that's what we do for all `const fn` in a
|
||||
// staged_api crate.
|
||||
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
|
||||
let c = ConstStability {
|
||||
feature: None,
|
||||
const_stable_indirect: const_stable_indirect.is_some(),
|
||||
promotable: false,
|
||||
level: StabilityLevel::Unstable {
|
||||
reason: UnstableReason::Default,
|
||||
issue: None,
|
||||
is_soft: false,
|
||||
implied_by: None,
|
||||
},
|
||||
};
|
||||
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
|
||||
}
|
||||
|
||||
const_stab
|
||||
}
|
||||
@ -394,7 +370,7 @@ pub fn unmarked_crate_const_stab(
|
||||
let const_stable_indirect =
|
||||
attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect);
|
||||
ConstStability {
|
||||
feature: Some(regular_stab.feature),
|
||||
feature: regular_stab.feature,
|
||||
const_stable_indirect,
|
||||
promotable: false,
|
||||
level: regular_stab.level,
|
||||
|
@ -709,6 +709,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
|
||||
// Intrinsics are language primitives, not regular calls, so treat them separately.
|
||||
if let Some(intrinsic) = tcx.intrinsic(callee) {
|
||||
if !tcx.is_const_fn(callee) {
|
||||
// Non-const intrinsic.
|
||||
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
|
||||
// If we allowed this, we're in miri-unleashed mode, so we might
|
||||
// as well skip the remaining checks.
|
||||
return;
|
||||
}
|
||||
// We use `intrinsic.const_stable` to determine if this can be safely exposed to
|
||||
// stable code, rather than `const_stable_indirect`. This is to make
|
||||
// `#[rustc_const_stable_indirect]` an attribute that is always safe to add.
|
||||
@ -716,17 +723,12 @@ 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
|
||||
&& tcx.is_const_fn(callee)
|
||||
&& is_safe_to_expose_on_stable_const_fn(tcx, callee));
|
||||
match tcx.lookup_const_stability(callee) {
|
||||
None => {
|
||||
// Non-const intrinsic.
|
||||
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
|
||||
}
|
||||
Some(ConstStability { feature: None, .. }) => {
|
||||
// Intrinsic does not need a separate feature gate (we rely on the
|
||||
// regular stability checker). However, we have to worry about recursive
|
||||
// const stability.
|
||||
// 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 !is_const_stable && self.enforce_recursive_const_stability() {
|
||||
self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
|
||||
span: self.span,
|
||||
@ -735,8 +737,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
Some(ConstStability {
|
||||
feature: Some(feature),
|
||||
level: StabilityLevel::Unstable { .. },
|
||||
feature,
|
||||
..
|
||||
}) => {
|
||||
self.check_op(ops::IntrinsicUnstable {
|
||||
@ -773,7 +775,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
|
||||
// All good.
|
||||
}
|
||||
None | Some(ConstStability { feature: None, .. }) => {
|
||||
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.
|
||||
@ -787,8 +789,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
Some(ConstStability {
|
||||
feature: Some(feature),
|
||||
level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
|
||||
feature,
|
||||
..
|
||||
}) => {
|
||||
// An unstable const fn with a feature gate.
|
||||
|
@ -110,14 +110,15 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b
|
||||
|
||||
match tcx.lookup_const_stability(def_id) {
|
||||
None => {
|
||||
// Only marked functions can be trusted. Note that this may be a function in a
|
||||
// non-staged-API crate where no recursive checks were done!
|
||||
false
|
||||
// In a `staged_api` crate, we do enforce recursive const stability for all unmarked
|
||||
// functions, so we can trust local functions. But in another crate we don't know which
|
||||
// rules were applied, so we can't trust that.
|
||||
def_id.is_local() && tcx.features().staged_api()
|
||||
}
|
||||
Some(stab) => {
|
||||
// We consider things safe-to-expose if they are stable, if they don't have any explicit
|
||||
// const stability attribute, or if they are marked as `const_stable_indirect`.
|
||||
stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect
|
||||
// We consider things safe-to-expose if they are stable or if they are marked as
|
||||
// `const_stable_indirect`.
|
||||
stab.is_const_stable() || stab.const_stable_indirect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -866,9 +866,7 @@ impl SyntaxExtension {
|
||||
})
|
||||
.unwrap_or_else(|| (None, helper_attrs));
|
||||
let stability = attr::find_stability(sess, attrs, span);
|
||||
// We set `is_const_fn` false to avoid getting any implicit const stability.
|
||||
let const_stability =
|
||||
attr::find_const_stability(sess, attrs, span, /* is_const_fn */ false);
|
||||
let const_stability = attr::find_const_stability(sess, attrs, span);
|
||||
let body_stability = attr::find_body_stability(sess, attrs);
|
||||
if let Some((_, sp)) = const_stability {
|
||||
sess.dcx().emit_err(errors::MacroConstStability {
|
||||
|
@ -16,7 +16,7 @@ use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::hir_id::CRATE_HIR_ID;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{Constness, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
|
||||
use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
|
||||
use rustc_middle::middle::privacy::EffectiveVisibilities;
|
||||
@ -166,68 +166,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
// # Regular and body stability
|
||||
|
||||
let stab = attr::find_stability(self.tcx.sess, attrs, item_sp);
|
||||
let const_stab = attr::find_const_stability(
|
||||
self.tcx.sess,
|
||||
attrs,
|
||||
item_sp,
|
||||
fn_sig.is_some_and(|s| s.header.is_const()),
|
||||
);
|
||||
let body_stab = attr::find_body_stability(self.tcx.sess, attrs);
|
||||
|
||||
// If the current node is a function with const stability attributes (directly given or
|
||||
// implied), check if the function/method is const or the parent impl block is const.
|
||||
if let Some(fn_sig) = fn_sig
|
||||
&& !fn_sig.header.is_const()
|
||||
&& const_stab.is_some()
|
||||
{
|
||||
self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
|
||||
}
|
||||
|
||||
// If this is marked const *stable*, it must also be regular-stable.
|
||||
if let Some((const_stab, const_span)) = const_stab
|
||||
&& let Some(fn_sig) = fn_sig
|
||||
&& const_stab.is_const_stable()
|
||||
&& !stab.is_some_and(|(s, _)| s.is_stable())
|
||||
{
|
||||
self.tcx
|
||||
.dcx()
|
||||
.emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
|
||||
}
|
||||
|
||||
// Stable *language* features shouldn't be used as unstable library features.
|
||||
// (Not doing this for stable library features is checked by tidy.)
|
||||
if let Some((
|
||||
ConstStability { level: Unstable { .. }, feature: Some(feature), .. },
|
||||
const_span,
|
||||
)) = const_stab
|
||||
{
|
||||
if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
|
||||
self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
|
||||
span: const_span,
|
||||
item_sp,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let const_stab = const_stab.map(|(const_stab, _span)| {
|
||||
self.index.const_stab_map.insert(def_id, const_stab);
|
||||
const_stab
|
||||
});
|
||||
|
||||
// `impl const Trait for Type` items forward their const stability to their
|
||||
// immediate children.
|
||||
// FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
|
||||
// Currently, once that is set, we do not inherit anything from the parent any more.
|
||||
if const_stab.is_none() {
|
||||
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
|
||||
if let Some(parent) = self.parent_const_stab {
|
||||
if parent.is_const_unstable() {
|
||||
self.index.const_stab_map.insert(def_id, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((depr, span)) = &depr
|
||||
&& depr.is_since_rustc_version()
|
||||
&& stab.is_none()
|
||||
@ -294,15 +237,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||
self.index.implications.insert(implied_by, feature);
|
||||
}
|
||||
|
||||
if let Some(ConstStability {
|
||||
level: Unstable { implied_by: Some(implied_by), .. },
|
||||
feature,
|
||||
..
|
||||
}) = const_stab
|
||||
{
|
||||
self.index.implications.insert(implied_by, feature.unwrap());
|
||||
}
|
||||
|
||||
self.index.stab_map.insert(def_id, stab);
|
||||
stab
|
||||
});
|
||||
@ -316,6 +250,91 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let final_stab = self.index.stab_map.get(&def_id);
|
||||
|
||||
// # Const stability
|
||||
|
||||
let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp);
|
||||
|
||||
// If the current node is a function with const stability attributes (directly given or
|
||||
// implied), check if the function/method is const.
|
||||
if let Some(fn_sig) = fn_sig
|
||||
&& !fn_sig.header.is_const()
|
||||
&& const_stab.is_some()
|
||||
{
|
||||
self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
|
||||
}
|
||||
|
||||
// If this is marked const *stable*, it must also be regular-stable.
|
||||
if let Some((const_stab, const_span)) = const_stab
|
||||
&& let Some(fn_sig) = fn_sig
|
||||
&& const_stab.is_const_stable()
|
||||
&& !stab.is_some_and(|s| s.is_stable())
|
||||
{
|
||||
self.tcx
|
||||
.dcx()
|
||||
.emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
|
||||
}
|
||||
|
||||
// Stable *language* features shouldn't be used as unstable library features.
|
||||
// (Not doing this for stable library features is checked by tidy.)
|
||||
if let Some((ConstStability { level: Unstable { .. }, feature, .. }, const_span)) =
|
||||
const_stab
|
||||
{
|
||||
if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
|
||||
self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
|
||||
span: const_span,
|
||||
item_sp,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// After checking the immediate attributes, get rid of the span and compute implied
|
||||
// const stability: inherit feature gate from regular stability.
|
||||
let mut const_stab = const_stab.map(|(stab, _span)| stab);
|
||||
|
||||
// If this is a const fn but not annotated with stability markers, see if we can inherit regular stability.
|
||||
if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
|
||||
// We only ever inherit unstable features.
|
||||
let Some(inherit_regular_stab) =
|
||||
final_stab.filter(|s| s.is_unstable())
|
||||
{
|
||||
const_stab = Some(ConstStability {
|
||||
// We subject these implicitly-const functions to recursive const stability.
|
||||
const_stable_indirect: true,
|
||||
promotable: false,
|
||||
level: inherit_regular_stab.level,
|
||||
feature: inherit_regular_stab.feature,
|
||||
});
|
||||
}
|
||||
|
||||
// Now that everything is computed, insert it into the table.
|
||||
const_stab.inspect(|const_stab| {
|
||||
self.index.const_stab_map.insert(def_id, *const_stab);
|
||||
});
|
||||
|
||||
if let Some(ConstStability {
|
||||
level: Unstable { implied_by: Some(implied_by), .. },
|
||||
feature,
|
||||
..
|
||||
}) = const_stab
|
||||
{
|
||||
self.index.implications.insert(implied_by, feature);
|
||||
}
|
||||
|
||||
// `impl const Trait for Type` items forward their const stability to their
|
||||
// immediate children.
|
||||
// FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
|
||||
// Currently, once that is set, we do not inherit anything from the parent any more.
|
||||
if const_stab.is_none() {
|
||||
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
|
||||
if let Some(parent) = self.parent_const_stab {
|
||||
if parent.is_const_unstable() {
|
||||
self.index.const_stab_map.insert(def_id, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.recurse_with_stability_attrs(
|
||||
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
|
||||
stab,
|
||||
@ -570,13 +589,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_missing_or_wrong_const_stability(&self, def_id: LocalDefId, span: Span) {
|
||||
// The visitor runs for "unstable-if-unmarked" crates, but we don't yet support
|
||||
// that on the const side.
|
||||
if !self.tcx.features().staged_api() {
|
||||
return;
|
||||
}
|
||||
|
||||
fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
|
||||
// if the const impl is derived using the `derive_const` attribute,
|
||||
// then it would be "stable" at least for the impl.
|
||||
// We gate usages of it using `feature(const_trait_impl)` anyways
|
||||
@ -587,12 +600,12 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
||||
|
||||
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
|
||||
|| self.tcx.is_const_trait_impl(def_id.to_def_id());
|
||||
let is_stable =
|
||||
self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable());
|
||||
let missing_const_stability_attribute =
|
||||
self.tcx.lookup_const_stability(def_id).is_none_or(|s| s.feature.is_none());
|
||||
|
||||
if is_const && is_stable && missing_const_stability_attribute {
|
||||
// Reachable const fn must have a stability attribute.
|
||||
if is_const
|
||||
&& self.effective_visibilities.is_reachable(def_id)
|
||||
&& self.tcx.lookup_const_stability(def_id).is_none()
|
||||
{
|
||||
let descr = self.tcx.def_descr(def_id.to_def_id());
|
||||
self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr });
|
||||
}
|
||||
@ -620,7 +633,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
|
||||
}
|
||||
|
||||
// Ensure stable `const fn` have a const stability attribute.
|
||||
self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span);
|
||||
self.check_missing_const_stability(i.owner_id.def_id, i.span);
|
||||
|
||||
intravisit::walk_item(self, i)
|
||||
}
|
||||
@ -634,7 +647,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
|
||||
let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
|
||||
if self.tcx.impl_trait_ref(impl_def_id).is_none() {
|
||||
self.check_missing_stability(ii.owner_id.def_id, ii.span);
|
||||
self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span);
|
||||
self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
|
||||
}
|
||||
intravisit::walk_impl_item(self, ii);
|
||||
}
|
||||
@ -765,23 +778,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
||||
// For implementations of traits, check the stability of each item
|
||||
// individually as it's possible to have a stable trait with unstable
|
||||
// items.
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
constness,
|
||||
of_trait: Some(ref t),
|
||||
self_ty,
|
||||
items,
|
||||
..
|
||||
}) => {
|
||||
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
|
||||
let features = self.tcx.features();
|
||||
if features.staged_api() {
|
||||
let attrs = self.tcx.hir().attrs(item.hir_id());
|
||||
let stab = attr::find_stability(self.tcx.sess, attrs, item.span);
|
||||
let const_stab = attr::find_const_stability(
|
||||
self.tcx.sess,
|
||||
attrs,
|
||||
item.span,
|
||||
matches!(constness, Constness::Const),
|
||||
);
|
||||
let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span);
|
||||
|
||||
// If this impl block has an #[unstable] attribute, give an
|
||||
// error if all involved types and traits are stable, because
|
||||
|
@ -1010,9 +1010,7 @@ fn render_stability_since_raw_with_extra(
|
||||
// don't display const unstable if entirely unstable
|
||||
None
|
||||
} else {
|
||||
let unstable = if let Some(n) = issue
|
||||
&& let Some(feature) = feature
|
||||
{
|
||||
let unstable = if let Some(n) = issue {
|
||||
format!(
|
||||
"<a \
|
||||
href=\"https://github.com/rust-lang/rust/issues/{n}\" \
|
||||
|
@ -393,12 +393,8 @@ fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
|
||||
|
||||
msrv.meets(const_stab_rust_version)
|
||||
} else {
|
||||
// Unstable const fn, check if the feature is enabled. We need both the regular stability
|
||||
// feature and (if set) the const stability feature to const-call this function.
|
||||
let stab = tcx.lookup_stability(def_id);
|
||||
let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature))
|
||||
&& const_stab.feature.is_none_or(|f| tcx.features().enabled(f));
|
||||
is_enabled && msrv.current().is_none()
|
||||
// Unstable const fn, check if the feature is enabled.
|
||||
tcx.features().enabled(const_stab.feature) && msrv.current().is_none()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ const fn const_main() {
|
||||
unsafe {
|
||||
unstable_intrinsic::size_of_val(&x);
|
||||
//~^ERROR: unstable library feature `unstable`
|
||||
//~|ERROR: cannot be (indirectly) exposed to stable
|
||||
//~|ERROR: not yet stable as a const intrinsic
|
||||
unstable_intrinsic::min_align_of_val(&x);
|
||||
//~^ERROR: unstable library feature `unstable`
|
||||
//~|ERROR: not yet stable as a const intrinsic
|
||||
|
||||
size_of_val(&x);
|
||||
//~^ERROR: cannot be (indirectly) exposed to stable
|
||||
//~^ERROR: cannot use `#[feature(local)]`
|
||||
min_align_of_val(&x);
|
||||
//~^ERROR: cannot use `#[feature(local)]`
|
||||
}
|
||||
@ -59,6 +59,6 @@ mod fallback {
|
||||
#[rustc_intrinsic]
|
||||
const unsafe fn copy<T>(src: *const T, _dst: *mut T, _count: usize) {
|
||||
super::size_of_val(src);
|
||||
//~^ ERROR cannot be (indirectly) exposed to stable
|
||||
//~^ ERROR cannot use `#[feature(local)]`
|
||||
}
|
||||
}
|
||||
|
@ -18,13 +18,13 @@ LL | unstable_intrinsic::min_align_of_val(&x);
|
||||
= help: add `#![feature(unstable)]` 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: intrinsic `unstable_intrinsic::size_of_val` cannot be (indirectly) exposed to stable
|
||||
error: `size_of_val` is not yet stable as a const intrinsic
|
||||
--> $DIR/const-unstable-intrinsic.rs:17:9
|
||||
|
|
||||
LL | unstable_intrinsic::size_of_val(&x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval)
|
||||
= help: add `#![feature(unstable)]` to the crate attributes to enable
|
||||
|
||||
error: `min_align_of_val` is not yet stable as a const intrinsic
|
||||
--> $DIR/const-unstable-intrinsic.rs:20:9
|
||||
@ -34,13 +34,22 @@ LL | unstable_intrinsic::min_align_of_val(&x);
|
||||
|
|
||||
= help: add `#![feature(unstable)]` to the crate attributes to enable
|
||||
|
||||
error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
|
||||
--> $DIR/const-unstable-intrinsic.rs:24:9
|
||||
|
|
||||
LL | size_of_val(&x);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval)
|
||||
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_main() {
|
||||
|
|
||||
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)]
|
||||
LL | const fn const_main() {
|
||||
|
|
||||
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
|
||||
--> $DIR/const-unstable-intrinsic.rs:26:9
|
||||
@ -67,13 +76,22 @@ LL | unsafe { copy(src, dst, count) }
|
||||
|
|
||||
= help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval)
|
||||
|
||||
error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable
|
||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
|
||||
--> $DIR/const-unstable-intrinsic.rs:61:9
|
||||
|
|
||||
LL | super::size_of_val(src);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval)
|
||||
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 unsafe fn copy<T>(src: *const T, _dst: *mut T, _count: usize) {
|
||||
|
|
||||
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)]
|
||||
LL | const unsafe fn copy<T>(src: *const T, _dst: *mut T, _count: usize) {
|
||||
|
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
@ -56,9 +56,3 @@ const fn barfoo_unmarked() {}
|
||||
#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
|
||||
pub const fn barfoo_unstable() {}
|
||||
//~^ ERROR can only be applied to functions that are declared `#[stable]`
|
||||
|
||||
// `#[rustc_const_stable_indirect]` also requires a const fn
|
||||
#[rustc_const_stable_indirect]
|
||||
#[unstable(feature = "unstable", issue = "none")]
|
||||
pub fn not_a_const_fn() {}
|
||||
//~^ ERROR require the function or method to be `const`
|
||||
|
@ -86,17 +86,5 @@ LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
|
||||
LL | pub const fn barfoo_unstable() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
|
||||
--> $DIR/rustc-const-stability-require-const.rs:63:1
|
||||
|
|
||||
LL | pub fn not_a_const_fn() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: make the function or method const
|
||||
--> $DIR/rustc-const-stability-require-const.rs:63:1
|
||||
|
|
||||
LL | pub fn not_a_const_fn() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
@ -1,17 +1,3 @@
|
||||
error: can't mark as unstable using an already stable feature
|
||||
--> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
|
||||
|
|
||||
LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
|
||||
LL | const fn my_fun() {}
|
||||
| -------------------- the stability attribute annotates this item
|
||||
|
|
||||
help: consider removing the attribute
|
||||
--> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
|
||||
|
|
||||
LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: can't mark as unstable using an already stable feature
|
||||
--> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
|
||||
|
|
||||
@ -27,5 +13,19 @@ help: consider removing the attribute
|
||||
LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: can't mark as unstable using an already stable feature
|
||||
--> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
|
||||
|
|
||||
LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
|
||||
LL | const fn my_fun() {}
|
||||
| -------------------- the stability attribute annotates this item
|
||||
|
|
||||
help: consider removing the attribute
|
||||
--> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
|
||||
|
|
||||
LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user