`const` blocks as a `mod` item
Tracking issue: rust-lang/rust#149226
This adds support for writing const { ... } as an item in a module. In the current implementation, this is a unique AST item that gets lowered to const _: () = const { ... }; in HIR.
rustfmt support included.
TODO:
pub const { ... }does not make sense (see rust-lang/rust#147136). Reject it. Should this be rejected by the parser or smth?- Improve diagnostics (preferably they should not mention the fake
_ident). - There's an invariant
ConstBlockItem{body: Expr{kind: ConstBlock(..), ..}}. Get rid of it?
The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)
Click to see the possible cause of the failure (guessed by this bot)
error: expected item, found keyword `const`
##[error] --> /checkout/library/core/src/ptr/alignment.rs:18:1
|
18 | const { assert!(size_of::<Alignment>() == size_of::<usize>()) }
| ^^^^^ expected item
|
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
error: expected item, found keyword `const`
---
error: expected item, found keyword `const`
##[error] --> /checkout/library/coretests/tests/cmp.rs:241:5
|
241 | const { assert!(S(1) == S(1)) }
| ^^^^^ expected item
|
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)
Click to see the possible cause of the failure (guessed by this bot)
fmt: checked 6559 files
tidy check
tidy [rustdoc_json (src)]: `rustdoc-json-types` modified, checking format version
tidy: Skipping binary file check, read-only filesystem
tidy [features]: /checkout/compiler/rustc_feature/src/unstable.rs:449: no tracking issue for feature const_block_items
tidy [features]: FAIL
removing old virtual environment
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'venv'
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'virtualenv'
Requirement already satisfied: pip in ./build/venv/lib/python3.10/site-packages (25.3)
linting python files
---
linting javascript files and applying suggestions
Running eslint on rustdoc JS files
info: ES-Check: there were no ES version matching errors! 🎉
typechecking javascript files
tidy: The following check failed: features
Command `/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-tools-bin/rust-tidy /checkout /checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo /checkout/obj/build 4 /node/bin/yarn --extra-checks=py,cpp,js,spellcheck` failed with exit code 1
Created at: src/bootstrap/src/core/build_steps/tool.rs:1594:23
Executed at: src/bootstrap/src/core/build_steps/test.rs:1285:29
Command has failed. Rerun with -v to see more details.
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
Build completed unsuccessfully in 0:02:57
local time: Fri Nov 21 20:33:59 UTC 2025
network time: Fri, 21 Nov 2025 20:33:59 GMT
##[error]Process completed with exit code 1.
The job pr-check-2 failed! Check out the build log: (web) (plain enhanced) (plain)
Click to see the possible cause of the failure (guessed by this bot)
The job pr-check-2 failed! Check out the build log: (web) (plain enhanced) (plain)
Click to see the possible cause of the failure (guessed by this bot)
121 | pub fn parse_item(
| ^^^^^^^^^^
help: provide the argument
|
64 | let item = match parser.parse_item(ForceCollect::No, /* AllowConstBlockItems */) {
| ++++++++++++++++++++++++++++
error[E0061]: this method takes 2 arguments but 1 argument was supplied
--> src/tools/rustfmt/src/parse/macros/mod.rs:70:42
|
70 | |parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No),
| ^^^^^^^^^^------------------ argument #2 of type `AllowConstBlockItems` is missing
|
note: method defined here
--> /checkout/compiler/rustc_parse/src/parser/item.rs:121:12
|
121 | pub fn parse_item(
| ^^^^^^^^^^
help: provide the argument
|
70 | |parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No, /* AllowConstBlockItems */),
| ++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `ItemKind::ConstBlock(_)` not covered
--> src/tools/rustfmt/src/visitor.rs:488:19
|
488 | match item.kind {
| ^^^^^^^^^ pattern `ItemKind::ConstBlock(_)` not covered
|
The job aarch64-gnu-llvm-20-2 failed! Check out the build log: (web) (plain enhanced) (plain)
Click to see the possible cause of the failure (guessed by this bot)
124 | allow_const_block_items: AllowConstBlockItems,
| ---------------------------------------------
help: provide the argument
|
2242 | .parse_item(ForceCollect::No, /* AllowConstBlockItems */)
| ++++++++++++++++++++++++++++
error[E0061]: this method takes 2 arguments but 1 argument was supplied
--> compiler/rustc_parse/src/parser/tests.rs:2257:59
|
2257 | with_error_checking_parse(source_str, &psess(), |p| p.parse_item(ForceCollect::No))
| ^^^^^^^^^^------------------ argument #2 of type `AllowConstBlockItems` is missing
|
note: method defined here
--> compiler/rustc_parse/src/parser/item.rs:121:12
|
121 | pub fn parse_item(
| ^^^^^^^^^^
...
124 | allow_const_block_items: AllowConstBlockItems,
| ---------------------------------------------
help: provide the argument
|
2257 | with_error_checking_parse(source_str, &psess(), |p| p.parse_item(ForceCollect::No, /* AllowConstBlockItems */))
| ++++++++++++++++++++++++++++
[RUSTC-TIMING] rustc_mir_dataflow test:true 5.559
Compiling rustc_ty_utils v0.0.0 (/checkout/compiler/rustc_ty_utils)
For more information about this error, try `rustc --explain E0061`.
Some changes occurred in src/tools/rustfmt
cc @rust-lang/rustfmt
r? @jdonszelmann
rustbot has assigned @jdonszelmann. 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
I can review this from compiler. @rust-lang/lang do you want to sign off on this in any way, formally starting a lang experiment for example?
@rustbot author
Reminder, once the PR becomes ready for a review, use @rustbot ready.
I can review this from compiler. @rust-lang/lang do you want to sign off on this in any way, formally starting a lang experiment for example?
I see that, @GrigorenkoPV, you created a tracking issue for the experiment. Thanks for doing that. We need a lang champion for the experiment; I'll nominate this so we can discuss and assign one.
Hmm, I worry that this would muddy the "items are items" thing, because now typing the same thing will work differently in different places, which seems non-great.
I wonder about maybe doing this a different way, like how we allow omitting -> () on functions, so maybe we could instead allow const _ = …; that has to be unit-typed? That way it'd clearly be an item even in a place where inline const expressions are also valid.
We discussed this in today's @rust-lang/lang meeting.
We're happy to see a lang experiment for this.
I would be happy to serve as the champion. @GrigorenkoPV, please check in with me as the experiment progresses, so we can keep lang up to date with the results of the experiment.
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.
:umbrella: The latest upstream changes (presumably #149646) made this pull request unmergeable. Please resolve the merge conflicts.
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.
Hmm, I worry that this would muddy the "items are items" thing, because now typing the same thing will work differently in different places, which seems non-great.
True.
I wonder about maybe doing this a different way, like how we allow omitting
-> ()on functions, so maybe we could instead allowconst _ = …;that has to be unit-typed? That way it'd clearly be an item even in a place where inline const expressions are also valid.
That sounds like a good idea. I will probably try to implement this as well (but later), as an alternative to this approach or maybe as a generally nice-to-have feature.
I guess further discussion with lang would be needed here, but I'd prefer to have it after I at least have some sort of a prototype.
@rustbot ready
Out of the remaining issues (listed in OP):
I would prefer to deal with diagnostic improvements later, outside of this PR, if that's acceptable. This includes exorcising _ identifiers from, general tailoring of the messages, and rejecting visibility qualifiers, which have no effect for const block items.
As for the AllowConstBlockItems::FIXME, I'm fine with either fixing them later (and meanwhile just adding a note about what they actually mean), or blocking this PR until they are gotten rid of, which would mean I would probably have to ping some people, more knowledgeable about the involved parts of the compiler, or maybe pester them on Zulip or smth.
left a comment at places where we use FIXME still (I thope all?) with my thoughts. If you agree, let's change to that. Diagnostics changes are ok, maybe make a not about that on the tracking issue so we don't forget. Other than that pretty much good from me and lang also it seems. Great!
@rustbot author
about the refactoring of that invariant, also maybe make a note of that on the tracking issue. lgtm otherwise
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.
Got rid of FIXME, rebased, updated the tracking issue.
@rustbot ready
https://github.com/rust-lang/rust/pull/149174#discussion_r2595414977 @rustbot author
Argh, pushed an outdated version from a wrong machine. I guess even NixOS can't always help when managing multiple devices.
@rustbot ready Hopefully for real this time
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)
Compiling rustc_expand v0.0.0 (/checkout/compiler/rustc_expand)
error[E0277]: the trait bound `AllowConstBlockItems: From<bool>` is not satisfied
--> compiler/rustc_expand/src/proc_macro.rs:159:66
|
159 | match parser.parse_item(ForceCollect::No, (!is_stmt).into()) {
| ^^^^ the trait `From<bool>` is not implemented for `AllowConstBlockItems`
|
= note: required for `bool` to implement `Into<AllowConstBlockItems>`
For more information about this error, try `rustc --explain E0277`.
[RUSTC-TIMING] rustc_expand test:false 0.932
error: could not compile `rustc_expand` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
Nope :/
by the way, why does a global const block desugar to const _: () = const {...}? Is that any different than const _: () = { ... }?
by the way, why does a global const block desugar to
const _: () = const {...}?
Ease of implementation, really.
Is that any different than
const _: () = { ... }?
To the best of my knowledge, it shouldn't matter.
then I think it might be better not to.
the const block will get its own defid, so with it we effectively allocate two
@rustbot author