about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonathan Brouwer <jonathantbrouwer@gmail.com>2025-06-10 19:18:31 +0200
committerJonathan Brouwer <jonathantbrouwer@gmail.com>2025-06-13 18:13:34 +0200
commitb131b6f630843d34a14f250e3b46733253f3465b (patch)
treee229b911fb48d680ff1632fbc5ee8f14784c6066
parent3160dfa5dc8675a5dcab296b52c4da9aca16b2f9 (diff)
downloadrust-b131b6f630843d34a14f250e3b46733253f3465b.tar.gz
rust-b131b6f630843d34a14f250e3b46733253f3465b.zip
Rework how the disallowed qualifier lints are generated
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/parser/item.rs81
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs65
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.fixed8
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.rs3
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.stderr160
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.rs3
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.stderr162
9 files changed, 208 insertions, 284 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 1f221b4bf78..f6e0b08b140 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -299,10 +299,12 @@ parse_float_literal_unsupported_base = {$base} float literal is not supported
 parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
     .label = `async` because of this
     .suggestion = remove the `async` qualifier
+    .note = allowed qualifiers are: `unsafe` and `extern`
 
 parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
     .label = `const` because of this
     .suggestion = remove the `const` qualifier
+    .note = allowed qualifiers are: `unsafe` and `extern`
 
 parse_fn_ptr_with_generics = function pointer types may not have generic parameters
     .suggestion = consider moving the lifetime {$arity ->
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 2dba568a258..0f0c5434800 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2938,22 +2938,22 @@ pub(crate) struct DynAfterMut {
 
 #[derive(Diagnostic)]
 #[diag(parse_fn_pointer_cannot_be_const)]
+#[note]
 pub(crate) struct FnPointerCannotBeConst {
     #[primary_span]
-    pub span: Span,
     #[label]
-    pub qualifier: Span,
+    pub span: Span,
     #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
 #[diag(parse_fn_pointer_cannot_be_async)]
+#[note]
 pub(crate) struct FnPointerCannotBeAsync {
     #[primary_span]
-    pub span: Span,
     #[label]
-    pub qualifier: Span,
+    pub span: Span,
     #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub suggestion: Span,
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index a325c2a57ab..658ed4bd41c 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -23,7 +23,7 @@ use super::{
     AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle,
     Recovered, Trailing, UsePreAttrPos,
 };
-use crate::errors::{self, MacroExpandsToAdtField};
+use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField};
 use crate::{exp, fluent_generated as fluent};
 
 impl<'a> Parser<'a> {
@@ -2402,7 +2402,7 @@ impl<'a> Parser<'a> {
         case: Case,
     ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<FnContract>>, Option<P<Block>>)> {
         let fn_span = self.token.span;
-        let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn`
+        let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
         let mut generics = self.parse_generics()?; // `<'a, T, ...>`
         let decl = match self.parse_fn_decl(
@@ -2658,16 +2658,37 @@ impl<'a> Parser<'a> {
     ///
     /// `vis` represents the visibility that was already parsed, if any. Use
     /// `Visibility::Inherited` when no visibility is known.
+    ///
+    /// If `parsing_mode` is `FrontMatterParsingMode::FunctionPtrType`, we error on `const` and `async` qualifiers,
+    /// which are not allowed in function pointer types.
     pub(super) fn parse_fn_front_matter(
         &mut self,
         orig_vis: &Visibility,
         case: Case,
+        parsing_mode: FrontMatterParsingMode,
     ) -> PResult<'a, FnHeader> {
         let sp_start = self.token.span;
         let constness = self.parse_constness(case);
+        if parsing_mode == FrontMatterParsingMode::FunctionPtrType
+            && let Const::Yes(const_span) = constness
+        {
+            self.dcx().emit_err(FnPointerCannotBeConst {
+                span: const_span,
+                suggestion: const_span.until(self.token.span),
+            });
+        }
 
         let async_start_sp = self.token.span;
         let coroutine_kind = self.parse_coroutine_kind(case);
+        if parsing_mode == FrontMatterParsingMode::FunctionPtrType
+            && let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind
+        {
+            self.dcx().emit_err(FnPointerCannotBeAsync {
+                span: async_span,
+                suggestion: async_span.until(self.token.span),
+            });
+        }
+        // FIXME(gen_blocks): emit a similar error for `gen fn()`
 
         let unsafe_start_sp = self.token.span;
         let safety = self.parse_safety(case);
@@ -2703,6 +2724,11 @@ impl<'a> Parser<'a> {
                     enum WrongKw {
                         Duplicated(Span),
                         Misplaced(Span),
+                        /// `MisplacedDisallowedQualifier` is only used instead of `Misplaced`,
+                        /// when the misplaced keyword is disallowed by the current `FrontMatterParsingMode`.
+                        /// In this case, we avoid generating the suggestion to swap around the keywords,
+                        /// as we already generated a suggestion to remove the keyword earlier.
+                        MisplacedDisallowedQualifier,
                     }
 
                     // We may be able to recover
@@ -2716,7 +2742,21 @@ impl<'a> Parser<'a> {
                             Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
                             Const::No => {
                                 recover_constness = Const::Yes(self.token.span);
-                                Some(WrongKw::Misplaced(async_start_sp))
+                                match parsing_mode {
+                                    FrontMatterParsingMode::Function => {
+                                        Some(WrongKw::Misplaced(async_start_sp))
+                                    }
+                                    FrontMatterParsingMode::FunctionPtrType => {
+                                        self.dcx().emit_err(FnPointerCannotBeConst {
+                                            span: self.token.span,
+                                            suggestion: self
+                                                .token
+                                                .span
+                                                .with_lo(self.prev_token.span.hi()),
+                                        });
+                                        Some(WrongKw::MisplacedDisallowedQualifier)
+                                    }
+                                }
                             }
                         }
                     } else if self.check_keyword(exp!(Async)) {
@@ -2742,7 +2782,21 @@ impl<'a> Parser<'a> {
                                     closure_id: DUMMY_NODE_ID,
                                     return_impl_trait_id: DUMMY_NODE_ID,
                                 });
-                                Some(WrongKw::Misplaced(unsafe_start_sp))
+                                match parsing_mode {
+                                    FrontMatterParsingMode::Function => {
+                                        Some(WrongKw::Misplaced(async_start_sp))
+                                    }
+                                    FrontMatterParsingMode::FunctionPtrType => {
+                                        self.dcx().emit_err(FnPointerCannotBeAsync {
+                                            span: self.token.span,
+                                            suggestion: self
+                                                .token
+                                                .span
+                                                .with_lo(self.prev_token.span.hi()),
+                                        });
+                                        Some(WrongKw::MisplacedDisallowedQualifier)
+                                    }
+                                }
                             }
                         }
                     } else if self.check_keyword(exp!(Unsafe)) {
@@ -2840,14 +2894,20 @@ impl<'a> Parser<'a> {
 
                     // FIXME(gen_blocks): add keyword recovery logic for genness
 
-                    if wrong_kw.is_some()
+                    if let Some(wrong_kw) = wrong_kw
                         && self.may_recover()
                         && self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case))
                     {
                         // Advance past the misplaced keyword and `fn`
                         self.bump();
                         self.bump();
-                        err.emit();
+                        // When we recover from a `MisplacedDisallowedQualifier`, we already emitted an error for the disallowed qualifier
+                        // So we don't emit another error that the qualifier is unexpected.
+                        if matches!(wrong_kw, WrongKw::MisplacedDisallowedQualifier) {
+                            err.cancel();
+                        } else {
+                            err.emit();
+                        }
                         return Ok(FnHeader {
                             constness: recover_constness,
                             safety: recover_safety,
@@ -3194,3 +3254,12 @@ enum IsMacroRulesItem {
     Yes { has_bang: bool },
     No,
 }
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub(super) enum FrontMatterParsingMode {
+    /// Parse the front matter of a function declaration
+    Function,
+    /// Parse the front matter of a function pointet type.
+    /// For function pointer types, the `const` and `async` keywords are not permitted.
+    FunctionPtrType,
+}
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 9ddfc179e9b..620a34044d1 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -15,10 +15,11 @@ use thin_vec::{ThinVec, thin_vec};
 use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
 use crate::errors::{
     self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
-    FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
-    HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
-    NestedCVariadicType, ReturnTypesUseThinArrow,
+    FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword,
+    LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
+    ReturnTypesUseThinArrow,
 };
+use crate::parser::item::FrontMatterParsingMode;
 use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
 
 /// Signals whether parsing a type should allow `+`.
@@ -669,62 +670,16 @@ impl<'a> Parser<'a> {
             tokens: None,
         };
         let span_start = self.token.span;
-        let ast::FnHeader { ext, safety, constness, coroutine_kind } =
-            self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
-        let fn_start_lo = self.prev_token.span.lo();
+        let ast::FnHeader { ext, safety, .. } = self.parse_fn_front_matter(
+            &inherited_vis,
+            Case::Sensitive,
+            FrontMatterParsingMode::FunctionPtrType,
+        )?;
         if self.may_recover() && self.token == TokenKind::Lt {
             self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
         }
         let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
-        let whole_span = lo.to(self.prev_token.span);
-
-        // Order/parsing of "front matter" follows:
-        // `<constness> <coroutine_kind> <safety> <extern> fn()`
-        //  ^           ^                ^        ^        ^
-        //  |           |                |        |        fn_start_lo
-        //  |           |                |        ext_sp.lo
-        //  |           |                safety_sp.lo
-        //  |           coroutine_sp.lo
-        //  const_sp.lo
-        if let ast::Const::Yes(const_span) = constness {
-            let next_token_lo = if let Some(
-                ast::CoroutineKind::Async { span, .. }
-                | ast::CoroutineKind::Gen { span, .. }
-                | ast::CoroutineKind::AsyncGen { span, .. },
-            ) = coroutine_kind
-            {
-                span.lo()
-            } else if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety {
-                span.lo()
-            } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
-                span.lo()
-            } else {
-                fn_start_lo
-            };
-            let sugg_span = const_span.with_hi(next_token_lo);
-            self.dcx().emit_err(FnPointerCannotBeConst {
-                span: whole_span,
-                qualifier: const_span,
-                suggestion: sugg_span,
-            });
-        }
-        if let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind {
-            let next_token_lo = if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety
-            {
-                span.lo()
-            } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
-                span.lo()
-            } else {
-                fn_start_lo
-            };
-            let sugg_span = async_span.with_hi(next_token_lo);
-            self.dcx().emit_err(FnPointerCannotBeAsync {
-                span: whole_span,
-                qualifier: async_span,
-                suggestion: sugg_span,
-            });
-        }
-        // FIXME(gen_blocks): emit a similar error for `gen fn()`
+
         let decl_span = span_start.to(self.prev_token.span);
         Ok(TyKind::BareFn(P(BareFnTy { ext, safety, generic_params: params, decl, decl_span })))
     }
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.fixed b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
index 8a97a2f09cc..e9b87a72aab 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.fixed
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
@@ -23,4 +23,12 @@ pub type FTT6 = for<'a> unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
 //~| ERROR an `fn` pointer type cannot be `async`
 
+// Tests with qualifiers in the wrong order
+pub type W1 = unsafe fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+pub type W2 = unsafe fn();
+//~^ ERROR an `fn` pointer type cannot be `async`
+pub type W3 = for<'a> unsafe fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+
 fn main() {}
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.rs b/tests/ui/parser/bad-fn-ptr-qualifier.rs
index 748852a76e1..f110375509c 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.rs
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.rs
@@ -26,12 +26,9 @@ pub type FTT6 = for<'a> const async unsafe extern "C" fn();
 // Tests with qualifiers in the wrong order
 pub type W1 = unsafe const fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
-//~| ERROR expected one of `extern` or `fn`, found keyword `const`
 pub type W2 = unsafe async fn();
 //~^ ERROR an `fn` pointer type cannot be `async`
-//~| ERROR expected one of `extern` or `fn`, found keyword `async`
 pub type W3 = for<'a> unsafe const fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
-//~| ERROR expected one of `extern` or `fn`, found keyword `const`
 
 fn main() {}
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
index a0bd3f974ab..f3fbbf67159 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
@@ -2,10 +2,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:5:15
    |
 LL | pub type T0 = const fn();
-   |               -----^^^^^
-   |               |
-   |               `const` because of this
+   |               ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type T0 = const fn();
@@ -16,10 +15,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:6:15
    |
 LL | pub type T1 = const extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^
-   |               |
-   |               `const` because of this
+   |               ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type T1 = const extern "C" fn();
@@ -30,10 +28,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:7:15
    |
 LL | pub type T2 = const unsafe extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `const` because of this
+   |               ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type T2 = const unsafe extern "C" fn();
@@ -44,10 +41,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:8:15
    |
 LL | pub type T3 = async fn();
-   |               -----^^^^^
-   |               |
-   |               `async` because of this
+   |               ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type T3 = async fn();
@@ -58,10 +54,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:9:15
    |
 LL | pub type T4 = async extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^
-   |               |
-   |               `async` because of this
+   |               ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type T4 = async extern "C" fn();
@@ -72,10 +67,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:10:15
    |
 LL | pub type T5 = async unsafe extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `async` because of this
+   |               ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type T5 = async unsafe extern "C" fn();
@@ -86,10 +80,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:11:15
    |
 LL | pub type T6 = const async unsafe extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `const` because of this
+   |               ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type T6 = const async unsafe extern "C" fn();
@@ -97,13 +90,12 @@ LL + pub type T6 = async unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:11:15
+  --> $DIR/bad-fn-ptr-qualifier.rs:11:21
    |
 LL | pub type T6 = const async unsafe extern "C" fn();
-   |               ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     `async` because of this
+   |                     ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type T6 = const async unsafe extern "C" fn();
@@ -111,13 +103,12 @@ LL + pub type T6 = const unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:15:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:15:25
    |
 LL | pub type FTT0 = for<'a> const fn();
-   |                 ^^^^^^^^-----^^^^^
-   |                         |
-   |                         `const` because of this
+   |                         ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type FTT0 = for<'a> const fn();
@@ -125,13 +116,12 @@ LL + pub type FTT0 = for<'a> fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:16:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:16:25
    |
 LL | pub type FTT1 = for<'a> const extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `const` because of this
+   |                         ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type FTT1 = for<'a> const extern "C" fn();
@@ -139,13 +129,12 @@ LL + pub type FTT1 = for<'a> extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:17:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:17:25
    |
 LL | pub type FTT2 = for<'a> const unsafe extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `const` because of this
+   |                         ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type FTT2 = for<'a> const unsafe extern "C" fn();
@@ -153,13 +142,12 @@ LL + pub type FTT2 = for<'a> unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:18:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:18:25
    |
 LL | pub type FTT3 = for<'a> async fn();
-   |                 ^^^^^^^^-----^^^^^
-   |                         |
-   |                         `async` because of this
+   |                         ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type FTT3 = for<'a> async fn();
@@ -167,13 +155,12 @@ LL + pub type FTT3 = for<'a> fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:19:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:19:25
    |
 LL | pub type FTT4 = for<'a> async extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `async` because of this
+   |                         ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type FTT4 = for<'a> async extern "C" fn();
@@ -181,13 +168,12 @@ LL + pub type FTT4 = for<'a> extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:20:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:20:25
    |
 LL | pub type FTT5 = for<'a> async unsafe extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `async` because of this
+   |                         ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type FTT5 = for<'a> async unsafe extern "C" fn();
@@ -195,13 +181,12 @@ LL + pub type FTT5 = for<'a> unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:22:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:22:25
    |
 LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `const` because of this
+   |                         ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn();
@@ -209,93 +194,56 @@ LL + pub type FTT6 = for<'a> async unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:22:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:22:31
    |
 LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn();
-   |                 ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                               |
-   |                               `async` because of this
+   |                               ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn();
 LL + pub type FTT6 = for<'a> const unsafe extern "C" fn();
    |
 
-error: expected one of `extern` or `fn`, found keyword `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:27:22
-   |
-LL | pub type W1 = unsafe const fn();
-   |               -------^^^^^
-   |               |      |
-   |               |      expected one of `extern` or `fn`
-   |               help: `const` must come before `unsafe`: `const unsafe`
-   |
-   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
-
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:27:15
+  --> $DIR/bad-fn-ptr-qualifier.rs:27:22
    |
 LL | pub type W1 = unsafe const fn();
-   |               ^^^^^^^-----^^^^^
-   |                      |
-   |                      `const` because of this
+   |                      ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type W1 = unsafe const fn();
-LL + pub type W1 = const fn();
+LL + pub type W1 = unsafe fn();
    |
 
-error: expected one of `extern` or `fn`, found keyword `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:30:22
-   |
-LL | pub type W2 = unsafe async fn();
-   |               -------^^^^^
-   |               |      |
-   |               |      expected one of `extern` or `fn`
-   |               help: `async` must come before `unsafe`: `async unsafe`
-   |
-   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
-
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:30:15
+  --> $DIR/bad-fn-ptr-qualifier.rs:29:22
    |
 LL | pub type W2 = unsafe async fn();
-   |               ^^^^^^^-----^^^^^
-   |                      |
-   |                      `async` because of this
+   |                      ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type W2 = unsafe async fn();
-LL + pub type W2 = async fn();
-   |
-
-error: expected one of `extern` or `fn`, found keyword `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:33:30
-   |
-LL | pub type W3 = for<'a> unsafe const fn();
-   |                       -------^^^^^
-   |                       |      |
-   |                       |      expected one of `extern` or `fn`
-   |                       help: `const` must come before `unsafe`: `const unsafe`
+LL + pub type W2 = unsafe fn();
    |
-   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:33:15
+  --> $DIR/bad-fn-ptr-qualifier.rs:31:30
    |
 LL | pub type W3 = for<'a> unsafe const fn();
-   |               ^^^^^^^^^^^^^^^-----^^^^^
-   |                              |
-   |                              `const` because of this
+   |                              ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type W3 = for<'a> unsafe const fn();
-LL + pub type W3 = for<'a> const fn();
+LL + pub type W3 = for<'a> unsafe fn();
    |
 
-error: aborting due to 22 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
index 8e4c6e92412..a74b618c282 100644
--- a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
@@ -23,13 +23,10 @@ type FT6 = for<'a> const async unsafe extern "C" fn();
 // Tests with qualifiers in the wrong order
 type W1 = unsafe const fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
-//~| ERROR expected one of `extern` or `fn`, found keyword `const`
 type W2 = unsafe async fn();
 //~^ ERROR an `fn` pointer type cannot be `async`
-//~| ERROR expected one of `extern` or `fn`, found keyword `async`
 type W3 = for<'a> unsafe const fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
-//~| ERROR expected one of `extern` or `fn`, found keyword `const`
 
 fn main() {
     let _recovery_witness: () = 0; //~ ERROR mismatched types
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
index 82b9162cfdc..3700bee6e15 100644
--- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
@@ -2,10 +2,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:3:11
    |
 LL | type T0 = const fn();
-   |           -----^^^^^
-   |           |
-   |           `const` because of this
+   |           ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type T0 = const fn();
@@ -16,10 +15,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:4:11
    |
 LL | type T1 = const extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^
-   |           |
-   |           `const` because of this
+   |           ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type T1 = const extern "C" fn();
@@ -30,10 +28,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:5:11
    |
 LL | type T2 = const unsafe extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^^^^^^^^
-   |           |
-   |           `const` because of this
+   |           ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type T2 = const unsafe extern "C" fn();
@@ -44,10 +41,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:6:11
    |
 LL | type T3 = async fn();
-   |           -----^^^^^
-   |           |
-   |           `async` because of this
+   |           ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type T3 = async fn();
@@ -58,10 +54,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:7:11
    |
 LL | type T4 = async extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^
-   |           |
-   |           `async` because of this
+   |           ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type T4 = async extern "C" fn();
@@ -72,10 +67,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:8:11
    |
 LL | type T5 = async unsafe extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^^^^^^^^
-   |           |
-   |           `async` because of this
+   |           ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type T5 = async unsafe extern "C" fn();
@@ -86,10 +80,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:9:11
    |
 LL | type T6 = const async unsafe extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |           |
-   |           `const` because of this
+   |           ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type T6 = const async unsafe extern "C" fn();
@@ -97,13 +90,12 @@ LL + type T6 = async unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:9:11
+  --> $DIR/recover-const-async-fn-ptr.rs:9:17
    |
 LL | type T6 = const async unsafe extern "C" fn();
-   |           ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                 |
-   |                 `async` because of this
+   |                 ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type T6 = const async unsafe extern "C" fn();
@@ -111,13 +103,12 @@ LL + type T6 = const unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:13:12
+  --> $DIR/recover-const-async-fn-ptr.rs:13:20
    |
 LL | type FT0 = for<'a> const fn();
-   |            ^^^^^^^^-----^^^^^
-   |                    |
-   |                    `const` because of this
+   |                    ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type FT0 = for<'a> const fn();
@@ -125,13 +116,12 @@ LL + type FT0 = for<'a> fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:14:12
+  --> $DIR/recover-const-async-fn-ptr.rs:14:20
    |
 LL | type FT1 = for<'a> const extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `const` because of this
+   |                    ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type FT1 = for<'a> const extern "C" fn();
@@ -139,13 +129,12 @@ LL + type FT1 = for<'a> extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:15:12
+  --> $DIR/recover-const-async-fn-ptr.rs:15:20
    |
 LL | type FT2 = for<'a> const unsafe extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `const` because of this
+   |                    ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type FT2 = for<'a> const unsafe extern "C" fn();
@@ -153,13 +142,12 @@ LL + type FT2 = for<'a> unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:16:12
+  --> $DIR/recover-const-async-fn-ptr.rs:16:20
    |
 LL | type FT3 = for<'a> async fn();
-   |            ^^^^^^^^-----^^^^^
-   |                    |
-   |                    `async` because of this
+   |                    ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type FT3 = for<'a> async fn();
@@ -167,13 +155,12 @@ LL + type FT3 = for<'a> fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:17:12
+  --> $DIR/recover-const-async-fn-ptr.rs:17:20
    |
 LL | type FT4 = for<'a> async extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `async` because of this
+   |                    ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type FT4 = for<'a> async extern "C" fn();
@@ -181,13 +168,12 @@ LL + type FT4 = for<'a> extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:18:12
+  --> $DIR/recover-const-async-fn-ptr.rs:18:20
    |
 LL | type FT5 = for<'a> async unsafe extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `async` because of this
+   |                    ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type FT5 = for<'a> async unsafe extern "C" fn();
@@ -195,13 +181,12 @@ LL + type FT5 = for<'a> unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:19:12
+  --> $DIR/recover-const-async-fn-ptr.rs:19:20
    |
 LL | type FT6 = for<'a> const async unsafe extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `const` because of this
+   |                    ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type FT6 = for<'a> const async unsafe extern "C" fn();
@@ -209,102 +194,65 @@ LL + type FT6 = for<'a> async unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:19:12
+  --> $DIR/recover-const-async-fn-ptr.rs:19:26
    |
 LL | type FT6 = for<'a> const async unsafe extern "C" fn();
-   |            ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                          |
-   |                          `async` because of this
+   |                          ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type FT6 = for<'a> const async unsafe extern "C" fn();
 LL + type FT6 = for<'a> const unsafe extern "C" fn();
    |
 
-error: expected one of `extern` or `fn`, found keyword `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:24:18
-   |
-LL | type W1 = unsafe const fn();
-   |           -------^^^^^
-   |           |      |
-   |           |      expected one of `extern` or `fn`
-   |           help: `const` must come before `unsafe`: `const unsafe`
-   |
-   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
-
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:24:11
+  --> $DIR/recover-const-async-fn-ptr.rs:24:18
    |
 LL | type W1 = unsafe const fn();
-   |           ^^^^^^^-----^^^^^
-   |                  |
-   |                  `const` because of this
+   |                  ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type W1 = unsafe const fn();
-LL + type W1 = const fn();
+LL + type W1 = unsafe fn();
    |
 
-error: expected one of `extern` or `fn`, found keyword `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:27:18
-   |
-LL | type W2 = unsafe async fn();
-   |           -------^^^^^
-   |           |      |
-   |           |      expected one of `extern` or `fn`
-   |           help: `async` must come before `unsafe`: `async unsafe`
-   |
-   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
-
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:27:11
+  --> $DIR/recover-const-async-fn-ptr.rs:26:18
    |
 LL | type W2 = unsafe async fn();
-   |           ^^^^^^^-----^^^^^
-   |                  |
-   |                  `async` because of this
+   |                  ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type W2 = unsafe async fn();
-LL + type W2 = async fn();
-   |
-
-error: expected one of `extern` or `fn`, found keyword `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:30:26
-   |
-LL | type W3 = for<'a> unsafe const fn();
-   |                   -------^^^^^
-   |                   |      |
-   |                   |      expected one of `extern` or `fn`
-   |                   help: `const` must come before `unsafe`: `const unsafe`
+LL + type W2 = unsafe fn();
    |
-   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:30:11
+  --> $DIR/recover-const-async-fn-ptr.rs:28:26
    |
 LL | type W3 = for<'a> unsafe const fn();
-   |           ^^^^^^^^^^^^^^^-----^^^^^
-   |                          |
-   |                          `const` because of this
+   |                          ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type W3 = for<'a> unsafe const fn();
-LL + type W3 = for<'a> const fn();
+LL + type W3 = for<'a> unsafe fn();
    |
 
 error[E0308]: mismatched types
-  --> $DIR/recover-const-async-fn-ptr.rs:35:33
+  --> $DIR/recover-const-async-fn-ptr.rs:32:33
    |
 LL |     let _recovery_witness: () = 0;
    |                            --   ^ expected `()`, found integer
    |                            |
    |                            expected due to this
 
-error: aborting due to 23 previous errors
+error: aborting due to 20 previous errors
 
 For more information about this error, try `rustc --explain E0308`.