Deny keyword lifetimes pre-expansion
This commit is contained in:
parent
a91f7d72f1
commit
d0a1851ec2
14 changed files with 99 additions and 70 deletions
|
@ -388,6 +388,9 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
|
|||
parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
|
||||
parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
|
||||
|
||||
parse_invalid_label =
|
||||
invalid label name `{$name}`
|
||||
|
||||
parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
|
||||
.label = invalid suffix `{$suffix}`
|
||||
.tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
|
||||
|
@ -414,6 +417,9 @@ parse_invalid_unicode_escape = invalid unicode character escape
|
|||
parse_invalid_variable_declaration =
|
||||
invalid variable declaration
|
||||
|
||||
parse_keyword_lifetime =
|
||||
lifetimes cannot use keyword names
|
||||
|
||||
parse_kw_bad_case = keyword `{$kw}` is written in the wrong case
|
||||
.suggestion = write it in the correct case
|
||||
|
||||
|
|
|
@ -2009,6 +2009,21 @@ pub struct CannotBeRawIdent {
|
|||
pub ident: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_keyword_lifetime)]
|
||||
pub struct KeywordLifetime {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_invalid_label)]
|
||||
pub struct InvalidLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_cr_doc_comment)]
|
||||
pub struct CrDocComment {
|
||||
|
|
|
@ -2932,10 +2932,17 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn eat_label(&mut self) -> Option<Label> {
|
||||
self.token.lifetime().map(|ident| {
|
||||
if let Some(ident) = self.token.lifetime() {
|
||||
// Disallow `'fn`, but with a better error message than `expect_lifetime`.
|
||||
if ident.without_first_quote().is_reserved() {
|
||||
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
|
||||
}
|
||||
|
||||
self.bump();
|
||||
Label { ident }
|
||||
})
|
||||
Some(Label { ident })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a `match ... { ... }` expression (`match` token already eaten).
|
||||
|
|
|
@ -177,8 +177,11 @@ impl<'a> Parser<'a> {
|
|||
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
|
||||
}
|
||||
NonterminalKind::Lifetime => {
|
||||
return if self.check_lifetime() {
|
||||
Ok(ParseNtResult::Lifetime(self.expect_lifetime().ident))
|
||||
// We want to keep `'keyword` parsing, just like `keyword` is still
|
||||
// an ident for nonterminal purposes.
|
||||
return if let Some(ident) = self.token.lifetime() {
|
||||
self.bump();
|
||||
Ok(ParseNtResult::Lifetime(ident))
|
||||
} else {
|
||||
Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
|
||||
span: self.token.span,
|
||||
|
|
|
@ -542,12 +542,12 @@ impl<'a> Parser<'a> {
|
|||
None => PatKind::Path(qself, path),
|
||||
}
|
||||
}
|
||||
} else if let token::Lifetime(lt) = self.token.kind
|
||||
} else if let Some(lt) = self.token.lifetime()
|
||||
// In pattern position, we're totally fine with using "next token isn't colon"
|
||||
// as a heuristic. We could probably just always try to recover if it's a lifetime,
|
||||
// because we never have `'a: label {}` in a pattern position anyways, but it does
|
||||
// keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
|
||||
&& could_be_unclosed_char_literal(Ident::with_dummy_span(lt))
|
||||
&& could_be_unclosed_char_literal(lt)
|
||||
&& !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
|
||||
{
|
||||
// Recover a `'a` as a `'a'` literal
|
||||
|
@ -683,12 +683,12 @@ impl<'a> Parser<'a> {
|
|||
/// Parse `&pat` / `&mut pat`.
|
||||
fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> {
|
||||
self.expect_and()?;
|
||||
if let token::Lifetime(name) = self.token.kind {
|
||||
if let Some(lifetime) = self.token.lifetime() {
|
||||
self.bump(); // `'a`
|
||||
|
||||
self.dcx().emit_err(UnexpectedLifetimeInPattern {
|
||||
span: self.prev_token.span,
|
||||
symbol: name,
|
||||
symbol: lifetime.name,
|
||||
suggestion: self.prev_token.span.until(self.token.span),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1230,6 +1230,12 @@ impl<'a> Parser<'a> {
|
|||
/// Parses a single lifetime `'a` or panics.
|
||||
pub(super) fn expect_lifetime(&mut self) -> Lifetime {
|
||||
if let Some(ident) = self.token.lifetime() {
|
||||
if ident.without_first_quote().is_reserved()
|
||||
&& ![kw::UnderscoreLifetime, kw::StaticLifetime].contains(&ident.name)
|
||||
{
|
||||
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
|
||||
}
|
||||
|
||||
self.bump();
|
||||
Lifetime { ident, id: ast::DUMMY_NODE_ID }
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue