Conversation
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Implement forced keywords (`k#`)
This comment has been minimized.
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)), |
There was a problem hiding this comment.
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.
| @@ -103,6 +104,26 @@ impl ToInternal<tk::LitKind> for LitKind { | |||
| } | |||
| } | |||
|
|
|||
There was a problem hiding this comment.
We can't test the roundtripping in the current form of this PR because I haven't added any k#-exclusive weak keywords where it'd be observable if we accidentally dropped k# during encoding&decoding.
I have however tested locally that it works by introducing a new dummy keyword. A hypothetical UI test would have a setup like
use proc_macro::TokenStream;
#[proc_macro]
pub fn perform(_: TokenStream) -> TokenStream {
let stream: TokenStream = "const _: Option<k#never> = None;").parse().unwrap(); // positive
//let stream: TokenStream = "fn k#branded() {}").parse().unwrap(); // negative
stream.into_iter().collect() // forces encoding+decoding
}
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (4eb8eac): comparison URL. Overall result: ✅ improvements - no action neededBenchmarking 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 countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
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.
CyclesResults (primary 2.1%, secondary -1.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.0%, secondary -0.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 477.576s -> 469.017s (-1.79%) |
This comment has been minimized.
This comment has been minimized.
9e590de to
1de8681
Compare
k#)k#)
|
Ready for review. Caution Only review the commits created after ------------------------- BRANCH SEPARATOR -------------------------. Best reviewed commit by commit. |
|
Some changes occurred in compiler/rustc_builtin_macros/src/autodiff.rs cc @ZuseZ4
cc @rust-lang/rust-analyzer |
…rochenkov Move parse error recovery for expression operators "out of line" & refactor in the area **Background**: While we do have 3k-line module `rustc_parse/src/parser/diagnostics.rs`[^1] dedicated to syntax error diagnostics & parse error recovery, the rest of the parser is still "littered" or "interwoven" through and through with complex or verbose diagnostic code. We support numerous recoveries from syntaxes found in other languages right next to code that actually decides what is and what isn't part of Rust syntactically. This makes the parser code very messy, illegible, bug prone and otherwise hard to maintain. So my long-term plan is to push all this diagnostic & recovery code "out of line", namely into new `rustc_parse/src/parser/$fragment/diagnostics.rs` files, to keep the "inline code" of parsing routines in `$fragment.rs` focused on actually parsing Rust code. Why not just use the pre-existing `parser/diagnostics.rs` module? Well, making diagnostic code for expressions, patterns, types etc. share the same module is the definition of a hodgepodge. Moreover, moving all diagnostic code there would make the file way too large. Of course, for common code (if any) `parser/diagnostics.rs` would remain suitable. Best reviewed commit by commit. Commit [Refactor check_assoc_op to make it more legible](rust-lang@66311aa) was cherry-picked from my PR rust-lang#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub> [^1]: Not to be confused with `rustc_parse/src/diagnostics.rs` which holds diagnostic structs.
…rochenkov Move parse error recovery for expression operators "out of line" & refactor in the area **Background**: While we do have 3k-line module `rustc_parse/src/parser/diagnostics.rs`[^1] dedicated to syntax error diagnostics & parse error recovery, the rest of the parser is still "littered" or "interwoven" through and through with complex or verbose diagnostic code. We support numerous recoveries from syntaxes found in other languages right next to code that actually decides what is and what isn't part of Rust syntactically. This makes the parser code very messy, illegible, bug prone and otherwise hard to maintain. So my long-term plan is to push all this diagnostic & recovery code "out of line", namely into new `rustc_parse/src/parser/$fragment/diagnostics.rs` files, to keep the "inline code" of parsing routines in `$fragment.rs` focused on actually parsing Rust code. Why not just use the pre-existing `parser/diagnostics.rs` module? Well, making diagnostic code for expressions, patterns, types etc. share the same module is the definition of a hodgepodge. Moreover, moving all diagnostic code there would make the file way too large. Of course, for common code (if any) `parser/diagnostics.rs` would remain suitable. Best reviewed commit by commit. Commit [Refactor check_assoc_op to make it more legible](rust-lang@66311aa) was cherry-picked from my PR rust-lang#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub> [^1]: Not to be confused with `rustc_parse/src/diagnostics.rs` which holds diagnostic structs.
…rochenkov Move parse error recovery for expression operators "out of line" & refactor in the area **Background**: While we do have 3k-line module `rustc_parse/src/parser/diagnostics.rs`[^1] dedicated to syntax error diagnostics & parse error recovery, the rest of the parser is still "littered" or "interwoven" through and through with complex or verbose diagnostic code. We support numerous recoveries from syntaxes found in other languages right next to code that actually decides what is and what isn't part of Rust syntactically. This makes the parser code very messy, illegible, bug prone and otherwise hard to maintain. So my long-term plan is to push all this diagnostic & recovery code "out of line", namely into new `rustc_parse/src/parser/$fragment/diagnostics.rs` files, to keep the "inline code" of parsing routines in `$fragment.rs` focused on actually parsing Rust code. Why not just use the pre-existing `parser/diagnostics.rs` module? Well, making diagnostic code for expressions, patterns, types etc. share the same module is the definition of a hodgepodge. Moreover, moving all diagnostic code there would make the file way too large. Of course, for common code (if any) `parser/diagnostics.rs` would remain suitable. Best reviewed commit by commit. Commit [Refactor check_assoc_op to make it more legible](rust-lang@66311aa) was cherry-picked from my PR rust-lang#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub> [^1]: Not to be confused with `rustc_parse/src/diagnostics.rs` which holds diagnostic structs.
…rochenkov Move parse error recovery for expression operators "out of line" & refactor in the area **Background**: While we do have 3k-line module `rustc_parse/src/parser/diagnostics.rs`[^1] dedicated to syntax error diagnostics & parse error recovery, the rest of the parser is still "littered" or "interwoven" through and through with complex or verbose diagnostic code. We support numerous recoveries from syntaxes found in other languages right next to code that actually decides what is and what isn't part of Rust syntactically. This makes the parser code very messy, illegible, bug prone and otherwise hard to maintain. So my long-term plan is to push all this diagnostic & recovery code "out of line", namely into new `rustc_parse/src/parser/$fragment/diagnostics.rs` files, to keep the "inline code" of parsing routines in `$fragment.rs` focused on actually parsing Rust code. Why not just use the pre-existing `parser/diagnostics.rs` module? Well, making diagnostic code for expressions, patterns, types etc. share the same module is the definition of a hodgepodge. Moreover, moving all diagnostic code there would make the file way too large. Of course, for common code (if any) `parser/diagnostics.rs` would remain suitable. Best reviewed commit by commit. Commit [Refactor check_assoc_op to make it more legible](rust-lang@66311aa) was cherry-picked from my PR rust-lang#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub> [^1]: Not to be confused with `rustc_parse/src/diagnostics.rs` which holds diagnostic structs.
Rollup merge of #162591 - fmease:out-of-line-recovery, r=petrochenkov Move parse error recovery for expression operators "out of line" & refactor in the area **Background**: While we do have 3k-line module `rustc_parse/src/parser/diagnostics.rs`[^1] dedicated to syntax error diagnostics & parse error recovery, the rest of the parser is still "littered" or "interwoven" through and through with complex or verbose diagnostic code. We support numerous recoveries from syntaxes found in other languages right next to code that actually decides what is and what isn't part of Rust syntactically. This makes the parser code very messy, illegible, bug prone and otherwise hard to maintain. So my long-term plan is to push all this diagnostic & recovery code "out of line", namely into new `rustc_parse/src/parser/$fragment/diagnostics.rs` files, to keep the "inline code" of parsing routines in `$fragment.rs` focused on actually parsing Rust code. Why not just use the pre-existing `parser/diagnostics.rs` module? Well, making diagnostic code for expressions, patterns, types etc. share the same module is the definition of a hodgepodge. Moreover, moving all diagnostic code there would make the file way too large. Of course, for common code (if any) `parser/diagnostics.rs` would remain suitable. Best reviewed commit by commit. Commit [Refactor check_assoc_op to make it more legible](66311aa) was cherry-picked from my PR #161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub> [^1]: Not to be confused with `rustc_parse/src/diagnostics.rs` which holds diagnostic structs.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Move parse error recovery for expression operators "out of line" & refactor in the area **Background**: While we do have 3k-line module `rustc_parse/src/parser/diagnostics.rs`[^1] dedicated to syntax error diagnostics & parse error recovery, the rest of the parser is still "littered" or "interwoven" through and through with complex or verbose diagnostic code. We support numerous recoveries from syntaxes found in other languages right next to code that actually decides what is and what isn't part of Rust syntactically. This makes the parser code very messy, illegible, bug prone and otherwise hard to maintain. So my long-term plan is to push all this diagnostic & recovery code "out of line", namely into new `rustc_parse/src/parser/$fragment/diagnostics.rs` files, to keep the "inline code" of parsing routines in `$fragment.rs` focused on actually parsing Rust code. Why not just use the pre-existing `parser/diagnostics.rs` module? Well, making diagnostic code for expressions, patterns, types etc. share the same module is the definition of a hodgepodge. Moreover, moving all diagnostic code there would make the file way too large. Of course, for common code (if any) `parser/diagnostics.rs` would remain suitable. Best reviewed commit by commit. Commit [Refactor check_assoc_op to make it more legible](rust-lang/rust@66311aa) was cherry-picked from my PR rust-lang/rust#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub> [^1]: Not to be confused with `rustc_parse/src/diagnostics.rs` which holds diagnostic structs.
This comment has been minimized.
This comment has been minimized.
…enkov Prepare for the introduction of forced keywords (`k#`) Split out of PR rust-lang#161775 as requested here: rust-lang#161775 (comment). These changes aren't super well-motivated in isolation IMO but it makes reviewing the other PR easier. r? petrochenkov <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
…enkov Prepare for the introduction of forced keywords (`k#`) Split out of PR rust-lang#161775 as requested here: rust-lang#161775 (comment). These changes aren't super well-motivated in isolation IMO but it makes reviewing the other PR easier. r? petrochenkov <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
…enkov Prepare for the introduction of forced keywords (`k#`) Split out of PR rust-lang#161775 as requested here: rust-lang#161775 (comment). These changes aren't super well-motivated in isolation IMO but it makes reviewing the other PR easier. r? petrochenkov <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
Rollup merge of #163019 - fmease:prepare-kay-hash, r=petrochenkov Prepare for the introduction of forced keywords (`k#`) Split out of PR #161775 as requested here: #161775 (comment). These changes aren't super well-motivated in isolation IMO but it makes reviewing the other PR easier. r? petrochenkov <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
Move parse error recovery for expression operators "out of line" & refactor in the area **Background**: While we do have 3k-line module `rustc_parse/src/parser/diagnostics.rs`[^1] dedicated to syntax error diagnostics & parse error recovery, the rest of the parser is still "littered" or "interwoven" through and through with complex or verbose diagnostic code. We support numerous recoveries from syntaxes found in other languages right next to code that actually decides what is and what isn't part of Rust syntactically. This makes the parser code very messy, illegible, bug prone and otherwise hard to maintain. So my long-term plan is to push all this diagnostic & recovery code "out of line", namely into new `rustc_parse/src/parser/$fragment/diagnostics.rs` files, to keep the "inline code" of parsing routines in `$fragment.rs` focused on actually parsing Rust code. Why not just use the pre-existing `parser/diagnostics.rs` module? Well, making diagnostic code for expressions, patterns, types etc. share the same module is the definition of a hodgepodge. Moreover, moving all diagnostic code there would make the file way too large. Of course, for common code (if any) `parser/diagnostics.rs` would remain suitable. Best reviewed commit by commit. Commit [Refactor check_assoc_op to make it more legible](rust-lang/rust@66311aa) was cherry-picked from my PR rust-lang/rust#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub> [^1]: Not to be confused with `rustc_parse/src/diagnostics.rs` which holds diagnostic structs.
Prepare for the introduction of forced keywords (`k#`) Split out of PR rust-lang/rust#161775 as requested here: rust-lang/rust#161775 (comment). These changes aren't super well-motivated in isolation IMO but it makes reviewing the other PR easier. r? petrochenkov <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
|
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. |
The primary (now only) commit doesn't require any "language process" either if you mean "T-lang interaction" by that. That's because it's completely unstable, doesn't break any stable code & is fully backed by a compiler MCP which is enough (no T-lang shepherd / T-lang blessed in-tree experiment needed, cf. the The change cannot be observed by stable users, neither syntactically nor lexically: Identifier prefixes are reserved in Rust >=2021 (i.e., hard errors) & forced keywords are pre-expansion feature gated. In Rust <2021, @rustbot review |
| //@ edition: 2021.. | ||
|
|
||
| #[cfg(false)] | ||
| k#fn start() {} //~ ERROR forced keywords are experimental |
There was a problem hiding this comment.
Could you check that it's gated in macro arguments as well?
drop_tokens!(k#fn);There was a problem hiding this comment.
And also that macro m(k#fn) {} doesn't accept fn, and vice versa (that's how it works for raw identifiers now too).
| compound_traits!(struct Ident<Span, Symbol> { sym, kind, span }); | ||
|
|
||
| #[derive(Copy, Clone, Eq, PartialEq)] | ||
| pub enum IdentKind { |
There was a problem hiding this comment.
(This stuff should have belonged to the previous PR ideally.)
| Err(dcx.struct_span_err( | ||
| span, | ||
| format!( | ||
| "`${{concat(..)}}` currently does not support {}", |
There was a problem hiding this comment.
| "`${{concat(..)}}` currently does not support {}", | |
| "`${{concat(..)}}` currently does not support {what}", |
Nit: a new variable for the match will allow using string interpolation and make the code formatting nicer.
| if span.edition().at_least_rust_2021() { | ||
| let sym = nfc_normalize(self.str_from(start + BytePos(2))); | ||
| self.psess.symbol_gallery.insert(sym, span); | ||
| if !sym.can_be_forced_keyword() { |
There was a problem hiding this comment.
This logic is breaking through abstraction layers, that's why we have issues with weak keywords and similar.
Here we are working with token streams, and at token stream / token tree level there are no keywords.
Keywords only appear when we start parsing some grammar from a token stream, e.g. standard Rust keywords when we start parsing Rust code, or entirely different keyword set specific to a macro x when we start parsing that macro's input.
So ideally my_macro!(k#non_keyword) would be just accepted by the compiler, and the macro itself would decide which tokens to accept in its input and which reject.
When parsing the Rust grammar proper I think it's safe to treat k#non_keyword in the same way as an unused reserved identifier (like virtual, for example). Like, it's a keyword, but there are no language constructions that use it. (But my_macro!(virtual) may work because my_macro's input language may have such keyword.)
In any case this is not very urgent, because it's a conservative error that can be relaxed at any time.
View all comments
Part of #153839. CC @dianne
Introduces a new token kind to Rust >=2021 that looks like
k#identand that is called forced keyword (identifier). This is gated behind a new unstable feature calledforced_keywords. This is backed by compiler MCP 945.The
identink#identmust be a keyword (from any edition) or a weak/contextual keyword for the token to be valid.What won't be done in this PR:
'k#static)builtin # $ident($($tt)*)/ introducingk#-exclusive (weak) keywordsbuiltin #withk##162232 insteadgenanyway IINM)unionis only "active" if it's followed by a non-reserved identifier and under this PR the same rules apply tok#unioneven though that's not necessary; changing it would result in better diagnostics (e.g., fork#union struct {}:error: expected item, found `k#union`=>expected identifier, found keyword `struct`) and maybe also allow for disambiguation for other context-dependent keywordsproc_macro::IdentAPI 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)