Skip to content

Commit 9833e21

Browse files
authored
Rollup merge of #126762 - compiler-errors:kw-lt, r=michaelwoerister
Deny keyword lifetimes pre-expansion #126452 (comment) > Secondly, we confirmed that we're OK with moving the validation of keywords in lifetimes to pre-expansion from post-expansion. We similarly consider this a bug fix. While the breakage of the convenience feature of the with_locals crate that relies on this is unfortunate, and we wish we had not overlooked this earlier for that reason, we're fortunate that the breakage is contained to only one crate, and we're going to accept this breakage as the extra complexity we'd need to carry in the compiler to work around this isn't deemed worth it. T-lang considers it to be a bugfix to deny `'keyword` lifetimes in the parser, rather than during AST validation that only happens post-expansion. This has one breakage: #126452 (comment) This probably should get lang FCP'd just for consistency.
2 parents 36ea068 + d0a1851 commit 9833e21

14 files changed

+99
-70
lines changed

compiler/rustc_ast_passes/messages.ftl

-6
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
159159
.type = inherent impl for this type
160160
.only_trait = only trait implementations may be annotated with {$annotation}
161161
162-
ast_passes_invalid_label =
163-
invalid label name `{$name}`
164-
165162
ast_passes_invalid_unnamed_field =
166163
unnamed fields are not allowed outside of structs or unions
167164
.label = unnamed field declared here
@@ -176,9 +173,6 @@ ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot
176173
ast_passes_item_underscore = `{$kind}` items in this context need a name
177174
.label = `_` is not a valid name for this `{$kind}` item
178175
179-
ast_passes_keyword_lifetime =
180-
lifetimes cannot use keyword names
181-
182176
ast_passes_match_arm_with_no_body =
183177
`match` arm with no body
184178
.suggestion = add a body after the pattern

compiler/rustc_ast_passes/src/ast_validation.rs

-30
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,6 @@ impl<'a> AstValidator<'a> {
269269
self.session.dcx()
270270
}
271271

272-
fn check_lifetime(&self, ident: Ident) {
273-
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
274-
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
275-
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
276-
}
277-
}
278-
279-
fn check_label(&self, ident: Ident) {
280-
if ident.without_first_quote().is_reserved() {
281-
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
282-
}
283-
}
284-
285272
fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
286273
if let VisibilityKind::Inherited = vis.kind {
287274
return;
@@ -908,16 +895,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
908895
self.walk_ty(ty)
909896
}
910897

911-
fn visit_label(&mut self, label: &'a Label) {
912-
self.check_label(label.ident);
913-
visit::walk_label(self, label);
914-
}
915-
916-
fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
917-
self.check_lifetime(lifetime.ident);
918-
visit::walk_lifetime(self, lifetime);
919-
}
920-
921898
fn visit_field_def(&mut self, field: &'a FieldDef) {
922899
self.deny_unnamed_field(field);
923900
visit::walk_field_def(self, field)
@@ -1356,13 +1333,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13561333
}
13571334
}
13581335

1359-
fn visit_generic_param(&mut self, param: &'a GenericParam) {
1360-
if let GenericParamKind::Lifetime { .. } = param.kind {
1361-
self.check_lifetime(param.ident);
1362-
}
1363-
visit::walk_generic_param(self, param);
1364-
}
1365-
13661336
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
13671337
match bound {
13681338
GenericBound::Trait(trait_ref, modifiers) => {

compiler/rustc_ast_passes/src/errors.rs

-15
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,6 @@ use rustc_span::{symbol::Ident, Span, Symbol};
99

1010
use crate::fluent_generated as fluent;
1111

12-
#[derive(Diagnostic)]
13-
#[diag(ast_passes_keyword_lifetime)]
14-
pub struct KeywordLifetime {
15-
#[primary_span]
16-
pub span: Span,
17-
}
18-
19-
#[derive(Diagnostic)]
20-
#[diag(ast_passes_invalid_label)]
21-
pub struct InvalidLabel {
22-
#[primary_span]
23-
pub span: Span,
24-
pub name: Symbol,
25-
}
26-
2712
#[derive(Diagnostic)]
2813
#[diag(ast_passes_visibility_not_permitted, code = E0449)]
2914
pub struct VisibilityNotPermitted {

compiler/rustc_parse/messages.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
388388
parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
389389
parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
390390
391+
parse_invalid_label =
392+
invalid label name `{$name}`
393+
391394
parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
392395
.label = invalid suffix `{$suffix}`
393396
.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
414417
parse_invalid_variable_declaration =
415418
invalid variable declaration
416419
420+
parse_keyword_lifetime =
421+
lifetimes cannot use keyword names
422+
417423
parse_kw_bad_case = keyword `{$kw}` is written in the wrong case
418424
.suggestion = write it in the correct case
419425

compiler/rustc_parse/src/errors.rs

+15
Original file line numberDiff line numberDiff line change
@@ -2009,6 +2009,21 @@ pub struct CannotBeRawIdent {
20092009
pub ident: Symbol,
20102010
}
20112011

2012+
#[derive(Diagnostic)]
2013+
#[diag(parse_keyword_lifetime)]
2014+
pub struct KeywordLifetime {
2015+
#[primary_span]
2016+
pub span: Span,
2017+
}
2018+
2019+
#[derive(Diagnostic)]
2020+
#[diag(parse_invalid_label)]
2021+
pub struct InvalidLabel {
2022+
#[primary_span]
2023+
pub span: Span,
2024+
pub name: Symbol,
2025+
}
2026+
20122027
#[derive(Diagnostic)]
20132028
#[diag(parse_cr_doc_comment)]
20142029
pub struct CrDocComment {

compiler/rustc_parse/src/parser/expr.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -2932,10 +2932,17 @@ impl<'a> Parser<'a> {
29322932
}
29332933

29342934
pub(crate) fn eat_label(&mut self) -> Option<Label> {
2935-
self.token.lifetime().map(|ident| {
2935+
if let Some(ident) = self.token.lifetime() {
2936+
// Disallow `'fn`, but with a better error message than `expect_lifetime`.
2937+
if ident.without_first_quote().is_reserved() {
2938+
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
2939+
}
2940+
29362941
self.bump();
2937-
Label { ident }
2938-
})
2942+
Some(Label { ident })
2943+
} else {
2944+
None
2945+
}
29392946
}
29402947

29412948
/// Parses a `match ... { ... }` expression (`match` token already eaten).

compiler/rustc_parse/src/parser/nonterminal.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,11 @@ impl<'a> Parser<'a> {
177177
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
178178
}
179179
NonterminalKind::Lifetime => {
180-
return if self.check_lifetime() {
181-
Ok(ParseNtResult::Lifetime(self.expect_lifetime().ident))
180+
// We want to keep `'keyword` parsing, just like `keyword` is still
181+
// an ident for nonterminal purposes.
182+
return if let Some(ident) = self.token.lifetime() {
183+
self.bump();
184+
Ok(ParseNtResult::Lifetime(ident))
182185
} else {
183186
Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
184187
span: self.token.span,

compiler/rustc_parse/src/parser/pat.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -542,12 +542,12 @@ impl<'a> Parser<'a> {
542542
None => PatKind::Path(qself, path),
543543
}
544544
}
545-
} else if let token::Lifetime(lt) = self.token.kind
545+
} else if let Some(lt) = self.token.lifetime()
546546
// In pattern position, we're totally fine with using "next token isn't colon"
547547
// as a heuristic. We could probably just always try to recover if it's a lifetime,
548548
// because we never have `'a: label {}` in a pattern position anyways, but it does
549549
// keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
550-
&& could_be_unclosed_char_literal(Ident::with_dummy_span(lt))
550+
&& could_be_unclosed_char_literal(lt)
551551
&& !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
552552
{
553553
// Recover a `'a` as a `'a'` literal
@@ -683,12 +683,12 @@ impl<'a> Parser<'a> {
683683
/// Parse `&pat` / `&mut pat`.
684684
fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> {
685685
self.expect_and()?;
686-
if let token::Lifetime(name) = self.token.kind {
686+
if let Some(lifetime) = self.token.lifetime() {
687687
self.bump(); // `'a`
688688

689689
self.dcx().emit_err(UnexpectedLifetimeInPattern {
690690
span: self.prev_token.span,
691-
symbol: name,
691+
symbol: lifetime.name,
692692
suggestion: self.prev_token.span.until(self.token.span),
693693
});
694694
}

compiler/rustc_parse/src/parser/ty.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,12 @@ impl<'a> Parser<'a> {
12301230
/// Parses a single lifetime `'a` or panics.
12311231
pub(super) fn expect_lifetime(&mut self) -> Lifetime {
12321232
if let Some(ident) = self.token.lifetime() {
1233+
if ident.without_first_quote().is_reserved()
1234+
&& ![kw::UnderscoreLifetime, kw::StaticLifetime].contains(&ident.name)
1235+
{
1236+
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
1237+
}
1238+
12331239
self.bump();
12341240
Lifetime { ident, id: ast::DUMMY_NODE_ID }
12351241
} else {
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Disallow `'keyword` even in cfg'd code.
2+
3+
#[cfg(any())]
4+
fn hello() -> &'ref () {}
5+
//~^ ERROR lifetimes cannot use keyword names
6+
7+
macro_rules! macro_invocation {
8+
($i:item) => {}
9+
}
10+
macro_invocation! {
11+
fn hello() -> &'ref () {}
12+
//~^ ERROR lifetimes cannot use keyword names
13+
}
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: lifetimes cannot use keyword names
2+
--> $DIR/cfg-keyword-lifetime.rs:4:16
3+
|
4+
LL | fn hello() -> &'ref () {}
5+
| ^^^^
6+
7+
error: lifetimes cannot use keyword names
8+
--> $DIR/cfg-keyword-lifetime.rs:11:20
9+
|
10+
LL | fn hello() -> &'ref () {}
11+
| ^^^^
12+
13+
error: aborting due to 2 previous errors
14+

tests/ui/parser/require-parens-for-chained-comparison.rs

+2
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ fn main() {
2424
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
2525
//~| ERROR expected
2626
//~| HELP add `'` to close the char literal
27+
//~| ERROR invalid label name
2728

2829
f<'_>();
2930
//~^ comparison operators cannot be chained
3031
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
3132
//~| ERROR expected
3233
//~| HELP add `'` to close the char literal
34+
//~| ERROR invalid label name
3335

3436
let _ = f<u8>;
3537
//~^ ERROR comparison operators cannot be chained

tests/ui/parser/require-parens-for-chained-comparison.stderr

+16-4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
5353
LL | let _ = f::<u8, i8>();
5454
| ++
5555

56+
error: invalid label name `'_`
57+
--> $DIR/require-parens-for-chained-comparison.rs:22:15
58+
|
59+
LL | let _ = f<'_, i8>();
60+
| ^^
61+
5662
error: expected `while`, `for`, `loop` or `{` after a label
5763
--> $DIR/require-parens-for-chained-comparison.rs:22:17
5864
|
@@ -75,8 +81,14 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
7581
LL | let _ = f::<'_, i8>();
7682
| ++
7783

84+
error: invalid label name `'_`
85+
--> $DIR/require-parens-for-chained-comparison.rs:29:7
86+
|
87+
LL | f<'_>();
88+
| ^^
89+
7890
error: expected `while`, `for`, `loop` or `{` after a label
79-
--> $DIR/require-parens-for-chained-comparison.rs:28:9
91+
--> $DIR/require-parens-for-chained-comparison.rs:29:9
8092
|
8193
LL | f<'_>();
8294
| ^ expected `while`, `for`, `loop` or `{` after a label
@@ -87,7 +99,7 @@ LL | f<'_'>();
8799
| +
88100

89101
error: comparison operators cannot be chained
90-
--> $DIR/require-parens-for-chained-comparison.rs:28:6
102+
--> $DIR/require-parens-for-chained-comparison.rs:29:6
91103
|
92104
LL | f<'_>();
93105
| ^ ^
@@ -98,13 +110,13 @@ LL | f::<'_>();
98110
| ++
99111

100112
error: comparison operators cannot be chained
101-
--> $DIR/require-parens-for-chained-comparison.rs:34:14
113+
--> $DIR/require-parens-for-chained-comparison.rs:36:14
102114
|
103115
LL | let _ = f<u8>;
104116
| ^ ^
105117
|
106118
= help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
107119
= help: or use `(...)` if you meant to specify fn arguments
108120

109-
error: aborting due to 10 previous errors
121+
error: aborting due to 12 previous errors
110122

tests/ui/self/self_type_keyword.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ error: expected identifier, found keyword `Self`
44
LL | struct Self;
55
| ^^^^ expected identifier, found keyword
66

7+
error: lifetimes cannot use keyword names
8+
--> $DIR/self_type_keyword.rs:6:12
9+
|
10+
LL | struct Bar<'Self>;
11+
| ^^^^^
12+
713
error: expected identifier, found keyword `Self`
814
--> $DIR/self_type_keyword.rs:14:13
915
|
@@ -53,12 +59,6 @@ error: expected identifier, found keyword `Self`
5359
LL | trait Self {}
5460
| ^^^^ expected identifier, found keyword
5561

56-
error: lifetimes cannot use keyword names
57-
--> $DIR/self_type_keyword.rs:6:12
58-
|
59-
LL | struct Bar<'Self>;
60-
| ^^^^^
61-
6262
error: cannot find macro `Self` in this scope
6363
--> $DIR/self_type_keyword.rs:21:9
6464
|

0 commit comments

Comments
 (0)