about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-10-05 11:30:55 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-10-26 06:49:17 +0000
commita61cf673cd10ed24394c3403e03d8f7cf1f50170 (patch)
treedbf3c9adb68cb079695fc7b2e6999f162aeb42dd
parentccb160d3432dff025ab62696a82e576bf08aa006 (diff)
downloadrust-a61cf673cd10ed24394c3403e03d8f7cf1f50170.tar.gz
rust-a61cf673cd10ed24394c3403e03d8f7cf1f50170.zip
Reserve `gen` keyword for `gen {}` blocks and `gen fn` in 2024 edition
-rw-r--r--compiler/rustc_ast/src/ast.rs6
-rw-r--r--compiler/rustc_ast/src/token.rs1
-rw-r--r--compiler/rustc_parse/messages.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs18
-rw-r--r--compiler/rustc_parse/src/parser/item.rs11
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs11
-rw-r--r--compiler/rustc_span/src/symbol.rs6
-rw-r--r--tests/ui/coroutine/gen_block.e2024.stderr10
-rw-r--r--tests/ui/coroutine/gen_block.none.stderr29
-rw-r--r--tests/ui/coroutine/gen_block.rs13
-rw-r--r--tests/ui/coroutine/gen_fn.e2024.stderr10
-rw-r--r--tests/ui/coroutine/gen_fn.none.stderr8
-rw-r--r--tests/ui/coroutine/gen_fn.rs8
14 files changed, 138 insertions, 4 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e94e26a63bc..543c528db44 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2357,6 +2357,12 @@ pub enum Async {
     No,
 }
 
+#[derive(Copy, Clone, Encodable, Decodable, Debug)]
+pub enum Gen {
+    Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
+    No,
+}
+
 impl Async {
     pub fn is_async(self) -> bool {
         matches!(self, Async::Yes { .. })
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index dd879a14567..914c97a14ac 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -197,6 +197,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
             kw::Continue,
             kw::False,
             kw::For,
+            kw::Gen,
             kw::If,
             kw::Let,
             kw::Loop,
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index e0778f72bfe..9bedd7b8a33 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -278,6 +278,9 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}`
 parse_function_body_equals_expr = function body cannot be `= expression;`
     .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
 
+parse_gen_block = `gen` blocks are not yet implemented
+    .help = only the keyword is reserved for now
+
 parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax
 
 parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index aeb4fd0a304..c0e94d15da0 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -521,6 +521,14 @@ pub(crate) struct CatchAfterTry {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_gen_block)]
+#[help]
+pub(crate) struct GenBlock {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_comma_after_base_struct)]
 #[note]
 pub(crate) struct CommaAfterBaseStruct {
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 5157106f4e2..e59076acf4c 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1422,6 +1422,9 @@ impl<'a> Parser<'a> {
             } else if this.is_try_block() {
                 this.expect_keyword(kw::Try)?;
                 this.parse_try_block(lo)
+            } else if this.is_gen_block() {
+                this.expect_keyword(kw::Gen)?;
+                this.parse_gen_block(lo)
             } else if this.eat_keyword(kw::Return) {
                 this.parse_expr_return()
             } else if this.eat_keyword(kw::Continue) {
@@ -3040,6 +3043,14 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Parses a `gen {...}` expression (`gen` token already eaten).
+    fn parse_gen_block(&mut self, _span_lo: Span) -> PResult<'a, P<Expr>> {
+        let (_attrs, _body) = self.parse_inner_attrs_and_block()?;
+
+        Err(errors::GenBlock { span: self.prev_token.span }
+            .into_diagnostic(&self.sess.span_diagnostic))
+    }
+
     fn is_do_catch_block(&self) -> bool {
         self.token.is_keyword(kw::Do)
             && self.is_keyword_ahead(1, &[kw::Catch])
@@ -3059,6 +3070,13 @@ impl<'a> Parser<'a> {
             && self.token.uninterpolated_span().at_least_rust_2018()
     }
 
+    fn is_gen_block(&self) -> bool {
+        self.token.is_keyword(kw::Gen)
+            && self
+                .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
+            && self.token.uninterpolated_span().at_least_rust_2024()
+    }
+
     /// Parses an `async move? {...}` expression.
     fn parse_async_block(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 982f601c0d5..4c76ade0139 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2297,9 +2297,9 @@ impl<'a> Parser<'a> {
         // `pub` is added in case users got confused with the ordering like `async pub fn`,
         // only if it wasn't preceded by `default` as `default pub` is invalid.
         let quals: &[Symbol] = if check_pub {
-            &[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
+            &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
         } else {
-            &[kw::Const, kw::Async, kw::Unsafe, kw::Extern]
+            &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
         };
         self.check_keyword_case(kw::Fn, case) // Definitely an `fn`.
             // `$qual fn` or `$qual $qual`:
@@ -2353,6 +2353,9 @@ impl<'a> Parser<'a> {
         let async_start_sp = self.token.span;
         let asyncness = self.parse_asyncness(case);
 
+        let _gen_start_sp = self.token.span;
+        let genness = self.parse_genness(case);
+
         let unsafe_start_sp = self.token.span;
         let unsafety = self.parse_unsafety(case);
 
@@ -2368,6 +2371,10 @@ impl<'a> Parser<'a> {
             }
         }
 
+        if let Gen::Yes { span, .. } = genness {
+            self.sess.emit_err(errors::GenBlock { span });
+        }
+
         if !self.eat_keyword_case(kw::Fn, case) {
             // It is possible for `expect_one_of` to recover given the contents of
             // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 597303cae73..53c6d8acff1 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -11,6 +11,7 @@ mod stmt;
 mod ty;
 
 use crate::lexer::UnmatchedDelim;
+use ast::Gen;
 pub use attr_wrapper::AttrWrapper;
 pub use diagnostics::AttemptLocalParseRecovery;
 pub(crate) use expr::ForbiddenLetReason;
@@ -1126,6 +1127,16 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Parses genness: `gen` or nothing.
+    fn parse_genness(&mut self, case: Case) -> Gen {
+        if self.token.span.at_least_rust_2024() && self.eat_keyword_case(kw::Gen, case) {
+            let span = self.prev_token.uninterpolated_span();
+            Gen::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
+        } else {
+            Gen::No
+        }
+    }
+
     /// Parses unsafety: `unsafe` or nothing.
     fn parse_unsafety(&mut self, case: Case) -> Unsafe {
         if self.eat_keyword_case(kw::Unsafe, case) {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ff61143a12b..8ef16ed0dbf 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -98,6 +98,7 @@ symbols! {
         Builtin:            "builtin",
         Catch:              "catch",
         Default:            "default",
+        Gen:                "gen",
         MacroRules:         "macro_rules",
         Raw:                "raw",
         Union:              "union",
@@ -2188,8 +2189,9 @@ impl Symbol {
         self >= kw::Abstract && self <= kw::Yield
     }
 
-    fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
-        self == kw::Try && edition() >= Edition::Edition2018
+    fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
+        self == kw::Try && edition().at_least_rust_2018()
+            || self == kw::Gen && edition().at_least_rust_2024()
     }
 
     pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr
new file mode 100644
index 00000000000..099a9d13cee
--- /dev/null
+++ b/tests/ui/coroutine/gen_block.e2024.stderr
@@ -0,0 +1,10 @@
+error: `gen` blocks are not yet implemented
+  --> $DIR/gen_block.rs:5:18
+   |
+LL |     let x = gen {};
+   |                  ^
+   |
+   = help: only the keyword is reserved for now
+
+error: aborting due to previous error
+
diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr
new file mode 100644
index 00000000000..1cdd5d070ee
--- /dev/null
+++ b/tests/ui/coroutine/gen_block.none.stderr
@@ -0,0 +1,29 @@
+error: expected identifier, found reserved keyword `yield`
+  --> $DIR/gen_block.rs:8:19
+   |
+LL |     let y = gen { yield 42 };
+   |             ---   ^^^^^ expected identifier, found reserved keyword
+   |             |
+   |             while parsing this struct
+
+error[E0422]: cannot find struct, variant or union type `gen` in this scope
+  --> $DIR/gen_block.rs:5:13
+   |
+LL |     let x = gen {};
+   |             ^^^ not found in this scope
+
+error[E0422]: cannot find struct, variant or union type `gen` in this scope
+  --> $DIR/gen_block.rs:8:13
+   |
+LL |     let y = gen { yield 42 };
+   |             ^^^ not found in this scope
+
+error[E0422]: cannot find struct, variant or union type `gen` in this scope
+  --> $DIR/gen_block.rs:11:5
+   |
+LL |     gen {};
+   |     ^^^ not found in this scope
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0422`.
diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs
new file mode 100644
index 00000000000..5c0db5b3d38
--- /dev/null
+++ b/tests/ui/coroutine/gen_block.rs
@@ -0,0 +1,13 @@
+// revisions: e2024 none
+//[e2024] compile-flags: --edition 2024 -Zunstable-options
+
+fn main() {
+    let x = gen {};
+    //[none]~^ ERROR: cannot find
+    //[e2024]~^^ ERROR: `gen` blocks are not yet implemented
+    let y = gen { yield 42 };
+    //[none]~^ ERROR: found reserved keyword `yield`
+    //[none]~| ERROR: cannot find
+    gen {};
+    //[none]~^ ERROR: cannot find
+}
diff --git a/tests/ui/coroutine/gen_fn.e2024.stderr b/tests/ui/coroutine/gen_fn.e2024.stderr
new file mode 100644
index 00000000000..41bd04d9769
--- /dev/null
+++ b/tests/ui/coroutine/gen_fn.e2024.stderr
@@ -0,0 +1,10 @@
+error: `gen` blocks are not yet implemented
+  --> $DIR/gen_fn.rs:4:1
+   |
+LL | gen fn foo() {}
+   | ^^^
+   |
+   = help: only the keyword is reserved for now
+
+error: aborting due to previous error
+
diff --git a/tests/ui/coroutine/gen_fn.none.stderr b/tests/ui/coroutine/gen_fn.none.stderr
new file mode 100644
index 00000000000..5e7bd9d8bbf
--- /dev/null
+++ b/tests/ui/coroutine/gen_fn.none.stderr
@@ -0,0 +1,8 @@
+error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen`
+  --> $DIR/gen_fn.rs:4:1
+   |
+LL | gen fn foo() {}
+   | ^^^ expected one of 9 possible tokens
+
+error: aborting due to previous error
+
diff --git a/tests/ui/coroutine/gen_fn.rs b/tests/ui/coroutine/gen_fn.rs
new file mode 100644
index 00000000000..9566660dfb5
--- /dev/null
+++ b/tests/ui/coroutine/gen_fn.rs
@@ -0,0 +1,8 @@
+// revisions: e2024 none
+//[e2024] compile-flags: --edition 2024 -Zunstable-options
+
+gen fn foo() {}
+//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen`
+//[e2024]~^^ ERROR: `gen` blocks are not yet implemented
+
+fn main() {}