Skip to content

Commit 760e111

Browse files
committed
add new rustc_const_stable_intrinsic attribute for const-stable intrinsics
1 parent 0844702 commit 760e111

File tree

11 files changed

+85
-73
lines changed

11 files changed

+85
-73
lines changed

compiler/rustc_const_eval/messages.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ const_eval_uninhabited_enum_variant_written =
402402
const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
403403
.help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
404404
const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable
405-
.help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
405+
.help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval)
406406
407407
const_eval_unreachable = entering unreachable code
408408
const_eval_unreachable_unwind =

compiler/rustc_const_eval/src/check_consts/check.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -699,16 +699,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
699699

700700
// Intrinsics are language primitives, not regular calls, so treat them separately.
701701
if let Some(intrinsic) = tcx.intrinsic(callee) {
702+
// We use `intrinsic.const_stable` to determine if this can be safely exposed to
703+
// stable code, rather than `const_stable_indirect`. This is to make
704+
// `#[rustc_const_stable_indirect]` an attribute that is always safe to add.
702705
match tcx.lookup_const_stability(callee) {
703706
None => {
704707
// Non-const intrinsic.
705708
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
706709
}
707-
Some(ConstStability { feature: None, const_stable_indirect, .. }) => {
710+
Some(ConstStability { feature: None, .. }) => {
708711
// Intrinsic does not need a separate feature gate (we rely on the
709712
// regular stability checker). However, we have to worry about recursive
710713
// const stability.
711-
if !const_stable_indirect && self.enforce_recursive_const_stability() {
714+
if !intrinsic.const_stable && self.enforce_recursive_const_stability() {
712715
self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
713716
span: self.span,
714717
def_path: self.tcx.def_path_str(callee),
@@ -718,17 +721,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
718721
Some(ConstStability {
719722
feature: Some(feature),
720723
level: StabilityLevel::Unstable { .. },
721-
const_stable_indirect,
722724
..
723725
}) => {
724726
self.check_op(ops::IntrinsicUnstable {
725727
name: intrinsic.name,
726728
feature,
727-
const_stable_indirect,
729+
const_stable: intrinsic.const_stable,
728730
});
729731
}
730732
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
731-
// All good.
733+
// All good. But ensure this is indeed a const-stable intrinsic.
734+
assert!(intrinsic.const_stable);
732735
}
733736
}
734737
// This completes the checks for intrinsics.

compiler/rustc_const_eval/src/check_consts/ops.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -355,14 +355,14 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
355355
pub(crate) struct IntrinsicUnstable {
356356
pub name: Symbol,
357357
pub feature: Symbol,
358-
pub const_stable_indirect: bool,
358+
pub const_stable: bool,
359359
}
360360

361361
impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
362362
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
363363
Status::Unstable {
364364
gate: self.feature,
365-
safe_to_expose_on_stable: self.const_stable_indirect,
365+
safe_to_expose_on_stable: self.const_stable,
366366
// We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
367367
// that's not a trivial change!
368368
is_function_call: false,

compiler/rustc_feature/src/builtin_attrs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
837837
rustc_const_stable_indirect, Normal,
838838
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
839839
),
840+
rustc_attr!(
841+
rustc_const_stable_intrinsic, Normal,
842+
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
843+
),
840844
gated!(
841845
rustc_allow_const_fn_unstable, Normal,
842846
template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,

compiler/rustc_middle/src/ty/intrinsic.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ pub struct IntrinsicDef {
99
pub name: Symbol,
1010
/// Whether the intrinsic has no meaningful body and all backends need to shim all calls to it.
1111
pub must_be_overridden: bool,
12+
/// Whether the intrinsic can be invoked from stable const fn
13+
pub const_stable: bool,
1214
}
1315

1416
impl TyCtxt<'_> {

compiler/rustc_middle/src/ty/util.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1790,6 +1790,8 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi
17901790
Some(ty::IntrinsicDef {
17911791
name: tcx.item_name(def_id.into()),
17921792
must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden),
1793+
const_stable: tcx.has_attr(def_id, sym::rustc_const_stable_intrinsic)
1794+
|| tcx.lookup_const_stability(def_id).is_some_and(|s| s.is_const_stable()),
17931795
})
17941796
} else {
17951797
None

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,7 @@ symbols! {
16641664
rustc_const_panic_str,
16651665
rustc_const_stable,
16661666
rustc_const_stable_indirect,
1667+
rustc_const_stable_intrinsic,
16671668
rustc_const_unstable,
16681669
rustc_conversion_suggestion,
16691670
rustc_deallocator,

0 commit comments

Comments
 (0)