Skip to content

Commit a61cf67

Browse files
committed
Reserve gen keyword for gen {} blocks and gen fn in 2024 edition
1 parent ccb160d commit a61cf67

File tree

14 files changed

+138
-4
lines changed

14 files changed

+138
-4
lines changed

Diff for: compiler/rustc_ast/src/ast.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2357,6 +2357,12 @@ pub enum Async {
23572357
No,
23582358
}
23592359

2360+
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
2361+
pub enum Gen {
2362+
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
2363+
No,
2364+
}
2365+
23602366
impl Async {
23612367
pub fn is_async(self) -> bool {
23622368
matches!(self, Async::Yes { .. })

Diff for: compiler/rustc_ast/src/token.rs

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
197197
kw::Continue,
198198
kw::False,
199199
kw::For,
200+
kw::Gen,
200201
kw::If,
201202
kw::Let,
202203
kw::Loop,

Diff for: compiler/rustc_parse/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}`
278278
parse_function_body_equals_expr = function body cannot be `= expression;`
279279
.suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
280280
281+
parse_gen_block = `gen` blocks are not yet implemented
282+
.help = only the keyword is reserved for now
283+
281284
parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax
282285
283286
parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets

Diff for: compiler/rustc_parse/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,14 @@ pub(crate) struct CatchAfterTry {
520520
pub span: Span,
521521
}
522522

523+
#[derive(Diagnostic)]
524+
#[diag(parse_gen_block)]
525+
#[help]
526+
pub(crate) struct GenBlock {
527+
#[primary_span]
528+
pub span: Span,
529+
}
530+
523531
#[derive(Diagnostic)]
524532
#[diag(parse_comma_after_base_struct)]
525533
#[note]

Diff for: compiler/rustc_parse/src/parser/expr.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,9 @@ impl<'a> Parser<'a> {
14221422
} else if this.is_try_block() {
14231423
this.expect_keyword(kw::Try)?;
14241424
this.parse_try_block(lo)
1425+
} else if this.is_gen_block() {
1426+
this.expect_keyword(kw::Gen)?;
1427+
this.parse_gen_block(lo)
14251428
} else if this.eat_keyword(kw::Return) {
14261429
this.parse_expr_return()
14271430
} else if this.eat_keyword(kw::Continue) {
@@ -3040,6 +3043,14 @@ impl<'a> Parser<'a> {
30403043
}
30413044
}
30423045

3046+
/// Parses a `gen {...}` expression (`gen` token already eaten).
3047+
fn parse_gen_block(&mut self, _span_lo: Span) -> PResult<'a, P<Expr>> {
3048+
let (_attrs, _body) = self.parse_inner_attrs_and_block()?;
3049+
3050+
Err(errors::GenBlock { span: self.prev_token.span }
3051+
.into_diagnostic(&self.sess.span_diagnostic))
3052+
}
3053+
30433054
fn is_do_catch_block(&self) -> bool {
30443055
self.token.is_keyword(kw::Do)
30453056
&& self.is_keyword_ahead(1, &[kw::Catch])
@@ -3059,6 +3070,13 @@ impl<'a> Parser<'a> {
30593070
&& self.token.uninterpolated_span().at_least_rust_2018()
30603071
}
30613072

3073+
fn is_gen_block(&self) -> bool {
3074+
self.token.is_keyword(kw::Gen)
3075+
&& self
3076+
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
3077+
&& self.token.uninterpolated_span().at_least_rust_2024()
3078+
}
3079+
30623080
/// Parses an `async move? {...}` expression.
30633081
fn parse_async_block(&mut self) -> PResult<'a, P<Expr>> {
30643082
let lo = self.token.span;

Diff for: compiler/rustc_parse/src/parser/item.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -2297,9 +2297,9 @@ impl<'a> Parser<'a> {
22972297
// `pub` is added in case users got confused with the ordering like `async pub fn`,
22982298
// only if it wasn't preceded by `default` as `default pub` is invalid.
22992299
let quals: &[Symbol] = if check_pub {
2300-
&[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
2300+
&[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
23012301
} else {
2302-
&[kw::Const, kw::Async, kw::Unsafe, kw::Extern]
2302+
&[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
23032303
};
23042304
self.check_keyword_case(kw::Fn, case) // Definitely an `fn`.
23052305
// `$qual fn` or `$qual $qual`:
@@ -2353,6 +2353,9 @@ impl<'a> Parser<'a> {
23532353
let async_start_sp = self.token.span;
23542354
let asyncness = self.parse_asyncness(case);
23552355

2356+
let _gen_start_sp = self.token.span;
2357+
let genness = self.parse_genness(case);
2358+
23562359
let unsafe_start_sp = self.token.span;
23572360
let unsafety = self.parse_unsafety(case);
23582361

@@ -2368,6 +2371,10 @@ impl<'a> Parser<'a> {
23682371
}
23692372
}
23702373

2374+
if let Gen::Yes { span, .. } = genness {
2375+
self.sess.emit_err(errors::GenBlock { span });
2376+
}
2377+
23712378
if !self.eat_keyword_case(kw::Fn, case) {
23722379
// It is possible for `expect_one_of` to recover given the contents of
23732380
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't

Diff for: 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) {

Diff for: 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",
@@ -2188,8 +2189,9 @@ impl Symbol {
21882189
self >= kw::Abstract && self <= kw::Yield
21892190
}
21902191

2191-
fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
2192-
self == kw::Try && edition() >= Edition::Edition2018
2192+
fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
2193+
self == kw::Try && edition().at_least_rust_2018()
2194+
|| self == kw::Gen && edition().at_least_rust_2024()
21932195
}
21942196

21952197
pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool {

Diff for: tests/ui/coroutine/gen_block.e2024.stderr

+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+

Diff for: tests/ui/coroutine/gen_block.none.stderr

+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`.

Diff for: tests/ui/coroutine/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+
}

Diff for: tests/ui/coroutine/gen_fn.e2024.stderr

+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+

Diff for: tests/ui/coroutine/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+

Diff for: tests/ui/coroutine/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)