Skip to content

Conversation

@oli-obk
Copy link
Contributor

@oli-obk oli-obk commented Nov 11, 2025

Implements functions that cannot be called at runtime (and thus also not from normal const functions, as those could be called from runtime).

This is done via the internal attribute rustc_comptime that can be added to normal functions, turning them into compile-time-only functions.

Because @fee1-dead and @compiler-errors did amazing work, we even get trait bounds that work inside comptime fns: via unconditionally-const const Trait bounds.

Use cases are

  • Reflection MVP #146923
  • const heap intrinsics
  • and the other various intrinsics (e.g. size_of 😆) that will just ICE in codegen or panic at runtime if they actually end up in runtime code

project goal issue: rust-lang/rust-project-goals#406

no tracking issue until we have a feature gate and some sort of syntax

cc @scottmcm as the T-lang goal champion

@rustbot
Copy link
Collaborator

rustbot commented Nov 11, 2025

Some changes occurred in compiler/rustc_attr_parsing

cc @jdonszelmann

Some changes occurred in compiler/rustc_passes/src/check_attr.rs

cc @jdonszelmann

Some changes occurred in compiler/rustc_hir/src/attrs

cc @jdonszelmann

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred in src/tools/rustfmt

cc @rust-lang/rustfmt

@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-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output. T-rustfmt Relevant to the rustfmt team, which will review and decide on the PR/issue. labels Nov 11, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 11, 2025

r? @JonathanBrouwer

rustbot has assigned @JonathanBrouwer.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rust-log-analyzer

This comment has been minimized.

@rustbot
Copy link
Collaborator

rustbot commented Nov 11, 2025

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

Comment on lines 4230 to 4231
Comptime,
Const,
Copy link
Member

Choose a reason for hiding this comment

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

Seems worth doc comments distinguishing these two.

let fn_span = self.token.span;
let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn`
let mut header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn`
if let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::rustc_comptime)) {
Copy link
Member

@fmease fmease Nov 11, 2025

Choose a reason for hiding this comment

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

This doesn't account for #[cfg_attr(…, rustc_comptime)]. I would just leave the parser and ast::Const alone and do the lowering to hir::Constness (which would still have Comptime) in AST lowering. This should simplify things a lot.

Even if you anticipate it being turned into a keyword / qualifier eventually, you can't assume that and it would be super easy anyway to update the parser & AST once it's truly necessary.

@rust-log-analyzer

This comment has been minimized.

}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)]
pub enum Constness {
Copy link
Member

@fmease fmease Nov 11, 2025

Choose a reason for hiding this comment

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

Personally speaking I would rename the variants like so:

pub enum Constness {
    Always, // `#[rustc_comptime]`
    Maybe, // `const`
    Never,
}

to mirror BoundConstness which is Always (for const), Maybe (for [const]) and Never. This makes it crystal clear what they represent and leaves no room for ambiguity.

If it were up to me, I would even rename Constness to ItemConstness if traits will be allowed to be compiletime, too. Otherwise, I would split it into FnConstness and TraitConstness.

Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer this naming over the suggestion I made in https://github.com/rust-lang/rust/pull/148820/files#r2517464261 actually

@jdonszelmann jdonszelmann self-assigned this Nov 11, 2025
@fee1-dead fee1-dead self-assigned this Nov 11, 2025
),
rustc_attr!(
rustc_comptime, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
Copy link
Member

Choose a reason for hiding this comment

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

It this necessary? The other queries would store this information

Copy link
Contributor

@jdonszelmann jdonszelmann Nov 12, 2025

Choose a reason for hiding this comment

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

find_attr!(tcx.get_all_attrs(), AttributeKind::Comptime(..))

would do the same (slightly slower?) but avoids a new query which might be worth it. You can set CrossCrateEncoding for attributes in compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Copy link
Contributor

Choose a reason for hiding this comment

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

In fact, you did mark it as cross-crate encodable oli, so if we keep the query you can turn cross crate encoding of the attribute off (see my other comment)

Comment on lines 922 to 928
if let hir::Constness::Comptime = self.tcx.constness(callee_did) {
match const_context {
Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => {}
Some(hir::ConstContext::ConstFn) | None => {
self.dcx().span_err(span, "comptime fns can only be called at compile time");
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't enforce cross crate if I use a comptime function in fn if my crate doesn't enable const_trait_impl.

Would it make sense to also add logic to constck? (check_const.rs)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well I'm working on turning this check on unconditionally. I can just move the comptime check before the feature gate check

#[derive(HashStable_Generic, Walkable)]
pub enum Const {
Comptime(Span),
Yes(Span),
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be nice to some day make all the variant names meaningful. Something like

enum EvaluationTime {
    Comptime,
    MaybeComptime,
    Runtime,
}

Looking at your PR yday that's one of the first things I thought. First decided not to comment it because it might not be for this PR but coming back I thought I'd mention it anyway.

BodyStability { .. } => No,
Coinductive(..) => No,
Cold(..) => No,
Comptime(..) => Yes,
Copy link
Contributor

Choose a reason for hiding this comment

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

can be No if we do the query

match s {
hir::Constness::NotConst => {}
hir::Constness::Const => self.word_nbsp("const"),
hir::Constness::Comptime => self.word_nbsp("comptime"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Comptime is an attribute for now right; #[rustc_comptime]? Pretty printing doesn't matter so much, but this makes it seem like it's already a keyword. You could make it an unstable keyword ofc. But otherwise, I think the attr is already printed itself in hir pretty printing, so you might not need to emit anything here

self.def_kind(def_id),
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure
) && self.constness(def_id) == hir::Constness::Const
) && self.constness(def_id) != hir::Constness::NotConst
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this enum is unlikely to change any time soon, but might be nicer to write as a match exhaustively naming the variants

@rustbot
Copy link
Collaborator

rustbot commented Nov 21, 2025

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

Some changes occurred to constck

cc @fee1-dead

@rustbot rustbot added the T-clippy Relevant to the Clippy team. label Nov 21, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 21, 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.

@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-gcc failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
test [crashes] tests/crashes/131787.rs ... ok
test [crashes] tests/crashes/131886.rs ... ok
test [crashes] tests/crashes/132126.rs ... ok
test [crashes] tests/crashes/132765.rs ... ok
2025-11-21T12:04:11.543685Z ERROR compiletest::runtest: fatal error, panic: "crashtest no longer crashes/triggers ICE, hooray! Please give it a meaningful name, add a doc-comment to the start of the test explaining why it exists and move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR description ensures that the corresponding ticket is auto-closed upon merge. If you want to see verbose output, set `COMPILETEST_VERBOSE_CRASHES=1`."
test [crashes] tests/crashes/132960.rs ... FAILED
test [crashes] tests/crashes/133965.rs ... ignored, ignored if rustc wasn't built with debug assertions
test [crashes] tests/crashes/133613.rs ... ok
test [crashes] tests/crashes/134061.rs ... ignored, ignored if rustc wasn't built with debug assertions
test [crashes] tests/crashes/134479.rs ... ignored, gcc backend is marked as ignore
---

---- [crashes] tests/crashes/132960.rs stdout ----
------rustc stdout------------------------------

------rustc stderr------------------------------
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
##[warning] --> /checkout/tests/crashes/132960.rs:3:46
  |
3 | #![feature(adt_const_params, const_ptr_read, generic_const_exprs, unsized_const_params)]
  |                                              ^^^^^^^^^^^^^^^^^^^
  |
  = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
---

error[E0601]: `main` function not found in crate `132960`
##[error]  --> /checkout/tests/crashes/132960.rs:36:48
   |
36 | const FOOBAR: &str = concat_strs::<FOO, BAR>();
   |                                                ^ consider adding a `main` function to `/checkout/tests/crashes/132960.rs`

error[E0517]: attribute should be applied to a struct, enum, or union
##[error]  --> /checkout/tests/crashes/132960.rs:11:12
   |
11 |     #[repr(C)]
   |            ^
...
14 |     const fn concat_arr<const M: usize, const N: usize>(a: [u8; M], b: [u8; N]) -> [u8; M + N] {}
   |     --------------------------------------------------------------------------------------------- not a struct, enum, or union

error[E0517]: attribute should be applied to a struct, enum, or union
##[error]  --> /checkout/tests/crashes/132960.rs:12:12
   |
12 |     #[repr(C)]
   |            ^
13 |
14 |     const fn concat_arr<const M: usize, const N: usize>(a: [u8; M], b: [u8; N]) -> [u8; M + N] {}
   |     --------------------------------------------------------------------------------------------- not a struct, enum, or union

warning: the feature `const_ptr_read` has been stable since 1.71.0 and no longer requires an attribute to enable
##[warning] --> /checkout/tests/crashes/132960.rs:3:30
  |
3 | #![feature(adt_const_params, const_ptr_read, generic_const_exprs, unsized_const_params)]
  |                              ^^^^^^^^^^^^^^
  |
  = note: `#[warn(stable_features)]` on by default

error[E0308]: mismatched types
##[error]  --> /checkout/tests/crashes/132960.rs:14:84
   |
14 |     const fn concat_arr<const M: usize, const N: usize>(a: [u8; M], b: [u8; N]) -> [u8; M + N] {}
   |              ----------                                                            ^^^^^^^^^^^ expected `[u8; M + N]`, found `()`
   |              |
   |              implicitly returns `()` as its body has no tail or `return` expression
   |
note: consider returning one of these bindings
  --> /checkout/tests/crashes/132960.rs:14:57
   |
14 |     const fn concat_arr<const M: usize, const N: usize>(a: [u8; M], b: [u8; N]) -> [u8; M + N] {}
   |                                                         ^           ^

warning: type annotations needed
##[warning]  --> /checkout/tests/crashes/132960.rs:25:35
   |
25 |                 A.as_ptr().cast().read(),
   |                                   ^^^^
   |
   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
   = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
   = note: `#[warn(tyvar_behind_raw_pointer)]` (part of `#[warn(rust_2018_compatibility)]`) on by default

warning: type annotations needed
##[warning]  --> /checkout/tests/crashes/132960.rs:26:35
   |
26 |                 B.as_ptr().cast().read(),
   |                                   ^^^^
   |
   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
   = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>

error[E0716]: temporary value dropped while borrowed
##[error]  --> /checkout/tests/crashes/132960.rs:24:44
   |
24 |                std::str::from_utf8_unchecked(&concat_arr(
   |   _____________-                              ^
   |  |____________________________________________|
25 | ||                 A.as_ptr().cast().read(),
26 | ||                 B.as_ptr().cast().read(),
27 | ||             ))
   | ||_____________^- using this value as a constant requires that borrow lasts for `'static`
   | |______________|
   |                creates a temporary value which is freed while still in use
28 |            };
   |            - temporary value is freed at the end of this statement

error: aborting due to 5 previous errors; 5 warnings emitted

Some errors have detailed explanations: E0308, E0517, E0601, E0716.
For more information about an error, try `rustc --explain E0308`.

------------------------------------------

error: crashtest no longer crashes/triggers ICE, hooray! Please give it a meaningful name, add a doc-comment to the start of the test explaining why it exists and move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR description ensures that the corresponding ticket is auto-closed upon merge. If you want to see verbose output, set `COMPILETEST_VERBOSE_CRASHES=1`.

thread '[crashes] tests/crashes/132960.rs' panicked at src/tools/compiletest/src/runtest/crashes.rs:17:18:
fatal error
stack backtrace:
   5: __rustc::rust_begin_unwind

For more information how to resolve CI failures of this job, visit this link.

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-review Status: Awaiting review from the assignee but also interested parties. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output. T-rustfmt Relevant to the rustfmt team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants