From b692d5ba1593762502b370014f56fcc66f1bbddc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 11 Apr 2024 13:15:34 +0000 Subject: [PATCH] Error on using `yield` without also using `gen` on the closure And suggest adding the `gen` to the closure or function --- compiler/rustc_ast_lowering/messages.ftl | 3 ++ compiler/rustc_ast_lowering/src/errors.rs | 9 ++++++ compiler/rustc_ast_lowering/src/expr.rs | 6 ++++ compiler/rustc_ast_lowering/src/item.rs | 2 +- ...async-outside-of-await-issue-121096.stderr | 2 +- .../incorrect-syntax-suggestions.stderr | 10 +++--- .../ui/async-await/issues/issue-51751.stderr | 2 +- .../async-await/issues/issue-62009-1.stderr | 6 ++-- .../async-await/issues/issue-62009-2.stderr | 2 +- .../issues/non-async-enclosing-span.stderr | 2 +- tests/ui/coroutine/gen_block.e2024.stderr | 13 +++++++- tests/ui/coroutine/gen_block.rs | 1 + tests/ui/coroutine/missing_gen_in_2024.fixed | 16 ++++++++++ tests/ui/coroutine/missing_gen_in_2024.rs | 16 ++++++++++ tests/ui/coroutine/missing_gen_in_2024.stderr | 31 +++++++++++++++++++ .../feature-gate-coroutines.e2024.stderr | 26 ++++++++++++++-- .../feature-gate-coroutines.none.stderr | 8 ++--- .../feature-gates/feature-gate-coroutines.rs | 2 ++ tests/ui/sanitizer/cfi-coroutine.rs | 2 +- 19 files changed, 138 insertions(+), 21 deletions(-) create mode 100644 tests/ui/coroutine/missing_gen_in_2024.fixed create mode 100644 tests/ui/coroutine/missing_gen_in_2024.rs create mode 100644 tests/ui/coroutine/missing_gen_in_2024.stderr diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index d91d65497e1c1..802fb7d2b714a 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -161,3 +161,6 @@ ast_lowering_underscore_expr_lhs_assign = .label = `_` not allowed here ast_lowering_use_angle_brackets = use angle brackets instead +ast_lowering_yield_in_closure = + `yield` can only be used in `gen` closures, functions, or blocks + .suggestion = use `gen` to make this item a coroutine diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 6fd980ed3ca96..be7b058ba4a76 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -414,3 +414,12 @@ pub(crate) struct AsyncBoundOnlyForFnTraits { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_yield_in_closure)] +pub(crate) struct YieldInClosure { + #[primary_span] + pub span: Span, + #[suggestion(code = "gen ", applicability = "maybe-incorrect", style = "verbose")] + pub suggestion: Option, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 3bbd4514a343c..60d32db192a2f 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -8,6 +8,7 @@ use super::errors::{ }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; +use crate::errors::YieldInClosure; use crate::{FnDeclKind, ImplTraitPosition}; use rustc_ast::ptr::P as AstP; use rustc_ast::*; @@ -1578,7 +1579,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ) .emit(); } + if self.tcx.sess.edition().at_least_rust_2024() { + let suggestion = self.current_item.map(|s| s.shrink_to_lo()); + self.dcx().emit_err(YieldInClosure { span, suggestion }); + } self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable)); + false } }; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index abfea6078f21c..3965b5b1cfdd7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -203,7 +203,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, .. }) => { - self.with_new_scopes(ident.span, |this| { + self.with_new_scopes(*fn_sig_span, |this| { // Note: we don't need to change the return type from `T` to // `impl Future` here because lower_body // only cares about the input argument patterns in the function diff --git a/tests/ui/async-await/async-outside-of-await-issue-121096.stderr b/tests/ui/async-await/async-outside-of-await-issue-121096.stderr index b0677a83864e0..d7caf6b3c0d21 100644 --- a/tests/ui/async-await/async-outside-of-await-issue-121096.stderr +++ b/tests/ui/async-await/async-outside-of-await-issue-121096.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/async-outside-of-await-issue-121096.rs:7:7 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | }.await | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 928eb0b821db1..a98bb0764c0e6 100644 --- a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -141,7 +141,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:68:19 | LL | fn foo13() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await(); | ^^^^^ only allowed inside `async` functions and blocks @@ -149,7 +149,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:73:19 | LL | fn foo14() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await()?; | ^^^^^ only allowed inside `async` functions and blocks @@ -157,7 +157,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:78:19 | LL | fn foo15() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await; | ^^^^^ only allowed inside `async` functions and blocks @@ -165,7 +165,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:82:19 | LL | fn foo16() -> Result<(), ()> { - | ----- this is not `async` + | ---------------------------- this is not `async` LL | let _ = bar().await?; | ^^^^^ only allowed inside `async` functions and blocks @@ -173,7 +173,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/incorrect-syntax-suggestions.rs:87:23 | LL | fn foo() -> Result<(), ()> { - | --- this is not `async` + | -------------------------- this is not `async` LL | let _ = bar().await?; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-51751.stderr b/tests/ui/async-await/issues/issue-51751.stderr index ba256b19948c0..ab12e0427b47a 100644 --- a/tests/ui/async-await/issues/issue-51751.stderr +++ b/tests/ui/async-await/issues/issue-51751.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51751.rs:9:27 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | let result = inc(10000); LL | let finished = result.await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-62009-1.stderr b/tests/ui/async-await/issues/issue-62009-1.stderr index 02933f4f2f233..f8a4b5d9af8b2 100644 --- a/tests/ui/async-await/issues/issue-62009-1.stderr +++ b/tests/ui/async-await/issues/issue-62009-1.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:6:23 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | async { let (); }.await; | ^^^^^ only allowed inside `async` functions and blocks @@ -10,7 +10,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:10:7 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | }.await; | ^^^^^ only allowed inside `async` functions and blocks @@ -19,7 +19,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-1.rs:12:16 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` ... LL | (|_| 2333).await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/issue-62009-2.stderr b/tests/ui/async-await/issues/issue-62009-2.stderr index 80a831cc5475f..0004f99f9018d 100644 --- a/tests/ui/async-await/issues/issue-62009-2.stderr +++ b/tests/ui/async-await/issues/issue-62009-2.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-62009-2.rs:8:23 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | (async || 2333)().await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/async-await/issues/non-async-enclosing-span.stderr b/tests/ui/async-await/issues/non-async-enclosing-span.stderr index 91a9e5aa6cabf..9c26de1c5047c 100644 --- a/tests/ui/async-await/issues/non-async-enclosing-span.stderr +++ b/tests/ui/async-await/issues/non-async-enclosing-span.stderr @@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/non-async-enclosing-span.rs:9:28 | LL | fn main() { - | ---- this is not `async` + | --------- this is not `async` LL | let x = move || {}; LL | let y = do_the_thing().await; | ^^^^^ only allowed inside `async` functions and blocks diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr index 2b9eb4a820b65..879e59e92ce12 100644 --- a/tests/ui/coroutine/gen_block.e2024.stderr +++ b/tests/ui/coroutine/gen_block.e2024.stderr @@ -8,13 +8,24 @@ LL | let _ = || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `gen` closures, functions, or blocks + --> $DIR/gen_block.rs:15:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | +help: use `gen` to make this item a coroutine + | +LL | let _ = gen || yield true; + | +++ + error[E0282]: type annotations needed --> $DIR/gen_block.rs:6:13 | LL | let x = gen {}; | ^^^^^^ cannot infer type -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0282, E0658. For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs index f6a775aa66199..68ca95b5c7d44 100644 --- a/tests/ui/coroutine/gen_block.rs +++ b/tests/ui/coroutine/gen_block.rs @@ -14,4 +14,5 @@ fn main() { let _ = || yield true; //[none]~ ERROR yield syntax is experimental //~^ ERROR yield syntax is experimental + //[e2024]~^^ ERROR `yield` can only be used in `gen` closures, functions, or blocks } diff --git a/tests/ui/coroutine/missing_gen_in_2024.fixed b/tests/ui/coroutine/missing_gen_in_2024.fixed new file mode 100644 index 0000000000000..5d05d93ce3bb2 --- /dev/null +++ b/tests/ui/coroutine/missing_gen_in_2024.fixed @@ -0,0 +1,16 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options +//@ run-rustfix + +#![feature(coroutines, gen_blocks)] + +fn main() { + let _ = gen || yield; + //~^ ERROR `yield` can only be used in `gen` closures, functions, or blocks +} + +gen fn _foo() { + yield; + //~^ ERROR `yield` can only be used in `gen` closures, functions, or blocks + //~| ERROR yield expression outside of coroutine literal +} diff --git a/tests/ui/coroutine/missing_gen_in_2024.rs b/tests/ui/coroutine/missing_gen_in_2024.rs new file mode 100644 index 0000000000000..9dc96867b573b --- /dev/null +++ b/tests/ui/coroutine/missing_gen_in_2024.rs @@ -0,0 +1,16 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options +//@ run-rustfix + +#![feature(coroutines, gen_blocks)] + +fn main() { + let _ = || yield; + //~^ ERROR `yield` can only be used in `gen` closures, functions, or blocks +} + +fn _foo() { + yield; + //~^ ERROR `yield` can only be used in `gen` closures, functions, or blocks + //~| ERROR yield expression outside of coroutine literal +} diff --git a/tests/ui/coroutine/missing_gen_in_2024.stderr b/tests/ui/coroutine/missing_gen_in_2024.stderr new file mode 100644 index 0000000000000..004a0b53744a2 --- /dev/null +++ b/tests/ui/coroutine/missing_gen_in_2024.stderr @@ -0,0 +1,31 @@ +error: `yield` can only be used in `gen` closures, functions, or blocks + --> $DIR/missing_gen_in_2024.rs:8:16 + | +LL | let _ = || yield; + | ^^^^^ + | +help: use `gen` to make this item a coroutine + | +LL | let _ = gen || yield; + | +++ + +error: `yield` can only be used in `gen` closures, functions, or blocks + --> $DIR/missing_gen_in_2024.rs:13:5 + | +LL | yield; + | ^^^^^ + | +help: use `gen` to make this item a coroutine + | +LL | gen fn _foo() { + | +++ + +error[E0627]: yield expression outside of coroutine literal + --> $DIR/missing_gen_in_2024.rs:13:5 + | +LL | yield; + | ^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0627`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr index 1cef163cef5c2..7f0165265cabd 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.e2024.stderr @@ -8,8 +8,19 @@ LL | yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `gen` closures, functions, or blocks + --> $DIR/feature-gate-coroutines.rs:5:5 + | +LL | yield true; + | ^^^^^^^^^^ + | +help: use `gen` to make this item a coroutine + | +LL | gen fn main() { + | +++ + error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -18,13 +29,24 @@ LL | let _ = || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error: `yield` can only be used in `gen` closures, functions, or blocks + --> $DIR/feature-gate-coroutines.rs:10:16 + | +LL | let _ = || yield true; + | ^^^^^^^^^^ + | +help: use `gen` to make this item a coroutine + | +LL | let _ = gen || yield true; + | +++ + error[E0627]: yield expression outside of coroutine literal --> $DIR/feature-gate-coroutines.rs:5:5 | LL | yield true; | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0627, E0658. For more information about an error, try `rustc --explain E0627`. diff --git a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr index 403f0549aef27..662cdfd81d1f4 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr +++ b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr @@ -9,7 +9,7 @@ LL | yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | let _ = || yield true; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:16:5 + --> $DIR/feature-gate-coroutines.rs:18:5 | LL | yield; | ^^^^^ @@ -29,7 +29,7 @@ LL | yield; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:17:5 + --> $DIR/feature-gate-coroutines.rs:19:5 | LL | yield 0; | ^^^^^^^ @@ -50,7 +50,7 @@ LL | yield true; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0658]: yield syntax is experimental - --> $DIR/feature-gate-coroutines.rs:9:16 + --> $DIR/feature-gate-coroutines.rs:10:16 | LL | let _ = || yield true; | ^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-coroutines.rs b/tests/ui/feature-gates/feature-gate-coroutines.rs index b3df2351b680b..e80e45edaa422 100644 --- a/tests/ui/feature-gates/feature-gate-coroutines.rs +++ b/tests/ui/feature-gates/feature-gate-coroutines.rs @@ -5,9 +5,11 @@ fn main() { yield true; //~ ERROR yield syntax is experimental //~^ ERROR yield expression outside of coroutine literal //[none]~^^ ERROR yield syntax is experimental + //[e2024]~^^^ ERROR `yield` can only be used in `gen` closures, functions, or blocks let _ = || yield true; //~ ERROR yield syntax is experimental //[none]~^ ERROR yield syntax is experimental + //[e2024]~^^ ERROR `yield` can only be used in `gen` closures, functions, or blocks } #[cfg(FALSE)] diff --git a/tests/ui/sanitizer/cfi-coroutine.rs b/tests/ui/sanitizer/cfi-coroutine.rs index 5c6a489a7e89e..611826de92341 100644 --- a/tests/ui/sanitizer/cfi-coroutine.rs +++ b/tests/ui/sanitizer/cfi-coroutine.rs @@ -27,7 +27,7 @@ use std::async_iter::AsyncIterator; #[test] fn general_coroutine() { - let mut coro = |x: i32| { + let mut coro = gen |x: i32| { yield x; "done" };