From edc405d383b896c0417ad1ba33558cf1c506af48 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 11 Jun 2025 14:03:57 +0200 Subject: Add expectation for `{` when parsing lone coroutine qualifiers --- compiler/rustc_parse/src/parser/expr.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a298c4d4dec..93489aa8ee9 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1520,22 +1520,20 @@ impl<'a> Parser<'a> { Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore)) } else if this.token_uninterpolated_span().at_least_rust_2018() { // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly. + let at_async = this.check_keyword(exp!(Async)); + // check for `gen {}` and `gen move {}` + // or `async gen {}` and `async gen move {}` + // FIXME: (async) gen closures aren't yet parsed. + // FIXME(gen_blocks): Parse `gen async` and suggest swap if this.token_uninterpolated_span().at_least_rust_2024() - // check for `gen {}` and `gen move {}` - // or `async gen {}` and `async gen move {}` - && (this.is_gen_block(kw::Gen, 0) - || (this.check_keyword(exp!(Async)) && this.is_gen_block(kw::Gen, 1))) + && this.is_gen_block(kw::Gen, at_async as usize) { - // FIXME: (async) gen closures aren't yet parsed. this.parse_gen_block() - } else if this.check_keyword(exp!(Async)) { - // FIXME(gen_blocks): Parse `gen async` and suggest swap - if this.is_gen_block(kw::Async, 0) { - // Check for `async {` and `async move {`, - this.parse_gen_block() - } else { - this.parse_expr_closure() - } + // Check for `async {` and `async move {`, + } else if this.is_gen_block(kw::Async, 0) { + this.parse_gen_block() + } else if at_async { + this.parse_expr_closure() } else if this.eat_keyword_noexpect(kw::Await) { this.recover_incorrect_await_syntax(lo) } else { @@ -2407,6 +2405,14 @@ impl<'a> Parser<'a> { None }; + if let ClosureBinder::NotPresent = binder + && coroutine_kind.is_some() + { + // coroutine closures and generators can have the same qualifiers, so we might end up + // in here if there is a missing `|` but also no `{`. Adjust the expectations in that case. + self.expected_token_types.insert(TokenType::OpenBrace); + } + let capture_clause = self.parse_capture_clause()?; let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; -- cgit 1.4.1-3-g733a5 From 5f0dd44b3b1b142582d3dc8264cb2b8dd8f7c7f0 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 12 Jun 2025 00:02:12 +0800 Subject: avoid `&mut P` in `visit_expr` etc methods --- compiler/rustc_ast/src/ast.rs | 26 +++++++++++++--- compiler/rustc_ast/src/mut_visit.rs | 6 ++-- compiler/rustc_builtin_macros/src/cfg_eval.rs | 2 +- .../src/deriving/coerce_pointee.rs | 5 ++-- compiler/rustc_expand/src/expand.rs | 35 +++++++++++----------- compiler/rustc_expand/src/placeholders.rs | 12 ++++---- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/pat.rs | 2 +- .../clippy_lints/src/unnested_or_patterns.rs | 6 ++-- tests/ui-fulldeps/pprust-expr-roundtrip.rs | 8 ++--- tests/ui-fulldeps/pprust-parenthesis-insertion.rs | 3 +- 11 files changed, 62 insertions(+), 45 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cf40c3f7f6f..760e43ef10f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -693,6 +693,12 @@ impl Pat { } } +impl From> for Pat { + fn from(value: P) -> Self { + *value + } +} + /// A single field in a struct pattern. /// /// Patterns like the fields of `Foo { x, ref y, ref mut z }` @@ -1522,17 +1528,23 @@ impl Expr { ) } - /// Creates a dummy `P`. + /// Creates a dummy `Expr`. /// /// Should only be used when it will be replaced afterwards or as a return value when an error was encountered. - pub fn dummy() -> P { - P(Expr { + pub fn dummy() -> Expr { + Expr { id: DUMMY_NODE_ID, kind: ExprKind::Dummy, span: DUMMY_SP, attrs: ThinVec::new(), tokens: None, - }) + } + } +} + +impl From> for Expr { + fn from(value: P) -> Self { + *value } } @@ -2343,6 +2355,12 @@ impl Clone for Ty { } } +impl From> for Ty { + fn from(value: P) -> Self { + *value + } +} + impl Ty { pub fn peel_refs(&self) -> &Self { let mut final_ty = self; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 71a47dcfcba..07fbe8045fc 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -168,7 +168,7 @@ pub trait MutVisitor: Sized + MutVisitorResult { walk_flat_map_arm(self, arm) } - fn visit_pat(&mut self, p: &mut P) { + fn visit_pat(&mut self, p: &mut Pat) { walk_pat(self, p); } @@ -176,7 +176,7 @@ pub trait MutVisitor: Sized + MutVisitorResult { walk_anon_const(self, c); } - fn visit_expr(&mut self, e: &mut P) { + fn visit_expr(&mut self, e: &mut Expr) { walk_expr(self, e); } @@ -194,7 +194,7 @@ pub trait MutVisitor: Sized + MutVisitorResult { walk_generic_arg(self, arg); } - fn visit_ty(&mut self, t: &mut P) { + fn visit_ty(&mut self, t: &mut Ty) { walk_ty(self, t); } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index da01e3e9607..fe44350863c 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -155,7 +155,7 @@ impl CfgEval<'_> { impl MutVisitor for CfgEval<'_> { #[instrument(level = "trace", skip(self))] - fn visit_expr(&mut self, expr: &mut P) { + fn visit_expr(&mut self, expr: &mut ast::Expr) { self.0.configure_expr(expr, false); mut_visit::walk_expr(self, expr); } diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 0794192621a..3a20b39798d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -1,5 +1,4 @@ use ast::HasAttrs; -use ast::ptr::P; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::visit::BoundKind; use rustc_ast::{ @@ -378,11 +377,11 @@ struct TypeSubstitution<'a> { } impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> { - fn visit_ty(&mut self, ty: &mut P) { + fn visit_ty(&mut self, ty: &mut ast::Ty) { if let Some(name) = ty.kind.is_simple_path() && name == self.from_name { - **ty = self.to_ty.clone(); + *ty = self.to_ty.clone(); self.rewritten = true; } else { ast::mut_visit::walk_ty(self, ty); diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 569165a64e5..301da8e604b 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1668,7 +1668,7 @@ impl InvocationCollectorNode for ast::Crate { } } -impl InvocationCollectorNode for P { +impl InvocationCollectorNode for ast::Ty { type OutputTy = P; const KIND: AstFragmentKind = AstFragmentKind::Ty; fn to_annotatable(self) -> Annotatable { @@ -1691,7 +1691,7 @@ impl InvocationCollectorNode for P { } } -impl InvocationCollectorNode for P { +impl InvocationCollectorNode for ast::Pat { type OutputTy = P; const KIND: AstFragmentKind = AstFragmentKind::Pat; fn to_annotatable(self) -> Annotatable { @@ -1714,11 +1714,11 @@ impl InvocationCollectorNode for P { } } -impl InvocationCollectorNode for P { +impl InvocationCollectorNode for ast::Expr { type OutputTy = P; const KIND: AstFragmentKind = AstFragmentKind::Expr; fn to_annotatable(self) -> Annotatable { - Annotatable::Expr(self) + Annotatable::Expr(P(self)) } fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_expr() @@ -1855,29 +1855,29 @@ impl DummyAstNode for ast::Crate { } } -impl DummyAstNode for P { +impl DummyAstNode for ast::Ty { fn dummy() -> Self { - P(ast::Ty { + ast::Ty { id: DUMMY_NODE_ID, kind: TyKind::Dummy, span: Default::default(), tokens: Default::default(), - }) + } } } -impl DummyAstNode for P { +impl DummyAstNode for ast::Pat { fn dummy() -> Self { - P(ast::Pat { + ast::Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: Default::default(), tokens: Default::default(), - }) + } } } -impl DummyAstNode for P { +impl DummyAstNode for ast::Expr { fn dummy() -> Self { ast::Expr::dummy() } @@ -1885,7 +1885,7 @@ impl DummyAstNode for P { impl DummyAstNode for AstNodeWrapper, MethodReceiverTag> { fn dummy() -> Self { - AstNodeWrapper::new(ast::Expr::dummy(), MethodReceiverTag) + AstNodeWrapper::new(P(ast::Expr::dummy()), MethodReceiverTag) } } @@ -2172,7 +2172,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } - fn visit_node + DummyAstNode>( + fn visit_node> + DummyAstNode>( &mut self, node: &mut Node, ) { @@ -2197,6 +2197,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { *node = self .collect_attr((attr, pos, derives), n.to_annotatable(), Node::KIND) .make_ast::() + .into() } }, None if node.is_mac_call() => { @@ -2204,7 +2205,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let (mac, attrs, _) = n.take_mac_call(); self.check_attributes(&attrs, &mac); - *node = self.collect_bang(mac, Node::KIND).make_ast::() + *node = self.collect_bang(mac, Node::KIND).make_ast::().into() } None if node.delegation().is_some() => unreachable!(), None => { @@ -2314,15 +2315,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.visit_node(node) } - fn visit_ty(&mut self, node: &mut P) { + fn visit_ty(&mut self, node: &mut ast::Ty) { self.visit_node(node) } - fn visit_pat(&mut self, node: &mut P) { + fn visit_pat(&mut self, node: &mut ast::Pat) { self.visit_node(node) } - fn visit_expr(&mut self, node: &mut P) { + fn visit_expr(&mut self, node: &mut ast::Expr) { // FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`. if let Some(attr) = node.attrs.first() { self.cfg().maybe_emit_expr_attr_err(attr); diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 3dcb20c8c76..2c486a02bdf 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -332,9 +332,9 @@ impl MutVisitor for PlaceholderExpander { } } - fn visit_expr(&mut self, expr: &mut P) { + fn visit_expr(&mut self, expr: &mut ast::Expr) { match expr.kind { - ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(), + ast::ExprKind::MacCall(_) => *expr = *self.remove(expr.id).make_expr(), _ => walk_expr(self, expr), } } @@ -399,16 +399,16 @@ impl MutVisitor for PlaceholderExpander { stmts } - fn visit_pat(&mut self, pat: &mut P) { + fn visit_pat(&mut self, pat: &mut ast::Pat) { match pat.kind { - ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(), + ast::PatKind::MacCall(_) => *pat = *self.remove(pat.id).make_pat(), _ => walk_pat(self, pat), } } - fn visit_ty(&mut self, ty: &mut P) { + fn visit_ty(&mut self, ty: &mut ast::Ty) { match ty.kind { - ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(), + ast::TyKind::MacCall(_) => *ty = *self.remove(ty.id).make_ty(), _ => walk_ty(self, ty), } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93489aa8ee9..93c76c47f06 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4087,7 +4087,7 @@ impl<'a> CondChecker<'a> { } impl MutVisitor for CondChecker<'_> { - fn visit_expr(&mut self, e: &mut P) { + fn visit_expr(&mut self, e: &mut Expr) { self.depth += 1; use ForbiddenLetReason::*; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 7a226136e23..64653ee2a04 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1094,7 +1094,7 @@ impl<'a> Parser<'a> { fn make_all_value_bindings_mutable(pat: &mut P) -> bool { struct AddMut(bool); impl MutVisitor for AddMut { - fn visit_pat(&mut self, pat: &mut P) { + fn visit_pat(&mut self, pat: &mut Pat) { if let PatKind::Ident(BindingMode(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind { diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index b839b6f5672..bd8420917f5 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -128,7 +128,7 @@ fn remove_all_parens(pat: &mut P) { } impl MutVisitor for Visitor { - fn visit_pat(&mut self, pat: &mut P) { + fn visit_pat(&mut self, pat: &mut Pat) { let is_inner = mem::replace(&mut self.is_inner, true); walk_pat(self, pat); let inner = match &mut pat.kind { @@ -145,7 +145,7 @@ fn remove_all_parens(pat: &mut P) { fn insert_necessary_parens(pat: &mut P) { struct Visitor; impl MutVisitor for Visitor { - fn visit_pat(&mut self, pat: &mut P) { + fn visit_pat(&mut self, pat: &mut Pat) { use ast::BindingMode; walk_pat(self, pat); let target = match &mut pat.kind { @@ -167,7 +167,7 @@ fn unnest_or_patterns(pat: &mut P) -> bool { changed: bool, } impl MutVisitor for Visitor { - fn visit_pat(&mut self, p: &mut P) { + fn visit_pat(&mut self, p: &mut Pat) { // This is a bottom up transformation, so recurse first. walk_pat(self, p); diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index f5cfa9e0bcc..8bca20852ad 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -187,9 +187,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { struct RemoveParens; impl MutVisitor for RemoveParens { - fn visit_expr(&mut self, e: &mut P) { + fn visit_expr(&mut self, e: &mut Expr) { match e.kind.clone() { - ExprKind::Paren(inner) => *e = inner, + ExprKind::Paren(inner) => *e = *inner, _ => {} }; mut_visit::walk_expr(self, e); @@ -200,11 +200,11 @@ impl MutVisitor for RemoveParens { struct AddParens; impl MutVisitor for AddParens { - fn visit_expr(&mut self, e: &mut P) { + fn visit_expr(&mut self, e: &mut Expr) { mut_visit::walk_expr(self, e); let expr = std::mem::replace(e, Expr::dummy()); - e.kind = ExprKind::Paren(expr); + e.kind = ExprKind::Paren(P(expr)); } } diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index c566ac459e0..2047f8dc765 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -43,7 +43,6 @@ use std::process::ExitCode; use parser::parse_expr; use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::mut_visit::{self, MutVisitor}; -use rustc_ast::ptr::P; use rustc_ast_pretty::pprust; use rustc_session::parse::ParseSess; @@ -152,7 +151,7 @@ static EXPRS: &[&str] = &[ struct Unparenthesize; impl MutVisitor for Unparenthesize { - fn visit_expr(&mut self, e: &mut P) { + fn visit_expr(&mut self, e: &mut Expr) { while let ExprKind::Paren(paren) = &mut e.kind { *e = mem::replace(paren, Expr::dummy()); } -- cgit 1.4.1-3-g733a5 From b131b6f630843d34a14f250e3b46733253f3465b Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 10 Jun 2025 19:18:31 +0200 Subject: Rework how the disallowed qualifier lints are generated Signed-off-by: Jonathan Brouwer --- compiler/rustc_parse/messages.ftl | 2 + compiler/rustc_parse/src/errors.rs | 8 +- compiler/rustc_parse/src/parser/item.rs | 81 ++++++++++- compiler/rustc_parse/src/parser/ty.rs | 65 ++------- tests/ui/parser/bad-fn-ptr-qualifier.fixed | 8 + tests/ui/parser/bad-fn-ptr-qualifier.rs | 3 - tests/ui/parser/bad-fn-ptr-qualifier.stderr | 160 +++++++------------- .../parser/recover/recover-const-async-fn-ptr.rs | 3 - .../recover/recover-const-async-fn-ptr.stderr | 162 +++++++-------------- 9 files changed, 208 insertions(+), 284 deletions(-) (limited to 'compiler/rustc_parse/src/parser') 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>, Option>)> { 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: - // ` 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`. -- cgit 1.4.1-3-g733a5 From 96fd9fc2dd8aa45ab19c2e07ed172b50566215ac Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 15 Jun 2025 14:59:05 +0800 Subject: use `if let` guards where possible --- compiler/rustc_builtin_macros/src/test.rs | 5 +---- compiler/rustc_parse/src/parser/diagnostics.rs | 27 +++++++++++--------------- 2 files changed, 12 insertions(+), 20 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index b439fa34f5b..b067578794b 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -118,10 +118,7 @@ pub(crate) fn expand_test_or_bench( let (item, is_stmt) = match item { Annotatable::Item(i) => (i, false), - Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { - // FIXME: Use an 'if let' guard once they are implemented - if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() } - } + Annotatable::Stmt(box ast::Stmt { kind: ast::StmtKind::Item(i), .. }) => (i, true), other => { not_testable_error(cx, attr_sp, None); return vec![other]; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b49a13ce584..215202c4bd5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2273,23 +2273,18 @@ impl<'a> Parser<'a> { ), // Also catches `fn foo(&a)`. PatKind::Ref(ref inner_pat, mutab) - if matches!(inner_pat.clone().kind, PatKind::Ident(..)) => + if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind => { - match inner_pat.clone().kind { - PatKind::Ident(_, ident, _) => { - let mutab = mutab.prefix_str(); - ( - ident, - "self: ", - format!("{ident}: &{mutab}TypeName"), - "_: ", - pat.span.shrink_to_lo(), - pat.span, - pat.span.shrink_to_lo(), - ) - } - _ => unreachable!(), - } + let mutab = mutab.prefix_str(); + ( + ident, + "self: ", + format!("{ident}: &{mutab}TypeName"), + "_: ", + pat.span.shrink_to_lo(), + pat.span, + pat.span.shrink_to_lo(), + ) } _ => { // Otherwise, try to get a type and emit a suggestion. -- cgit 1.4.1-3-g733a5 From c63665cd73dda46c63aaa17c51d1cd83750fe2e1 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 11 Jun 2025 15:06:50 +0800 Subject: Dont suggest converting `///` to regular comment when it appears after missing `,` in list Signed-off-by: xizheyin --- compiler/rustc_parse/src/parser/diagnostics.rs | 45 ++++++++++++++-------- ...doc-comment-after-missing-comma-issue-142311.rs | 34 ++++++++++++++++ ...comment-after-missing-comma-issue-142311.stderr | 43 +++++++++++++++++++++ 3 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 tests/ui/parser/doc-comment-after-missing-comma-issue-142311.rs create mode 100644 tests/ui/parser/doc-comment-after-missing-comma-issue-142311.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b49a13ce584..26b5548df17 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -686,23 +686,34 @@ impl<'a> Parser<'a> { } if let token::DocComment(kind, style, _) = self.token.kind { - // We have something like `expr //!val` where the user likely meant `expr // !val` - let pos = self.token.span.lo() + BytePos(2); - let span = self.token.span.with_lo(pos).with_hi(pos); - err.span_suggestion_verbose( - span, - format!( - "add a space before {} to write a regular comment", - match (kind, style) { - (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`", - (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`", - (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`", - (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`", - }, - ), - " ".to_string(), - Applicability::MachineApplicable, - ); + // This is to avoid suggesting converting a doc comment to a regular comment + // when missing a comma before the doc comment in lists (#142311): + // + // ``` + // enum Foo{ + // A /// xxxxxxx + // B, + // } + // ``` + if !expected.contains(&TokenType::Comma) { + // We have something like `expr //!val` where the user likely meant `expr // !val` + let pos = self.token.span.lo() + BytePos(2); + let span = self.token.span.with_lo(pos).with_hi(pos); + err.span_suggestion_verbose( + span, + format!( + "add a space before {} to write a regular comment", + match (kind, style) { + (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`", + (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`", + (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`", + (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`", + }, + ), + " ".to_string(), + Applicability::MaybeIncorrect, + ); + } } let sp = if self.token == token::Eof { diff --git a/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.rs b/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.rs new file mode 100644 index 00000000000..7ac6fa127f4 --- /dev/null +++ b/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.rs @@ -0,0 +1,34 @@ +//! Check that if the parser suggests converting `///` to a regular comment +//! when it appears after a missing comma in an list (e.g. `enum` variants). +//! +//! Related issue +//! - https://github.com/rust-lang/rust/issues/142311 + +enum Foo { + /// Like the noise a sheep makes + Bar + /// Like where people drink + //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `/// Like where people drink` + Baa///xxxxxx + //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `///xxxxxx` + Baz///xxxxxx + //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `///xxxxxx` +} + +fn foo() { + let a = [ + 1///xxxxxx + //~^ ERROR expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found doc comment `///xxxxxx` + 2 + ]; +} + +fn bar() { + let a = [ + 1, + 2///xxxxxx + //~^ ERROR expected one of `,`, `.`, `?`, `]`, or an operator, found doc comment `///xxxxxx` + ]; +} + +fn main() {} diff --git a/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.stderr b/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.stderr new file mode 100644 index 00000000000..d95cecfc560 --- /dev/null +++ b/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.stderr @@ -0,0 +1,43 @@ +error: expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `/// Like where people drink` + --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:10:5 + | +LL | Bar + | - + | | + | expected one of `(`, `,`, `=`, `{`, or `}` + | help: missing `,` +LL | /// Like where people drink + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected token + +error: expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `///xxxxxx` + --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:12:8 + | +LL | Baa///xxxxxx + | -^^^^^^^^ + | | + | expected one of `(`, `,`, `=`, `{`, or `}` + | help: missing `,` + +error: expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `///xxxxxx` + --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:14:8 + | +LL | Baz///xxxxxx + | ^^^^^^^^^ expected one of `(`, `,`, `=`, `{`, or `}` + | + = help: doc comments must come before what they document, if a comment was intended use `//` + = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + +error: expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found doc comment `///xxxxxx` + --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:20:10 + | +LL | 1///xxxxxx + | ^^^^^^^^^ expected one of `,`, `.`, `;`, `?`, `]`, or an operator + +error: expected one of `,`, `.`, `?`, `]`, or an operator, found doc comment `///xxxxxx` + --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:29:10 + | +LL | 2///xxxxxx + | ^^^^^^^^^ expected one of `,`, `.`, `?`, `]`, or an operator + +error: aborting due to 5 previous errors + -- cgit 1.4.1-3-g733a5