Re-do recursive const stability checks

Fundamentally, we have *three* disjoint categories of functions:
1. const-stable functions
2. private/unstable functions that are meant to be callable from const-stable functions
3. functions that can make use of unstable const features

This PR implements the following system:
- `#[rustc_const_stable]` puts functions in the first category. It may only be applied to `#[stable]` functions.
- `#[rustc_const_unstable]` by default puts functions in the third category. The new attribute `#[rustc_const_stable_indirect]` can be added to such a function to move it into the second category.
- `const fn` without a const stability marker are in the second category if they are still unstable. They automatically inherit the feature gate for regular calls, it can now also be used for const-calls.

Also, several holes in recursive const stability checking are being closed.
There's still one potential hole that is hard to avoid, which is when MIR
building automatically inserts calls to a particular function in stable
functions -- which happens in the panic machinery. Those need to *not* be
`rustc_const_unstable` (or manually get a `rustc_const_stable_indirect`) to be
sure they follow recursive const stability. But that's a fairly rare and special
case so IMO it's fine.

The net effect of this is that a `#[unstable]` or unmarked function can be
constified simply by marking it as `const fn`, and it will then be
const-callable from stable `const fn` and subject to recursive const stability
requirements. If it is publicly reachable (which implies it cannot be unmarked),
it will be const-unstable under the same feature gate. Only if the function ever
becomes `#[stable]` does it need a `#[rustc_const_unstable]` or
`#[rustc_const_stable]` marker to decide if this should also imply
const-stability.

Adding `#[rustc_const_unstable]` is only needed for (a) functions that need to
use unstable const lang features (including intrinsics), or (b) `#[stable]`
functions that are not yet intended to be const-stable. Adding
`#[rustc_const_stable]` is only needed for functions that are actually meant to
be directly callable from stable const code. `#[rustc_const_stable_indirect]` is
used to mark intrinsics as const-callable and for `#[rustc_const_unstable]`
functions that are actually called from other, exposed-on-stable `const fn`. No
other attributes are required.
This commit is contained in:
Ralf Jung 2024-10-06 19:59:19 +02:00
parent 45089ec19e
commit a0215d8e46
102 changed files with 1520 additions and 663 deletions

View File

@ -91,6 +91,9 @@ attr_non_ident_feature =
attr_rustc_allowed_unstable_pairing =
`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
attr_rustc_const_stable_indirect_pairing =
`const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied
attr_rustc_promotable_pairing =
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute

View File

@ -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,7 +92,11 @@ impl Stability {
#[derive(HashStable_Generic)]
pub struct ConstStability {
pub level: StabilityLevel,
pub feature: Symbol,
/// 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>,
/// This is true iff the `const_stable_indirect` attribute is present.
pub const_stable_indirect: bool,
/// whether the function has a `#[rustc_promotable]` attribute
pub promotable: bool,
}
@ -268,17 +272,23 @@ 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`. It will always
/// be false for intrinsics in an `extern` block!
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;
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_unstable => {
if const_stab.is_some() {
sess.dcx()
@ -287,8 +297,15 @@ pub fn find_const_stability(
}
if let Some((feature, level)) = parse_unstability(sess, attr) {
const_stab =
Some((ConstStability { level, feature, promotable: false }, attr.span));
const_stab = Some((
ConstStability {
level,
feature: Some(feature),
const_stable_indirect: false,
promotable: false,
},
attr.span,
));
}
}
sym::rustc_const_stable => {
@ -298,15 +315,22 @@ pub fn find_const_stability(
break;
}
if let Some((feature, level)) = parse_stability(sess, attr) {
const_stab =
Some((ConstStability { level, feature, promotable: false }, attr.span));
const_stab = Some((
ConstStability {
level,
feature: Some(feature),
const_stable_indirect: false,
promotable: false,
},
attr.span,
));
}
}
_ => {}
}
}
// Merge the const-unstable info into the stability info
// Merge promotable and not_exposed_on_stable into stability info
if promotable {
match &mut const_stab {
Some((stab, _)) => stab.promotable = promotable,
@ -317,6 +341,46 @@ pub fn find_const_stability(
}
}
}
if const_stable_indirect.is_some() {
match &mut const_stab {
Some((stab, _)) => {
if stab.is_const_unstable() {
stab.const_stable_indirect = true;
} else {
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
span: item_sp,
})
}
}
_ => {
// We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
// the `default_const_unstable` logic.
}
}
}
// 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
}

View File

@ -318,6 +318,13 @@ pub(crate) struct RustcPromotablePairing {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_rustc_const_stable_indirect_pairing)]
pub(crate) struct RustcConstStableIndirectPairing {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_rustc_allowed_unstable_pairing, code = E0789)]
pub(crate) struct RustcAllowedUnstablePairing {

View File

@ -38,7 +38,7 @@ diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index d9de37e..8293fce 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -2996,42 +2996,6 @@ atomic_int! {
@@ -2996,44 +2996,6 @@ atomic_int! {
8,
u64 AtomicU64
}
@ -52,7 +52,8 @@ index d9de37e..8293fce 100644
- unstable(feature = "integer_atomics", issue = "99069"),
- unstable(feature = "integer_atomics", issue = "99069"),
- unstable(feature = "integer_atomics", issue = "99069"),
- rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
- cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
- "i128",
- "#![feature(integer_atomics)]\n\n",
@ -70,7 +71,8 @@ index d9de37e..8293fce 100644
- unstable(feature = "integer_atomics", issue = "99069"),
- unstable(feature = "integer_atomics", issue = "99069"),
- unstable(feature = "integer_atomics", issue = "99069"),
- rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
- cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
- "u128",
- "#![feature(integer_atomics)]\n\n",

View File

@ -41,8 +41,6 @@ const_eval_const_context = {$kind ->
*[other] {""}
}
const_eval_const_stable = const-stable functions can only call other const-stable functions
const_eval_copy_nonoverlapping_overlapping =
`copy_nonoverlapping` called on overlapping ranges
@ -259,6 +257,9 @@ const_eval_non_const_fn_call =
const_eval_non_const_impl =
impl defined here, but it is not `const`
const_eval_non_const_intrinsic =
cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s
const_eval_not_enough_caller_args =
calling a function with fewer arguments than it requires
@ -397,17 +398,29 @@ const_eval_uninhabited_enum_variant_read =
read discriminant of an uninhabited enum variant
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
.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_const_stable_indirect]` (but this requires team approval)
const_eval_unreachable = entering unreachable code
const_eval_unreachable_unwind =
unwinding past a stack frame that does not allow unwinding
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_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 unsafe features
.unstable_sugg = if the {$is_function_call2 ->
[true] caller
*[false] function
} is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
.bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
const_eval_unstable_in_stable =
const-stable function cannot use `#[feature({$gate})]`
.unstable_sugg = if the function is not (yet) meant to be stable, make this function unstably const
.bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic
.help = add `#![feature({$feature})]` to the crate attributes to enable
const_eval_unterminated_c_string =
reading a null-terminated string starting at {$pointer} with no null found before end of allocation

View File

@ -5,6 +5,7 @@ use std::borrow::Cow;
use std::mem;
use std::ops::Deref;
use rustc_attr::{ConstStability, StabilityLevel};
use rustc_errors::{Diag, ErrorGuaranteed};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, LangItem};
@ -28,8 +29,8 @@ use super::ops::{self, NonConstOp, Status};
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
use super::resolver::FlowSensitiveAnalysis;
use super::{ConstCx, Qualif};
use crate::const_eval::is_unstable_const_fn;
use crate::errors::UnstableInStable;
use crate::check_consts::is_safe_to_expose_on_stable_const_fn;
use crate::errors;
type QualifResults<'mir, 'tcx, Q> =
rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
@ -274,19 +275,22 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
/// context.
pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
let gate = match op.status_in_item(self.ccx) {
Status::Allowed => return,
Status::Unstable(gate) if self.tcx.features().enabled(gate) => {
let unstable_in_stable = self.ccx.is_const_stable_const_fn()
&& !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
if unstable_in_stable {
emit_unstable_in_stable_error(self.ccx, span, gate);
Status::Unstable { gate, safe_to_expose_on_stable, is_function_call }
if self.tcx.features().enabled(gate) =>
{
// Generally this is allowed since the feature gate is enabled -- except
// if this function wants to be safe-to-expose-on-stable.
if !safe_to_expose_on_stable
&& self.enforce_recursive_const_stability()
&& !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate)
{
emit_unstable_in_stable_exposed_error(self.ccx, span, gate, is_function_call);
}
return;
}
Status::Unstable(gate) => Some(gate),
Status::Unstable { gate, .. } => Some(gate),
Status::Forbidden => None,
};
@ -304,7 +308,13 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
self.error_emitted = Some(reported);
}
ops::DiagImportance::Secondary => self.secondary_errors.push(err),
ops::DiagImportance::Secondary => {
self.secondary_errors.push(err);
self.tcx.dcx().span_delayed_bug(
span,
"compilation must fail when there is a secondary const checker error",
);
}
}
}
@ -569,6 +579,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
ty::FnPtr(..) => {
self.check_op(ops::FnCallIndirect);
// We can get here without an error in miri-unleashed mode... might as well
// skip the rest of the checks as well then.
return;
}
_ => {
@ -612,6 +624,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// checks.
// FIXME(effects) we might consider moving const stability checks to typeck as well.
if tcx.features().effects() {
// This skips the check below that ensures we only call `const fn`.
is_trait = true;
if let Ok(Some(instance)) =
@ -637,6 +650,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
sym::const_trait_impl
}),
});
// If we allowed this, we're in miri-unleashed mode, so we might
// as well skip the remaining checks.
return;
}
}
@ -650,28 +665,72 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// const-eval of the `begin_panic` fn assumes the argument is `&str`
if tcx.is_lang_item(callee, LangItem::BeginPanic) {
match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() {
ty::Ref(_, ty, _) if ty.is_str() => return,
ty::Ref(_, ty, _) if ty.is_str() => {}
_ => self.check_op(ops::PanicNonStr),
}
// Allow this call, skip all the checks below.
return;
}
// const-eval of `#[rustc_const_panic_str]` functions assumes the argument is `&&str`
if tcx.has_attr(callee, sym::rustc_const_panic_str) {
match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() {
ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
{
return;
{}
_ => {
self.check_op(ops::PanicNonStr);
}
_ => self.check_op(ops::PanicNonStr),
}
// Allow this call, skip all the checks below.
return;
}
// This can be called on stable via the `vec!` macro.
if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) {
self.check_op(ops::HeapAllocation);
// Allow this call, skip all the checks below.
return;
}
// Intrinsics are language primitives, not regular calls, so treat them separately.
if let Some(intrinsic) = tcx.intrinsic(callee) {
match tcx.lookup_const_stability(callee) {
None => {
// Non-const intrinsic.
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
}
Some(ConstStability { feature: None, const_stable_indirect, .. }) => {
// Intrinsic does not need a separate feature gate (we rely on the
// regular stability checker). However, we have to worry about recursive
// const stability.
if !const_stable_indirect && self.enforce_recursive_const_stability() {
self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
span: self.span,
def_path: self.tcx.def_path_str(callee),
});
}
}
Some(ConstStability {
feature: Some(feature),
level: StabilityLevel::Unstable { .. },
const_stable_indirect,
..
}) => {
self.check_op(ops::IntrinsicUnstable {
name: intrinsic.name,
feature,
const_stable_indirect,
});
}
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
// All good.
}
}
// This completes the checks for intrinsics.
return;
}
// Trait functions are not `const fn` so we have to skip them here.
if !tcx.is_const_fn_raw(callee) && !is_trait {
self.check_op(ops::FnCallNonConst {
caller,
@ -681,66 +740,68 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
call_source,
feature: None,
});
// If we allowed this, we're in miri-unleashed mode, so we might
// as well skip the remaining checks.
return;
}
// If the `const fn` we are trying to call is not const-stable, ensure that we have
// the proper feature gate enabled.
if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) {
trace!(?gate, "calling unstable const fn");
if self.span.allows_unstable(gate) {
return;
// Finally, stability for regular function calls -- this is the big one.
match tcx.lookup_const_stability(callee) {
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
// All good.
}
if let Some(implied_by_gate) = implied_by
&& self.span.allows_unstable(implied_by_gate)
{
return;
None | Some(ConstStability { feature: 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 {
feature: Some(feature),
level: StabilityLevel::Unstable { implied_by: implied_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);
// Calling an unstable function *always* requires that the corresponding gate
// (or implied gate) be enabled, even if the function has
// `#[rustc_allow_const_fn_unstable(the_gate)]`.
let gate_enabled = |gate| tcx.features().enabled(gate);
let feature_gate_enabled = gate_enabled(gate);
let implied_gate_enabled = implied_by.is_some_and(gate_enabled);
if !feature_gate_enabled && !implied_gate_enabled {
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
return;
}
// We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
// the callee is safe to expose, to avoid bypassing recursive 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;
}
// If this crate is not using stability attributes, or the caller is not claiming to be a
// stable `const fn`, that is all that is required.
if !self.ccx.is_const_stable_const_fn() {
trace!("crate not using stability attributes or caller not stably const");
return;
}
// Otherwise, we are something const-stable calling a const-unstable fn.
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
trace!("rustc_allow_const_fn_unstable gate enabled");
return;
}
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
return;
}
// FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that
// have no `rustc_const_stable` attributes to be const-unstable as well. This
// should be fixed later.
let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
&& tcx.lookup_stability(callee).is_some_and(|s| s.is_unstable());
if callee_is_unstable_unmarked {
trace!("callee_is_unstable_unmarked");
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
// `extern` functions, and these have no way to get marked `const`. So instead we
// use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
if self.ccx.is_const_stable_const_fn() || tcx.intrinsic(callee).is_some() {
self.check_op(ops::FnCallUnstable(callee, None));
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));
// We do *not* honor this if we are in the "danger zone": we have to enforce
// recursive const-stability and the callee is not safe-to-expose. In that
// case we need `check_op` to do the check.
let danger_zone = !callee_safe_to_expose_on_stable
&& self.enforce_recursive_const_stability();
if danger_zone || !feature_enabled {
self.check_op(ops::FnCallUnstable {
def_id: callee,
feature,
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
});
}
}
}
trace!("permitting call");
}
// Forbid all `Drop` terminators unless the place being dropped is a local with no
@ -785,11 +846,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine(
self.tcx
.coroutine_kind(self.body.source.def_id())
.expect("Only expected to have a yield in a coroutine"),
)),
TerminatorKind::Yield { .. } => {
self.check_op(ops::Coroutine(
self.tcx
.coroutine_kind(self.body.source.def_id())
.expect("Only expected to have a yield in a coroutine"),
));
}
TerminatorKind::CoroutineDrop => {
span_bug!(
@ -819,8 +882,19 @@ fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool {
ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point()
}
fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
fn emit_unstable_in_stable_exposed_error(
ccx: &ConstCx<'_, '_>,
span: Span,
gate: Symbol,
is_function_call: bool,
) -> ErrorGuaranteed {
let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo();
ccx.dcx().emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span });
ccx.dcx().emit_err(errors::UnstableInStableExposed {
gate: gate.to_string(),
span,
attr_span,
is_function_call,
is_function_call2: is_function_call,
})
}

View File

@ -59,10 +59,12 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
self.const_kind.expect("`const_kind` must not be called on a non-const fn")
}
pub fn is_const_stable_const_fn(&self) -> bool {
pub fn enforce_recursive_const_stability(&self) -> bool {
// We can skip this if `staged_api` is not enabled, since in such crates
// `lookup_const_stability` will always be `None`.
self.const_kind == Some(hir::ConstContext::ConstFn)
&& self.tcx.features().staged_api()
&& is_const_stable_const_fn(self.tcx, self.def_id().to_def_id())
&& is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id())
}
fn is_async(&self) -> bool {
@ -90,50 +92,38 @@ 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 "const-stable".
/// 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`.
///
/// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
/// functions can be called in a const-context by users of the stable compiler. "const-stable"
/// functions are subject to more stringent restrictions than "const-unstable" functions: They
/// cannot use unstable features and can only call other "const-stable" functions.
pub fn is_const_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. We shouldn't
// restrict default bodies to only call const-stable functions.
/// 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_raw(def_id));
// A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
// to is const-stable.
match tcx.lookup_const_stability(def_id) {
Some(stab) => stab.is_const_stable(),
None if is_parent_const_stable_trait(tcx, def_id) => {
// Remove this when `#![feature(const_trait_impl)]` is stabilized,
// returning `true` unconditionally.
tcx.dcx().span_delayed_bug(
tcx.def_span(def_id),
"trait implementations cannot be const stable yet",
);
true
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
}
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
}
None => false, // By default, items are not const stable.
}
}
fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let local_def_id = def_id.expect_local();
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
let parent_owner_id = tcx.parent_hir_id(hir_id).owner;
if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) {
return false;
}
tcx.lookup_const_stability(parent_owner_id).is_some_and(|stab| stab.is_const_stable())
}

View File

@ -26,8 +26,16 @@ use crate::{errors, fluent_generated};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Status {
Allowed,
Unstable(Symbol),
Unstable {
/// The feature that must be enabled to use this operation.
gate: Symbol,
/// Whether it is allowed to use this operation from stable `const fn`.
/// This will usually be `false`.
safe_to_expose_on_stable: bool,
/// We indicate whether this is a function call, since we can use targeted
/// diagnostics for "callee is not safe to expose om stable".
is_function_call: bool,
},
Forbidden,
}
@ -40,9 +48,9 @@ pub enum DiagImportance {
Secondary,
}
/// An operation that is not *always* allowed in a const context.
/// An operation that is *not allowed* in a const context.
pub trait NonConstOp<'tcx>: std::fmt::Debug {
/// Returns an enum indicating whether this operation is allowed within the given item.
/// Returns an enum indicating whether this operation can be enabled with a feature gate.
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Forbidden
}
@ -298,30 +306,78 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
///
/// Contains the name of the feature that would allow the use of this function.
#[derive(Debug)]
pub(crate) struct FnCallUnstable(pub DefId, pub Option<Symbol>);
pub(crate) struct FnCallUnstable {
pub def_id: DefId,
pub feature: Symbol,
pub safe_to_expose_on_stable: bool,
}
impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable {
gate: self.feature,
safe_to_expose_on_stable: self.safe_to_expose_on_stable,
is_function_call: true,
}
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
let FnCallUnstable(def_id, feature) = *self;
let mut err = ccx
.dcx()
.create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) });
let mut err = ccx.dcx().create_err(errors::UnstableConstFn {
span,
def_path: ccx.tcx.def_path_str(self.def_id),
});
// FIXME: make this translatable
#[allow(rustc::untranslatable_diagnostic)]
if ccx.is_const_stable_const_fn() {
err.help(fluent_generated::const_eval_const_stable);
} else if ccx.tcx.sess.is_nightly_build() {
if let Some(feature) = feature {
err.help(format!("add `#![feature({feature})]` to the crate attributes to enable"));
}
}
err.help(format!("add `#![feature({})]` to the crate attributes to enable", self.feature));
err
}
}
/// A call to an intrinsic that is just not const-callable at all.
#[derive(Debug)]
pub(crate) struct IntrinsicNonConst {
pub name: Symbol,
}
impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
ccx.dcx().create_err(errors::NonConstIntrinsic {
span,
name: self.name,
kind: ccx.const_kind(),
})
}
}
/// A call to an intrinsic that is just not const-callable at all.
#[derive(Debug)]
pub(crate) struct IntrinsicUnstable {
pub name: Symbol,
pub feature: Symbol,
pub const_stable_indirect: bool,
}
impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable {
gate: self.feature,
safe_to_expose_on_stable: self.const_stable_indirect,
// We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
// that's not a trivial change!
is_function_call: false,
}
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
ccx.dcx().create_err(errors::UnstableIntrinsic {
span,
name: self.name,
feature: self.feature,
})
}
}
#[derive(Debug)]
pub(crate) struct Coroutine(pub hir::CoroutineKind);
impl<'tcx> NonConstOp<'tcx> for Coroutine {
@ -331,7 +387,11 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
hir::CoroutineSource::Block,
) = self.0
{
Status::Unstable(sym::const_async_blocks)
Status::Unstable {
gate: sym::const_async_blocks,
safe_to_expose_on_stable: false,
is_function_call: false,
}
} else {
Status::Forbidden
}

View File

@ -15,7 +15,7 @@ use crate::check_consts::rustc_allow_const_fn_unstable;
/// elaboration.
pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
// Const-stable functions must always use the stable live drop checker...
if ccx.is_const_stable_const_fn() {
if ccx.enforce_recursive_const_stability() {
// ...except if they have the feature flag set via `rustc_allow_const_fn_unstable`.
return rustc_allow_const_fn_unstable(
ccx.tcx,

View File

@ -1,25 +1,8 @@
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use {rustc_attr as attr, rustc_hir as hir};
/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable
/// it.
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option<Symbol>)> {
if tcx.is_const_fn_raw(def_id) {
let const_stab = tcx.lookup_const_stability(def_id)?;
match const_stab.level {
attr::StabilityLevel::Unstable { implied_by, .. } => {
Some((const_stab.feature, implied_by))
}
attr::StabilityLevel::Stable { .. } => None,
}
} else {
None
}
}
pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
let parent_id = tcx.local_parent(def_id);

View File

@ -219,7 +219,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
}
/// "Intercept" a function call, because we have something special to do for it.
/// All `#[rustc_do_not_const_check]` functions should be hooked here.
/// All `#[rustc_do_not_const_check]` functions MUST be hooked here.
/// If this returns `Some` function, which may be `instance` or a different function with
/// compatible arguments, then evaluation should continue with that function.
/// If this returns `None`, the function call has been handled and the function has returned.

View File

@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::{
UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
};
use rustc_middle::ty::{self, Mutability, Ty};
use rustc_span::Span;
use rustc_span::{Span, Symbol};
use rustc_target::abi::WrappingRange;
use rustc_target::abi::call::AdjustForForeignAbiError;
@ -44,11 +44,15 @@ pub(crate) struct MutablePtrInFinal {
}
#[derive(Diagnostic)]
#[diag(const_eval_unstable_in_stable)]
pub(crate) struct UnstableInStable {
#[diag(const_eval_unstable_in_stable_exposed)]
pub(crate) struct UnstableInStableExposed {
pub gate: String,
#[primary_span]
pub span: Span,
#[help(const_eval_is_function_call)]
pub is_function_call: bool,
/// Need to duplicate the field so that fluent also provides it as a variable...
pub is_function_call2: bool,
#[suggestion(
const_eval_unstable_sugg,
code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
@ -117,6 +121,34 @@ pub(crate) struct UnstableConstFn {
pub def_path: String,
}
#[derive(Diagnostic)]
#[diag(const_eval_unstable_intrinsic)]
#[help]
pub(crate) struct UnstableIntrinsic {
#[primary_span]
pub span: Span,
pub name: Symbol,
pub feature: Symbol,
}
#[derive(Diagnostic)]
#[diag(const_eval_unmarked_const_fn_exposed)]
#[help]
pub(crate) struct UnmarkedConstFnExposed {
#[primary_span]
pub span: Span,
pub def_path: String,
}
#[derive(Diagnostic)]
#[diag(const_eval_unmarked_intrinsic_exposed)]
#[help]
pub(crate) struct UnmarkedIntrinsicExposed {
#[primary_span]
pub span: Span,
pub def_path: String,
}
#[derive(Diagnostic)]
#[diag(const_eval_mutable_ref_escaping, code = E0764)]
pub(crate) struct MutableRefEscaping {
@ -153,6 +185,15 @@ pub(crate) struct NonConstFnCall {
pub kind: ConstContext,
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_intrinsic)]
pub(crate) struct NonConstIntrinsic {
#[primary_span]
pub span: Span,
pub name: Symbol,
pub kind: ConstContext,
}
#[derive(Diagnostic)]
#[diag(const_eval_unallowed_op_in_const_context)]
pub(crate) struct UnallowedOpInConstContext {

View File

@ -866,7 +866,9 @@ impl SyntaxExtension {
})
.unwrap_or_else(|| (None, helper_attrs));
let stability = attr::find_stability(sess, attrs, span);
let const_stability = attr::find_const_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 body_stability = attr::find_body_stability(sess, attrs);
if let Some((_, sp)) = const_stability {
sess.dcx().emit_err(errors::MacroConstStability {

View File

@ -617,11 +617,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
DuplicatesOk, EncodeCrossCrate::Yes,
"allow_internal_unstable side-steps feature gating and stability checks",
),
gated!(
rustc_allow_const_fn_unstable, Normal,
template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
),
gated!(
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
@ -838,6 +833,15 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_const_panic_str, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
),
rustc_attr!(
rustc_const_stable_indirect, Normal,
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
),
gated!(
rustc_allow_const_fn_unstable, Normal,
template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
),
// ==========================================================================
// Internal attributes, Layout related:

View File

@ -3128,7 +3128,7 @@ impl<'tcx> TyCtxt<'tcx> {
Some(stability) if stability.is_const_unstable() => {
// has a `rustc_const_unstable` attribute, check whether the user enabled the
// corresponding feature gate.
self.features().enabled(stability.feature)
stability.feature.is_some_and(|f| self.features().enabled(f))
}
// functions without const stability are either stable user written
// const fn or the user is using feature gates and we thus don't

View File

@ -99,6 +99,10 @@ passes_collapse_debuginfo =
passes_confusables = attribute should be applied to an inherent method
.label = not an inherent method
passes_const_stable_not_stable =
attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
.label = attribute specified here
passes_continue_labeled_block =
`continue` pointing to a labeled block
.label = labeled blocks cannot be `continue`'d
@ -465,10 +469,10 @@ passes_may_dangle =
`#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
passes_missing_const_err =
attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
.help = make the function or method const
.label = attribute specified here
passes_missing_const_stab_attr =
{$descr} has missing const stability attribute

View File

@ -1574,12 +1574,20 @@ pub(crate) struct DuplicateFeatureErr {
pub span: Span,
pub feature: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes_missing_const_err)]
pub(crate) struct MissingConstErr {
#[primary_span]
#[help]
pub fn_sig_span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_const_stable_not_stable)]
pub(crate) struct ConstStableNotStable {
#[primary_span]
pub fn_sig_span: Span,
#[label]
pub const_span: Span,
}

View File

@ -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::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_hir::{Constness, 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;
@ -27,7 +27,6 @@ use rustc_session::lint;
use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
use rustc_span::Span;
use rustc_span::symbol::{Symbol, sym};
use rustc_target::spec::abi::Abi;
use tracing::{debug, info};
use crate::errors;
@ -107,6 +106,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
def_id: LocalDefId,
item_sp: Span,
fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
is_foreign_item: bool,
kind: AnnotationKind,
inherit_deprecation: InheritDeprecation,
inherit_const_stability: InheritConstStability,
@ -163,30 +163,62 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
let stab = attr::find_stability(self.tcx.sess, attrs, item_sp);
let const_stab = attr::find_const_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);
let mut const_span = None;
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
self.index.const_stab_map.insert(def_id, const_stab);
const_span = Some(const_span_node);
const_stab
});
// If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
// check if the function/method is const or the parent impl block is const
if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig)
&& fn_sig.header.abi != Abi::RustIntrinsic
// 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()
// We have to exclude foreign items as they might be intrinsics. Sadly we can't check
// their ABI; `fn_sig.abi` is *not* correct for foreign functions.
&& !is_foreign_item
&& const_stab.is_some()
&& (!self.in_trait_impl || !self.tcx.is_const_fn_raw(def_id.to_def_id()))
{
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::MissingConstErr { fn_sig_span: fn_sig.span, const_span });
.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(effects): 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 {
@ -247,6 +279,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
}
// Stable *language* features shouldn't be used as unstable library features.
// (Not doing this for stable library features is checked by tidy.)
if let Stability { level: Unstable { .. }, feature } = stab {
if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
self.tcx
@ -260,21 +294,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
self.index.implications.insert(implied_by, feature);
}
if let Some(ConstStability { level: Unstable { .. }, feature, .. }) = const_stab {
if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
span: const_span.unwrap(), // If const_stab contains Some(..), same is true for const_span
item_sp,
});
}
}
if let Some(ConstStability {
level: Unstable { implied_by: Some(implied_by), .. },
feature,
..
}) = const_stab
{
self.index.implications.insert(implied_by, feature);
self.index.implications.insert(implied_by, feature.unwrap());
}
self.index.stab_map.insert(def_id, stab);
@ -372,6 +398,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
ctor_def_id,
i.span,
None,
/* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -390,6 +417,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
i.owner_id.def_id,
i.span,
fn_sig,
/* is_foreign_item */ false,
kind,
InheritDeprecation::Yes,
const_stab_inherit,
@ -409,6 +437,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
ti.owner_id.def_id,
ti.span,
fn_sig,
/* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -432,6 +461,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
ii.owner_id.def_id,
ii.span,
fn_sig,
/* is_foreign_item */ false,
kind,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -447,6 +477,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
var.def_id,
var.span,
None,
/* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -457,6 +488,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
ctor_def_id,
var.span,
None,
/* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -475,6 +507,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
s.def_id,
s.span,
None,
/* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -486,10 +519,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
}
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
let fn_sig = match &i.kind {
rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig),
_ => None,
};
self.annotate(
i.owner_id.def_id,
i.span,
None,
fn_sig,
/* is_foreign_item */ true,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -512,6 +550,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
p.def_id,
p.span,
None,
/* is_foreign_item */ false,
kind,
InheritDeprecation::No,
InheritConstStability::No,
@ -540,7 +579,9 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
}
}
fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
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;
}
@ -553,11 +594,12 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
return;
}
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
let is_const = self.tcx.is_const_fn_raw(def_id.to_def_id())
|| self.tcx.is_const_trait_impl_raw(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();
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 {
let descr = self.tcx.def_descr(def_id.to_def_id());
@ -587,7 +629,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
}
// Ensure stable `const fn` have a const stability attribute.
self.check_missing_const_stability(i.owner_id.def_id, i.span);
self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span);
intravisit::walk_item(self, i)
}
@ -601,7 +643,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_const_stability(ii.owner_id.def_id, ii.span);
self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span);
}
intravisit::walk_impl_item(self, ii);
}
@ -670,6 +712,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
CRATE_DEF_ID,
tcx.hir().span(CRATE_HIR_ID),
None,
/* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@ -732,12 +775,23 @@ 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 { of_trait: Some(ref t), self_ty, items, .. }) => {
hir::ItemKind::Impl(hir::Impl {
constness,
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);
let const_stab = attr::find_const_stability(
self.tcx.sess,
attrs,
item.span,
matches!(constness, Constness::Const),
);
// If this impl block has an #[unstable] attribute, give an
// error if all involved types and traits are stable, because

View File

@ -1660,6 +1660,7 @@ symbols! {
rustc_confusables,
rustc_const_panic_str,
rustc_const_stable,
rustc_const_stable_indirect,
rustc_const_unstable,
rustc_conversion_suggestion,
rustc_deallocator,

View File

@ -103,7 +103,7 @@ impl<T> RawVec<T, Global> {
/// `RawVec` with capacity `usize::MAX`. Useful for implementing
/// delayed allocation.
#[must_use]
#[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
pub const fn new() -> Self {
Self::new_in(Global)
}
@ -179,7 +179,7 @@ impl<T, A: Allocator> RawVec<T, A> {
/// Like `new`, but parameterized over the choice of allocator for
/// the returned `RawVec`.
#[inline]
#[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
pub const fn new_in(alloc: A) -> Self {
Self { inner: RawVecInner::new_in(alloc, align_of::<T>()), _marker: PhantomData }
}
@ -409,7 +409,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
impl<A: Allocator> RawVecInner<A> {
#[inline]
#[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
const fn new_in(alloc: A, align: usize) -> Self {
let ptr = unsafe { core::mem::transmute(align) };
// `cap: 0` means "unallocated". zero-sized types are ignored.

View File

@ -66,7 +66,6 @@ impl Layout {
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
#[inline]
#[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
if Layout::is_size_align_valid(size, align) {
// SAFETY: Layout::is_size_align_valid checks the preconditions for this call.
@ -127,7 +126,6 @@ impl Layout {
#[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")]
#[must_use]
#[inline]
#[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
assert_unsafe_precondition!(
check_library_ub,
@ -159,7 +157,7 @@ impl Layout {
#[must_use = "this returns the minimum alignment, \
without modifying the layout"]
#[inline]
#[rustc_allow_const_fn_unstable(ptr_alignment_type)]
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(ptr_alignment_type))]
pub const fn align(&self) -> usize {
self.align.as_usize()
}

View File

@ -2287,6 +2287,7 @@ impl<T> SyncUnsafeCell<T> {
/// Unwraps the value, consuming the cell.
#[inline]
#[rustc_const_unstable(feature = "sync_unsafe_cell", issue = "95439")]
pub const fn into_inner(self) -> T {
self.value.into_inner()
}

View File

@ -79,6 +79,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
/// ```
#[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
#[rustc_const_unstable(feature = "lazy_cell_into_inner", issue = "125623")]
pub const fn into_inner(this: Self) -> Result<T, F> {
match this.state.into_inner() {
State::Init(data) => Ok(data),

View File

@ -1770,7 +1770,7 @@ const fn len_utf16(code: u32) -> usize {
/// Panics if the buffer is not large enough.
/// A buffer of length four is large enough to encode any `char`.
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
#[rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0"))]
#[doc(hidden)]
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]

View File

@ -137,11 +137,11 @@ enum FromBytesWithNulErrorKind {
// FIXME: const stability attributes should not be required here, I think
impl FromBytesWithNulError {
#[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))]
const fn interior_nul(pos: usize) -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
}
#[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))]
const fn not_nul_terminated() -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
}
@ -730,7 +730,7 @@ impl AsRef<CStr> for CStr {
/// located within `isize::MAX` from `ptr`.
#[inline]
#[unstable(feature = "cstr_internals", issue = "none")]
#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const unsafe fn strlen(ptr: *const c_char) -> usize {
const fn strlen_ct(s: *const c_char) -> usize {

View File

@ -333,7 +333,10 @@ pub struct Arguments<'a> {
#[unstable(feature = "fmt_internals", issue = "none")]
impl<'a> Arguments<'a> {
#[inline]
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
#[cfg_attr(
bootstrap,
rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")
)]
pub const fn new_const<const N: usize>(pieces: &'a [&'static str; N]) -> Self {
const { assert!(N <= 1) };
Arguments { pieces, fmt: None, args: &[] }
@ -438,6 +441,7 @@ impl<'a> Arguments<'a> {
#[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
#[must_use]
#[inline]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
pub const fn as_str(&self) -> Option<&'static str> {
match (self.pieces, self.args) {
([], []) => Some(""),

View File

@ -506,7 +506,7 @@ pub const fn black_box<T>(dummy: T) -> T {
/// # }
/// ```
#[unstable(feature = "hint_must_use", issue = "94745")]
#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "hint_must_use", issue = "94745"))]
#[must_use] // <-- :)
#[inline(always)]
pub const fn must_use<T>(value: T) -> T {

View File

@ -14,9 +14,10 @@
//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
//!
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
//! without T-lang consultation, because it bakes a feature into the language that cannot be
//! replicated in user code without compiler support.
//! `#[rustc_const_stable_indirect]` needs to be added to the intrinsic (`#[rustc_const_unstable]`
//! can be removed then). Such a change should not be done without T-lang consultation, because it
//! may bake a feature into the language that cannot be replicated in user code without compiler
//! support.
//!
//! # Volatiles
//!
@ -943,7 +944,11 @@ extern "rust-intrinsic" {
/// reach code marked with this function.
///
/// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`].
#[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
#[cfg_attr(
bootstrap,
rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")
)]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unreachable() -> !;
}
@ -958,7 +963,8 @@ extern "rust-intrinsic" {
/// own, or if it does not enable any significant optimizations.
///
/// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`].
#[rustc_const_stable(feature = "const_assume", since = "1.77.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
@ -980,7 +986,8 @@ pub const unsafe fn assume(b: bool) {
/// any safety invariants.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_likely", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
@ -1000,7 +1007,8 @@ pub const fn likely(b: bool) -> bool {
/// any safety invariants.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_likely", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
@ -1041,7 +1049,8 @@ extern "rust-intrinsic" {
/// This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn assert_inhabited<T>();
@ -1050,7 +1059,8 @@ extern "rust-intrinsic" {
/// zero-initialization: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn assert_zero_valid<T>();
@ -1058,7 +1068,8 @@ extern "rust-intrinsic" {
/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn assert_mem_uninitialized_valid<T>();
@ -1071,7 +1082,8 @@ extern "rust-intrinsic" {
/// any safety invariants.
///
/// Consider using [`core::panic::Location::caller`] instead.
#[rustc_const_stable(feature = "const_caller_location", since = "1.79.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn caller_location() -> &'static crate::panic::Location<'static>;
@ -1085,7 +1097,8 @@ extern "rust-intrinsic" {
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
#[rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn forget<T: ?Sized>(_: T);
@ -1391,7 +1404,8 @@ extern "rust-intrinsic" {
///
/// This is not expected to ever be exposed directly to users, rather it
/// may eventually be exposed through some more-constrained API.
#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn transmute_unchecked<Src, Dst>(src: Src) -> Dst;
@ -1408,7 +1422,8 @@ extern "rust-intrinsic" {
/// any safety invariants.
///
/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
#[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn needs_drop<T: ?Sized>() -> bool;
@ -1430,7 +1445,8 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is [`pointer::offset`].
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
@ -1448,7 +1464,8 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is [`pointer::wrapping_offset`].
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
@ -2131,7 +2148,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `count_ones` method. For example,
/// [`u32::count_ones`]
#[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn ctpop<T: Copy>(x: T) -> u32;
@ -2172,7 +2190,8 @@ extern "rust-intrinsic" {
/// let num_leading = ctlz(x);
/// assert_eq!(num_leading, 16);
/// ```
#[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn ctlz<T: Copy>(x: T) -> u32;
@ -2194,7 +2213,8 @@ extern "rust-intrinsic" {
/// let num_leading = unsafe { ctlz_nonzero(x) };
/// assert_eq!(num_leading, 3);
/// ```
#[rustc_const_stable(feature = "constctlz", since = "1.50.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn ctlz_nonzero<T: Copy>(x: T) -> u32;
@ -2234,7 +2254,8 @@ extern "rust-intrinsic" {
/// let num_trailing = cttz(x);
/// assert_eq!(num_trailing, 16);
/// ```
#[rustc_const_stable(feature = "const_cttz", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn cttz<T: Copy>(x: T) -> u32;
@ -2256,7 +2277,8 @@ extern "rust-intrinsic" {
/// let num_trailing = unsafe { cttz_nonzero(x) };
/// assert_eq!(num_trailing, 3);
/// ```
#[rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn cttz_nonzero<T: Copy>(x: T) -> u32;
@ -2270,7 +2292,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `swap_bytes` method. For example,
/// [`u32::swap_bytes`]
#[rustc_const_stable(feature = "const_bswap", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn bswap<T: Copy>(x: T) -> T;
@ -2285,7 +2308,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `reverse_bits` method. For example,
/// [`u32::reverse_bits`]
#[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn bitreverse<T: Copy>(x: T) -> T;
@ -2311,7 +2335,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_add` method. For example,
/// [`u32::overflowing_add`]
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@ -2326,7 +2351,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_sub` method. For example,
/// [`u32::overflowing_sub`]
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@ -2341,7 +2367,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_mul` method. For example,
/// [`u32::overflowing_mul`]
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@ -2360,7 +2387,11 @@ extern "rust-intrinsic" {
/// Safe wrappers for this intrinsic are available on the integer
/// primitives via the `checked_div` method. For example,
/// [`u32::checked_div`]
#[rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")]
#[cfg_attr(
bootstrap,
rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")
)]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_div<T: Copy>(x: T, y: T) -> T;
/// Returns the remainder of an unchecked division, resulting in
@ -2369,7 +2400,11 @@ extern "rust-intrinsic" {
/// Safe wrappers for this intrinsic are available on the integer
/// primitives via the `checked_rem` method. For example,
/// [`u32::checked_rem`]
#[rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")]
#[cfg_attr(
bootstrap,
rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")
)]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_rem<T: Copy>(x: T, y: T) -> T;
@ -2379,7 +2414,8 @@ extern "rust-intrinsic" {
/// Safe wrappers for this intrinsic are available on the integer
/// primitives via the `checked_shl` method. For example,
/// [`u32::checked_shl`]
#[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_shl<T: Copy, U: Copy>(x: T, y: U) -> T;
/// Performs an unchecked right shift, resulting in undefined behavior when
@ -2388,7 +2424,8 @@ extern "rust-intrinsic" {
/// Safe wrappers for this intrinsic are available on the integer
/// primitives via the `checked_shr` method. For example,
/// [`u32::checked_shr`]
#[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_shr<T: Copy, U: Copy>(x: T, y: U) -> T;
@ -2397,7 +2434,8 @@ extern "rust-intrinsic" {
///
/// The stable counterpart of this intrinsic is `unchecked_add` on the various
/// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`].
#[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_add<T: Copy>(x: T, y: T) -> T;
@ -2406,7 +2444,8 @@ extern "rust-intrinsic" {
///
/// The stable counterpart of this intrinsic is `unchecked_sub` on the various
/// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`].
#[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T;
@ -2415,7 +2454,8 @@ extern "rust-intrinsic" {
///
/// The stable counterpart of this intrinsic is `unchecked_mul` on the various
/// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`].
#[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T;
@ -2429,7 +2469,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `rotate_left` method. For example,
/// [`u32::rotate_left`]
#[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn rotate_left<T: Copy>(x: T, shift: u32) -> T;
@ -2444,7 +2485,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `rotate_right` method. For example,
/// [`u32::rotate_right`]
#[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn rotate_right<T: Copy>(x: T, shift: u32) -> T;
@ -2459,7 +2501,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_add` method. For example,
/// [`u32::wrapping_add`]
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
@ -2473,7 +2516,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_sub` method. For example,
/// [`u32::wrapping_sub`]
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
@ -2487,7 +2531,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_mul` method. For example,
/// [`u32::wrapping_mul`]
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
@ -2502,7 +2547,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `saturating_add` method. For example,
/// [`u32::saturating_add`]
#[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn saturating_add<T: Copy>(a: T, b: T) -> T;
@ -2516,7 +2562,8 @@ extern "rust-intrinsic" {
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `saturating_sub` method. For example,
/// [`u32::saturating_sub`]
#[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
@ -2527,7 +2574,8 @@ extern "rust-intrinsic" {
/// This intrinsic can *only* be called where the pointer is a local without
/// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it
/// trivially obeys runtime-MIR rules about derefs in operands.
#[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn read_via_copy<T>(ptr: *const T) -> T;
@ -2537,7 +2585,8 @@ extern "rust-intrinsic" {
/// This intrinsic can *only* be called where the pointer is a local without
/// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so
/// that it trivially obeys runtime-MIR rules about derefs in operands.
#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn write_via_move<T>(ptr: *mut T, value: T);
@ -2550,7 +2599,8 @@ extern "rust-intrinsic" {
/// any safety invariants.
///
/// The stabilized version of this intrinsic is [`core::mem::discriminant`].
#[rustc_const_stable(feature = "const_discriminant", since = "1.75.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
@ -2584,7 +2634,8 @@ extern "rust-intrinsic" {
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
/// See documentation of `<*const T>::offset_from` for details.
#[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
@ -2850,7 +2901,8 @@ pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
/// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the
/// user has UB checks disabled, the checks will still get optimized out. This intrinsic is
/// primarily used by [`ub_checks::assert_unsafe_precondition`].
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // just for UB checks
#[unstable(feature = "core_intrinsics", issue = "none")]
#[inline(always)]
#[rustc_intrinsic]
@ -2935,7 +2987,8 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize {
/// The stabilized version of this intrinsic is [`core::mem::size_of`].
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const fn size_of<T>() -> usize {
@ -2952,7 +3005,8 @@ pub const fn size_of<T>() -> usize {
/// The stabilized version of this intrinsic is [`core::mem::align_of`].
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const fn min_align_of<T>() -> usize {
@ -3065,7 +3119,8 @@ pub const fn type_id<T: ?Sized + 'static>() -> u128 {
/// change the possible layouts of pointers.
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P {
@ -3090,7 +3145,11 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
/// This is used to implement functions like `ptr::metadata`.
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
#[cfg_attr(
bootstrap,
cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))
)]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
@ -3197,7 +3256,15 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *cons
#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
#[cfg_attr(
bootstrap,
rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")
)]
#[cfg_attr(
not(bootstrap),
rustc_const_unstable(feature = "core_intrinsics", issue = "none")
)]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
}
@ -3301,7 +3368,15 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
#[rustc_diagnostic_item = "ptr_copy"]
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
#[cfg_attr(
bootstrap,
rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")
)]
#[cfg_attr(
not(bootstrap),
rustc_const_unstable(feature = "core_intrinsics", issue = "none")
)]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
@ -3382,7 +3457,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
#[rustc_diagnostic_item = "ptr_write_bytes"]
pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
extern "rust-intrinsic" {
#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
}
@ -3643,6 +3719,7 @@ pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 {
/// Inform Miri that a given pointer definitely has a certain alignment.
#[cfg(miri)]
#[rustc_allow_const_fn_unstable(const_eval_select)]
pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) {
extern "Rust" {
/// Miri-provided extern function to promise that a given pointer is properly aligned for

View File

@ -346,7 +346,6 @@ pub trait IntoIterator {
fn into_iter(self) -> Self::IntoIter;
}
#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> IntoIterator for I {
type Item = I::Item;

View File

@ -107,6 +107,7 @@
//
// Library features:
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))]
#![feature(array_ptr_get)]
#![feature(asm_experimental_arch)]
#![feature(const_align_of_val)]
@ -121,11 +122,8 @@
#![feature(const_eval_select)]
#![feature(const_exact_div)]
#![feature(const_float_methods)]
#![feature(const_fmt_arguments_new)]
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_index_range_slice_index)]
#![feature(const_likely)]
#![feature(const_nonnull_new)]
#![feature(const_num_midpoint)]
#![feature(const_option_ext)]
@ -144,6 +142,7 @@
#![feature(const_typed_swap)]
#![feature(const_ub_checks)]
#![feature(const_unicode_case_lookup)]
#![feature(core_intrinsics)]
#![feature(coverage_attribute)]
#![feature(do_not_recommend)]
#![feature(internal_impls_macro)]
@ -159,6 +158,7 @@
#![feature(ptr_alignment_type)]
#![feature(ptr_metadata)]
#![feature(set_ptr_value)]
#![feature(slice_as_chunks)]
#![feature(slice_ptr_get)]
#![feature(str_internals)]
#![feature(str_split_inclusive_remainder)]

View File

@ -373,6 +373,7 @@ impl IpAddr {
/// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
/// ```
#[unstable(feature = "ip", issue = "27709")]
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
#[must_use]
#[inline]
pub const fn is_benchmarking(&self) -> bool {

View File

@ -288,7 +288,6 @@ impl f128 {
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub(crate) const fn abs_private(self) -> f128 {
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe {
@ -319,7 +318,6 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_infinite(self) -> bool {
(self == f128::INFINITY) | (self == f128::NEG_INFINITY)
}
@ -346,7 +344,6 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_finite(self) -> bool {
// There's no need to handle NaN separately: if self is NaN,
// the comparison is not true, exactly as desired.
@ -380,7 +377,6 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_subnormal(self) -> bool {
matches!(self.classify(), FpCategory::Subnormal)
}
@ -412,7 +408,6 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_normal(self) -> bool {
matches!(self.classify(), FpCategory::Normal)
}
@ -437,7 +432,6 @@ impl f128 {
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn classify(self) -> FpCategory {
let bits = self.to_bits();
match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
@ -915,7 +909,6 @@ impl f128 {
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_bits(self) -> u128 {
// SAFETY: `u128` is a plain old datatype so we can always transmute to it.
@ -964,7 +957,6 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn from_bits(v: u128) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
// SAFETY: `u128` is a plain old datatype so we can always transmute from it.
@ -991,7 +983,6 @@ impl f128 {
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_be_bytes(self) -> [u8; 16] {
self.to_bits().to_be_bytes()
@ -1017,7 +1008,6 @@ impl f128 {
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_le_bytes(self) -> [u8; 16] {
self.to_bits().to_le_bytes()
@ -1054,7 +1044,6 @@ impl f128 {
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_ne_bytes(self) -> [u8; 16] {
self.to_bits().to_ne_bytes()
@ -1082,7 +1071,6 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn from_be_bytes(bytes: [u8; 16]) -> Self {
Self::from_bits(u128::from_be_bytes(bytes))
}
@ -1109,7 +1097,6 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {
Self::from_bits(u128::from_le_bytes(bytes))
}
@ -1146,7 +1133,6 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self {
Self::from_bits(u128::from_ne_bytes(bytes))
}

View File

@ -282,7 +282,6 @@ impl f16 {
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub(crate) const fn abs_private(self) -> f16 {
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) }
@ -310,7 +309,6 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_infinite(self) -> bool {
(self == f16::INFINITY) | (self == f16::NEG_INFINITY)
}
@ -336,7 +334,6 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_finite(self) -> bool {
// There's no need to handle NaN separately: if self is NaN,
// the comparison is not true, exactly as desired.
@ -368,7 +365,6 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_subnormal(self) -> bool {
matches!(self.classify(), FpCategory::Subnormal)
}
@ -398,7 +394,6 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_normal(self) -> bool {
matches!(self.classify(), FpCategory::Normal)
}
@ -422,7 +417,6 @@ impl f16 {
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn classify(self) -> FpCategory {
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
@ -901,7 +895,6 @@ impl f16 {
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_bits(self) -> u16 {
// SAFETY: `u16` is a plain old datatype so we can always transmute to it.
@ -949,7 +942,6 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn from_bits(v: u16) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
// SAFETY: `u16` is a plain old datatype so we can always transmute from it.
@ -975,7 +967,6 @@ impl f16 {
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_be_bytes(self) -> [u8; 2] {
self.to_bits().to_be_bytes()
@ -1000,7 +991,6 @@ impl f16 {
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_le_bytes(self) -> [u8; 2] {
self.to_bits().to_le_bytes()
@ -1038,7 +1028,6 @@ impl f16 {
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_ne_bytes(self) -> [u8; 2] {
self.to_bits().to_ne_bytes()
@ -1062,7 +1051,6 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn from_be_bytes(bytes: [u8; 2]) -> Self {
Self::from_bits(u16::from_be_bytes(bytes))
}
@ -1085,7 +1073,6 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn from_le_bytes(bytes: [u8; 2]) -> Self {
Self::from_bits(u16::from_le_bytes(bytes))
}
@ -1119,7 +1106,6 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self {
Self::from_bits(u16::from_ne_bytes(bytes))
}

View File

@ -16,7 +16,7 @@ macro_rules! try_opt {
};
}
#[allow_internal_unstable(const_likely)]
#[cfg_attr(bootstrap, allow_internal_unstable(const_likely))]
macro_rules! unlikely {
($e: expr) => {
intrinsics::unlikely($e)
@ -1397,7 +1397,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
#[doc(hidden)]
#[inline(always)]
#[unstable(issue = "none", feature = "std_internals")]
#[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_from_str", since = "1.82.0"))]
pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
}
@ -1416,6 +1416,7 @@ fn from_str_radix_panic_rt(radix: u32) -> ! {
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn from_str_radix_panic(radix: u32) {
// The only difference between these two functions is their panic message.
intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt);

View File

@ -3009,7 +3009,7 @@ macro_rules! uint_impl {
// overflow cases it instead ends up returning the maximum value
// of the type, and can return 0 for 0.
#[inline]
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_pow", since = "1.50.0"))]
const fn one_less_than_next_power_of_two(self) -> Self {
if self <= 1 { return 0; }

View File

@ -168,6 +168,7 @@ impl<'a> PanicMessage<'a> {
#[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
#[must_use]
#[inline]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
pub const fn as_str(&self) -> Option<&'static str> {
self.message.as_str()
}

View File

@ -50,7 +50,8 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C
#[track_caller]
#[lang = "panic_fmt"] // needed for const-evaluated panics
#[rustc_do_not_const_check] // hooked by const-eval
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
@ -84,7 +85,9 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
// which causes a "panic in a function that cannot unwind".
#[rustc_nounwind]
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
#[rustc_allow_const_fn_unstable(const_eval_select)]
pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
#[inline] // this should always be inlined into `panic_nounwind_fmt`
#[track_caller]
@ -131,7 +134,8 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
#[lang = "panic"] // used by lints and miri for panics
pub const fn panic(expr: &'static str) -> ! {
// Use Arguments::new_const instead of format_args!("{expr}") to potentially
@ -169,7 +173,8 @@ macro_rules! panic_const {
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
#[lang = stringify!($lang)]
pub const fn $lang() -> ! {
// Use Arguments::new_const instead of format_args!("{expr}") to potentially
@ -216,7 +221,8 @@ panic_const! {
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
#[rustc_nounwind]
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_nounwind(expr: &'static str) -> ! {
panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false);
}
@ -232,7 +238,8 @@ pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
#[track_caller]
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_explicit() -> ! {
panic_display(&"explicit panic");
}
@ -249,7 +256,8 @@ pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
#[inline]
#[track_caller]
#[rustc_diagnostic_item = "panic_str_2015"]
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_str_2015(expr: &str) -> ! {
panic_display(&expr);
}
@ -259,7 +267,8 @@ pub const fn panic_str_2015(expr: &str) -> ! {
#[rustc_do_not_const_check] // hooked by const-eval
// enforce a &&str argument in const-check and hook this by const-eval
#[rustc_const_panic_str]
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
panic_fmt(format_args!("{}", *x));
}
@ -327,8 +336,9 @@ fn panic_in_cleanup() -> ! {
}
/// This function is used instead of panic_fmt in const eval.
#[lang = "const_panic_fmt"]
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
#[lang = "const_panic_fmt"] // needed by const-eval machine to replace calls to `panic_fmt` lang item
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if let Some(msg) = fmt.as_str() {
// The panic_display function is hooked by const eval.

View File

@ -41,7 +41,7 @@ impl Alignment {
/// This provides the same numerical value as [`mem::align_of`],
/// but in an `Alignment` instead of a `usize`.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn of<T>() -> Self {
// SAFETY: rustc ensures that type alignment is always a power of two.
@ -53,7 +53,7 @@ impl Alignment {
///
/// Note that `0` is not a power of two, nor a valid alignment.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn new(align: usize) -> Option<Self> {
if align.is_power_of_two() {
@ -73,7 +73,7 @@ impl Alignment {
/// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`.
/// It must *not* be zero.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const unsafe fn new_unchecked(align: usize) -> Self {
assert_unsafe_precondition!(
@ -89,7 +89,7 @@ impl Alignment {
/// Returns the alignment as a [`usize`].
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn as_usize(self) -> usize {
self.0 as usize
@ -97,7 +97,7 @@ impl Alignment {
/// Returns the alignment as a <code>[NonZero]<[usize]></code>.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn as_nonzero(self) -> NonZero<usize> {
// SAFETY: All the discriminants are non-zero.
@ -118,7 +118,7 @@ impl Alignment {
/// assert_eq!(Alignment::new(1024).unwrap().log2(), 10);
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros()
@ -148,7 +148,7 @@ impl Alignment {
/// assert_ne!(one.mask(Alignment::of::<Align4>().mask()), one);
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn mask(self) -> usize {
// SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.

View File

@ -39,6 +39,7 @@ impl<T: ?Sized> *const T {
}
#[inline]
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
const fn const_impl(ptr: *const u8) -> bool {
match (ptr).guaranteed_eq(null_mut()) {
Some(res) => res,
@ -113,7 +114,7 @@ impl<T: ?Sized> *const T {
/// println!("{:?}", unsafe { &*bad });
/// ```
#[unstable(feature = "set_ptr_value", issue = "75091")]
#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[inline]
pub const fn with_metadata_of<U>(self, meta: *const U) -> *const U
@ -409,6 +410,7 @@ impl<T: ?Sized> *const T {
T: Sized,
{
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: isize, size: usize) -> bool {
@ -761,6 +763,7 @@ impl<T: ?Sized> *const T {
where
T: Sized,
{
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_ptr_ge(this: *const (), origin: *const ()) -> bool {
fn runtime(this: *const (), origin: *const ()) -> bool {
this >= origin
@ -902,6 +905,7 @@ impl<T: ?Sized> *const T {
{
#[cfg(debug_assertions)]
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: usize, size: usize) -> bool {
@ -1010,6 +1014,7 @@ impl<T: ?Sized> *const T {
{
#[cfg(debug_assertions)]
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: usize, size: usize) -> bool {
@ -1622,6 +1627,7 @@ impl<T: ?Sized> *const T {
}
#[inline]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
const fn const_impl(ptr: *const (), align: usize) -> bool {
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
ptr.align_offset(align) == 0

View File

@ -92,7 +92,7 @@ pub trait Thin = Pointee<Metadata = ()>;
///
/// assert_eq!(std::ptr::metadata("foo"), 3_usize);
/// ```
#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[inline]
pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
ptr_metadata(ptr)
@ -106,7 +106,7 @@ pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
///
/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
#[unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[inline]
pub const fn from_raw_parts<T: ?Sized>(
data_pointer: *const impl Thin,
@ -120,7 +120,7 @@ pub const fn from_raw_parts<T: ?Sized>(
///
/// See the documentation of [`from_raw_parts`] for more details.
#[unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[inline]
pub const fn from_raw_parts_mut<T: ?Sized>(
data_pointer: *mut impl Thin,

View File

@ -591,8 +591,8 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn without_provenance<T>(addr: usize) -> *const T {
// An int-to-pointer transmute currently has exactly the intended semantics: it creates a
// pointer without provenance. Note that this is *not* a stable guarantee about transmute
@ -613,8 +613,8 @@ pub const fn without_provenance<T>(addr: usize) -> *const T {
/// some other means.
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn dangling<T>() -> *const T {
without_provenance(mem::align_of::<T>())
}
@ -634,8 +634,8 @@ pub const fn dangling<T>() -> *const T {
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
// An int-to-pointer transmute currently has exactly the intended semantics: it creates a
// pointer without provenance. Note that this is *not* a stable guarantee about transmute
@ -656,8 +656,8 @@ pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
/// some other means.
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn dangling_mut<T>() -> *mut T {
without_provenance_mut(mem::align_of::<T>())
}
@ -1854,6 +1854,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
/// Any questions go to @nagisa.
#[allow(ptr_to_integer_transmute_in_consts)]
#[lang = "align_offset"]
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
// 1, where the method versions of these operations are not inlined.

View File

@ -94,7 +94,7 @@ impl<T: ?Sized> *mut T {
/// // This dereference is UB. The pointer only has provenance for `x` but points to `y`.
/// println!("{:?}", unsafe { &*bad });
#[unstable(feature = "set_ptr_value", issue = "75091")]
#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[inline]
pub const fn with_metadata_of<U>(self, meta: *const U) -> *mut U
@ -405,6 +405,7 @@ impl<T: ?Sized> *mut T {
T: Sized,
{
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: isize, size: usize) -> bool {
@ -984,6 +985,7 @@ impl<T: ?Sized> *mut T {
{
#[cfg(debug_assertions)]
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: usize, size: usize) -> bool {
@ -1092,6 +1094,7 @@ impl<T: ?Sized> *mut T {
{
#[cfg(debug_assertions)]
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: usize, size: usize) -> bool {
@ -1871,6 +1874,7 @@ impl<T: ?Sized> *mut T {
}
#[inline]
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
const fn const_impl(ptr: *mut (), align: usize) -> bool {
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
ptr.align_offset(align) == 0

View File

@ -1508,7 +1508,6 @@ impl<T> NonNull<[T]> {
#[inline]
#[must_use]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
pub const fn as_non_null_ptr(self) -> NonNull<T> {
self.cast()
}

View File

@ -92,6 +92,7 @@ impl<T: ?Sized> Unique<T> {
/// Creates a new `Unique` if `ptr` is non-null.
#[inline]
#[rustc_const_unstable(feature = "ptr_internals", issue = "none")]
pub const fn new(ptr: *mut T) -> Option<Self> {
if let Some(pointer) = NonNull::new(ptr) {
Some(Unique { pointer, _marker: PhantomData })

View File

@ -346,6 +346,8 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
/// If any of these loads produces something for which `contains_nonascii`
/// (above) returns true, then we know the answer is false.
#[inline]
#[rustc_allow_const_fn_unstable(const_raw_ptr_comparison, const_pointer_is_aligned)] // only in a debug assertion
#[rustc_allow_const_fn_unstable(const_align_offset)] // behavior does not change when `align_offset` fails
const fn is_ascii(s: &[u8]) -> bool {
const USIZE_SIZE: usize = mem::size_of::<usize>();

View File

@ -31,6 +31,7 @@ where
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
// FIXME(const-hack): once integer formatting in panics is possible, we
// should use the same implementation at compiletime and runtime.
@ -52,6 +53,7 @@ const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
// FIXME(const-hack): once integer formatting in panics is possible, we
// should use the same implementation at compiletime and runtime.
@ -73,6 +75,7 @@ const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
// FIXME(const-hack): once integer formatting in panics is possible, we
// should use the same implementation at compiletime and runtime.
@ -310,7 +313,6 @@ unsafe impl<T> SliceIndex<[T]> for usize {
/// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here
/// than there are for a general `Range<usize>` (which might be `100..3`).
#[rustc_const_unstable(feature = "const_index_range_slice_index", issue = "none")]
unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
type Output = [T];

View File

@ -15,7 +15,7 @@ const USIZE_BYTES: usize = mem::size_of::<usize>();
/// bytes where the borrow propagated all the way to the most significant
/// bit."
#[inline]
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
const fn contains_zero_byte(x: usize) -> bool {
x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
}
@ -23,7 +23,7 @@ const fn contains_zero_byte(x: usize) -> bool {
/// Returns the first index matching the byte `x` in `text`.
#[inline]
#[must_use]
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
// Fast path for small slices.
if text.len() < 2 * USIZE_BYTES {
@ -34,7 +34,7 @@ pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
}
#[inline]
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
let mut i = 0;
@ -52,7 +52,7 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
#[rustc_allow_const_fn_unstable(const_cmp)]
#[rustc_allow_const_fn_unstable(const_align_offset)]
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
// Scan for a single byte value by reading two `usize` words at a time.
//

View File

@ -1265,6 +1265,7 @@ impl<T> [T] {
/// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[must_use]
pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
@ -1310,6 +1311,7 @@ impl<T> [T] {
/// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@ -1344,6 +1346,7 @@ impl<T> [T] {
/// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@ -1422,6 +1425,7 @@ impl<T> [T] {
/// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[must_use]
pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
@ -1462,6 +1466,7 @@ impl<T> [T] {
/// assert_eq!(v, &[1, 1, 2, 2, 9]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@ -1502,6 +1507,7 @@ impl<T> [T] {
/// assert_eq!(v, &[9, 1, 1, 2, 2]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]

View File

@ -2122,7 +2122,8 @@ macro_rules! atomic_int {
$stable_access:meta,
$stable_from:meta,
$stable_nand:meta,
$const_stable:meta,
$const_stable_new:meta,
$const_stable_into_inner:meta,
$diagnostic_item:meta,
$s_int_type:literal,
$extra_feature:expr,
@ -2204,7 +2205,7 @@ macro_rules! atomic_int {
/// ```
#[inline]
#[$stable]
#[$const_stable]
#[$const_stable_new]
#[must_use]
pub const fn new(v: $int_type) -> Self {
Self {v: UnsafeCell::new(v)}
@ -2406,7 +2407,7 @@ macro_rules! atomic_int {
/// ```
#[inline]
#[$stable_access]
#[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
#[$const_stable_into_inner]
pub const fn into_inner(self) -> $int_type {
self.v.into_inner()
}
@ -3054,6 +3055,7 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"),
"i8",
"",
@ -3072,6 +3074,7 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"),
"u8",
"",
@ -3090,6 +3093,7 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"),
"i16",
"",
@ -3108,6 +3112,7 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"),
"u16",
"",
@ -3126,6 +3131,7 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"),
"i32",
"",
@ -3144,6 +3150,7 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"),
"u32",
"",
@ -3162,6 +3169,7 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"),
"i64",
"",
@ -3180,6 +3188,7 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"),
"u64",
"",
@ -3197,7 +3206,8 @@ atomic_int! {
unstable(feature = "integer_atomics", issue = "99069"),
unstable(feature = "integer_atomics", issue = "99069"),
unstable(feature = "integer_atomics", issue = "99069"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
"i128",
"#![feature(integer_atomics)]\n\n",
@ -3215,7 +3225,8 @@ atomic_int! {
unstable(feature = "integer_atomics", issue = "99069"),
unstable(feature = "integer_atomics", issue = "99069"),
unstable(feature = "integer_atomics", issue = "99069"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
"u128",
"#![feature(integer_atomics)]\n\n",
@ -3238,6 +3249,7 @@ macro_rules! atomic_int_ptr_sized {
stable(feature = "atomic_from", since = "1.23.0"),
stable(feature = "atomic_nand", since = "1.27.0"),
rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"),
"isize",
"",
@ -3256,6 +3268,7 @@ macro_rules! atomic_int_ptr_sized {
stable(feature = "atomic_from", since = "1.23.0"),
stable(feature = "atomic_nand", since = "1.27.0"),
rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"),
"usize",
"",

View File

@ -106,6 +106,7 @@ impl<T: Sized> Exclusive<T> {
/// Unwrap the value contained in the `Exclusive`
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
#[inline]
pub const fn into_inner(self) -> T {
@ -129,6 +130,7 @@ impl<T: ?Sized> Exclusive<T> {
/// access to the underlying value, but _pinned_ `Exclusive`s only
/// produce _pinned_ access to the underlying value.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
#[inline]
pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
@ -152,6 +154,7 @@ impl<T: ?Sized> Exclusive<T> {
/// a _pinned mutable_ reference to a `T`. This allows you to skip
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
#[inline]
pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {

View File

@ -321,7 +321,7 @@ impl<'a> ContextBuilder<'a> {
/// Creates a ContextBuilder from a Waker.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
#[rustc_const_stable(feature = "const_waker", since = "1.82.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))]
pub const fn from_waker(waker: &'a Waker) -> Self {
// SAFETY: LocalWaker is just Waker without thread safety
let local_waker = unsafe { transmute(waker) };
@ -379,7 +379,7 @@ impl<'a> ContextBuilder<'a> {
/// Builds the `Context`.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
#[rustc_const_stable(feature = "const_waker", since = "1.82.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))]
pub const fn build(self) -> Context<'a> {
let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 }

View File

@ -47,7 +47,7 @@ use crate::intrinsics::{self, const_eval_select};
/// order to call it. Since the precompiled standard library is built with full debuginfo and these
/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
/// debuginfo to have a measurable compile-time impact on debug builds.
#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn
#[cfg_attr(bootstrap, allow_internal_unstable(const_ub_checks))] // permit this to be called in stably-const fn
#[macro_export]
#[unstable(feature = "ub_checks", issue = "none")]
macro_rules! assert_unsafe_precondition {
@ -64,7 +64,8 @@ macro_rules! assert_unsafe_precondition {
#[rustc_no_mir_inline]
#[inline]
#[rustc_nounwind]
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
#[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks
const fn precondition_check($($name:$ty),*) {
if !$e {
::core::panicking::panic_nounwind(
@ -90,8 +91,9 @@ pub use intrinsics::ub_checks as check_library_ub;
///
/// The intention is to not do that when running in the interpreter, as that one has its own
/// language UB checks which generally produce better errors.
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
pub(crate) const fn check_language_ub() -> bool {
#[inline]
fn runtime() -> bool {
@ -116,6 +118,7 @@ pub(crate) const fn check_language_ub() -> bool {
/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
/// check is anyway not executed in `const`.
#[inline]
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
}
@ -132,6 +135,7 @@ pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
/// Note that in const-eval this function just returns `true` and therefore must
/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
#[inline]
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
pub(crate) const fn is_nonoverlapping(
src: *const (),
dst: *const (),

View File

@ -1,4 +1,5 @@
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(const_likely))]
#![cfg_attr(bootstrap, feature(strict_provenance))]
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
@ -22,7 +23,6 @@
#![feature(const_eval_select)]
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_likely)]
#![feature(const_nonnull_new)]
#![feature(const_num_midpoint)]
#![feature(const_option_ext)]

View File

@ -116,7 +116,7 @@ fn to_state(current: StateAndQueue) -> usize {
impl Once {
#[inline]
#[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))]
pub const fn new() -> Once {
Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) }
}

View File

@ -30,7 +30,7 @@ const KEY_SENTVAL: usize = 0;
const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1;
impl LazyKey {
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> LazyKey {
LazyKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
}

View File

@ -60,7 +60,7 @@ struct Value<T: 'static> {
}
impl<T: 'static> Storage<T> {
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
pub const fn new() -> Storage<T> {
Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData }
}

View File

@ -237,7 +237,7 @@ impl<T: 'static> LocalKey<T> {
reason = "recently added to create a key",
issue = "none"
)]
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
pub const unsafe fn new(inner: fn(Option<&mut Option<T>>) -> *const T) -> LocalKey<T> {
LocalKey { inner }
}

View File

@ -8,7 +8,6 @@ use arrayvec::ArrayVec;
use rustc_ast::MetaItemInner;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
use rustc_const_eval::const_eval::is_unstable_const_fn;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@ -641,12 +640,11 @@ impl Item {
asyncness: ty::Asyncness,
) -> hir::FnHeader {
let sig = tcx.fn_sig(def_id).skip_binder();
let constness =
if tcx.is_const_fn(def_id) || is_unstable_const_fn(tcx, def_id).is_some() {
hir::Constness::Const
} else {
hir::Constness::NotConst
};
let constness = if tcx.is_const_fn_raw(def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst
};
let asyncness = match asyncness {
ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
ty::Asyncness::No => hir::IsAsync::NotAsync,
@ -664,9 +662,7 @@ impl Item {
safety
},
abi,
constness: if tcx.is_const_fn(def_id)
|| is_unstable_const_fn(tcx, def_id).is_some()
{
constness: if tcx.is_const_fn_raw(def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst

View File

@ -1010,7 +1010,9 @@ 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 unstable = if let Some(n) = issue
&& let Some(feature) = feature
{
format!(
"<a \
href=\"https://github.com/rust-lang/rust/issues/{n}\" \

View File

@ -37,7 +37,6 @@ extern crate rustc_abi;
extern crate rustc_ast;
extern crate rustc_ast_pretty;
extern crate rustc_attr;
extern crate rustc_const_eval;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_errors;

View File

@ -89,10 +89,4 @@ impl Bar {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const2", since = "1.2.0")]
pub const fn stable_impl() -> u32 { 42 }
// Show const-stability even for unstable functions.
//@ matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$'
#[unstable(feature = "foo2", issue = "none")]
#[rustc_const_stable(feature = "const3", since = "1.3.0")]
pub const fn const_stable_unstable() -> u32 { 42 }
}

View File

@ -3,7 +3,6 @@ struct Value;
static settings_dir: String = format!("");
//~^ ERROR cannot call non-const fn
//~| ERROR is not yet stable as a const
fn from_string(_: String) -> Value {
Value

View File

@ -1,12 +1,3 @@
error: `Arguments::<'a>::new_const` is not yet stable as a const fn
--> $DIR/issue-64453.rs:4:31
|
LL | static settings_dir: String = format!("");
| ^^^^^^^^^^^
|
= help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
= note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0015]: cannot call non-const fn `format` in statics
--> $DIR/issue-64453.rs:4:31
|
@ -18,7 +9,7 @@ LL | static settings_dir: String = format!("");
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0507]: cannot move out of static item `settings_dir`
--> $DIR/issue-64453.rs:14:37
--> $DIR/issue-64453.rs:13:37
|
LL | let settings_data = from_string(settings_dir);
| ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait
@ -28,7 +19,7 @@ help: consider cloning the value if the performance cost is acceptable
LL | let settings_data = from_string(settings_dir.clone());
| ++++++++
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0015, E0507.
For more information about an error, try `rustc --explain E0015`.

View File

@ -1,13 +0,0 @@
#![feature(staged_api, rustc_attrs, intrinsics)]
#![stable(since="1.0.0", feature = "stable")]
extern "rust-intrinsic" {
#[unstable(feature = "unstable", issue = "42")]
#[rustc_const_stable(feature = "stable", since = "1.0.0")]
#[rustc_nounwind]
pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
}
#[unstable(feature = "unstable", issue = "42")]
#[rustc_const_stable(feature = "stable", since = "1.0.0")]
pub const fn some_unstable_fn() {}

View File

@ -0,0 +1,26 @@
#![feature(staged_api, rustc_attrs, intrinsics)]
#![stable(since="1.0.0", feature = "stable")]
#[stable(since="1.0.0", feature = "stable")]
pub mod old_way {
extern "rust-intrinsic" {
#[unstable(feature = "unstable", issue = "42")]
pub fn size_of_val<T>(x: *const T) -> usize;
#[unstable(feature = "unstable", issue = "42")]
#[rustc_const_unstable(feature = "unstable", issue = "42")]
pub fn min_align_of_val<T>(x: *const T) -> usize;
}
}
#[stable(since="1.0.0", feature = "stable")]
pub mod new_way {
#[unstable(feature = "unstable", issue = "42")]
#[rustc_intrinsic]
pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
#[unstable(feature = "unstable", issue = "42")]
#[rustc_const_unstable(feature = "unstable", issue = "42")]
#[rustc_intrinsic]
pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
}

View File

@ -3,7 +3,7 @@
we're apparently really bad at it",
issue = "none")]
#![feature(staged_api)]
#![feature(staged_api, foo)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
@ -11,7 +11,7 @@ const fn foo() -> u32 { 42 }
fn meh() -> u32 { 42 }
const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
fn a() {
let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed

View File

@ -1,10 +1,20 @@
error: `foo` is not yet stable as a const fn
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/dont_promote_unstable_const_fn.rs:14:25
|
LL | const fn bar() -> u32 { foo() }
| ^^^^^
|
= help: add `#![feature(foo)]` to the crate attributes to enable
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 bar() -> u32 { foo() }
|
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(foo)]
LL | const fn bar() -> u32 { foo() }
|
error[E0716]: temporary value dropped while borrowed
--> $DIR/dont_promote_unstable_const_fn.rs:17:28

View File

@ -11,8 +11,11 @@
#[repr(simd)] struct f32x4([f32; 4]);
extern "rust-intrinsic" {
#[stable(feature = "foo", since = "1.3.37")]
#[rustc_const_stable(feature = "foo", since = "1.3.37")]
fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
#[stable(feature = "foo", since = "1.3.37")]
#[rustc_const_stable(feature = "foo", since = "1.3.37")]
fn simd_extract<T, U>(x: T, idx: u32) -> U;
}

View File

@ -0,0 +1,76 @@
//! Ensure that unstable intrinsics can actually not be called,
//! neither within a crate nor cross-crate.
//@ aux-build:unstable_intrinsic.rs
#![feature(staged_api, rustc_attrs, intrinsics)]
#![stable(since="1.0.0", feature = "stable")]
#![feature(local)]
extern crate unstable_intrinsic;
fn main() {
const_main();
}
const fn const_main() {
let x = 42;
unsafe {
unstable_intrinsic::old_way::size_of_val(&x);
//~^ERROR: unstable library feature 'unstable'
//~|ERROR: cannot call non-const intrinsic
unstable_intrinsic::old_way::min_align_of_val(&x);
//~^ERROR: unstable library feature 'unstable'
//~|ERROR: not yet stable as a const intrinsic
unstable_intrinsic::new_way::size_of_val(&x);
//~^ERROR: unstable library feature 'unstable'
//~|ERROR: cannot be (indirectly) exposed to stable
unstable_intrinsic::new_way::min_align_of_val(&x);
//~^ERROR: unstable library feature 'unstable'
//~|ERROR: not yet stable as a const intrinsic
old_way::size_of_val(&x);
//~^ERROR: cannot call non-const intrinsic
old_way::min_align_of_val(&x);
//~^ERROR: cannot use `#[feature(local)]`
new_way::size_of_val(&x);
//~^ERROR: cannot be (indirectly) exposed to stable
new_way::min_align_of_val(&x);
//~^ERROR: cannot use `#[feature(local)]`
}
}
#[stable(since="1.0.0", feature = "stable")]
pub mod old_way {
extern "rust-intrinsic" {
#[unstable(feature = "local", issue = "42")]
pub fn size_of_val<T>(x: *const T) -> usize;
#[unstable(feature = "local", issue = "42")]
#[rustc_const_unstable(feature = "local", issue = "42")]
pub fn min_align_of_val<T>(x: *const T) -> usize;
}
}
#[stable(since="1.0.0", feature = "stable")]
pub mod new_way {
#[unstable(feature = "local", issue = "42")]
#[rustc_intrinsic]
pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
#[unstable(feature = "local", issue = "42")]
#[rustc_const_unstable(feature = "local", issue = "42")]
#[rustc_intrinsic]
pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[inline]
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
// Const stability attributes are not inherited from parent items.
extern "rust-intrinsic" {
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
unsafe { copy(src, dst, count) }
//~^ ERROR cannot call non-const intrinsic
}

View File

@ -0,0 +1,127 @@
error[E0658]: use of unstable library feature 'unstable'
--> $DIR/const-unstable-intrinsic.rs:17:9
|
LL | unstable_intrinsic::old_way::size_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
= 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[E0658]: use of unstable library feature 'unstable'
--> $DIR/const-unstable-intrinsic.rs:20:9
|
LL | unstable_intrinsic::old_way::min_align_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
= 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[E0658]: use of unstable library feature 'unstable'
--> $DIR/const-unstable-intrinsic.rs:23:9
|
LL | unstable_intrinsic::new_way::size_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
= 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[E0658]: use of unstable library feature 'unstable'
--> $DIR/const-unstable-intrinsic.rs:26:9
|
LL | unstable_intrinsic::new_way::min_align_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
= 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: cannot call non-const intrinsic `size_of_val` in constant functions
--> $DIR/const-unstable-intrinsic.rs:17:9
|
LL | unstable_intrinsic::old_way::size_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `min_align_of_val` is not yet stable as a const intrinsic
--> $DIR/const-unstable-intrinsic.rs:20:9
|
LL | unstable_intrinsic::old_way::min_align_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(unstable)]` to the crate attributes to enable
error: intrinsic `unstable_intrinsic::new_way::size_of_val` cannot be (indirectly) exposed to stable
--> $DIR/const-unstable-intrinsic.rs:23:9
|
LL | unstable_intrinsic::new_way::size_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
error: `min_align_of_val` is not yet stable as a const intrinsic
--> $DIR/const-unstable-intrinsic.rs:26:9
|
LL | unstable_intrinsic::new_way::min_align_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(unstable)]` to the crate attributes to enable
error: cannot call non-const intrinsic `size_of_val` in constant functions
--> $DIR/const-unstable-intrinsic.rs:30:9
|
LL | old_way::size_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
--> $DIR/const-unstable-intrinsic.rs:32:9
|
LL | old_way::min_align_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
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: intrinsic `new_way::size_of_val` cannot be (indirectly) exposed to stable
--> $DIR/const-unstable-intrinsic.rs:34:9
|
LL | new_way::size_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
--> $DIR/const-unstable-intrinsic.rs:36:9
|
LL | new_way::min_align_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
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: cannot call non-const intrinsic `copy` in constant functions
--> $DIR/const-unstable-intrinsic.rs:74:14
|
LL | unsafe { copy(src, dst, count) }
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 13 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -5,9 +5,11 @@
use std::mem;
extern "rust-intrinsic" {
#[stable(feature = "dummy", since = "1.0.0")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
#[stable(feature = "dummy", since = "1.0.0")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}

View File

@ -1,23 +1,23 @@
error[E0080]: evaluation of constant value failed
--> $DIR/copy-intrinsic.rs:28:5
--> $DIR/copy-intrinsic.rs:30:5
|
LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance)
error[E0080]: evaluation of constant value failed
--> $DIR/copy-intrinsic.rs:37:5
--> $DIR/copy-intrinsic.rs:39:5
|
LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes
error[E0080]: evaluation of constant value failed
--> $DIR/copy-intrinsic.rs:44:5
--> $DIR/copy-intrinsic.rs:46:5
|
LL | copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
error[E0080]: evaluation of constant value failed
--> $DIR/copy-intrinsic.rs:50:5
--> $DIR/copy-intrinsic.rs:52:5
|
LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`

View File

@ -1,17 +0,0 @@
#![feature(intrinsics, staged_api)]
#![stable(feature = "core", since = "1.6.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[inline]
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
// Const stability attributes are not inherited from parent items.
extern "rust-intrinsic" {
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
unsafe { copy(src, dst, count) }
//~^ ERROR cannot call non-const fn
}
fn main() {}

View File

@ -1,11 +0,0 @@
error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions
--> $DIR/intrinsic_without_const_stab.rs:13:14
|
LL | unsafe { copy(src, dst, count) }
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0015`.

View File

@ -1,15 +0,0 @@
#![feature(intrinsics, staged_api)]
#![stable(feature = "core", since = "1.6.0")]
extern "rust-intrinsic" {
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[inline]
pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn
}
fn main() {}

View File

@ -1,11 +0,0 @@
error[E0015]: cannot call non-const fn `copy::<T>` in constant functions
--> $DIR/intrinsic_without_const_stab_fail.rs:12:14
|
LL | unsafe { copy(src, dst, count) }
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0015`.

View File

@ -5,7 +5,7 @@
issue = "none")]
#![feature(foo, foo2)]
#![feature(const_async_blocks, staged_api)]
#![feature(const_async_blocks, staged_api, rustc_attrs)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
@ -14,33 +14,55 @@ const fn foo() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
#[unstable(feature = "foo2", issue = "none")]
#[rustc_const_unstable(feature = "foo2", issue = "none")]
const fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
const fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]`
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// conformity is required
const fn bar3() -> u32 {
let x = async { 13 };
//~^ ERROR const-stable function cannot use `#[feature(const_async_blocks)]`
//~^ ERROR cannot use `#[feature(const_async_blocks)]`
foo()
//~^ ERROR is not yet stable as a const fn
//~^ ERROR cannot use `#[feature(foo)]`
}
// check whether this function cannot be called even with the feature gate active
#[unstable(feature = "foo2", issue = "none")]
#[rustc_const_unstable(feature = "foo2", issue = "none")]
const fn foo2_gated() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
// Functions without any attribute are checked like stable functions,
// even if they are in a stable module.
mod stable {
#![stable(feature = "rust1", since = "1.0.0")]
pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
}
// And same for const-unstable functions that are marked as "stable_indirect".
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
#[rustc_const_stable_indirect]
const fn stable_indirect() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
// These functiuons *can* be called from fully stable functions.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
const fn bar2_gated_exposed() -> u32 {
stable::bar2_gated_stable_indirect() + stable_indirect()
}
fn main() {}

View File

@ -1,51 +1,127 @@
error: `foo` is not yet stable as a const fn
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/min_const_fn_libstd_stability.rs:17:25
|
LL | const fn bar() -> u32 { foo() }
| ^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 bar() -> u32 { foo() }
|
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(foo)]
LL | const fn bar() -> u32 { foo() }
|
error: `foo2` is not yet stable as a const fn
--> $DIR/min_const_fn_libstd_stability.rs:25:26
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
--> $DIR/min_const_fn_libstd_stability.rs:26:26
|
LL | const fn bar2() -> u32 { foo2() }
| ^^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 bar2() -> u32 { foo2() }
|
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(foo2)]
LL | const fn bar2() -> u32 { foo2() }
|
error: const-stable function cannot use `#[feature(const_async_blocks)]`
--> $DIR/min_const_fn_libstd_stability.rs:31:13
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]`
--> $DIR/min_const_fn_libstd_stability.rs:32:13
|
LL | let x = async { 13 };
| ^^^^^^^^^^^^
|
help: if the function is not (yet) meant to be stable, make this function unstably const
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 bar3() -> u32 {
|
help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
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_async_blocks)]
LL | const fn bar3() -> u32 {
|
error: `foo` is not yet stable as a const fn
--> $DIR/min_const_fn_libstd_stability.rs:33:5
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/min_const_fn_libstd_stability.rs:34:5
|
LL | foo()
| ^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 bar3() -> u32 {
|
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(foo)]
LL | const fn bar3() -> u32 {
|
error: `foo2_gated` is not yet stable as a const fn
--> $DIR/min_const_fn_libstd_stability.rs:44:32
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
--> $DIR/min_const_fn_libstd_stability.rs:46:32
|
LL | const fn bar2_gated() -> u32 { foo2_gated() }
| ^^^^^^^^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 bar2_gated() -> u32 { foo2_gated() }
|
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(foo2)]
LL | const fn bar2_gated() -> u32 { foo2_gated() }
|
error: aborting due to 5 previous errors
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
--> $DIR/min_const_fn_libstd_stability.rs:53:63
|
LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
| ^^^^^^^^^^^^^^^^^^^
|
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
|
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(foo2)]
LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
|
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
--> $DIR/min_const_fn_libstd_stability.rs:59:37
|
LL | const fn stable_indirect() -> u32 { foo2_gated() }
| ^^^^^^^^^^^^
|
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 stable_indirect() -> u32 { foo2_gated() }
|
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(foo2)]
LL | const fn stable_indirect() -> u32 { foo2_gated() }
|
error: aborting due to 7 previous errors

View File

@ -13,24 +13,26 @@ const unsafe fn foo() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR cannot use `#[feature(foo)]`
#[unstable(feature = "foo2", issue = "none")]
#[rustc_const_unstable(feature = "foo2", issue = "none")]
const unsafe fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn
const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR cannot use `#[feature(foo2)]`
// check whether this function cannot be called even with the feature gate active
#[unstable(feature = "foo2", issue = "none")]
#[rustc_const_unstable(feature = "foo2", issue = "none")]
const unsafe fn foo2_gated() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
//~^ ERROR not yet stable as a const fn
//~^ ERROR cannot use `#[feature(foo2)]`
fn main() {}

View File

@ -1,26 +1,56 @@
error: `foo` is not yet stable as a const fn
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
|
LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
| ^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 unsafe fn bar() -> u32 { unsafe { foo() } }
|
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(foo)]
LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
|
error: `foo2` is not yet stable as a const fn
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:25:42
|
LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
| ^^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 unsafe fn bar2() -> u32 { unsafe { foo2() } }
|
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(foo2)]
LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
|
error: `foo2_gated` is not yet stable as a const fn
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:48
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:35:48
|
LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
| ^^^^^^^^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
|
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(foo2)]
LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
|
error: aborting due to 3 previous errors

View File

@ -13,23 +13,25 @@ const fn foo() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
const unsafe fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
#[unstable(feature = "foo2", issue = "none")]
#[rustc_const_unstable(feature="foo2", issue = "none")]
const fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
const unsafe fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]`
// check whether this function cannot be called even with the feature gate active
#[unstable(feature = "foo2", issue = "none")]
#[rustc_const_unstable(feature="foo2", issue = "none")]
const fn foo2_gated() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
fn main() {}

View File

@ -1,26 +1,56 @@
error: `foo` is not yet stable as a const fn
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
|
LL | const unsafe fn bar() -> u32 { foo() }
| ^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 unsafe fn bar() -> u32 { foo() }
|
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(foo)]
LL | const unsafe fn bar() -> u32 { foo() }
|
error: `foo2` is not yet stable as a const fn
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:25:33
|
LL | const unsafe fn bar2() -> u32 { foo2() }
| ^^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 unsafe fn bar2() -> u32 { foo2() }
|
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(foo2)]
LL | const unsafe fn bar2() -> u32 { foo2() }
|
error: `foo2_gated` is not yet stable as a const fn
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:35:39
|
LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
| ^^^^^^^^^^^^
|
= help: const-stable functions can only call other const-stable functions
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe 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 unsafe fn bar2_gated() -> u32 { foo2_gated() }
|
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(foo2)]
LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
|
error: aborting due to 3 previous errors

View File

@ -1,16 +1,16 @@
#![crate_type = "lib"]
#![feature(staged_api)]
#![feature(staged_api, rustc_attrs)]
#![stable(feature = "foo", since = "1.0.0")]
#[stable(feature = "foo", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_foo", issue = "none")]
pub fn foo() {}
//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
//~^ ERROR require the function or method to be `const`
#[stable(feature = "bar", since = "1.0.0")]
#[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
pub fn bar() {}
//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
//~^ ERROR require the function or method to be `const`
#[stable(feature = "potato", since = "1.0.0")]
pub struct Potato;
@ -19,23 +19,23 @@ impl Potato {
#[stable(feature = "salad", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_salad", issue = "none")]
pub fn salad(&self) -> &'static str { "mmmmmm" }
//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
//~^ ERROR require the function or method to be `const`
#[stable(feature = "roasted", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_roasted", issue = "none")]
pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
//~^ ERROR require the function or method to be `const`
}
#[stable(feature = "bar", since = "1.0.0")]
#[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
pub extern "C" fn bar_c() {}
//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
//~^ ERROR require the function or method to be `const`
#[stable(feature = "foo", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_foo", issue = "none")]
pub extern "C" fn foo_c() {}
//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
//~^ ERROR require the function or method to be `const`
#[stable(feature = "foobar", since = "1.0.0")]
@ -45,3 +45,20 @@ pub const fn foobar() {}
#[stable(feature = "barfoo", since = "1.0.0")]
#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
pub const fn barfoo() {}
// `rustc_const_stable` also requires the function to be stable.
#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
const fn barfoo_unmarked() {}
//~^ ERROR can only be applied to functions that are declared `#[stable]`
#[unstable(feature = "unstable", issue = "none")]
#[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`

View File

@ -1,8 +1,6 @@
error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
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:7:1
|
LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
| -------------------------------------------------------------- attribute specified here
LL | pub fn foo() {}
| ^^^^^^^^^^^^
|
@ -12,11 +10,9 @@ help: make the function or method const
LL | pub fn foo() {}
| ^^^^^^^^^^^^
error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
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:12:1
|
LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
| ------------------------------------------------------------- attribute specified here
LL | pub fn bar() {}
| ^^^^^^^^^^^^
|
@ -26,11 +22,9 @@ help: make the function or method const
LL | pub fn bar() {}
| ^^^^^^^^^^^^
error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
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:21:5
|
LL | #[rustc_const_unstable(feature = "const_salad", issue = "none")]
| ---------------------------------------------------------------- attribute specified here
LL | pub fn salad(&self) -> &'static str { "mmmmmm" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@ -40,11 +34,9 @@ help: make the function or method const
LL | pub fn salad(&self) -> &'static str { "mmmmmm" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
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:26:5
|
LL | #[rustc_const_unstable(feature = "const_roasted", issue = "none")]
| ------------------------------------------------------------------ attribute specified here
LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@ -54,11 +46,9 @@ help: make the function or method const
LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
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:32:1
|
LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
| ------------------------------------------------------------- attribute specified here
LL | pub extern "C" fn bar_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
@ -68,11 +58,9 @@ help: make the function or method const
LL | pub extern "C" fn bar_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
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:37:1
|
LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
| -------------------------------------------------------------- attribute specified here
LL | pub extern "C" fn foo_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
@ -82,5 +70,33 @@ help: make the function or method const
LL | pub extern "C" fn foo_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
--> $DIR/rustc-const-stability-require-const.rs:52:1
|
LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
| ---------------------------------------------------------------- attribute specified here
LL | const fn barfoo_unmarked() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
--> $DIR/rustc-const-stability-require-const.rs:57:1
|
LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
| ---------------------------------------------------------------- attribute specified here
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

View File

@ -1,14 +0,0 @@
//@ aux-build:unstable_but_const_stable.rs
extern crate unstable_but_const_stable;
use unstable_but_const_stable::*;
fn main() {
some_unstable_fn(); //~ERROR use of unstable library feature
unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
}
const fn const_main() {
some_unstable_fn(); //~ERROR use of unstable library feature
unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
}

View File

@ -1,43 +0,0 @@
error[E0658]: use of unstable library feature 'unstable'
--> $DIR/unstable-const-stable.rs:7:5
|
LL | some_unstable_fn();
| ^^^^^^^^^^^^^^^^
|
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
= 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[E0658]: use of unstable library feature 'unstable'
--> $DIR/unstable-const-stable.rs:8:14
|
LL | unsafe { write_bytes(4 as *mut u8, 0, 0) };
| ^^^^^^^^^^^
|
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
= 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[E0658]: use of unstable library feature 'unstable'
--> $DIR/unstable-const-stable.rs:12:5
|
LL | some_unstable_fn();
| ^^^^^^^^^^^^^^^^
|
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
= 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[E0658]: use of unstable library feature 'unstable'
--> $DIR/unstable-const-stable.rs:13:14
|
LL | unsafe { write_bytes(4 as *mut u8, 0, 0) };
| ^^^^^^^^^^^
|
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
= 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: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,3 +1,17 @@
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
|
@ -13,19 +27,5 @@ 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

View File

@ -15,7 +15,7 @@ const fn nothing(){}
#[rustc_const_stable(since = "1.0", feature = "const_hey")]
pub const fn hey() {
const_eval_select((), nothing, log);
//~^ ERROR `const_eval_select` is not yet stable as a const fn
//~^ ERROR cannot use `#[feature(const_eval_select)]`
}
fn main() {}

View File

@ -1,10 +1,19 @@
error: `const_eval_select` is not yet stable as a const fn
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_eval_select)]`
--> $DIR/const-eval-select-stability.rs:17:5
|
LL | const_eval_select((), nothing, log);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: const-stable functions can only call other const-stable functions
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 | pub const fn hey() {
|
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_eval_select)]
LL | pub const fn hey() {
|
error: aborting due to 1 previous error

View File

@ -14,4 +14,3 @@ pub const fn foobar() -> u32 {
}
const VAR: u32 = foobar();
//~^ ERROR: `foobar` is not yet stable as a const fn

View File

@ -4,13 +4,5 @@ error: feature `const_bar` implying `const_foobar` does not exist
LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `foobar` is not yet stable as a const fn
--> $DIR/const-stability-attribute-implies-missing.rs:16:18
|
LL | const VAR: u32 = foobar();
| ^^^^^^^^
|
= help: add `#![feature(const_foobar)]` to the crate attributes to enable
error: aborting due to 2 previous errors
error: aborting due to 1 previous error

View File

@ -1,6 +1,6 @@
//@ compile-flags: -Znext-solver
#![feature(staged_api)]
#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
#![feature(const_trait_impl, effects, rustc_attrs, intrinsics)] //~ WARN the feature `effects` is incomplete
#![stable(feature = "stable", since = "1.0.0")]
#[stable(feature = "stable", since = "1.0.0")]
@ -31,4 +31,15 @@ impl const Bar for Foo {
fn fun() {}
}
#[stable(feature = "stable", since = "1.0.0")]
#[rustc_intrinsic]
pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
//~^ ERROR function has missing const stability attribute
extern "rust-intrinsic" {
#[stable(feature = "stable", since = "1.0.0")]
#[rustc_const_stable_indirect]
pub fn min_align_of_val<T>(x: *const T) -> usize;
}
fn main() {}

View File

@ -1,7 +1,7 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/missing-const-stability.rs:3:30
|
LL | #![feature(const_trait_impl, effects)]
LL | #![feature(const_trait_impl, effects, rustc_attrs, intrinsics)]
| ^^^^^^^
|
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
@ -22,11 +22,17 @@ LL | | fn fun() {}
LL | | }
| |_^
error: function has missing const stability attribute
--> $DIR/missing-const-stability.rs:36:1
|
LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: associated function has missing const stability attribute
--> $DIR/missing-const-stability.rs:16:5
|
LL | pub const fn foo() {}
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors; 1 warning emitted
error: aborting due to 4 previous errors; 1 warning emitted

View File

@ -19,6 +19,7 @@ trait Copy {}
impl Copy for bool {}
extern "rust-intrinsic" {
#[stable(feature = "test", since = "1.0.0")]
#[rustc_const_stable(feature = "test", since = "1.0.0")]
fn unreachable() -> !;
}

View File

@ -17,6 +17,7 @@ trait Copy {}
impl Copy for bool {}
extern "rust-intrinsic" {
#[stable(feature = "test", since = "1.0.0")]
#[rustc_const_stable(feature = "test", since = "1.0.0")]
fn unreachable() -> !;
}

View File

@ -19,3 +19,12 @@ pub struct Unstable;
impl const MyTrait for Unstable {
fn func() {}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Unstable2;
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "unstable2", issue = "none")]
impl const MyTrait for Unstable2 {
fn func() {}
}

View File

@ -515,7 +515,7 @@ trait StructuralPartialEq {}
const fn drop<T: ~const Destruct>(_: T) {}
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
#[rustc_const_stable_indirect]
#[rustc_intrinsic_must_be_overridden]
#[rustc_intrinsic]
const fn const_eval_select<ARG: Tuple, F, G, RET>(

View File

@ -1,6 +1,5 @@
//@ compile-flags: -Znext-solver
#![allow(incomplete_features)]
#![feature(const_fmt_arguments_new)]
#![feature(const_trait_impl, effects)]
#[const_trait]

View File

@ -1,5 +1,5 @@
error[E0015]: cannot call non-const fn `_print` in constant functions
--> $DIR/issue-79450.rs:11:9
--> $DIR/issue-79450.rs:10:9
|
LL | println!("lul");
| ^^^^^^^^^^^^^^^

View File

@ -2,6 +2,7 @@
//@ compile-flags: -Znext-solver
#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
#![cfg_attr(unstable, feature(local_feature))]
#![feature(const_trait_impl, effects)]
#![allow(incomplete_features)]
#![feature(staged_api)]
@ -16,8 +17,8 @@ use staged_api::*;
pub struct Foo;
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))]
#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
#[cfg_attr(stable, rustc_const_stable(feature = "local_feature", since = "1.0.0"))]
impl const MyTrait for Foo {
//[stable]~^ ERROR trait implementations cannot be const stable yet
fn func() {}
@ -32,32 +33,43 @@ fn non_const_context() {
#[unstable(feature = "none", issue = "none")]
const fn const_context() {
Unstable::func();
//[stable]~^ ERROR not yet stable as a const fn
//[unstable]~^ ERROR cannot use `#[feature(unstable)]`
//[stable]~^^ ERROR not yet stable as a const fn
Foo::func();
//[unstable]~^ ERROR not yet stable as a const fn
// ^ fails, because the `foo` feature is not active
//[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
//[stable]~^^ cannot be (indirectly) exposed to stable
// We get the error on `stable` since this is a trait function.
Unstable2::func();
//~^ ERROR not yet stable as a const fn
// ^ fails, because the `unstable2` feature is not active
}
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
pub const fn const_context_not_const_stable() {
//[stable]~^ ERROR function has missing const stability attribute
Unstable::func();
//[stable]~^ ERROR not yet stable as a const fn
Foo::func();
//[unstable]~^ ERROR not yet stable as a const fn
// ^ fails, because the `foo` feature is not active
//[stable]~^ cannot be (indirectly) exposed to stable
// We get the error on `stable` since this is a trait function.
Unstable2::func();
//~^ ERROR not yet stable as a const fn
// ^ fails, because the `unstable2` feature is not active
}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "cheese", since = "1.0.0")]
const fn stable_const_context() {
Unstable::func();
//~^ ERROR not yet stable as a const fn
//[unstable]~^ ERROR cannot use `#[feature(unstable)]`
//[stable]~^^ ERROR not yet stable as a const fn
Foo::func();
//[unstable]~^ ERROR not yet stable as a const fn
//[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
//[stable]~^^ cannot be (indirectly) exposed to stable
// We get the error on `stable` since this is a trait function.
const_context_not_const_stable()
//[unstable]~^ ERROR not yet stable as a const fn
//[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
}
fn main() {}

Some files were not shown because too many files have changed in this diff Show More