-
-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Confusing error when using non-XID_Start characters in lifetime names #141081
Copy link
Copy link
Open
Labels
A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-lexerArea: lexerArea: lexerD-confusingDiagnostics: Confusing error or lint that should be reworked.Diagnostics: Confusing error or lint that should be reworked.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
Code
fn bad_lifetime_name<'🐛>(_: &'🐛 ()) {}Current output
error: character literal may only contain one codepoint
--> src/lib.rs:1:22
|
1 | fn bad_lifetime_name<'🐛>(_: &'🐛 ()) {}
| ^^^^^^^^^^
|
help: if you meant to write a string literal, use double quotes
|
1 - fn bad_lifetime_name<'🐛>(_: &'🐛 ()) {}
1 + fn bad_lifetime_name<"🐛>(_: &"🐛 ()) {}
|
error: unexpected closing delimiter: `)`
--> src/lib.rs:1:35
|
1 | fn bad_lifetime_name<'🐛>(_: &'🐛 ()) {}
| ^ unexpected closing delimiterDesired output
error: a lifetime name cannot begin with a character that is neither `_` nor a `XID_Start` character
--> src/lib.rs:1:22
|
1 | fn bad_lifetime_name<'🐛>(_: &'🐛 ()) {}
| ^--
| help: `\u{1F41B}` is neither `_` nor in `XID_Start`Rationale and extra context
See also https://doc.rust-lang.org/reference/identifiers.html.
Initially reported at #general > Compiler isn't helpful with invalid lifetimes.
Looks like this recovery path(?) is hit when starting a lifetime name (not including the ') with a non-XID_Start character fails both is_id_start check and ASCII digit check hitting the !can_be_a_lifetime codepath.
rust/compiler/rustc_lexer/src/lib.rs
Lines 824 to 842 in c79bbfa
| let can_be_a_lifetime = if self.second() == '\'' { | |
| // It's surely not a lifetime. | |
| false | |
| } else { | |
| // If the first symbol is valid for identifier, it can be a lifetime. | |
| // Also check if it's a number for a better error reporting (so '0 will | |
| // be reported as invalid lifetime and not as unterminated char literal). | |
| is_id_start(self.first()) || self.first().is_ascii_digit() | |
| }; | |
| if !can_be_a_lifetime { | |
| let terminated = self.single_quoted_string(); | |
| let suffix_start = self.pos_within_token(); | |
| if terminated { | |
| self.eat_literal_suffix(); | |
| } | |
| let kind = Char { terminated }; | |
| return Literal { kind, suffix_start }; | |
| } |
Other cases
Marginally related is loop labels, this complains about "unterminated character literal".
fn main() {
'🐛: {
todo!();
};
}Rust Version
$ rustc --version --verbose
rustc 1.87.0 (17067e9ac 2025-05-09)
binary: rustc
commit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359
commit-date: 2025-05-09
host: aarch64-unknown-linux-gnu
release: 1.87.0
LLVM version: 20.1.1Anything else?
No response
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-lexerArea: lexerArea: lexerD-confusingDiagnostics: Confusing error or lint that should be reworked.Diagnostics: Confusing error or lint that should be reworked.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Type
Fields
Give feedbackNo fields configured for issues without a type.