Skip to content

Conversation

@oli-obk
Copy link
Contributor

@oli-obk oli-obk commented Dec 9, 2025

cc @RalfJung

Having moved several intrinsics from sth that gets invoked directly in a const fn to sth invoked in a const block kind of broke our "indirectly usable intrinsic" logic. So now we're actually checking it again. This required changing some intrinsics to now be indirectly callable

r? @jdonszelmann

@rustbot
Copy link
Collaborator

rustbot commented Dec 9, 2025

Some changes occurred in compiler/rustc_attr_parsing

cc @jdonszelmann

Some changes occurred to constck

cc @fee1-dead

Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter
gets adapted for the changes, if necessary.

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

⚠️ #[rustc_intrinsic_const_stable_indirect] controls whether intrinsics can be exposed to stable const
code; adding it needs t-lang approval.

cc @rust-lang/wg-const-eval

@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Dec 9, 2025
#[rustc_intrinsic]
#[miri::intrinsic_fallback_is_spec]
#[rustc_intrinsic_const_stable_indirect]
pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this and make_global are needed in

let alloc: *mut u8 = const_allocate(alloc_size, alloc_align);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one really shouldn't be callable-from-stable, it is the very definition of not stable... same for const_make_global.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would strongly prefer to add allow_const_unstable to new_unsize_zst -- and we should consider if it's really safe to use these highly experimental features there.

That said, Thin is entirely unstable, so we can also add allow_const_unstable with a comment saying that this isn't actually stable -- but then we should also add that as a blocker on the tracking issue as it seems easy to miss.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would strongly prefer to add allow_const_unstable to new_unsize_zst
That does feel nicer, to guard it against any other uses. With a comment there why specifically this call needs it and is safe

@oli-obk oli-obk force-pushed the stable_inline_const_using_unstable_intrinsics branch from 5640606 to 8666a33 Compare December 9, 2025 16:34
@RalfJung
Copy link
Member

RalfJung commented Dec 9, 2025

Is this a fix for #132536? Or only a partial fix since it "just" applies to inline consts, not const items?

|| self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked)
matches!(
self.const_kind,
Some(hir::ConstContext::ConstFn | hir::ConstContext::Const { inline: true })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only a partial fix. I can remove the inline limitation here, but it has a lot of fallout that I haven't analyzed yet. I'll do that in a follow-up

Copy link
Member

@RalfJung RalfJung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the remaining intrinsics, they aren't actually used from const fn either, are they? We just expose them via regular functions? The fact that those use a constant internally seems more of an implementation detail -- and we haven't had the t-lang FCP that would be required to actually expose them in a const fn.

View changes since this review

#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_intrinsic_const_stable_indirect]
pub const fn variant_count<T>() -> usize;
Copy link
Member

@RalfJung RalfJung Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't actually stable either, I think? std::mem::variant_count is still unstable.

#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_intrinsic_const_stable_indirect]
pub const fn type_name<T: ?Sized>() -> &'static str;
Copy link
Member

@RalfJung RalfJung Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't const-stable, it can only be invoked via a regular function.

#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_intrinsic_const_stable_indirect]
pub const fn type_id<T: ?Sized + 'static>() -> crate::any::TypeId;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And neither is this const-stable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is const stable. TypeId::of is const stable

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah fair, somehow I didn't find that one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, the t-lang FCP that justifies adding this attribute passed here.

Maybe we should have a separate PR just adding that attribute? This PR shouldn't add any more since we don't have FCP for any of the others.

}
InlineAsmOperand::Const { anon_const } => hir::InlineAsmOperand::Const {
anon_const: self.lower_const_block(anon_const),
anon_const: self.lower_const_block(anon_const, &[]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can put at least some atributes on const operands. Iirc recently cfg was stabilized here? Though that one is of course expanded out early. Still wonder where those attributes go and whether they should be forwarded here 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if in this case it only matters for their stability attrs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know where the attribute would go. If it's on the anon const, it will end up as part of its body's expression. You can't add attrs on operands, at least the ast has nowhere to put them. This change should be behaviour-preserving, but I could add a FIXME

Allow(Target::AssocConst),
Allow(Target::Trait),
Allow(Target::Static),
Allow(Target::Expression), // FIXME: we really only want to allow inline consts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could make up a new target for that 🤷‍♀️ . This would be its current only use but it's not that hard to do otherwise

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea I had that, but I felt I already changed enough in this PR 😅

#[rustc_intrinsic]
#[miri::intrinsic_fallback_is_spec]
#[rustc_intrinsic_const_stable_indirect]
pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would strongly prefer to add allow_const_unstable to new_unsize_zst
That does feel nicer, to guard it against any other uses. With a comment there why specifically this call needs it and is safe

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 10, 2025
@rustbot
Copy link
Collaborator

rustbot commented Dec 10, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

Remove the custom special case rejecting const stability on macros as it is now handled by the general check
@oli-obk
Copy link
Contributor Author

oli-obk commented Dec 16, 2025

The fact that those use a constant internally seems more of an implementation detail -- and we haven't had the t-lang FCP that would be required to actually expose them in a const fn.

I think it is important that non-const public items that contain const blocks using unstable things are also stability checked, otherwise we end up with situations where const features like const_allocate end up used in ways that we can only keep supporting in even hackier ways (worst case completely computing the const inside rustc via a new intrinsic). Limiting it to things that need to have a stability attribute added to it seems useful to me. But I agree that it's different from exposing calling it directly in const fns.

const fns that just have a const block in their body are no different from non-const fns that have a const block in their body.

And in case we don't do this kind of checking for const blocks, why would we do it for const items/assoc consts?

@oli-obk oli-obk force-pushed the stable_inline_const_using_unstable_intrinsics branch from 8666a33 to 2bf4c76 Compare December 16, 2025 13:27
@rustbot
Copy link
Collaborator

rustbot commented Dec 16, 2025

⚠️ #[rustc_allow_const_fn_unstable] needs careful audit to avoid accidentally exposing unstable
implementation details on stable.

cc @rust-lang/wg-const-eval

@rustbot
Copy link
Collaborator

rustbot commented Dec 16, 2025

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

Comment on lines 27 to 40
#[stable(feature = "asdf", since = "99.0.0")]
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const fn my_fun4() {
#[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
const {
my_fun()
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok this logic is borked 😆 I can make a const block const unstable and the function using it stable and it just keeps on working using very unstable things in the const block

@RalfJung
Copy link
Member

RalfJung commented Dec 16, 2025

I think it is important that non-const public items that contain const blocks using unstable things are also stability checked, otherwise we end up with situations where const features like const_allocate end up used in ways that we can only keep supporting in even hackier ways (worst case completely computing the const inside rustc via a new intrinsic). Limiting it to things that need to have a stability attribute added to it seems useful to me. But I agree that it's different from exposing calling it directly in const fns.

If we can find the right rules then I agree, it's good to have some sort of check here -- type_id shows that we can expose an intrinsic on stable in a const fn without having to add the attribute, which is clearly a gap in our const stability checking. (In this particular case it wasn't an accidental stabilization, we really did want to expose that intrinsic and we did go through t-lang FCP. But it could happen accidentally and that would be bad.)

However, the PR as-is (when I wrote those comments) requires too many annotations. For the very reasons you state, we should not mark anything that is related to const-heaps as indirectly-const-stable at the moment -- and the compiler shouldn't ask us to do that. Given that regular stability is not recursive, I am not sure it will be possible to fully check for indirect exposure of const intrinsics via const blocks in non-const functions.

@oli-obk oli-obk force-pushed the stable_inline_const_using_unstable_intrinsics branch from 2bf4c76 to 5b232db Compare December 16, 2025 14:21
@oli-obk
Copy link
Contributor Author

oli-obk commented Dec 16, 2025

mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`

is what the compiler tells us. The latter comes with a suggestion, too (tho the span is a bit off).

It doesn't actually suggest the option of using rustc_allow_const_fn_unstable, should probably fix that.

Either way, it correctly errors on calls to unstable const fns from const blocks now, with about the same UX as calling them from within const fns (see required changes to libcore)

@rust-log-analyzer

This comment has been minimized.

@oli-obk oli-obk force-pushed the stable_inline_const_using_unstable_intrinsics branch from 5b232db to 7958dfe Compare December 16, 2025 14:29
@RalfJung
Copy link
Member

It doesn't actually suggest the option of using rustc_allow_const_fn_unstable, should probably fix that.

It used to suggest that. Then people did it all the time when it wasn't appropriate, so I removed the suggestion.

@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-20-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
2   --> $DIR/const-fn-lang-feature-inline-const.rs:13:5
3    |
4 LL |     #[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]

15 LL | #[rustc_const_stable(feature = "asdf", since = "99.0.0")]
16    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17 
- error: const stability of inline consts must match const stability of containing item.
+ error: const stability of inline consts must match const stability of containing item
19   --> $DIR/const-fn-lang-feature-inline-const.rs:42:5
---
To only update this specific test, also pass `--test-args consts/min_const_fn/const-fn-lang-feature-inline-const.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/consts/min_const_fn/const-fn-lang-feature-inline-const.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/consts/min_const_fn/const-fn-lang-feature-inline-const" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers"
stdout: none
--- stderr -------------------------------
error: const stability of inline consts must match const stability of containing item
##[error]  --> /checkout/tests/ui/consts/min_const_fn/const-fn-lang-feature-inline-const.rs:13:5
   |
---
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: stability marker of containing item defined here
  --> /checkout/tests/ui/consts/min_const_fn/const-fn-lang-feature-inline-const.rs:11:1
   |
LL | #[rustc_const_stable(feature = "asdf", since = "99.0.0")]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: const stability of inline consts must match const stability of containing item
##[error]  --> /checkout/tests/ui/consts/min_const_fn/const-fn-lang-feature-inline-const.rs:42:5
   |
---
   |
LL |     #[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: const function that might be (indirectly) exposed to stable cannot use `#[feature(abi_unadjusted)]`
##[error]  --> /checkout/tests/ui/consts/min_const_fn/const-fn-lang-feature-inline-const.rs:26:9
   |
LL |         my_fun()
   |         ^^^^^^^^
   |
   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`
   |
LL |     const #[rustc_const_unstable(feature = "...", issue = "...")]
   |           +++++++++++++++++++++++++++++++++++++++++++++++++++++++

error: const function that might be (indirectly) exposed to stable cannot use `#[feature(abi_unadjusted)]`
##[error]  --> /checkout/tests/ui/consts/min_const_fn/const-fn-lang-feature-inline-const.rs:36:9
   |
LL |         my_fun()
   |         ^^^^^^^^
   |

#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub const fn type_name<T: ?Sized>() -> &'static str {
const { intrinsics::type_name::<T>() }
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does rustc_const_unstable on a const block mean?

It would help to see e.g. a patch updating the dev guide on these attributes, to understand the intended behavior without having to reverse engineer it from the implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants