about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs13
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_middle/src/ty/intrinsic.rs2
-rw-r--r--compiler/rustc_middle/src/ty/util.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
7 files changed, 20 insertions, 8 deletions
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 2bc5adb2dce..826e34930ea 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -399,7 +399,7 @@ const_eval_uninhabited_enum_variant_written =
 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)
+    .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval)
 
 const_eval_unreachable = entering unreachable code
 const_eval_unreachable_unwind =
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 8cb7e02036f..1c17421e782 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -736,16 +736,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                 // Intrinsics are language primitives, not regular calls, so treat them separately.
                 if let Some(intrinsic) = tcx.intrinsic(callee) {
+                    // We use `intrinsic.const_stable` to determine if this can be safely exposed to
+                    // stable code, rather than `const_stable_indirect`. This is to make
+                    // `#[rustc_const_stable_indirect]` an attribute that is always safe to add.
                     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, .. }) => {
+                        Some(ConstStability { feature: None, .. }) => {
                             // Intrinsic does not need a separate feature gate (we rely on the
                             // regular stability checker). However, we have to worry about recursive
                             // const stability.
-                            if !const_stable_indirect && self.enforce_recursive_const_stability() {
+                            if !intrinsic.const_stable && self.enforce_recursive_const_stability() {
                                 self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
                                     span: self.span,
                                     def_path: self.tcx.def_path_str(callee),
@@ -755,17 +758,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                         Some(ConstStability {
                             feature: Some(feature),
                             level: StabilityLevel::Unstable { .. },
-                            const_stable_indirect,
                             ..
                         }) => {
                             self.check_op(ops::IntrinsicUnstable {
                                 name: intrinsic.name,
                                 feature,
-                                const_stable_indirect,
+                                const_stable: intrinsic.const_stable,
                             });
                         }
                         Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
-                            // All good.
+                            // All good. But ensure this is indeed a const-stable intrinsic.
+                            assert!(intrinsic.const_stable);
                         }
                     }
                     // This completes the checks for intrinsics.
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index d264cab1511..2931159842f 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -354,14 +354,14 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
 pub(crate) struct IntrinsicUnstable {
     pub name: Symbol,
     pub feature: Symbol,
-    pub const_stable_indirect: bool,
+    pub const_stable: 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,
+            safe_to_expose_on_stable: self.const_stable,
             // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
             // that's not a trivial change!
             is_function_call: false,
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 0069b07ad62..cc0bdec7019 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -837,6 +837,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_const_stable_indirect, Normal,
         template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
     ),
+    rustc_attr!(
+        rustc_const_stable_intrinsic, Normal,
+        template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
+    ),
     gated!(
         rustc_allow_const_fn_unstable, Normal,
         template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
diff --git a/compiler/rustc_middle/src/ty/intrinsic.rs b/compiler/rustc_middle/src/ty/intrinsic.rs
index ed0fb37d3b8..6a3ddacb424 100644
--- a/compiler/rustc_middle/src/ty/intrinsic.rs
+++ b/compiler/rustc_middle/src/ty/intrinsic.rs
@@ -9,6 +9,8 @@ pub struct IntrinsicDef {
     pub name: Symbol,
     /// Whether the intrinsic has no meaningful body and all backends need to shim all calls to it.
     pub must_be_overridden: bool,
+    /// Whether the intrinsic can be invoked from stable const fn
+    pub const_stable: bool,
 }
 
 impl TyCtxt<'_> {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 83276808a28..b5811824683 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1789,6 +1789,8 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi
         Some(ty::IntrinsicDef {
             name: tcx.item_name(def_id.into()),
             must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden),
+            const_stable: tcx.has_attr(def_id, sym::rustc_const_stable_intrinsic)
+                || tcx.lookup_const_stability(def_id).is_some_and(|s| s.is_const_stable()),
         })
     } else {
         None
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index fac2180d63b..21a74bd4020 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1663,6 +1663,7 @@ symbols! {
         rustc_const_panic_str,
         rustc_const_stable,
         rustc_const_stable_indirect,
+        rustc_const_stable_intrinsic,
         rustc_const_unstable,
         rustc_conversion_suggestion,
         rustc_deallocator,