Skip to content

Commit 23ef001

Browse files
Rollup merge of #132492 - RalfJung:const-intrinsics, r=compiler-errors
remove support for extern-block const intrinsics This converts all const-callable intrinsics into the "new" form of a regular `fn` with `#[rustc_intrinsic]` attribute. That simplifies some of the logic since those functions can be marked `const fn` like regular functions, so intrinsics no longer need a special case to be considered const-callable at all. I also added a new attribute `#[rustc_const_stable_intrinsic]` to mark an intrinsic as being ready to be exposed on stable. Previously we used the `#[rustc_const_stable_indirect]` attribute for that, but that attribute had a dual role -- when used on a regular function, it is an entirely safe marker to make this function part of recursive const stability, but on an intrinsic it is a trusted marker requiring special care. It's not great for the same attribute to be sometimes fully checked and safe, and sometimes trusted and requiring special care, so I split this into two attributes. This also fixes #122652 by accepting intrinsics as const-stable if they have a fallback body that is recursively const-stable. The library changes are best reviewed with whitespace hidden. r? `@compiler-errors`
2 parents 56aa51e + a741b33 commit 23ef001

32 files changed

+1333
-1268
lines changed

compiler/rustc_attr/src/builtin.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,7 @@ pub fn find_stability(
273273
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
274274
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
275275
///
276-
/// `is_const_fn` indicates whether this is a function marked as `const`. It will always
277-
/// be false for intrinsics in an `extern` block!
276+
/// `is_const_fn` indicates whether this is a function marked as `const`.
278277
pub fn find_const_stability(
279278
sess: &Session,
280279
attrs: &[Attribute],
@@ -330,7 +329,7 @@ pub fn find_const_stability(
330329
}
331330
}
332331

333-
// Merge promotable and not_exposed_on_stable into stability info
332+
// Merge promotable and const_stable_indirect into stability info
334333
if promotable {
335334
match &mut const_stab {
336335
Some((stab, _)) => stab.promotable = promotable,
@@ -352,10 +351,7 @@ pub fn find_const_stability(
352351
})
353352
}
354353
}
355-
_ => {
356-
// We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
357-
// the `default_const_unstable` logic.
358-
}
354+
_ => {}
359355
}
360356
}
361357
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const

compiler/rustc_const_eval/messages.ftl

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

compiler/rustc_const_eval/src/check_consts/check.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -736,16 +736,25 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
736736

737737
// Intrinsics are language primitives, not regular calls, so treat them separately.
738738
if let Some(intrinsic) = tcx.intrinsic(callee) {
739+
// We use `intrinsic.const_stable` to determine if this can be safely exposed to
740+
// stable code, rather than `const_stable_indirect`. This is to make
741+
// `#[rustc_const_stable_indirect]` an attribute that is always safe to add.
742+
// We also ask is_safe_to_expose_on_stable_const_fn; this determines whether the intrinsic
743+
// fallback body is safe to expose on stable.
744+
let is_const_stable = intrinsic.const_stable
745+
|| (!intrinsic.must_be_overridden
746+
&& tcx.is_const_fn(callee)
747+
&& is_safe_to_expose_on_stable_const_fn(tcx, callee));
739748
match tcx.lookup_const_stability(callee) {
740749
None => {
741750
// Non-const intrinsic.
742751
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
743752
}
744-
Some(ConstStability { feature: None, const_stable_indirect, .. }) => {
753+
Some(ConstStability { feature: None, .. }) => {
745754
// Intrinsic does not need a separate feature gate (we rely on the
746755
// regular stability checker). However, we have to worry about recursive
747756
// const stability.
748-
if !const_stable_indirect && self.enforce_recursive_const_stability() {
757+
if !is_const_stable && self.enforce_recursive_const_stability() {
749758
self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
750759
span: self.span,
751760
def_path: self.tcx.def_path_str(callee),
@@ -755,17 +764,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
755764
Some(ConstStability {
756765
feature: Some(feature),
757766
level: StabilityLevel::Unstable { .. },
758-
const_stable_indirect,
759767
..
760768
}) => {
761769
self.check_op(ops::IntrinsicUnstable {
762770
name: intrinsic.name,
763771
feature,
764-
const_stable_indirect,
772+
const_stable: is_const_stable,
765773
});
766774
}
767775
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
768-
// All good.
776+
// All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it
777+
// can be *directly* invoked from stable const code) does not always
778+
// have the `#[rustc_const_stable_intrinsic]` attribute (which controls
779+
// exposing an intrinsic indirectly); we accept this call anyway.
769780
}
770781
}
771782
// 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
@@ -354,14 +354,14 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
354354
pub(crate) struct IntrinsicUnstable {
355355
pub name: Symbol,
356356
pub feature: Symbol,
357-
pub const_stable_indirect: bool,
357+
pub const_stable: bool,
358358
}
359359

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

compiler/rustc_const_eval/src/const_eval/fn_queries.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,9 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
2525
hir::Constness::Const
2626
}
2727
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
28-
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
29-
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
30-
// foreign items cannot be evaluated at compile-time.
31-
let is_const = if tcx.intrinsic(def_id).is_some() {
32-
tcx.lookup_const_stability(def_id).is_some()
33-
} else {
34-
false
35-
};
36-
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
28+
hir::Node::ForeignItem(_) => {
29+
// Foreign items cannot be evaluated at compile-time.
30+
hir::Constness::NotConst
3731
}
3832
hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness,
3933
_ => {

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

+1
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,7 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi
17891789
Some(ty::IntrinsicDef {
17901790
name: tcx.item_name(def_id.into()),
17911791
must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden),
1792+
const_stable: tcx.has_attr(def_id, sym::rustc_const_stable_intrinsic),
17921793
})
17931794
} else {
17941795
None

compiler/rustc_passes/src/stability.rs

-15
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
106106
def_id: LocalDefId,
107107
item_sp: Span,
108108
fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
109-
is_foreign_item: bool,
110109
kind: AnnotationKind,
111110
inherit_deprecation: InheritDeprecation,
112111
inherit_const_stability: InheritConstStability,
@@ -175,11 +174,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
175174
// implied), check if the function/method is const or the parent impl block is const.
176175
if let Some(fn_sig) = fn_sig
177176
&& !fn_sig.header.is_const()
178-
// We have to exclude foreign items as they might be intrinsics. Sadly we can't check
179-
// their ABI; `fn_sig.abi` is *not* correct for foreign functions.
180-
&& !is_foreign_item
181177
&& const_stab.is_some()
182-
&& (!self.in_trait_impl || !self.tcx.is_const_fn(def_id.to_def_id()))
183178
{
184179
self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
185180
}
@@ -398,7 +393,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
398393
ctor_def_id,
399394
i.span,
400395
None,
401-
/* is_foreign_item */ false,
402396
AnnotationKind::Required,
403397
InheritDeprecation::Yes,
404398
InheritConstStability::No,
@@ -417,7 +411,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
417411
i.owner_id.def_id,
418412
i.span,
419413
fn_sig,
420-
/* is_foreign_item */ false,
421414
kind,
422415
InheritDeprecation::Yes,
423416
const_stab_inherit,
@@ -437,7 +430,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
437430
ti.owner_id.def_id,
438431
ti.span,
439432
fn_sig,
440-
/* is_foreign_item */ false,
441433
AnnotationKind::Required,
442434
InheritDeprecation::Yes,
443435
InheritConstStability::No,
@@ -461,7 +453,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
461453
ii.owner_id.def_id,
462454
ii.span,
463455
fn_sig,
464-
/* is_foreign_item */ false,
465456
kind,
466457
InheritDeprecation::Yes,
467458
InheritConstStability::No,
@@ -477,7 +468,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
477468
var.def_id,
478469
var.span,
479470
None,
480-
/* is_foreign_item */ false,
481471
AnnotationKind::Required,
482472
InheritDeprecation::Yes,
483473
InheritConstStability::No,
@@ -488,7 +478,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
488478
ctor_def_id,
489479
var.span,
490480
None,
491-
/* is_foreign_item */ false,
492481
AnnotationKind::Required,
493482
InheritDeprecation::Yes,
494483
InheritConstStability::No,
@@ -507,7 +496,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
507496
s.def_id,
508497
s.span,
509498
None,
510-
/* is_foreign_item */ false,
511499
AnnotationKind::Required,
512500
InheritDeprecation::Yes,
513501
InheritConstStability::No,
@@ -527,7 +515,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
527515
i.owner_id.def_id,
528516
i.span,
529517
fn_sig,
530-
/* is_foreign_item */ true,
531518
AnnotationKind::Required,
532519
InheritDeprecation::Yes,
533520
InheritConstStability::No,
@@ -550,7 +537,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
550537
p.def_id,
551538
p.span,
552539
None,
553-
/* is_foreign_item */ false,
554540
kind,
555541
InheritDeprecation::No,
556542
InheritConstStability::No,
@@ -712,7 +698,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
712698
CRATE_DEF_ID,
713699
tcx.hir().span(CRATE_HIR_ID),
714700
None,
715-
/* is_foreign_item */ false,
716701
AnnotationKind::Required,
717702
InheritDeprecation::Yes,
718703
InheritConstStability::No,

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1663,6 +1663,7 @@ symbols! {
16631663
rustc_const_panic_str,
16641664
rustc_const_stable,
16651665
rustc_const_stable_indirect,
1666+
rustc_const_stable_intrinsic,
16661667
rustc_const_unstable,
16671668
rustc_conversion_suggestion,
16681669
rustc_deallocator,

0 commit comments

Comments
 (0)