Auto merge of #131349 - RalfJung:const-stability-checks, r=compiler-errors

Const stability checks v2

The const stability system has served us well ever since `const fn` were first stabilized. It's main feature is that it enforces *recursive* validity -- a stable const fn cannot internally make use of unstable const features without an explicit marker in the form of `#[rustc_allow_const_fn_unstable]`. This is done to make sure that we don't accidentally expose unstable const features on stable in a way that would be hard to take back. As part of this, it is enforced that a `#[rustc_const_stable]` can only call `#[rustc_const_stable]` functions. However, some problems have been coming up with increased usage:
- It is baffling that we have to mark private or even unstable functions as `#[rustc_const_stable]` when they are used as helpers in regular stable `const fn`, and often people will rather add `#[rustc_allow_const_fn_unstable]` instead which was not our intention.
- The system has several gaping holes: a private `const fn` without stability attributes whose inherited stability (walking up parent modules) is `#[stable]` is allowed to call *arbitrary* unstable const operations, but can itself be called from stable `const fn`. Similarly, `#[allow_internal_unstable]` on a macro completely bypasses the recursive nature of the check.

Fundamentally, the problem is that we have *three* disjoint categories of functions, and not enough attributes to distinguish them:
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

Functions in the first two categories cannot use unstable const features and they can only call functions from the first two categories.

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, all the holes mentioned above have been 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 be manually marked `#[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.

Also see the updated dev-guide at https://github.com/rust-lang/rustc-dev-guide/pull/2098.

I think in the future we may want to tweak this further, so that in the hopefully common case where a public function's const-stability just exactly mirrors its regular stability, we never have to add any attribute. But right now, once the function is stable this requires `#[rustc_const_stable]`.

### Open question

There is one point I could see we might want to do differently, and that is putting `#[rustc_const_unstable]`  functions (but not intrinsics) in category 2 by default, and requiring an extra attribute for `#[rustc_const_not_exposed_on_stable]` or so. This would require a bunch of extra annotations, but would have the advantage that turning a `#[rustc_const_unstable]` into `#[rustc_const_stable]`  will never change the way the function is const-checked. Currently, we often discover in the const stabilization PR that a function needs some other unstable const things, and then we rush to quickly deal with that. In this alternative universe, we'd work towards getting rid of the `rustc_const_not_exposed_on_stable` before stabilization, and once that is done stabilization becomes a trivial matter. `#[rustc_const_stable_indirect]` would then only be used for intrinsics.

I think I like this idea, but might want to do it in a follow-up PR, as it will need a whole bunch of annotations in the standard library. Also, we probably want to convert all const intrinsics to the "new" form (`#[rustc_intrinsic]` instead of an `extern` block) before doing this to avoid having to deal with two different ways of declaring intrinsics.

Cc `@rust-lang/wg-const-eval` `@rust-lang/libs-api`
Part of https://github.com/rust-lang/rust/issues/129815 (but not finished since this is not yet sufficient to safely let us expose `const fn` from hashbrown)
Fixes https://github.com/rust-lang/rust/issues/131073 by making it so that const-stable functions are always stable

try-job: test-various
This commit is contained in:
bors 2024-10-25 23:29:40 +00:00
commit 54761cb3e8
118 changed files with 1605 additions and 760 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

@ -313,14 +313,23 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
match m {
ProcMacro::Derive(cd) => {
cx.resolver.declare_proc_macro(cd.id);
cx.expr_call(span, proc_macro_ty_method_path(cx, custom_derive), thin_vec![
cx.expr_str(span, cd.trait_name),
cx.expr_array_ref(
span,
cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<ThinVec<_>>(),
),
local_path(cx, cd.function_name),
])
// The call needs to use `harness_span` so that the const stability checker
// accepts it.
cx.expr_call(
harness_span,
proc_macro_ty_method_path(cx, custom_derive),
thin_vec![
cx.expr_str(span, cd.trait_name),
cx.expr_array_ref(
span,
cd.attrs
.iter()
.map(|&s| cx.expr_str(span, s))
.collect::<ThinVec<_>>(),
),
local_path(cx, cd.function_name),
],
)
}
ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => {
cx.resolver.declare_proc_macro(ca.id);
@ -330,7 +339,9 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
ProcMacro::Derive(_) => unreachable!(),
};
cx.expr_call(span, proc_macro_ty_method_path(cx, ident), thin_vec![
// The call needs to use `harness_span` so that the const stability checker
// accepts it.
cx.expr_call(harness_span, proc_macro_ty_method_path(cx, ident), thin_vec![
cx.expr_str(span, ca.function_name.name),
local_path(cx, ca.function_name),
])

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,29 +665,73 @@ 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;
}
if !tcx.is_const_fn_raw(callee) && !is_trait {
// 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(callee) && !is_trait {
self.check_op(ops::FnCallNonConst {
caller,
callee,
@ -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));
assert!(tcx.is_const_fn(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
}
@ -114,7 +122,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
// FIXME(effects) revisit this
if !tcx.is_const_trait_impl_raw(data.impl_def_id) {
if !tcx.is_const_trait_impl(data.impl_def_id) {
let span = tcx.def_span(data.impl_def_id);
err.subdiagnostic(errors::NonConstImplNote { span });
}
@ -166,7 +174,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
let note = match self_ty.kind() {
FnDef(def_id, ..) => {
let span = tcx.def_span(*def_id);
if ccx.tcx.is_const_fn_raw(*def_id) {
if ccx.tcx.is_const_fn(*def_id) {
span_bug!(span, "calling const FnDef errored when it shouldn't");
}
@ -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.
@ -431,8 +431,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
// sensitive check here. But we can at least rule out functions that are not const at
// all. That said, we have to allow calling functions inside a trait marked with
// #[const_trait]. These *are* const-checked!
// FIXME: why does `is_const_fn_raw` not classify them as const?
if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def))
// FIXME(effects): why does `is_const_fn` not classify them as const?
if (!ecx.tcx.is_const_fn(def) && !ecx.tcx.is_const_default_method(def))
|| ecx.tcx.has_attr(def, sym::rustc_do_not_const_check)
{
// We certainly do *not* want to actually call the fn

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

@ -1597,7 +1597,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id).instantiate_identity();
check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref);
check_impl_constness(tcx, tcx.is_const_trait_impl(def_id.to_def_id()), ast_trait_ref);
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);

View File

@ -537,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
//
// This check is here because there is currently no way to express a trait bound for `FnDef` types only.
if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
if idx == 0 && !self.tcx.is_const_fn(def_id) {
self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
}
} else {

View File

@ -1751,7 +1751,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// to tell them that in the diagnostic. Does not affect typeck.
let is_constable = match element.kind {
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
ty::FnDef(def_id, _) if tcx.is_const_fn(def_id) => traits::IsConstable::Fn,
ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn,
_ => traits::IsConstable::No,
},
hir::ExprKind::Path(qpath) => {

View File

@ -1081,7 +1081,7 @@ fn should_encode_mir(
&& (generics.requires_monomorphization(tcx)
|| tcx.cross_crate_inlinable(def_id)));
// The function has a `const` modifier or is in a `#[const_trait]`.
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
let is_const_fn = tcx.is_const_fn(def_id.to_def_id())
|| tcx.is_const_default_method(def_id.to_def_id());
(is_const_fn, opt)
}

View File

@ -329,7 +329,7 @@ impl<'hir> Map<'hir> {
BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability),
BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None,
BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn_raw(def_id) => {
BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn(def_id) => {
ConstContext::ConstFn
}
BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id) => ConstContext::ConstFn,

View File

@ -17,7 +17,7 @@ where
let mirs = def_ids
.iter()
.flat_map(|def_id| {
if tcx.is_const_fn_raw(*def_id) {
if tcx.is_const_fn(*def_id) {
vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
} else {
vec![tcx.instance_mir(ty::InstanceKind::Item(*def_id))]

View File

@ -317,7 +317,7 @@ pub fn write_mir_pretty<'tcx>(
};
// For `const fn` we want to render both the optimized MIR and the MIR for ctfe.
if tcx.is_const_fn_raw(def_id) {
if tcx.is_const_fn(def_id) {
render_body(w, tcx.optimized_mir(def_id))?;
writeln!(w)?;
writeln!(w, "// MIR FOR CTFE")?;

View File

@ -741,12 +741,11 @@ rustc_queries! {
desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
}
/// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate
/// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might
/// not have the feature gate active).
/// Returns `true` if this is a const fn / const impl.
///
/// **Do not call this function manually.** It is only meant to cache the base data for the
/// `is_const_fn` function. Consider using `is_const_fn` or `is_const_fn_raw` instead.
/// higher-level functions. Consider using `is_const_fn` or `is_const_trait_impl` instead.
/// Also note that neither of them takes into account feature gates and stability.
query constness(key: DefId) -> hir::Constness {
desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) }
separate_provide_extern

View File

@ -3120,39 +3120,24 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Whether the `def_id` counts as const fn in the current crate, considering all active
/// feature gates
pub fn is_const_fn(self, def_id: DefId) -> bool {
if self.is_const_fn_raw(def_id) {
match self.lookup_const_stability(def_id) {
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)
}
// functions without const stability are either stable user written
// const fn or the user is using feature gates and we thus don't
// care what they do
_ => true,
/// Whether `def_id` is a stable const fn (i.e., doesn't need any feature gates to be called).
///
/// When this is `false`, the function may still be callable as a `const fn` due to features
/// being enabled!
pub fn is_stable_const_fn(self, def_id: DefId) -> bool {
self.is_const_fn(def_id)
&& match self.lookup_const_stability(def_id) {
None => true, // a fn in a non-staged_api crate
Some(stability) if stability.is_const_stable() => true,
_ => false,
}
} else {
false
}
}
// FIXME(effects): Please remove this. It's a footgun.
/// Whether the trait impl is marked const. This does not consider stability or feature gates.
pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
let Some(local_def_id) = def_id.as_local() else { return false };
let node = self.hir_node_by_def_id(local_def_id);
matches!(
node,
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
..
}) if matches!(constness, hir::Constness::Const)
)
pub fn is_const_trait_impl(self, def_id: DefId) -> bool {
self.def_kind(def_id) == DefKind::Impl { of_trait: true }
&& self.constness(def_id) == hir::Constness::Const
}
pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> {

View File

@ -1995,8 +1995,11 @@ impl<'tcx> TyCtxt<'tcx> {
(ident, scope)
}
/// Checks whether this is a `const fn`. Returns `false` for non-functions.
///
/// Even if this returns `true`, constness may still be unstable!
#[inline]
pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
pub fn is_const_fn(self, def_id: DefId) -> bool {
matches!(
self.def_kind(def_id),
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure

View File

@ -673,7 +673,7 @@ impl<'tcx> Validator<'_, 'tcx> {
}
// Make sure the callee is a `const fn`.
let is_const_fn = match *fn_ty.kind() {
ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id),
ty::FnDef(def_id, _) => self.tcx.is_const_fn(def_id),
_ => false,
};
if !is_const_fn {

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

@ -1997,7 +1997,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
) {
match target {
Target::Fn | Target::Method(_)
if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) => {}
if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {}
// FIXME(#80564): We permit struct fields and match arms to have an
// `#[allow_internal_unstable]` attribute with just a lint, because we previously
// erroneously allowed it and some crates used it accidentally, to be compatible

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,65 @@ 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()
&& (!self.in_trait_impl || !self.tcx.is_const_fn_raw(def_id.to_def_id()))
// 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(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())
// FIXME: we skip this check targets until
// <https://github.com/rust-lang/stdarch/pull/1654> propagates.
&& false
{
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 +282,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 +297,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 +401,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 +420,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 +440,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 +464,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 +480,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 +491,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 +510,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 +522,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 +553,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 +582,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;
}
@ -554,10 +598,11 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
}
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
|| self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
|| self.tcx.is_const_trait_impl(def_id.to_def_id());
let is_stable =
self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable());
let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
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 +632,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 +646,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 +715,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 +778,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
@ -763,7 +820,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
// needs to have an error emitted.
if features.const_trait_impl()
&& self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id())
&& self.tcx.is_const_trait_impl(item.owner_id.to_def_id())
&& const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
{
self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span });

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

@ -393,7 +393,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let self_ty = obligation.self_ty().skip_binder();
match *self_ty.kind() {
ty::Closure(def_id, _) => {
let is_const = self.tcx().is_const_fn_raw(def_id);
let is_const = self.tcx().is_const_fn(def_id);
debug!(?kind, ?obligation, "assemble_unboxed_candidates");
match self.infcx.closure_kind(self_ty) {
Some(closure_kind) => {
@ -413,7 +413,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::CoroutineClosure(def_id, args) => {
let args = args.as_coroutine_closure();
let is_const = self.tcx().is_const_fn_raw(def_id);
let is_const = self.tcx().is_const_fn(def_id);
if let Some(closure_kind) = self.infcx.closure_kind(self_ty)
// Ambiguity if upvars haven't been constrained yet
&& !args.tupled_upvars_ty().is_ty_var()

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,11 @@ 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_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
)]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
@ -1000,7 +1010,11 @@ 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_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
)]
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
@ -1041,7 +1055,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 +1065,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 +1074,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 +1088,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 +1103,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 +1410,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 +1428,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 +1451,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 +1470,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 +2154,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 +2196,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 +2219,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 +2260,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 +2283,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 +2298,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 +2314,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 +2341,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 +2357,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 +2373,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 +2393,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 +2406,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 +2420,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 +2430,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 +2440,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 +2450,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 +2460,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 +2475,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 +2491,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 +2507,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 +2522,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 +2537,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 +2553,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 +2568,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 +2580,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 +2591,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 +2605,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 +2640,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 +2907,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 +2993,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 +3011,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 +3125,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 +3151,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 +3262,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 +3374,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 +3463,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 +3725,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

@ -449,7 +449,7 @@ macro_rules! int_impl {
#[inline]
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_add(rhs);
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict integer addition. Computes `self + rhs`, panicking
@ -545,7 +545,7 @@ macro_rules! int_impl {
#[inline]
pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
let (a, b) = self.overflowing_add_unsigned(rhs);
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict addition with an unsigned integer. Computes `self + rhs`,
@ -601,7 +601,7 @@ macro_rules! int_impl {
#[inline]
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_sub(rhs);
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict integer subtraction. Computes `self - rhs`, panicking if
@ -697,7 +697,7 @@ macro_rules! int_impl {
#[inline]
pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
let (a, b) = self.overflowing_sub_unsigned(rhs);
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict subtraction with an unsigned integer. Computes `self - rhs`,
@ -753,7 +753,7 @@ macro_rules! int_impl {
#[inline]
pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_mul(rhs);
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict integer multiplication. Computes `self * rhs`, panicking if
@ -849,7 +849,7 @@ macro_rules! int_impl {
without modifying the original"]
#[inline]
pub const fn checked_div(self, rhs: Self) -> Option<Self> {
if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
None
} else {
// SAFETY: div by zero and by INT_MIN have been checked above
@ -924,7 +924,7 @@ macro_rules! int_impl {
#[inline]
pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
// Using `&` helps LLVM see that it is the same check made in division.
if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
None
} else {
Some(self.div_euclid(rhs))
@ -997,7 +997,7 @@ macro_rules! int_impl {
without modifying the original"]
#[inline]
pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
None
} else {
// SAFETY: div by zero and by INT_MIN have been checked above
@ -1071,7 +1071,7 @@ macro_rules! int_impl {
#[inline]
pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
// Using `&` helps LLVM see that it is the same check made in division.
if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
None
} else {
Some(self.rem_euclid(rhs))
@ -1142,7 +1142,7 @@ macro_rules! int_impl {
#[inline]
pub const fn checked_neg(self) -> Option<Self> {
let (a, b) = self.overflowing_neg();
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Unchecked negation. Computes `-self`, assuming overflow cannot occur.
@ -2564,7 +2564,7 @@ macro_rules! int_impl {
without modifying the original"]
pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
// Using `&` helps LLVM see that it is the same check made in division.
if unlikely!((self == Self::MIN) & (rhs == -1)) {
if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) {
(self, true)
} else {
(self / rhs, false)
@ -2595,7 +2595,7 @@ macro_rules! int_impl {
without modifying the original"]
pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
// Using `&` helps LLVM see that it is the same check made in division.
if unlikely!((self == Self::MIN) & (rhs == -1)) {
if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) {
(self, true)
} else {
(self.div_euclid(rhs), false)
@ -2625,7 +2625,7 @@ macro_rules! int_impl {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
if unlikely!(rhs == -1) {
if intrinsics::unlikely(rhs == -1) {
(0, self == Self::MIN)
} else {
(self % rhs, false)
@ -2657,7 +2657,7 @@ macro_rules! int_impl {
#[inline]
#[track_caller]
pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
if unlikely!(rhs == -1) {
if intrinsics::unlikely(rhs == -1) {
(0, self == Self::MIN)
} else {
(self.rem_euclid(rhs), false)
@ -2686,7 +2686,7 @@ macro_rules! int_impl {
without modifying the original"]
#[allow(unused_attributes)]
pub const fn overflowing_neg(self) -> (Self, bool) {
if unlikely!(self == Self::MIN) {
if intrinsics::unlikely(self == Self::MIN) {
(Self::MIN, true)
} else {
(-self, false)

View File

@ -16,13 +16,6 @@ macro_rules! try_opt {
};
}
#[allow_internal_unstable(const_likely)]
macro_rules! unlikely {
($e: expr) => {
intrinsics::unlikely($e)
};
}
// Use this when the generated code should differ between signed and unsigned types.
macro_rules! sign_dependent_expr {
(signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => {
@ -1397,7 +1390,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 +1409,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

@ -491,7 +491,7 @@ macro_rules! uint_impl {
// Per <https://github.com/rust-lang/rust/pull/124114#issuecomment-2066173305>,
// LLVM is happy to re-form the intrinsic later if useful.
if unlikely!(intrinsics::add_with_overflow(self, rhs).1) {
if intrinsics::unlikely(intrinsics::add_with_overflow(self, rhs).1) {
None
} else {
// SAFETY: Just checked it doesn't overflow
@ -593,7 +593,7 @@ macro_rules! uint_impl {
#[inline]
pub const fn checked_add_signed(self, rhs: $SignedT) -> Option<Self> {
let (a, b) = self.overflowing_add_signed(rhs);
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict addition with a signed integer. Computes `self + rhs`,
@ -845,7 +845,7 @@ macro_rules! uint_impl {
#[inline]
pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_mul(rhs);
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict integer multiplication. Computes `self * rhs`, panicking if
@ -940,7 +940,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
pub const fn checked_div(self, rhs: Self) -> Option<Self> {
if unlikely!(rhs == 0) {
if intrinsics::unlikely(rhs == 0) {
None
} else {
// SAFETY: div by zero has been checked above and unsigned types have no other
@ -1001,7 +1001,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
if unlikely!(rhs == 0) {
if intrinsics::unlikely(rhs == 0) {
None
} else {
Some(self.div_euclid(rhs))
@ -1061,7 +1061,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
if unlikely!(rhs == 0) {
if intrinsics::unlikely(rhs == 0) {
None
} else {
// SAFETY: div by zero has been checked above and unsigned types have no other
@ -1123,7 +1123,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
if unlikely!(rhs == 0) {
if intrinsics::unlikely(rhs == 0) {
None
} else {
Some(self.rem_euclid(rhs))
@ -1362,7 +1362,7 @@ macro_rules! uint_impl {
#[inline]
pub const fn checked_neg(self) -> Option<Self> {
let (a, b) = self.overflowing_neg();
if unlikely!(b) { None } else { Some(a) }
if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict negation. Computes `-self`, panicking unless `self ==
@ -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

@ -22,7 +22,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(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(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

@ -334,7 +334,7 @@ fn check_terminator<'tcx>(
| TerminatorKind::TailCall { func, args, fn_span: _ } => {
let fn_ty = func.ty(body, tcx);
if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
if !is_const_fn(tcx, fn_def_id, msrv) {
if !is_stable_const_fn(tcx, fn_def_id, msrv) {
return Err((
span,
format!(
@ -377,12 +377,12 @@ fn check_terminator<'tcx>(
}
}
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
tcx.is_const_fn(def_id)
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
&& tcx.lookup_const_stability(def_id).is_none_or(|const_stab| {
if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
// function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
// function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`.
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
let const_stab_rust_version = match since {
@ -393,8 +393,12 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
msrv.meets(const_stab_rust_version)
} else {
// Unstable const fn with the feature enabled.
msrv.current().is_none()
// Unstable const fn, check if the feature is enabled. We need both the regular stability
// feature and (if set) the const stability feature to const-call this function.
let stab = tcx.lookup_stability(def_id);
let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature))
&& const_stab.feature.is_none_or(|f| tcx.features().enabled(f));
is_enabled && msrv.current().is_none()
}
})
}

View File

@ -346,13 +346,13 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
.cx
.qpath_res(p, hir_id)
.opt_def_id()
.map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
.map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
ExprKind::MethodCall(..)
if self
.cx
.typeck_results()
.type_dependent_def_id(e.hir_id)
.map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
.map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
ExprKind::Binary(_, lhs, rhs)
if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty()
&& self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},

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,21 @@ 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.
// FIXME: these are disabled until <https://github.com/rust-lang/stdarch/pull/1654> propagates.
#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
const fn barfoo_unmarked() {}
// FIXME disabled 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() {}
// FIXME disabled 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,17 @@ help: make the function or method const
LL | pub extern "C" fn foo_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
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:64:1
|
LL | pub fn not_a_const_fn() {}
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function or method const
--> $DIR/rustc-const-stability-require-const.rs:64:1
|
LL | pub fn not_a_const_fn() {}
| ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors

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