Skip to content

Implement forced keywords (k#) - #161775

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
fmease:kay-hash
Sep 28, 2026
Merged

rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
fmease:kay-hash

Conversation

@fmease

@fmease fmease commented Aug 25, 2026 •

Copy link
Copy Markdown
Member

View all comments

Part of #153839. CC @dianne

Introduces a new token kind to Rust >=2021 that looks like k#ident and that is called forced keyword (identifier). This is gated behind a new unstable feature called forced_keywords. This is backed by compiler MCP 945.

The ident in k#ident must be a keyword (from any edition) or a weak/contextual keyword for the token to be valid. The ident in k#ident needn't be a keyword to be lexically valid (CC #161775 (comment)).


What won't be done in this PR:

  1. implementing forced keyword lifetimes ('k#static)
  2. migrating away from built-in syntax builtin # $ident($($tt)*) / introducing k#-exclusive (weak) keywords
  3. allowing the user to force edition-dependent & context-dependent keywords to be keywords
    • re. edition-dependent: forcing them to be keywords even in editions where they're usually not a (strong) keyword (today, that only affects gen anyway IINM)
    • re. context-dependent: E.g., union is only "active" if it's followed by a non-reserved identifier and under this PR the same rules apply to k#union even though that's not necessary; changing it would result in better diagnostics (e.g., for k#union struct {}: error: expected item, found `k#union` => expected identifier, found keyword `struct`) and maybe also allow for disambiguation for other context-dependent keywords
  4. extending the proc_macro::Ident API to allow users to programmatically create forced keywords (might never be added)

(No LLM was or will be used by me during the entire creation process of this PR)

@rustbot rustbot added 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-rust-analyzer Relevant to the rust-analyzer 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. labels Aug 25, 2026
@fmease

fmease commented Aug 25, 2026

Copy link
Copy Markdown
Member Author

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 25, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Aug 25, 2026
Implement forced keywords (`k#`)
@rust-log-analyzer

This comment has been minimized.

/// Traits for function pointers and items
(unstable, fn_static, "CURRENT_RUSTC_VERSION", Some(148768)),
/// Allows using forced keywords `k#fn`.
(unstable, forced_keywords, "CURRENT_RUSTC_VERSION", Some(153839)),

@fmease fmease Aug 25, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I've intentionally not marked it internal even though this feature is only backed by a T-compiler MCP and not by a T-lang RFC or in-tree experiment:

I would find it a bit weird if we (in a hypothetical future) told users to "please try out" "k#only bounds" or "&k#own types & exprs" (features that would obviously be non-internal) but they'd have to enable an internal feature in tandem (could be perceived as off-putting).

However, I'm okay with switching it to incomplete or even internal if requested.

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No opinion on this.

Comment thread compiler/rustc_expand/src/proc_macro_server.rs
@rust-log-analyzer

This comment has been minimized.

@rust-bors

rust-bors Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 4eb8eac (4eb8eac3e01e4dbc9d58546df979f51a2ac2e5d5)
Base parent: b751e7a (b751e7a48501be14dcd57b4a430b73a0e51a0c52)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (4eb8eac): comparison URL.

Overall result: ✅ improvements - no action needed

Benchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up.

@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.2% [-0.3%, -0.2%] 2
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results (primary -3.0%, secondary 1.1%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
2.8% [2.5%, 3.1%] 2
Improvements ✅
(primary)
-3.0% [-4.1%, -1.9%] 3
Improvements ✅
(secondary)
-2.2% [-2.2%, -2.2%] 1
All ❌✅ (primary) -3.0% [-4.1%, -1.9%] 3

Cycles

Results (primary 2.1%, secondary -1.4%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.1% [2.1%, 2.1%] 1
Regressions ❌
(secondary)
2.2% [2.2%, 2.2%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-3.2% [-4.1%, -2.3%] 2
All ❌✅ (primary) 2.1% [2.1%, 2.1%] 1

Binary size

Results (primary 0.0%, secondary -0.0%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.1% [0.0%, 0.1%] 4
Regressions ❌
(secondary)
0.0% [0.0%, 0.0%] 1
Improvements ✅
(primary)
-0.0% [-0.1%, -0.0%] 4
Improvements ✅
(secondary)
-0.0% [-0.1%, -0.0%] 2
All ❌✅ (primary) 0.0% [-0.1%, 0.1%] 8

Bootstrap: 477.576s -> 469.017s (-1.79%)
Artifact size: 400.35 MiB -> 400.38 MiB (0.01%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 25, 2026
@rust-bors

This comment has been minimized.

@fmease
fmease force-pushed the kay-hash branch 2 times, most recently from 9e590de to 1de8681 Compare August 27, 2026 14:25
@fmease fmease added the S-blocked Status: Blocked on something else such as an RFC or other implementation work. label Aug 27, 2026
@fmease fmease changed the title Implement forced keywords (k#) [STACKED] Implement forced keywords (k#) Aug 27, 2026
@fmease

fmease commented Aug 27, 2026 •

Copy link
Copy Markdown
Member Author

Ready for review.

Caution

Only review the commits created after ------------------------- BRANCH SEPARATOR -------------------------.
That's because this PR is stacked on top of PR #161792. Hence, it's marked S-blocked Status: Blocked on something else such as an RFC or other implementation work. .

Best reviewed commit by commit.

@fmease
fmease marked this pull request as ready for review August 27, 2026 14:33
@rustbot

rustbot commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in compiler/rustc_builtin_macros/src/autodiff.rs

cc @ZuseZ4

rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead.

cc @rust-lang/rust-analyzer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 27, 2026
@petrochenkov petrochenkov added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Sep 25, 2026
@rustbot

rustbot commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

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.

@fmease

fmease commented Sep 27, 2026

Copy link
Copy Markdown
Member Author

I've addressed all of your suggestions & added a new commit that drops the abstraction-layer-breaking check from the lexer (can be squashed away).

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 27, 2026
@petrochenkov

Copy link
Copy Markdown
Contributor

@bors squash

@rust-bors

This comment has been minimized.

* Implement forced keywords
* Allow any identifier to be forced as a keyword even if not reserved
@rust-bors

rust-bors Bot commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

🔨 2 commits were squashed into abcef06.

@petrochenkov

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-bors Bot commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

📌 Commit abcef06 has been tentatively approved by petrochenkov

It will be put into the queue for this repository once PR CI succeeds.

@petrochenkov petrochenkov added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 27, 2026
@rust-bors

This comment has been minimized.

@rust-bors rust-bors Bot added merged-by-bors This PR was explicitly merged by bors. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Sep 28, 2026
@rust-bors

rust-bors Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

☀️ Test successful - CI
Approved by: petrochenkov
Duration: 3h 3m 33s
Pushing 2269776 to main...

@rust-bors
rust-bors Bot merged commit 2269776 into rust-lang:main Sep 28, 2026
14 checks passed
@rustbot rustbot added this to the 1.101.0 milestone Sep 28, 2026
@fmease
fmease deleted the kay-hash branch September 28, 2026 04:12
@github-actions

Copy link
Copy Markdown
Contributor
What is this? This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.

Comparing d080e7d (parent) -> 2269776 (this PR)

Test differences

Show 37 test diffs

Stage 1

  • [ui] tests/ui/parser/forced-keywords/basic.rs: [missing] -> pass (J0)
  • [ui] tests/ui/parser/forced-keywords/decl-macro-matching.rs: [missing] -> pass (J0)
  • [ui] tests/ui/parser/forced-keywords/feature-gate-forced-keywords.rs: [missing] -> pass (J0)
  • [ui] tests/ui/parser/forced-keywords/non-keyword-neg.rs: [missing] -> pass (J0)
  • [ui] tests/ui/parser/forced-keywords/non-keyword-pos.rs: [missing] -> pass (J0)
  • [ui] tests/ui/parser/forced-keywords/pre-2021-edition-fail.rs: [missing] -> pass (J0)
  • [ui] tests/ui/parser/forced-keywords/pre-2021-edition-pass.rs: [missing] -> pass (J0)
  • [ui (polonius)] tests/ui/parser/forced-keywords/basic.rs: [missing] -> pass (J1)
  • [ui (polonius)] tests/ui/parser/forced-keywords/decl-macro-matching.rs: [missing] -> pass (J1)
  • [ui (polonius)] tests/ui/parser/forced-keywords/feature-gate-forced-keywords.rs: [missing] -> pass (J1)
  • [ui (polonius)] tests/ui/parser/forced-keywords/non-keyword-neg.rs: [missing] -> pass (J1)
  • [ui (polonius)] tests/ui/parser/forced-keywords/non-keyword-pos.rs: [missing] -> pass (J1)
  • [ui (polonius)] tests/ui/parser/forced-keywords/pre-2021-edition-fail.rs: [missing] -> pass (J1)
  • [ui (polonius)] tests/ui/parser/forced-keywords/pre-2021-edition-pass.rs: [missing] -> pass (J1)

Stage 2

  • [ui] tests/ui/parser/forced-keywords/basic.rs: [missing] -> pass (J2)
  • [ui] tests/ui/parser/forced-keywords/decl-macro-matching.rs: [missing] -> pass (J2)
  • [ui] tests/ui/parser/forced-keywords/feature-gate-forced-keywords.rs: [missing] -> pass (J2)
  • [ui] tests/ui/parser/forced-keywords/non-keyword-neg.rs: [missing] -> pass (J2)
  • [ui] tests/ui/parser/forced-keywords/non-keyword-pos.rs: [missing] -> pass (J2)
  • [ui] tests/ui/parser/forced-keywords/pre-2021-edition-fail.rs: [missing] -> pass (J2)
  • [ui] tests/ui/parser/forced-keywords/pre-2021-edition-pass.rs: [missing] -> pass (J2)

Additionally, 16 doctest diffs were found. These are ignored, as they are noisy.

Job group index

Test dashboard

Run

cargo run --manifest-path src/ci/citool/Cargo.toml -- \
    test-dashboard 22697761c6a01e8d12adcd91e4a5bc755596767a --output-dir test-dashboard

And then open test-dashboard/index.html in your browser to see an overview of all executed tests.

Job duration changes

  1. test-x86_64-gnu-distcheck: 1h 35m -> 2h 24m (+52.2%)
  2. test-x86_64-gnu-aux: 1h 54m -> 2h 41m (+41.3%)
  3. dist-x86_64-msvc: 3h 27m -> 2h 3m (-40.4%)
  4. dist-ohos-x86_64: 58m 4s -> 1h 21m (+40.0%)
  5. test-x86_64-msvc-ext3: 1h 25m -> 1h 58m (+39.8%)
  6. test-x86_64-gnu: 2h 37m -> 1h 38m (-37.5%)
  7. dist-x86_64-solaris: 1h 15m -> 1h 43m (+36.2%)
  8. dist-loongarch64-musl: 2h 9m -> 1h 23m (-35.7%)
  9. dist-riscv64-linux-musl: 1h 7m -> 1h 30m (+32.8%)
  10. dist-loongarch64-linux: 2h 5m -> 1h 27m (-30.0%)
How to interpret the job duration changes?

Job durations can vary a lot, based on the actual runner instance
that executed the job, system noise, invalidated caches, etc. The table above is provided
mostly for t-infra members, for simpler debugging of potential CI slow-downs.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (2269776): comparison URL.

Overall result: ✅ improvements - no action needed

@rustbot label: -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.2% [-0.3%, -0.2%] 11
Improvements ✅
(secondary)
-0.4% [-0.6%, -0.2%] 23
All ❌✅ (primary) -0.2% [-0.3%, -0.2%] 11

Max RSS (memory usage)

Results (primary 0.8%, secondary 2.3%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.8% [0.8%, 0.8%] 1
Regressions ❌
(secondary)
2.3% [2.3%, 2.3%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.8% [0.8%, 0.8%] 1

Cycles

Results (primary -2.2%, secondary -3.6%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
2.4% [2.4%, 2.4%] 1
Improvements ✅
(primary)
-2.2% [-2.2%, -2.2%] 1
Improvements ✅
(secondary)
-5.6% [-7.1%, -3.4%] 3
All ❌✅ (primary) -2.2% [-2.2%, -2.2%] 1

Binary size

This perf run didn't have relevant results for this metric.

Bootstrap: 488.289s -> 489.806s (0.31%)
Artifact size: 407.14 MiB -> 406.32 MiB (-0.20%)

pull Bot pushed a commit to xtqqczze/rust-lang-miri that referenced this pull request Sep 28, 2026
Implement forced keywords (`k#`)



Part of rust-lang/rust#153839. CC @dianne

Introduces a new token kind to Rust >=2021 that looks like `k#ident` and that is called *forced keyword (identifier)*. This is gated behind a new unstable feature called `forced_keywords`. This is backed by [compiler MCP 945](rust-lang/compiler-team#945).

~~The `ident` in `k#ident` *must* be a keyword (from any edition) or a weak/contextual keyword for the token to be valid.~~ The `ident` in `k#ident` needn't be a keyword to be lexically valid (CC rust-lang/rust#161775 (comment)).

---

What **won't** be done in this PR:

1. implementing forced keyword lifetimes (`'k#static`)
2. migrating away from built-in syntax `builtin # $ident($($tt)*)` / introducing `k#`-exclusive (weak) keywords
   * that'll be done in PR rust-lang/rust#162232 instead
3. allowing the user to force edition-dependent & context-dependent keywords to be keywords
   * re. edition-dependent: forcing them to be keywords even in editions where they're usually not a (strong) keyword (today, that only affects `gen` anyway IINM)
   * re. context-dependent: E.g., `union` is only "active" if it's followed by a non-reserved identifier and under this PR the same rules apply to `k#union` even though that's not necessary; changing it would result in better diagnostics (e.g., for `k#union struct {}`: `` error: expected item, found `k#union` `` => `` expected identifier, found keyword `struct` ``) and maybe also allow for disambiguation for other context-dependent keywords
4. extending the `proc_macro::Ident` API to allow users to programmatically create forced keywords (might never be added)

<sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
@panstromek

Copy link
Copy Markdown
Contributor

perf triage:

This improvement looks real, but it didn't show up before merge. Do we know where this could come from?

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

Labels

merged-by-bors This PR was explicitly merged by bors. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rust-analyzer Relevant to the rust-analyzer 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants