about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs25
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs5
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs25
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs23
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs18
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs9
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs3
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs2
-rw-r--r--compiler/rustc_expand/src/build.rs2
-rw-r--r--compiler/rustc_lint/src/early.rs12
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs10
-rw-r--r--compiler/rustc_parse/src/parser/item.rs26
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs16
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs2
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs16
-rw-r--r--compiler/rustc_resolve/src/late.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs13
-rw-r--r--src/tools/rustfmt/src/closures.rs13
-rw-r--r--src/tools/rustfmt/src/items.rs5
-rw-r--r--src/tools/rustfmt/src/utils.rs1
22 files changed, 117 insertions, 122 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index bf648388f4e..d6c2bfacf66 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1311,7 +1311,7 @@ pub struct Closure {
     pub binder: ClosureBinder,
     pub capture_clause: CaptureBy,
     pub constness: Const,
-    pub coro_kind: CoroutineKind,
+    pub coro_kind: Option<CoroutineKind>,
     pub movability: Movability,
     pub fn_decl: P<FnDecl>,
     pub body: P<Expr>,
@@ -2417,8 +2417,6 @@ pub enum CoroutineKind {
     Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
     /// `gen`, which evaluates to `impl Iterator`
     Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
-    /// Neither `async` nor `gen`
-    None,
 }
 
 impl CoroutineKind {
@@ -2430,14 +2428,12 @@ impl CoroutineKind {
         matches!(self, CoroutineKind::Gen { .. })
     }
 
-    /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
-    pub fn opt_return_id(self) -> Option<(NodeId, Span)> {
+    /// In this case this is an `async` or `gen` return, the `NodeId` for the generated `impl Trait`
+    /// item.
+    pub fn return_id(self) -> (NodeId, Span) {
         match self {
             CoroutineKind::Async { return_impl_trait_id, span, .. }
-            | CoroutineKind::Gen { return_impl_trait_id, span, .. } => {
-                Some((return_impl_trait_id, span))
-            }
-            CoroutineKind::None => None,
+            | CoroutineKind::Gen { return_impl_trait_id, span, .. } => (return_impl_trait_id, span),
         }
     }
 }
@@ -2842,7 +2838,7 @@ pub struct FnHeader {
     /// The `unsafe` keyword, if any
     pub unsafety: Unsafe,
     /// Whether this is `async`, `gen`, or nothing.
-    pub coro_kind: CoroutineKind,
+    pub coro_kind: Option<CoroutineKind>,
     /// The `const` keyword, if any
     pub constness: Const,
     /// The `extern` keyword and corresponding ABI string, if any
@@ -2854,7 +2850,7 @@ impl FnHeader {
     pub fn has_qualifiers(&self) -> bool {
         let Self { unsafety, coro_kind, constness, ext } = self;
         matches!(unsafety, Unsafe::Yes(_))
-            || !matches!(coro_kind, CoroutineKind::None)
+            || coro_kind.is_some()
             || matches!(constness, Const::Yes(_))
             || !matches!(ext, Extern::None)
     }
@@ -2862,12 +2858,7 @@ impl FnHeader {
 
 impl Default for FnHeader {
     fn default() -> FnHeader {
-        FnHeader {
-            unsafety: Unsafe::No,
-            coro_kind: CoroutineKind::None,
-            constness: Const::No,
-            ext: Extern::None,
-        }
+        FnHeader { unsafety: Unsafe::No, coro_kind: None, constness: Const::No, ext: Extern::None }
     }
 }
 
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index f9f767862f5..c6aa7a6ae37 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -878,7 +878,6 @@ pub fn noop_visit_coro_kind<T: MutVisitor>(coro_kind: &mut CoroutineKind, vis: &
             vis.visit_id(closure_id);
             vis.visit_id(return_impl_trait_id);
         }
-        CoroutineKind::None => {}
     }
 }
 
@@ -1173,7 +1172,7 @@ fn visit_const_item<T: MutVisitor>(
 pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
     let FnHeader { unsafety, coro_kind, constness, ext: _ } = header;
     visit_constness(constness, vis);
-    vis.visit_coro_kind(coro_kind);
+    coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind));
     visit_unsafety(unsafety, vis);
 }
 
@@ -1416,7 +1415,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
         }) => {
             vis.visit_closure_binder(binder);
             visit_constness(constness, vis);
-            vis.visit_coro_kind(coro_kind);
+            coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind));
             vis.visit_capture_by(capture_clause);
             vis.visit_fn_decl(fn_decl);
             vis.visit_expr(body);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 5846f17c539..3556ee02bd7 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -202,8 +202,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     fn_decl_span,
                     fn_arg_span,
                 }) => match coro_kind {
-                    CoroutineKind::Async { closure_id, .. }
-                    | CoroutineKind::Gen { closure_id, .. } => self.lower_expr_async_closure(
+                    Some(
+                        CoroutineKind::Async { closure_id, .. }
+                        | CoroutineKind::Gen { closure_id, .. },
+                    ) => self.lower_expr_async_closure(
                         binder,
                         *capture_clause,
                         e.id,
@@ -214,7 +216,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         *fn_decl_span,
                         *fn_arg_span,
                     ),
-                    CoroutineKind::None => self.lower_expr_closure(
+                    None => self.lower_expr_closure(
                         binder,
                         *capture_clause,
                         e.id,
@@ -933,13 +935,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
         // Lower outside new scope to preserve `is_in_loop_condition`.
-        let fn_decl = self.lower_fn_decl(
-            decl,
-            closure_id,
-            fn_decl_span,
-            FnDeclKind::Closure,
-            CoroutineKind::None,
-        );
+        let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
 
         let c = self.arena.alloc(hir::Closure {
             def_id: self.local_def_id(closure_id),
@@ -1054,13 +1050,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // We need to lower the declaration outside the new scope, because we
         // have to conserve the state of being inside a loop condition for the
         // closure argument types.
-        let fn_decl = self.lower_fn_decl(
-            &outer_decl,
-            closure_id,
-            fn_decl_span,
-            FnDeclKind::Closure,
-            CoroutineKind::None,
-        );
+        let fn_decl =
+            self.lower_fn_decl(&outer_decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
 
         let c = self.arena.alloc(hir::Closure {
             def_id: self.local_def_id(closure_id),
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 5d32e1a78f1..a23a77f45be 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -602,7 +602,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                                     i.id,
                                     sig.span,
                                     FnDeclKind::ExternFn,
-                                    CoroutineKind::None,
+                                    None,
                                 ),
                                 this.lower_fn_params_to_names(fdec),
                             )
@@ -841,7 +841,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 },
             ),
             AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
-                self.current_item = Some(i.span);
                 let body_id = self.lower_maybe_coroutine_body(
                     i.span,
                     hir_id,
@@ -1025,15 +1024,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         span: Span,
         fn_id: hir::HirId,
         decl: &FnDecl,
-        coro_kind: CoroutineKind,
+        coro_kind: Option<CoroutineKind>,
         body: Option<&Block>,
     ) -> hir::BodyId {
-        let (closure_id, body) = match (coro_kind, body) {
-            (
-                CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. },
-                Some(body),
-            ) => (closure_id, body),
-            _ => return self.lower_fn_body_block(span, decl, body),
+        let (Some(coro_kind), Some(body)) = (coro_kind, body) else {
+            return self.lower_fn_body_block(span, decl, body);
+        };
+        let closure_id = match coro_kind {
+            CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. } => {
+                closure_id
+            }
         };
 
         self.lower_body(|this| {
@@ -1218,7 +1218,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::CoroutineSource::Fn,
                     mkbody,
                 ),
-                CoroutineKind::None => unreachable!("we must have either an async fn or a gen fn"),
             };
 
             let hir_id = this.lower_node_id(closure_id);
@@ -1235,7 +1234,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         sig: &FnSig,
         id: NodeId,
         kind: FnDeclKind,
-        coro_kind: CoroutineKind,
+        coro_kind: Option<CoroutineKind>,
     ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header);
         let itctx = ImplTraitContext::Universal;
@@ -1247,7 +1246,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
-        let asyncness = if let CoroutineKind::Async { span, .. } = h.coro_kind {
+        let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coro_kind {
             hir::IsAsync::Async(span)
         } else {
             hir::IsAsync::NotAsync
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 92650f0c47e..a35b1513e14 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1359,13 +1359,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     generic_params,
                     unsafety: self.lower_unsafety(f.unsafety),
                     abi: self.lower_extern(f.ext),
-                    decl: self.lower_fn_decl(
-                        &f.decl,
-                        t.id,
-                        t.span,
-                        FnDeclKind::Pointer,
-                        CoroutineKind::None,
-                    ),
+                    decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
                     param_names: self.lower_fn_params_to_names(&f.decl),
                 }))
             }
@@ -1800,7 +1794,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         fn_node_id: NodeId,
         fn_span: Span,
         kind: FnDeclKind,
-        coro: CoroutineKind,
+        coro: Option<CoroutineKind>,
     ) -> &'hir hir::FnDecl<'hir> {
         let c_variadic = decl.c_variadic();
 
@@ -1830,11 +1824,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }));
 
         let output = match coro {
-            CoroutineKind::Async { .. } | CoroutineKind::Gen { .. } => {
+            Some(coro) => {
                 let fn_def_id = self.local_def_id(fn_node_id);
                 self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind, fn_span)
             }
-            CoroutineKind::None => match &decl.output {
+            None => match &decl.output {
                 FnRetTy::Ty(ty) => {
                     let context = if kind.return_impl_trait_allowed() {
                         let fn_def_id = self.local_def_id(fn_node_id);
@@ -1911,9 +1905,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let opaque_ty_node_id = match coro {
             CoroutineKind::Async { return_impl_trait_id, .. }
             | CoroutineKind::Gen { return_impl_trait_id, .. } => return_impl_trait_id,
-            CoroutineKind::None => {
-                unreachable!("lower_coroutine_fn_ret_ty must be called with either Async or Gen")
-            }
         };
 
         let captured_lifetimes: Vec<_> = self
@@ -1971,7 +1962,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let (symbol, lang_item) = match coro {
             CoroutineKind::Async { .. } => (hir::FN_OUTPUT_NAME, hir::LangItem::Future),
             CoroutineKind::Gen { .. } => (hir::ITERATOR_ITEM_NAME, hir::LangItem::Iterator),
-            CoroutineKind::None => panic!("attemping to lower output type of non-coroutine fn"),
         };
 
         let future_args = self.arena.alloc(hir::GenericArgs {
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index ce680afdc3e..311ab96aba0 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1268,13 +1268,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
         self.check_c_variadic_type(fk);
 
-        // Functions cannot both be `const async`
+        // Functions cannot both be `const async` or `const gen`
         if let Some(&FnHeader {
             constness: Const::Yes(cspan),
-            coro_kind: CoroutineKind::Async { span: aspan, .. },
+            coro_kind:
+                Some(
+                    CoroutineKind::Async { span: aspan, .. }
+                    | CoroutineKind::Gen { span: aspan, .. },
+                ),
             ..
         }) = fk.header()
         {
+            // FIXME(eholk): Report a different error for `const gen`
             self.err_handler().emit_err(errors::ConstAndAsync {
                 spans: vec![cspan, aspan],
                 cspan,
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 1e69674d30a..1ad28ffbf2b 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1492,7 +1492,6 @@ impl<'a> State<'a> {
 
     fn print_coro_kind(&mut self, coro_kind: ast::CoroutineKind) {
         match coro_kind {
-            ast::CoroutineKind::None => {}
             ast::CoroutineKind::Gen { .. } => {
                 self.word_nbsp("gen");
             }
@@ -1691,7 +1690,7 @@ impl<'a> State<'a> {
 
     fn print_fn_header_info(&mut self, header: ast::FnHeader) {
         self.print_constness(header.constness);
-        self.print_coro_kind(header.coro_kind);
+        header.coro_kind.map(|coro_kind| self.print_coro_kind(coro_kind));
         self.print_unsafety(header.unsafety);
 
         match header.ext {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index d8641e745d0..0082d6e350e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -423,7 +423,7 @@ impl<'a> State<'a> {
                 self.print_closure_binder(binder);
                 self.print_constness(*constness);
                 self.print_movability(*movability);
-                self.print_coro_kind(*coro_kind);
+                coro_kind.map(|coro_kind| self.print_coro_kind(coro_kind));
                 self.print_capture_clause(*capture_clause);
 
                 self.print_fn_params_and_ret(fn_decl, true);
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 8f4234b4138..38fdddf5834 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -541,7 +541,7 @@ fn check_test_signature(
         return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
     }
 
-    if let ast::CoroutineKind::Async { span, .. } = f.sig.header.coro_kind {
+    if let Some(ast::CoroutineKind::Async { span, .. }) = f.sig.header.coro_kind {
         return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" }));
     }
 
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 49b52d265d6..794e11d87d1 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -547,7 +547,7 @@ impl<'a> ExtCtxt<'a> {
                 binder: ast::ClosureBinder::NotPresent,
                 capture_clause: ast::CaptureBy::Ref,
                 constness: ast::Const::No,
-                coro_kind: ast::CoroutineKind::None,
+                coro_kind: None,
                 movability: ast::Movability::Movable,
                 fn_decl,
                 body,
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 41fbf1f3e2c..7c4f81a4c39 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -162,8 +162,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         // Explicitly check for lints associated with 'closure_id', since
         // it does not have a corresponding AST node
         if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
-            if let ast::CoroutineKind::Async { closure_id, .. }
-            | ast::CoroutineKind::Gen { closure_id, .. } = sig.header.coro_kind
+            if let Some(
+                ast::CoroutineKind::Async { closure_id, .. }
+                | ast::CoroutineKind::Gen { closure_id, .. },
+            ) = sig.header.coro_kind
             {
                 self.check_id(closure_id);
             }
@@ -226,8 +228,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         match e.kind {
             ast::ExprKind::Closure(box ast::Closure {
                 coro_kind:
-                    ast::CoroutineKind::Async { closure_id, .. }
-                    | ast::CoroutineKind::Gen { closure_id, .. },
+                    Some(
+                        ast::CoroutineKind::Async { closure_id, .. }
+                        | ast::CoroutineKind::Gen { closure_id, .. },
+                    ),
                 ..
             }) => self.check_id(closure_id),
             _ => {}
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 8a09d4e0549..8482824ec4b 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -10,7 +10,7 @@ use super::{
 use crate::errors;
 use crate::maybe_recover_from_interpolated_ty_qpath;
 use ast::mut_visit::{noop_visit_expr, MutVisitor};
-use ast::{GenBlockKind, Pat, Path, PathSegment};
+use ast::{CoroutineKind, GenBlockKind, Pat, Path, PathSegment};
 use core::mem;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
@@ -21,9 +21,7 @@ use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
 use rustc_ast::visit::Visitor;
 use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID};
 use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind};
-use rustc_ast::{
-    Arm, BlockCheckMode, CoroutineKind, Expr, ExprKind, Label, Movability, RangeLimits,
-};
+use rustc_ast::{Arm, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -2239,7 +2237,7 @@ impl<'a> Parser<'a> {
         let asyncness = if self.token.uninterpolated_span().at_least_rust_2018() {
             self.parse_asyncness(Case::Sensitive)
         } else {
-            CoroutineKind::None
+            None
         };
 
         let capture_clause = self.parse_capture_clause()?;
@@ -2263,7 +2261,7 @@ impl<'a> Parser<'a> {
             }
         };
 
-        if let CoroutineKind::Async { span, .. } = asyncness {
+        if let Some(CoroutineKind::Async { span, .. }) = asyncness {
             // Feature-gate `async ||` closures.
             self.sess.gated_spans.gate(sym::async_closure, span);
         }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 2bee4d5d5c6..589fc46b722 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2401,7 +2401,7 @@ impl<'a> Parser<'a> {
         let ext_start_sp = self.token.span;
         let ext = self.parse_extern(case);
 
-        if let CoroutineKind::Async { span, .. } = asyncness {
+        if let Some(CoroutineKind::Async { span, .. }) = asyncness {
             if span.is_rust_2015() {
                 self.sess.emit_err(errors::AsyncFnIn2015 {
                     span,
@@ -2410,13 +2410,13 @@ impl<'a> Parser<'a> {
             }
         }
 
-        if let CoroutineKind::Gen { span, .. } = genness {
+        if let Some(CoroutineKind::Gen { span, .. }) = genness {
             self.sess.gated_spans.gate(sym::gen_blocks, span);
         }
 
         if let (
-            CoroutineKind::Async { span: async_span, .. },
-            CoroutineKind::Gen { span: gen_span, .. },
+            Some(CoroutineKind::Async { span: async_span, .. }),
+            Some(CoroutineKind::Gen { span: gen_span, .. }),
         ) = (asyncness, genness)
         {
             self.sess.emit_err(errors::AsyncGenFn { span: async_span.to(gen_span) });
@@ -2452,16 +2452,18 @@ impl<'a> Parser<'a> {
                         }
                     } else if self.check_keyword(kw::Async) {
                         match asyncness {
-                            CoroutineKind::Async { span, .. } => Some(WrongKw::Duplicated(span)),
-                            CoroutineKind::Gen { .. } => {
+                            Some(CoroutineKind::Async { span, .. }) => {
+                                Some(WrongKw::Duplicated(span))
+                            }
+                            Some(CoroutineKind::Gen { .. }) => {
                                 panic!("not sure how to recover here")
                             }
-                            CoroutineKind::None => {
-                                recover_asyncness = CoroutineKind::Async {
+                            None => {
+                                recover_asyncness = Some(CoroutineKind::Async {
                                     span: self.token.span,
                                     closure_id: DUMMY_NODE_ID,
                                     return_impl_trait_id: DUMMY_NODE_ID,
-                                };
+                                });
                                 Some(WrongKw::Misplaced(unsafe_start_sp))
                             }
                         }
@@ -2566,9 +2568,9 @@ impl<'a> Parser<'a> {
         }
 
         let coro_kind = match asyncness {
-            CoroutineKind::Async { .. } => asyncness,
-            CoroutineKind::Gen { .. } => unreachable!("asycness cannot be Gen"),
-            CoroutineKind::None => genness,
+            Some(CoroutineKind::Async { .. }) => asyncness,
+            Some(CoroutineKind::Gen { .. }) => unreachable!("asycness cannot be Gen"),
+            None => genness,
         };
 
         Ok(FnHeader { constness, unsafety, coro_kind, ext })
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index a9da3043117..2816386cbad 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1125,30 +1125,30 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses asyncness: `async` or nothing.
-    fn parse_asyncness(&mut self, case: Case) -> CoroutineKind {
+    fn parse_asyncness(&mut self, case: Case) -> Option<CoroutineKind> {
         if self.eat_keyword_case(kw::Async, case) {
             let span = self.prev_token.uninterpolated_span();
-            CoroutineKind::Async {
+            Some(CoroutineKind::Async {
                 span,
                 closure_id: DUMMY_NODE_ID,
                 return_impl_trait_id: DUMMY_NODE_ID,
-            }
+            })
         } else {
-            CoroutineKind::None
+            None
         }
     }
 
     /// Parses genness: `gen` or nothing.
-    fn parse_genness(&mut self, case: Case) -> CoroutineKind {
+    fn parse_genness(&mut self, case: Case) -> Option<CoroutineKind> {
         if self.token.span.at_least_rust_2024() && self.eat_keyword_case(kw::Gen, case) {
             let span = self.prev_token.uninterpolated_span();
-            CoroutineKind::Gen {
+            Some(CoroutineKind::Gen {
                 span,
                 closure_id: DUMMY_NODE_ID,
                 return_impl_trait_id: DUMMY_NODE_ID,
-            }
+            })
         } else {
-            CoroutineKind::None
+            None
         }
     }
 
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index a8e147a05b0..73487f4af0e 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -609,7 +609,7 @@ impl<'a> Parser<'a> {
             // cover it.
             self.sess.emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
         }
-        if let ast::CoroutineKind::Async { span, .. } = coro_kind {
+        if let Some(ast::CoroutineKind::Async { span, .. }) = coro_kind {
             self.sess.emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span });
         }
         // FIXME(eholk): emit a similar error for `gen fn()`
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index c43ec99f42a..ab5d3b368eb 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -156,9 +156,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
 
     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
         if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
-            // FIXME(eholk): handle `async gen fn`
-            if let CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. } =
-                sig.header.coro_kind
+            if let Some(
+                CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. },
+            ) = sig.header.coro_kind
             {
                 self.visit_generics(generics);
 
@@ -285,11 +285,11 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
                 // we must create two defs.
                 let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
                 match closure.coro_kind {
-                    CoroutineKind::Async { closure_id, .. }
-                    | CoroutineKind::Gen { closure_id, .. } => {
-                        self.create_def(closure_id, kw::Empty, DefKind::Closure, expr.span)
-                    }
-                    CoroutineKind::None => closure_def,
+                    Some(
+                        CoroutineKind::Async { closure_id, .. }
+                        | CoroutineKind::Gen { closure_id, .. },
+                    ) => self.create_def(closure_id, kw::Empty, DefKind::Closure, expr.span),
+                    None => closure_def,
                 }
             }
             ExprKind::Gen(_, _, _) => {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 2f7d1835113..c5d6574af60 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -916,7 +916,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                             &sig.decl.output,
                         );
 
-                        if let Some((async_node_id, _)) = sig.header.coro_kind.opt_return_id() {
+                        if let Some((async_node_id, _)) =
+                            sig.header.coro_kind.map(|coro_kind| coro_kind.return_id())
+                        {
                             this.record_lifetime_params_for_impl_trait(async_node_id);
                         }
                     },
@@ -940,7 +942,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                         this.visit_generics(generics);
 
                         let declaration = &sig.decl;
-                        let async_node_id = sig.header.coro_kind.opt_return_id();
+                        let async_node_id =
+                            sig.header.coro_kind.map(|coro_kind| coro_kind.return_id());
 
                         this.with_lifetime_rib(
                             LifetimeRibKind::AnonymousCreateParameter {
@@ -4289,7 +4292,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             // resolve the arguments within the proper scopes so that usages of them inside the
             // closure are detected as upvars rather than normal closure arg usages.
             ExprKind::Closure(box ast::Closure {
-                coro_kind: CoroutineKind::Async { .. },
+                coro_kind: Some(CoroutineKind::Async { .. }),
                 ref fn_decl,
                 ref body,
                 ..
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index ec4abc21f48..0c623dba369 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -700,7 +700,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<u
                             ItemKind::Fn(box Fn {
                                 sig, body: Some(block), ..
                             }) if item.ident.name == sym::main => {
-                                let is_async = sig.header.coro_kind.is_async();
+                                let is_async = sig.header.coro_kind.map_or(false, |coro| coro.is_async());
                                 let returns_nothing = match &sig.decl.output {
                                     FnRetTy::Default(..) => true,
                                     FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index ac9da383b93..12403bbff3c 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -206,7 +206,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         ) => {
             eq_closure_binder(lb, rb)
                 && lc == rc
-                && la.is_async() == ra.is_async()
+                && la.map_or(false, |la| la.is_async()) == ra.map_or(false, |ra| ra.is_async())
                 && lm == rm
                 && eq_fn_decl(lf, rf)
                 && eq_expr(le, re)
@@ -563,9 +563,18 @@ pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool {
     eq_fn_decl(&l.decl, &r.decl) && eq_fn_header(&l.header, &r.header)
 }
 
+fn eq_opt_coro_kind(l: Option<CoroutineKind>, r: Option<CoroutineKind>) -> bool {
+    match (l, r) {
+        (Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. }))
+        | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) => true,
+        (None, None) => true,
+        _ => false,
+    }
+}
+
 pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
     matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No)
-        && (l.coro_kind.is_async() == r.coro_kind.is_async() || l.coro_kind.is_gen() == r.coro_kind.is_gen())
+        && eq_opt_coro_kind(l.coro_kind, r.coro_kind)
         && matches!(l.constness, Const::No) == matches!(r.constness, Const::No)
         && eq_ext(&l.ext, &r.ext)
 }
diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs
index 23cd6e4c092..d79218e78ee 100644
--- a/src/tools/rustfmt/src/closures.rs
+++ b/src/tools/rustfmt/src/closures.rs
@@ -29,7 +29,7 @@ pub(crate) fn rewrite_closure(
     binder: &ast::ClosureBinder,
     constness: ast::Const,
     capture: ast::CaptureBy,
-    coro_kind: &ast::CoroutineKind,
+    coro_kind: &Option<ast::CoroutineKind>,
     movability: ast::Movability,
     fn_decl: &ast::FnDecl,
     body: &ast::Expr,
@@ -233,7 +233,7 @@ fn rewrite_closure_fn_decl(
     binder: &ast::ClosureBinder,
     constness: ast::Const,
     capture: ast::CaptureBy,
-    coro_kind: &ast::CoroutineKind,
+    coro_kind: &Option<ast::CoroutineKind>,
     movability: ast::Movability,
     fn_decl: &ast::FnDecl,
     body: &ast::Expr,
@@ -263,8 +263,13 @@ fn rewrite_closure_fn_decl(
     } else {
         ""
     };
-    let is_async = if coro_kind.is_async() { "async " } else { "" };
-    let is_gen = if coro_kind.is_gen() { "gen " } else { "" };
+    let (is_async, is_gen) = if let Some(coro_kind) = coro_kind {
+        let is_async = if coro_kind.is_async() { "async " } else { "" };
+        let is_gen = if coro_kind.is_gen() { "gen " } else { "" };
+        (is_async, is_gen)
+    } else {
+        ("", "")
+    };
     let mover = if matches!(capture, ast::CaptureBy::Value { .. }) {
         "move "
     } else {
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 0a1f823fe87..4dff65f8cd0 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -287,7 +287,7 @@ pub(crate) struct FnSig<'a> {
     decl: &'a ast::FnDecl,
     generics: &'a ast::Generics,
     ext: ast::Extern,
-    coro_kind: Cow<'a, ast::CoroutineKind>,
+    coro_kind: Cow<'a, Option<ast::CoroutineKind>>,
     constness: ast::Const,
     defaultness: ast::Defaultness,
     unsafety: ast::Unsafe,
@@ -343,7 +343,8 @@ impl<'a> FnSig<'a> {
         result.push_str(&*format_visibility(context, self.visibility));
         result.push_str(format_defaultness(self.defaultness));
         result.push_str(format_constness(self.constness));
-        result.push_str(format_coro(&self.coro_kind));
+        self.coro_kind
+            .map(|coro_kind| result.push_str(format_coro(&coro_kind)));
         result.push_str(format_unsafety(self.unsafety));
         result.push_str(&format_extern(
             self.ext,
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index 18d8f0cdbd7..5805e417c04 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -79,7 +79,6 @@ pub(crate) fn format_coro(coro_kind: &ast::CoroutineKind) -> &'static str {
     match coro_kind {
         ast::CoroutineKind::Async { .. } => "async ",
         ast::CoroutineKind::Gen { .. } => "gen ",
-        ast::CoroutineKind::None => "",
     }
 }