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 |
…diags, r=mejrs Fix and improve diagnostics for lint `rust_2021_prefixes_incompatible_syntax` On main, when encountering token sequences in Rust <2021 that would get interpreted as... 1. ...C string literals in Rust >=2021, 1. we report "*prefix `c` is unknown*" / "*prefix `cr` is unknown*" despite them obviously being known 2. we claim that they "*[are] a hard error in Rust 2021*" 2. ...raw lifetimes in Rust >=2021 like `'r#a`, we suggest splitting them *after* the hash (so `'r#` and `a`) which obviously doesn't fix the issue; they need to be split *before* the hash (so `'r` and `#a`) 3. ...unknown (reserved) prefixes in Rust >=2021, we report "*prefix […] is unknown*" but to be pedantic the sequence is *not* a prefix in the current edition, it's just a normal identifier; to be correct & precise we should thus say that they *will* be parsed as a prefix (in Rust >=2021) Lastly, unify / streamline all diagnostics pertaining to "reserved prefixes" (identifier/literal prefixes, hash prefixes (aka guarded string prefixes / multihashes)) --- Best reviewed commit by commit. > [!NOTE] > **Unblocks** PR rust-lang#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
…diags, r=mejrs Fix and improve diagnostics for lint `rust_2021_prefixes_incompatible_syntax` On main, when encountering token sequences in Rust <2021 that would get interpreted as... 1. ...C string literals in Rust >=2021, 1. we report "*prefix `c` is unknown*" / "*prefix `cr` is unknown*" despite them obviously being known 2. we claim that they "*[are] a hard error in Rust 2021*" 2. ...raw lifetimes in Rust >=2021 like `'r#a`, we suggest splitting them *after* the hash (so `'r#` and `a`) which obviously doesn't fix the issue; they need to be split *before* the hash (so `'r` and `#a`) 3. ...unknown (reserved) prefixes in Rust >=2021, we report "*prefix […] is unknown*" but to be pedantic the sequence is *not* a prefix in the current edition, it's just a normal identifier; to be correct & precise we should thus say that they *will* be parsed as a prefix (in Rust >=2021) Lastly, unify / streamline all diagnostics pertaining to "reserved prefixes" (identifier/literal prefixes, hash prefixes (aka guarded string prefixes / multihashes)) --- Best reviewed commit by commit. > [!NOTE] > **Unblocks** PR rust-lang#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
…diags, r=mejrs Fix and improve diagnostics for lint `rust_2021_prefixes_incompatible_syntax` On main, when encountering token sequences in Rust <2021 that would get interpreted as... 1. ...C string literals in Rust >=2021, 1. we report "*prefix `c` is unknown*" / "*prefix `cr` is unknown*" despite them obviously being known 2. we claim that they "*[are] a hard error in Rust 2021*" 2. ...raw lifetimes in Rust >=2021 like `'r#a`, we suggest splitting them *after* the hash (so `'r#` and `a`) which obviously doesn't fix the issue; they need to be split *before* the hash (so `'r` and `#a`) 3. ...unknown (reserved) prefixes in Rust >=2021, we report "*prefix […] is unknown*" but to be pedantic the sequence is *not* a prefix in the current edition, it's just a normal identifier; to be correct & precise we should thus say that they *will* be parsed as a prefix (in Rust >=2021) Lastly, unify / streamline all diagnostics pertaining to "reserved prefixes" (identifier/literal prefixes, hash prefixes (aka guarded string prefixes / multihashes)) --- Best reviewed commit by commit. > [!NOTE] > **Unblocks** PR rust-lang#161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
Rollup merge of #161792 - fmease:fix-reserved-prefixes-lint-diags, r=mejrs Fix and improve diagnostics for lint `rust_2021_prefixes_incompatible_syntax` On main, when encountering token sequences in Rust <2021 that would get interpreted as... 1. ...C string literals in Rust >=2021, 1. we report "*prefix `c` is unknown*" / "*prefix `cr` is unknown*" despite them obviously being known 2. we claim that they "*[are] a hard error in Rust 2021*" 2. ...raw lifetimes in Rust >=2021 like `'r#a`, we suggest splitting them *after* the hash (so `'r#` and `a`) which obviously doesn't fix the issue; they need to be split *before* the hash (so `'r` and `#a`) 3. ...unknown (reserved) prefixes in Rust >=2021, we report "*prefix […] is unknown*" but to be pedantic the sequence is *not* a prefix in the current edition, it's just a normal identifier; to be correct & precise we should thus say that they *will* be parsed as a prefix (in Rust >=2021) Lastly, unify / streamline all diagnostics pertaining to "reserved prefixes" (identifier/literal prefixes, hash prefixes (aka guarded string prefixes / multihashes)) --- Best reviewed commit by commit. > [!NOTE] > **Unblocks** PR #161775. <sub>(No LLM was or will be used by me during the entire creation process of this PR)</sub>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
k#)k#)
|
PR #161792 has been merged. This PR is no longer stacked and blocked. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
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. |
|
|
||
| /// Returns `true` if this symbol can be a forced keyword. | ||
| pub fn can_be_forced_keyword(self) -> bool { | ||
| self.is_reserved(|| Edition::EditionFuture) || self.is_weak() |
There was a problem hiding this comment.
Either in this PR or in a follow-up PR I'll do something less hazardous than blindly using is_weak wrt. stability:
Let's assume forced_keywords was stable, then we certainly wouldn't want to insta-stabilize k#WEAK if somebody introduced an unstable keyword WEAK but that's what would happen in the current implementation as we'd immediately start accepting #[cfg(false)] M!(k#WEAK);.
(On main, declaring a weak keyword in symbol.rs doesn't have any semantic consequences, it just defines a new interned symbol for which is_weak (only used in diagnostics & tools atm) returns true. It's more of a convention, so you can write things like .is_keyword(kw::Weak) instead of .is_keyword(sym::weak) in the parser.)
Anyways, I plan on splitting splitting weak keywords into two categories, "stable" and "non-committal" (…). For the latter category, I'm either gonna issue a feature gate in lexer/mod.rs if forced with k# or I'm just not gonna allow using k# until stabilization. Emitting a feature gate for the token, too, means we'd start emitting two feature gates for unstable syntax (one in the lexer, one in the parser) which most likely wouldn't get deduplicated by our diagnostic infra since the spans will differ. There might be some tricks for avoiding it though. Will think about that some other 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)