Skip to content

Commit 7e1e1b5

Browse files
committed
Reserve gen keyword for gen {} blocks and gen fn in 2024 edition
1 parent e293927 commit 7e1e1b5

File tree

14 files changed

+138
-4
lines changed

14 files changed

+138
-4
lines changed

compiler/rustc_ast/src/ast.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2418,6 +2418,12 @@ pub enum Async {
24182418
No,
24192419
}
24202420

2421+
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
2422+
pub enum Gen {
2423+
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
2424+
No,
2425+
}
2426+
24212427
impl Async {
24222428
pub fn is_async(self) -> bool {
24232429
matches!(self, Async::Yes { .. })

compiler/rustc_ast/src/token.rs

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
199199
kw::Continue,
200200
kw::False,
201201
kw::For,
202+
kw::Gen,
202203
kw::If,
203204
kw::Let,
204205
kw::Loop,

compiler/rustc_parse/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}`
274274
parse_function_body_equals_expr = function body cannot be `= expression;`
275275
.suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
276276
277+
parse_gen_block = `gen` blocks are not yet implemented
278+
.help = only the keyword is reserved for now
279+
277280
parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax
278281
279282
parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets

compiler/rustc_parse/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,14 @@ pub(crate) struct CatchAfterTry {
509509
pub span: Span,
510510
}
511511

512+
#[derive(Diagnostic)]
513+
#[diag(parse_gen_block)]
514+
#[help]
515+
pub(crate) struct GenBlock {
516+
#[primary_span]
517+
pub span: Span,
518+
}
519+
512520
#[derive(Diagnostic)]
513521
#[diag(parse_comma_after_base_struct)]
514522
#[note]

compiler/rustc_parse/src/parser/expr.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,9 @@ impl<'a> Parser<'a> {
14211421
} else if this.is_try_block() {
14221422
this.expect_keyword(kw::Try)?;
14231423
this.parse_try_block(lo)
1424+
} else if this.is_gen_block() {
1425+
this.expect_keyword(kw::Gen)?;
1426+
this.parse_gen_block(lo)
14241427
} else if this.eat_keyword(kw::Return) {
14251428
this.parse_expr_return()
14261429
} else if this.eat_keyword(kw::Continue) {
@@ -2996,6 +2999,14 @@ impl<'a> Parser<'a> {
29962999
}
29973000
}
29983001

3002+
/// Parses a `gen {...}` expression (`gen` token already eaten).
3003+
fn parse_gen_block(&mut self, _span_lo: Span) -> PResult<'a, P<Expr>> {
3004+
let (_attrs, _body) = self.parse_inner_attrs_and_block()?;
3005+
3006+
Err(errors::GenBlock { span: self.prev_token.span }
3007+
.into_diagnostic(&self.sess.span_diagnostic))
3008+
}
3009+
29993010
fn is_do_catch_block(&self) -> bool {
30003011
self.token.is_keyword(kw::Do)
30013012
&& self.is_keyword_ahead(1, &[kw::Catch])
@@ -3015,6 +3026,13 @@ impl<'a> Parser<'a> {
30153026
&& self.token.uninterpolated_span().at_least_rust_2018()
30163027
}
30173028

3029+
fn is_gen_block(&self) -> bool {
3030+
self.token.is_keyword(kw::Gen)
3031+
&& self
3032+
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
3033+
&& self.token.uninterpolated_span().at_least_rust_2024()
3034+
}
3035+
30183036
/// Parses an `async move? {...}` expression.
30193037
fn parse_async_block(&mut self) -> PResult<'a, P<Expr>> {
30203038
let lo = self.token.span;

compiler/rustc_parse/src/parser/item.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -2293,9 +2293,9 @@ impl<'a> Parser<'a> {
22932293
// `pub` is added in case users got confused with the ordering like `async pub fn`,
22942294
// only if it wasn't preceded by `default` as `default pub` is invalid.
22952295
let quals: &[Symbol] = if check_pub {
2296-
&[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
2296+
&[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
22972297
} else {
2298-
&[kw::Const, kw::Async, kw::Unsafe, kw::Extern]
2298+
&[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
22992299
};
23002300
self.check_keyword_case(kw::Fn, case) // Definitely an `fn`.
23012301
// `$qual fn` or `$qual $qual`:
@@ -2349,6 +2349,9 @@ impl<'a> Parser<'a> {
23492349
let async_start_sp = self.token.span;
23502350
let asyncness = self.parse_asyncness(case);
23512351

2352+
let _gen_start_sp = self.token.span;
2353+
let genness = self.parse_genness(case);
2354+
23522355
let unsafe_start_sp = self.token.span;
23532356
let unsafety = self.parse_unsafety(case);
23542357

@@ -2364,6 +2367,10 @@ impl<'a> Parser<'a> {
23642367
}
23652368
}
23662369

2370+
if let Gen::Yes { span, .. } = genness {
2371+
self.sess.emit_err(errors::GenBlock { span });
2372+
}
2373+
23672374
if !self.eat_keyword_case(kw::Fn, case) {
23682375
// It is possible for `expect_one_of` to recover given the contents of
23692376
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't

compiler/rustc_parse/src/parser/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod stmt;
1111
mod ty;
1212

1313
use crate::lexer::UnmatchedDelim;
14+
use ast::Gen;
1415
pub use attr_wrapper::AttrWrapper;
1516
pub use diagnostics::AttemptLocalParseRecovery;
1617
pub(crate) use expr::ForbiddenLetReason;
@@ -1126,6 +1127,16 @@ impl<'a> Parser<'a> {
11261127
}
11271128
}
11281129

1130+
/// Parses genness: `gen` or nothing.
1131+
fn parse_genness(&mut self, case: Case) -> Gen {
1132+
if self.token.span.at_least_rust_2024() && self.eat_keyword_case(kw::Gen, case) {
1133+
let span = self.prev_token.uninterpolated_span();
1134+
Gen::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
1135+
} else {
1136+
Gen::No
1137+
}
1138+
}
1139+
11291140
/// Parses unsafety: `unsafe` or nothing.
11301141
fn parse_unsafety(&mut self, case: Case) -> Unsafe {
11311142
if self.eat_keyword_case(kw::Unsafe, case) {

compiler/rustc_span/src/symbol.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ symbols! {
9898
Builtin: "builtin",
9999
Catch: "catch",
100100
Default: "default",
101+
Gen: "gen",
101102
MacroRules: "macro_rules",
102103
Raw: "raw",
103104
Union: "union",
@@ -2132,8 +2133,9 @@ impl Symbol {
21322133
self >= kw::Abstract && self <= kw::Yield
21332134
}
21342135

2135-
fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
2136-
self == kw::Try && edition() >= Edition::Edition2018
2136+
fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
2137+
self == kw::Try && edition().at_least_rust_2018()
2138+
|| self == kw::Gen && edition().at_least_rust_2024()
21372139
}
21382140

21392141
pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: `gen` blocks are not yet implemented
2+
--> $DIR/gen_block.rs:5:18
3+
|
4+
LL | let x = gen {};
5+
| ^
6+
|
7+
= help: only the keyword is reserved for now
8+
9+
error: aborting due to previous error
10+
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: expected identifier, found reserved keyword `yield`
2+
--> $DIR/gen_block.rs:8:19
3+
|
4+
LL | let y = gen { yield 42 };
5+
| --- ^^^^^ expected identifier, found reserved keyword
6+
| |
7+
| while parsing this struct
8+
9+
error[E0422]: cannot find struct, variant or union type `gen` in this scope
10+
--> $DIR/gen_block.rs:5:13
11+
|
12+
LL | let x = gen {};
13+
| ^^^ not found in this scope
14+
15+
error[E0422]: cannot find struct, variant or union type `gen` in this scope
16+
--> $DIR/gen_block.rs:8:13
17+
|
18+
LL | let y = gen { yield 42 };
19+
| ^^^ not found in this scope
20+
21+
error[E0422]: cannot find struct, variant or union type `gen` in this scope
22+
--> $DIR/gen_block.rs:11:5
23+
|
24+
LL | gen {};
25+
| ^^^ not found in this scope
26+
27+
error: aborting due to 4 previous errors
28+
29+
For more information about this error, try `rustc --explain E0422`.

tests/ui/generator/gen_block.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// revisions: e2024 none
2+
//[e2024] compile-flags: --edition 2024 -Zunstable-options
3+
4+
fn main() {
5+
let x = gen {};
6+
//[none]~^ ERROR: cannot find
7+
//[e2024]~^^ ERROR: `gen` blocks are not yet implemented
8+
let y = gen { yield 42 };
9+
//[none]~^ ERROR: found reserved keyword `yield`
10+
//[none]~| ERROR: cannot find
11+
gen {};
12+
//[none]~^ ERROR: cannot find
13+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: `gen` blocks are not yet implemented
2+
--> $DIR/gen_fn.rs:4:1
3+
|
4+
LL | gen fn foo() {}
5+
| ^^^
6+
|
7+
= help: only the keyword is reserved for now
8+
9+
error: aborting due to previous error
10+

tests/ui/generator/gen_fn.none.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen`
2+
--> $DIR/gen_fn.rs:4:1
3+
|
4+
LL | gen fn foo() {}
5+
| ^^^ expected one of 9 possible tokens
6+
7+
error: aborting due to previous error
8+

tests/ui/generator/gen_fn.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// revisions: e2024 none
2+
//[e2024] compile-flags: --edition 2024 -Zunstable-options
3+
4+
gen fn foo() {}
5+
//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen`
6+
//[e2024]~^^ ERROR: `gen` blocks are not yet implemented
7+
8+
fn main() {}

0 commit comments

Comments
 (0)