Deny keyword lifetimes pre-expansion
This commit is contained in:
parent
a91f7d72f1
commit
d0a1851ec2
@ -159,9 +159,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
|
|||||||
.type = inherent impl for this type
|
.type = inherent impl for this type
|
||||||
.only_trait = only trait implementations may be annotated with {$annotation}
|
.only_trait = only trait implementations may be annotated with {$annotation}
|
||||||
|
|
||||||
ast_passes_invalid_label =
|
|
||||||
invalid label name `{$name}`
|
|
||||||
|
|
||||||
ast_passes_invalid_unnamed_field =
|
ast_passes_invalid_unnamed_field =
|
||||||
unnamed fields are not allowed outside of structs or unions
|
unnamed fields are not allowed outside of structs or unions
|
||||||
.label = unnamed field declared here
|
.label = unnamed field declared here
|
||||||
@ -176,9 +173,6 @@ ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot
|
|||||||
ast_passes_item_underscore = `{$kind}` items in this context need a name
|
ast_passes_item_underscore = `{$kind}` items in this context need a name
|
||||||
.label = `_` is not a valid name for this `{$kind}` item
|
.label = `_` is not a valid name for this `{$kind}` item
|
||||||
|
|
||||||
ast_passes_keyword_lifetime =
|
|
||||||
lifetimes cannot use keyword names
|
|
||||||
|
|
||||||
ast_passes_match_arm_with_no_body =
|
ast_passes_match_arm_with_no_body =
|
||||||
`match` arm with no body
|
`match` arm with no body
|
||||||
.suggestion = add a body after the pattern
|
.suggestion = add a body after the pattern
|
||||||
|
@ -284,19 +284,6 @@ fn dcx(&self) -> DiagCtxtHandle<'a> {
|
|||||||
self.session.dcx()
|
self.session.dcx()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_lifetime(&self, ident: Ident) {
|
|
||||||
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
|
|
||||||
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
|
|
||||||
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_label(&self, ident: Ident) {
|
|
||||||
if ident.without_first_quote().is_reserved() {
|
|
||||||
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
|
fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
|
||||||
if let VisibilityKind::Inherited = vis.kind {
|
if let VisibilityKind::Inherited = vis.kind {
|
||||||
return;
|
return;
|
||||||
@ -923,16 +910,6 @@ fn visit_ty(&mut self, ty: &'a Ty) {
|
|||||||
self.walk_ty(ty)
|
self.walk_ty(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_label(&mut self, label: &'a Label) {
|
|
||||||
self.check_label(label.ident);
|
|
||||||
visit::walk_label(self, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
|
|
||||||
self.check_lifetime(lifetime.ident);
|
|
||||||
visit::walk_lifetime(self, lifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
||||||
self.deny_unnamed_field(field);
|
self.deny_unnamed_field(field);
|
||||||
visit::walk_field_def(self, field)
|
visit::walk_field_def(self, field)
|
||||||
@ -1371,13 +1348,6 @@ fn visit_generics(&mut self, generics: &'a Generics) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_generic_param(&mut self, param: &'a GenericParam) {
|
|
||||||
if let GenericParamKind::Lifetime { .. } = param.kind {
|
|
||||||
self.check_lifetime(param.ident);
|
|
||||||
}
|
|
||||||
visit::walk_generic_param(self, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
|
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
|
||||||
match bound {
|
match bound {
|
||||||
GenericBound::Trait(trait_ref, modifiers) => {
|
GenericBound::Trait(trait_ref, modifiers) => {
|
||||||
|
@ -9,21 +9,6 @@
|
|||||||
|
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(ast_passes_keyword_lifetime)]
|
|
||||||
pub struct KeywordLifetime {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(ast_passes_invalid_label)]
|
|
||||||
pub struct InvalidLabel {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
pub name: Symbol,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(ast_passes_visibility_not_permitted, code = E0449)]
|
#[diag(ast_passes_visibility_not_permitted, code = E0449)]
|
||||||
pub struct VisibilityNotPermitted {
|
pub struct VisibilityNotPermitted {
|
||||||
|
@ -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_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_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
|
parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
|
||||||
.label = invalid suffix `{$suffix}`
|
.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
|
.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 =
|
parse_invalid_variable_declaration =
|
||||||
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
|
parse_kw_bad_case = keyword `{$kw}` is written in the wrong case
|
||||||
.suggestion = write it in the correct case
|
.suggestion = write it in the correct case
|
||||||
|
|
||||||
|
@ -2009,6 +2009,21 @@ pub struct CannotBeRawIdent {
|
|||||||
pub ident: Symbol,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_cr_doc_comment)]
|
#[diag(parse_cr_doc_comment)]
|
||||||
pub struct CrDocComment {
|
pub struct CrDocComment {
|
||||||
|
@ -2932,10 +2932,17 @@ fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eat_label(&mut self) -> Option<Label> {
|
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();
|
self.bump();
|
||||||
Label { ident }
|
Some(Label { ident })
|
||||||
})
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a `match ... { ... }` expression (`match` token already eaten).
|
/// Parses a `match ... { ... }` expression (`match` token already eaten).
|
||||||
|
@ -177,8 +177,11 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN
|
|||||||
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
|
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
|
||||||
}
|
}
|
||||||
NonterminalKind::Lifetime => {
|
NonterminalKind::Lifetime => {
|
||||||
return if self.check_lifetime() {
|
// We want to keep `'keyword` parsing, just like `keyword` is still
|
||||||
Ok(ParseNtResult::Lifetime(self.expect_lifetime().ident))
|
// an ident for nonterminal purposes.
|
||||||
|
return if let Some(ident) = self.token.lifetime() {
|
||||||
|
self.bump();
|
||||||
|
Ok(ParseNtResult::Lifetime(ident))
|
||||||
} else {
|
} else {
|
||||||
Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
|
Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
|
||||||
span: self.token.span,
|
span: self.token.span,
|
||||||
|
@ -542,12 +542,12 @@ fn parse_pat_with_range_pat(
|
|||||||
None => PatKind::Path(qself, path),
|
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"
|
// 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,
|
// 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
|
// 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 = ..`
|
// 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))
|
&& !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
|
||||||
{
|
{
|
||||||
// Recover a `'a` as a `'a'` literal
|
// Recover a `'a` as a `'a'` literal
|
||||||
@ -683,12 +683,12 @@ fn ban_pat_range_if_ambiguous(&self, pat: &Pat) {
|
|||||||
/// Parse `&pat` / `&mut pat`.
|
/// Parse `&pat` / `&mut pat`.
|
||||||
fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> {
|
fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> {
|
||||||
self.expect_and()?;
|
self.expect_and()?;
|
||||||
if let token::Lifetime(name) = self.token.kind {
|
if let Some(lifetime) = self.token.lifetime() {
|
||||||
self.bump(); // `'a`
|
self.bump(); // `'a`
|
||||||
|
|
||||||
self.dcx().emit_err(UnexpectedLifetimeInPattern {
|
self.dcx().emit_err(UnexpectedLifetimeInPattern {
|
||||||
span: self.prev_token.span,
|
span: self.prev_token.span,
|
||||||
symbol: name,
|
symbol: lifetime.name,
|
||||||
suggestion: self.prev_token.span.until(self.token.span),
|
suggestion: self.prev_token.span.until(self.token.span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1230,6 +1230,12 @@ pub(super) fn check_lifetime(&mut self) -> bool {
|
|||||||
/// Parses a single lifetime `'a` or panics.
|
/// Parses a single lifetime `'a` or panics.
|
||||||
pub(super) fn expect_lifetime(&mut self) -> Lifetime {
|
pub(super) fn expect_lifetime(&mut self) -> Lifetime {
|
||||||
if let Some(ident) = self.token.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();
|
self.bump();
|
||||||
Lifetime { ident, id: ast::DUMMY_NODE_ID }
|
Lifetime { ident, id: ast::DUMMY_NODE_ID }
|
||||||
} else {
|
} else {
|
||||||
|
15
tests/ui/parser/cfg-keyword-lifetime.rs
Normal file
15
tests/ui/parser/cfg-keyword-lifetime.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Disallow `'keyword` even in cfg'd code.
|
||||||
|
|
||||||
|
#[cfg(any())]
|
||||||
|
fn hello() -> &'ref () {}
|
||||||
|
//~^ ERROR lifetimes cannot use keyword names
|
||||||
|
|
||||||
|
macro_rules! macro_invocation {
|
||||||
|
($i:item) => {}
|
||||||
|
}
|
||||||
|
macro_invocation! {
|
||||||
|
fn hello() -> &'ref () {}
|
||||||
|
//~^ ERROR lifetimes cannot use keyword names
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
tests/ui/parser/cfg-keyword-lifetime.stderr
Normal file
14
tests/ui/parser/cfg-keyword-lifetime.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error: lifetimes cannot use keyword names
|
||||||
|
--> $DIR/cfg-keyword-lifetime.rs:4:16
|
||||||
|
|
|
||||||
|
LL | fn hello() -> &'ref () {}
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: lifetimes cannot use keyword names
|
||||||
|
--> $DIR/cfg-keyword-lifetime.rs:11:20
|
||||||
|
|
|
||||||
|
LL | fn hello() -> &'ref () {}
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -24,12 +24,14 @@ fn main() {
|
|||||||
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
|
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
|
||||||
//~| ERROR expected
|
//~| ERROR expected
|
||||||
//~| HELP add `'` to close the char literal
|
//~| HELP add `'` to close the char literal
|
||||||
|
//~| ERROR invalid label name
|
||||||
|
|
||||||
f<'_>();
|
f<'_>();
|
||||||
//~^ comparison operators cannot be chained
|
//~^ comparison operators cannot be chained
|
||||||
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
|
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
|
||||||
//~| ERROR expected
|
//~| ERROR expected
|
||||||
//~| HELP add `'` to close the char literal
|
//~| HELP add `'` to close the char literal
|
||||||
|
//~| ERROR invalid label name
|
||||||
|
|
||||||
let _ = f<u8>;
|
let _ = f<u8>;
|
||||||
//~^ ERROR comparison operators cannot be chained
|
//~^ ERROR comparison operators cannot be chained
|
||||||
|
@ -53,6 +53,12 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
|
|||||||
LL | let _ = f::<u8, i8>();
|
LL | let _ = f::<u8, i8>();
|
||||||
| ++
|
| ++
|
||||||
|
|
||||||
|
error: invalid label name `'_`
|
||||||
|
--> $DIR/require-parens-for-chained-comparison.rs:22:15
|
||||||
|
|
|
||||||
|
LL | let _ = f<'_, i8>();
|
||||||
|
| ^^
|
||||||
|
|
||||||
error: expected `while`, `for`, `loop` or `{` after a label
|
error: expected `while`, `for`, `loop` or `{` after a label
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:22:17
|
--> $DIR/require-parens-for-chained-comparison.rs:22:17
|
||||||
|
|
|
|
||||||
@ -75,8 +81,14 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
|
|||||||
LL | let _ = f::<'_, i8>();
|
LL | let _ = f::<'_, i8>();
|
||||||
| ++
|
| ++
|
||||||
|
|
||||||
|
error: invalid label name `'_`
|
||||||
|
--> $DIR/require-parens-for-chained-comparison.rs:29:7
|
||||||
|
|
|
||||||
|
LL | f<'_>();
|
||||||
|
| ^^
|
||||||
|
|
||||||
error: expected `while`, `for`, `loop` or `{` after a label
|
error: expected `while`, `for`, `loop` or `{` after a label
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:28:9
|
--> $DIR/require-parens-for-chained-comparison.rs:29:9
|
||||||
|
|
|
|
||||||
LL | f<'_>();
|
LL | f<'_>();
|
||||||
| ^ expected `while`, `for`, `loop` or `{` after a label
|
| ^ expected `while`, `for`, `loop` or `{` after a label
|
||||||
@ -87,7 +99,7 @@ LL | f<'_'>();
|
|||||||
| +
|
| +
|
||||||
|
|
||||||
error: comparison operators cannot be chained
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:28:6
|
--> $DIR/require-parens-for-chained-comparison.rs:29:6
|
||||||
|
|
|
|
||||||
LL | f<'_>();
|
LL | f<'_>();
|
||||||
| ^ ^
|
| ^ ^
|
||||||
@ -98,7 +110,7 @@ LL | f::<'_>();
|
|||||||
| ++
|
| ++
|
||||||
|
|
||||||
error: comparison operators cannot be chained
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:34:14
|
--> $DIR/require-parens-for-chained-comparison.rs:36:14
|
||||||
|
|
|
|
||||||
LL | let _ = f<u8>;
|
LL | let _ = f<u8>;
|
||||||
| ^ ^
|
| ^ ^
|
||||||
@ -106,5 +118,5 @@ LL | let _ = f<u8>;
|
|||||||
= help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
|
= help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
|
||||||
= help: or use `(...)` if you meant to specify fn arguments
|
= help: or use `(...)` if you meant to specify fn arguments
|
||||||
|
|
||||||
error: aborting due to 10 previous errors
|
error: aborting due to 12 previous errors
|
||||||
|
|
||||||
|
@ -4,6 +4,12 @@ error: expected identifier, found keyword `Self`
|
|||||||
LL | struct Self;
|
LL | struct Self;
|
||||||
| ^^^^ expected identifier, found keyword
|
| ^^^^ expected identifier, found keyword
|
||||||
|
|
||||||
|
error: lifetimes cannot use keyword names
|
||||||
|
--> $DIR/self_type_keyword.rs:6:12
|
||||||
|
|
|
||||||
|
LL | struct Bar<'Self>;
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
error: expected identifier, found keyword `Self`
|
error: expected identifier, found keyword `Self`
|
||||||
--> $DIR/self_type_keyword.rs:14:13
|
--> $DIR/self_type_keyword.rs:14:13
|
||||||
|
|
|
|
||||||
@ -53,12 +59,6 @@ error: expected identifier, found keyword `Self`
|
|||||||
LL | trait Self {}
|
LL | trait Self {}
|
||||||
| ^^^^ expected identifier, found keyword
|
| ^^^^ expected identifier, found keyword
|
||||||
|
|
||||||
error: lifetimes cannot use keyword names
|
|
||||||
--> $DIR/self_type_keyword.rs:6:12
|
|
||||||
|
|
|
||||||
LL | struct Bar<'Self>;
|
|
||||||
| ^^^^^
|
|
||||||
|
|
||||||
error: cannot find macro `Self` in this scope
|
error: cannot find macro `Self` in this scope
|
||||||
--> $DIR/self_type_keyword.rs:21:9
|
--> $DIR/self_type_keyword.rs:21:9
|
||||||
|
|
|
|
||||||
|
Loading…
Reference in New Issue
Block a user