From b4c4bc09dde2a6f6ce2978e00fb57b083ea4accc Mon Sep 17 00:00:00 2001
From: threadexception <hannes.gaumann@outlook.de>
Date: Tue, 7 Dec 2021 16:44:51 +0100
Subject: [PATCH] Do not attempt to suggest help for overly malformed
 struct/function call

---
 compiler/rustc_parse/src/parser/expr.rs      | 47 +++++++++++---------
 src/test/ui/parser/issues/issue-91461.rs     |  6 +++
 src/test/ui/parser/issues/issue-91461.stderr | 31 +++++++++++++
 3 files changed, 64 insertions(+), 20 deletions(-)
 create mode 100644 src/test/ui/parser/issues/issue-91461.rs
 create mode 100644 src/test/ui/parser/issues/issue-91461.stderr

diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 1dbd7bad0f023..0f8c0e1b8cff8 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1100,30 +1100,37 @@ impl<'a> Parser<'a> {
                 snapshot.bump(); // `(`
                 match snapshot.parse_struct_fields(path, false, token::Paren) {
                     Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => {
-                        // We have are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
+                        // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
                         // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
                         *self = snapshot;
                         let close_paren = self.prev_token.span;
                         let span = lo.to(self.prev_token.span);
-                        err.cancel();
-                        self.struct_span_err(
-                            span,
-                            "invalid `struct` delimiters or `fn` call arguments",
-                        )
-                        .multipart_suggestion(
-                            &format!("if `{}` is a struct, use braces as delimiters", name),
-                            vec![(open_paren, " { ".to_string()), (close_paren, " }".to_string())],
-                            Applicability::MaybeIncorrect,
-                        )
-                        .multipart_suggestion(
-                            &format!("if `{}` is a function, use the arguments directly", name),
-                            fields
-                                .into_iter()
-                                .map(|field| (field.span.until(field.expr.span), String::new()))
-                                .collect(),
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
+                        if !fields.is_empty() {
+                            err.cancel();
+                            let mut err = self.struct_span_err(
+                                span,
+                                "invalid `struct` delimiters or `fn` call arguments",
+                            );
+                            err.multipart_suggestion(
+                                &format!("if `{}` is a struct, use braces as delimiters", name),
+                                vec![
+                                    (open_paren, " { ".to_string()),
+                                    (close_paren, " }".to_string()),
+                                ],
+                                Applicability::MaybeIncorrect,
+                            );
+                            err.multipart_suggestion(
+                                &format!("if `{}` is a function, use the arguments directly", name),
+                                fields
+                                    .into_iter()
+                                    .map(|field| (field.span.until(field.expr.span), String::new()))
+                                    .collect(),
+                                Applicability::MaybeIncorrect,
+                            );
+                            err.emit();
+                        } else {
+                            err.emit();
+                        }
                         return Some(self.mk_expr_err(span));
                     }
                     Ok(_) => {}
diff --git a/src/test/ui/parser/issues/issue-91461.rs b/src/test/ui/parser/issues/issue-91461.rs
new file mode 100644
index 0000000000000..3e3c411c478ab
--- /dev/null
+++ b/src/test/ui/parser/issues/issue-91461.rs
@@ -0,0 +1,6 @@
+fn main() {
+    a(_:b:,)
+    //~^ ERROR: expected identifier, found reserved identifier `_`
+    //~| ERROR: expected type, found `,`
+    //~| ERROR: expected type, found `,`
+}
diff --git a/src/test/ui/parser/issues/issue-91461.stderr b/src/test/ui/parser/issues/issue-91461.stderr
new file mode 100644
index 0000000000000..94fcf1721d8c1
--- /dev/null
+++ b/src/test/ui/parser/issues/issue-91461.stderr
@@ -0,0 +1,31 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-91461.rs:2:7
+   |
+LL |     a(_:b:,)
+   |       ^ expected identifier, found reserved identifier
+
+error: expected type, found `,`
+  --> $DIR/issue-91461.rs:2:11
+   |
+LL |     a(_:b:,)
+   |     -    -^ expected type
+   |     |    |
+   |     |    tried to parse a type due to this type ascription
+   |     while parsing this struct
+   |
+   = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+   = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+
+error: expected type, found `,`
+  --> $DIR/issue-91461.rs:2:11
+   |
+LL |     a(_:b:,)
+   |          -^ expected type
+   |          |
+   |          tried to parse a type due to this type ascription
+   |
+   = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+   = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+
+error: aborting due to 3 previous errors
+