about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs12
-rw-r--r--compiler/rustc_ast_passes/messages.ftl10
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs17
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs12
-rw-r--r--tests/ui/coroutine/const_gen_fn.rs12
-rw-r--r--tests/ui/coroutine/const_gen_fn.stderr20
7 files changed, 66 insertions, 28 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index c5aa9f56733..9dfebfae5ed 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2602,12 +2602,12 @@ impl CoroutineKind {
         }
     }
 
-    pub fn is_async(self) -> bool {
-        matches!(self, CoroutineKind::Async { .. })
-    }
-
-    pub fn is_gen(self) -> bool {
-        matches!(self, CoroutineKind::Gen { .. })
+    pub fn as_str(self) -> &'static str {
+        match self {
+            CoroutineKind::Async { .. } => "async",
+            CoroutineKind::Gen { .. } => "gen",
+            CoroutineKind::AsyncGen { .. } => "async gen",
+        }
     }
 
     pub fn closure_id(self) -> NodeId {
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index df5c639382f..c361c35b723 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -40,15 +40,15 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
 
 ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
 
-ast_passes_const_and_async = functions cannot be both `const` and `async`
-    .const = `const` because of this
-    .async = `async` because of this
-    .label = {""}
-
 ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic
     .const = `const` because of this
     .variadic = C-variadic because of this
 
+ast_passes_const_and_coroutine = functions cannot be both `const` and `{$coroutine_kind}`
+    .const = `const` because of this
+    .coroutine = `{$coroutine_kind}` because of this
+    .label = {""}
+
 ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types
 
 ast_passes_const_without_body =
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 67dd18fd89c..93881f5ed42 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1418,21 +1418,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
         // Functions cannot both be `const async` or `const gen`
         if let Some(&FnHeader {
-            constness: Const::Yes(cspan),
+            constness: Const::Yes(const_span),
             coroutine_kind: Some(coroutine_kind),
             ..
         }) = fk.header()
         {
-            let aspan = match coroutine_kind {
-                CoroutineKind::Async { span: aspan, .. }
-                | CoroutineKind::Gen { span: aspan, .. }
-                | CoroutineKind::AsyncGen { span: aspan, .. } => aspan,
-            };
-            // FIXME(gen_blocks): Report a different error for `const gen`
-            self.dcx().emit_err(errors::ConstAndAsync {
-                spans: vec![cspan, aspan],
-                cspan,
-                aspan,
+            self.dcx().emit_err(errors::ConstAndCoroutine {
+                spans: vec![coroutine_kind.span(), const_span],
+                const_span,
+                coroutine_span: coroutine_kind.span(),
+                coroutine_kind: coroutine_kind.as_str(),
                 span,
             });
         }
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 67c0396333c..5cce47ce7bd 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -657,16 +657,17 @@ pub(crate) enum TildeConstReason {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_const_and_async)]
-pub(crate) struct ConstAndAsync {
+#[diag(ast_passes_const_and_coroutine)]
+pub(crate) struct ConstAndCoroutine {
     #[primary_span]
     pub spans: Vec<Span>,
     #[label(ast_passes_const)]
-    pub cspan: Span,
-    #[label(ast_passes_async)]
-    pub aspan: Span,
+    pub const_span: Span,
+    #[label(ast_passes_coroutine)]
+    pub coroutine_span: Span,
     #[label]
     pub span: Span,
+    pub coroutine_kind: &'static str,
 }
 
 #[derive(Diagnostic)]
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 181bbdde8e5..de8bbb619f8 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -221,7 +221,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         ) => {
             eq_closure_binder(lb, rb)
                 && lc == rc
-                && la.map_or(false, CoroutineKind::is_async) == ra.map_or(false, CoroutineKind::is_async)
+                && eq_coroutine_kind(*la, *ra)
                 && lm == rm
                 && eq_fn_decl(lf, rf)
                 && eq_expr(le, re)
@@ -241,6 +241,16 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
     }
 }
 
+fn eq_coroutine_kind(a: Option<CoroutineKind>, b: Option<CoroutineKind>) -> bool {
+    match (a, b) {
+        (Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. }))
+        | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. }))
+        | (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. }))
+        | (None, None) => true,
+        _ => false,
+    }
+}
+
 pub fn eq_field(l: &ExprField, r: &ExprField) -> bool {
     l.is_placeholder == r.is_placeholder
         && eq_id(l.ident, r.ident)
diff --git a/tests/ui/coroutine/const_gen_fn.rs b/tests/ui/coroutine/const_gen_fn.rs
new file mode 100644
index 00000000000..986693f33ab
--- /dev/null
+++ b/tests/ui/coroutine/const_gen_fn.rs
@@ -0,0 +1,12 @@
+//@ edition:2024
+//@ compile-flags: -Zunstable-options
+
+#![feature(gen_blocks)]
+
+const gen fn a() {}
+//~^ ERROR functions cannot be both `const` and `gen`
+
+const async gen fn b() {}
+//~^ ERROR functions cannot be both `const` and `async gen`
+
+fn main() {}
diff --git a/tests/ui/coroutine/const_gen_fn.stderr b/tests/ui/coroutine/const_gen_fn.stderr
new file mode 100644
index 00000000000..b58446ac88f
--- /dev/null
+++ b/tests/ui/coroutine/const_gen_fn.stderr
@@ -0,0 +1,20 @@
+error: functions cannot be both `const` and `gen`
+  --> $DIR/const_gen_fn.rs:6:1
+   |
+LL | const gen fn a() {}
+   | ^^^^^-^^^----------
+   | |     |
+   | |     `gen` because of this
+   | `const` because of this
+
+error: functions cannot be both `const` and `async gen`
+  --> $DIR/const_gen_fn.rs:9:1
+   |
+LL | const async gen fn b() {}
+   | ^^^^^-^^^^^^^^^----------
+   | |     |
+   | |     `async gen` because of this
+   | `const` because of this
+
+error: aborting due to 2 previous errors
+