about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_metadata/cstore_impl.rs2
-rw-r--r--src/librustc_passes/entry.rs9
-rw-r--r--src/libsyntax/parse/lexer/mod.rs2
-rw-r--r--src/libsyntax/parse/lexer/tokentrees.rs9
-rw-r--r--src/libsyntax/parse/mod.rs17
-rw-r--r--src/libsyntax/parse/parser.rs46
-rw-r--r--src/libsyntax/parse/parser/diagnostics.rs50
-rw-r--r--src/libsyntax/parse/parser/item.rs17
-rw-r--r--src/libsyntax/sess.rs3
-rw-r--r--src/test/ui/did_you_mean/issue-40006.rs28
-rw-r--r--src/test/ui/did_you_mean/issue-40006.stderr52
-rw-r--r--src/test/ui/issues/issue-60075.rs5
-rw-r--r--src/test/ui/issues/issue-60075.stderr14
-rw-r--r--src/test/ui/parser-recovery-1.rs1
-rw-r--r--src/test/ui/parser-recovery-1.stderr26
-rw-r--r--src/test/ui/parser/issue-2354.rs7
-rw-r--r--src/test/ui/parser/issue-2354.stderr28
-rw-r--r--src/test/ui/parser/issue-62973.stderr8
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs12
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr33
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs14
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr28
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs10
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr25
24 files changed, 293 insertions, 153 deletions
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index de187a3f5e0..c5f830c0d04 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -424,7 +424,7 @@ impl cstore::CStore {
         let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body);
         let local_span = Span::with_root_ctxt(source_file.start_pos, source_file.end_pos);
         let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None);
-        emit_unclosed_delims(&mut errors, &sess.diagnostic());
+        emit_unclosed_delims(&mut errors, &sess.parse_sess);
 
         // Mark the attrs as used
         let attrs = data.get_item_attrs(id.index, sess);
diff --git a/src/librustc_passes/entry.rs b/src/librustc_passes/entry.rs
index bf68807a0c2..66004719060 100644
--- a/src/librustc_passes/entry.rs
+++ b/src/librustc_passes/entry.rs
@@ -154,6 +154,14 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(De
 }
 
 fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
+    let sp = tcx.hir().krate().span;
+    if *tcx.sess.parse_sess.reached_eof.borrow() {
+        // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
+        // the missing `fn main()` then as it might have been hidden inside an unclosed block.
+        tcx.sess.delay_span_bug(sp, "`main` not found, but expected unclosed brace error");
+        return;
+    }
+
     // There is no main function.
     let mut err = struct_err!(tcx.sess, E0601,
         "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
@@ -173,7 +181,6 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
     } else {
         String::from("consider adding a `main` function at the crate level")
     };
-    let sp = tcx.hir().krate().span;
     // The file may be empty, which leads to the diagnostic machinery not emitting this
     // note. This is a relatively simple way to detect that case and emit a span-less
     // note instead.
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index e6dc9a4c134..48cf117f65a 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -23,7 +23,7 @@ mod unicode_chars;
 #[derive(Clone, Debug)]
 pub struct UnmatchedBrace {
     pub expected_delim: token::DelimToken,
-    pub found_delim: token::DelimToken,
+    pub found_delim: Option<token::DelimToken>,
     pub found_span: Span,
     pub unclosed_span: Option<Span>,
     pub candidate_span: Option<Span>,
diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index 853723de14f..de8ac2c71e8 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -80,6 +80,13 @@ impl<'a> TokenTreesReader<'a> {
                     .struct_span_err(self.token.span, msg);
                 for &(_, sp) in &self.open_braces {
                     err.span_label(sp, "un-closed delimiter");
+                    self.unmatched_braces.push(UnmatchedBrace {
+                        expected_delim: token::DelimToken::Brace,
+                        found_delim: None,
+                        found_span: self.token.span,
+                        unclosed_span: Some(sp),
+                        candidate_span: None,
+                    });
                 }
 
                 if let Some((delim, _)) = self.open_braces.last() {
@@ -170,7 +177,7 @@ impl<'a> TokenTreesReader<'a> {
                             let (tok, _) = self.open_braces.pop().unwrap();
                             self.unmatched_braces.push(UnmatchedBrace {
                                 expected_delim: tok,
-                                found_delim: other,
+                                found_delim: Some(other),
                                 found_span: self.token.span,
                                 unclosed_span: unclosed_delimiter,
                                 candidate_span: candidate,
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index f5e416b722b..6d8ecdf805b 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -1,7 +1,7 @@
 //! The main parser interface.
 
 use crate::ast;
-use crate::parse::parser::{Parser, emit_unclosed_delims};
+use crate::parse::parser::{Parser, emit_unclosed_delims, make_unclosed_delims_error};
 use crate::parse::token::Nonterminal;
 use crate::tokenstream::{self, TokenStream, TokenTree};
 use crate::print::pprust;
@@ -108,7 +108,7 @@ pub fn parse_stream_from_source_str(
         sess.source_map().new_source_file(name, source),
         override_span,
     );
-    emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
+    emit_unclosed_delims(&mut errors, &sess);
     stream
 }
 
@@ -242,18 +242,9 @@ pub fn maybe_file_to_stream(
             err.buffer(&mut buffer);
             // Not using `emit_unclosed_delims` to use `db.buffer`
             for unmatched in unmatched_braces {
-                let mut db = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!(
-                    "incorrect close delimiter: `{}`",
-                    pprust::token_kind_to_string(&token::CloseDelim(unmatched.found_delim)),
-                ));
-                db.span_label(unmatched.found_span, "incorrect close delimiter");
-                if let Some(sp) = unmatched.candidate_span {
-                    db.span_label(sp, "close delimiter possibly meant for this");
+                if let Some(err) = make_unclosed_delims_error(unmatched, &sess) {
+                    err.buffer(&mut buffer);
                 }
-                if let Some(sp) = unmatched.unclosed_span {
-                    db.span_label(sp, "un-closed delimiter");
-                }
-                db.buffer(&mut buffer);
             }
             Err(buffer)
         }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 6ead1ce811d..e81d4573b73 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -27,7 +27,7 @@ use crate::symbol::{kw, sym, Symbol};
 use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
 use crate::ThinVec;
 
-use errors::{Applicability, DiagnosticId, FatalError};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
 use rustc_target::spec::abi::{self, Abi};
 use syntax_pos::{Span, BytePos, DUMMY_SP, FileName};
 use log::debug;
@@ -148,8 +148,7 @@ pub struct Parser<'a> {
 
 impl<'a> Drop for Parser<'a> {
     fn drop(&mut self) {
-        let diag = self.diagnostic();
-        emit_unclosed_delims(&mut self.unclosed_delims, diag);
+        emit_unclosed_delims(&mut self.unclosed_delims, &self.sess);
     }
 }
 
@@ -1370,20 +1369,31 @@ impl<'a> Parser<'a> {
     }
 }
 
-pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) {
-    for unmatched in unclosed_delims.iter() {
-        let mut err = handler.struct_span_err(unmatched.found_span, &format!(
-            "incorrect close delimiter: `{}`",
-            pprust::token_kind_to_string(&token::CloseDelim(unmatched.found_delim)),
-        ));
-        err.span_label(unmatched.found_span, "incorrect close delimiter");
-        if let Some(sp) = unmatched.candidate_span {
-            err.span_label(sp, "close delimiter possibly meant for this");
-        }
-        if let Some(sp) = unmatched.unclosed_span {
-            err.span_label(sp, "un-closed delimiter");
-        }
-        err.emit();
+crate fn make_unclosed_delims_error(
+    unmatched: UnmatchedBrace,
+    sess: &ParseSess,
+) -> Option<DiagnosticBuilder<'_>> {
+    // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
+    // `unmatched_braces` only for error recovery in the `Parser`.
+    let found_delim = unmatched.found_delim?;
+    let mut err = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!(
+        "incorrect close delimiter: `{}`",
+        pprust::token_kind_to_string(&token::CloseDelim(found_delim)),
+    ));
+    err.span_label(unmatched.found_span, "incorrect close delimiter");
+    if let Some(sp) = unmatched.candidate_span {
+        err.span_label(sp, "close delimiter possibly meant for this");
+    }
+    if let Some(sp) = unmatched.unclosed_span {
+        err.span_label(sp, "un-closed delimiter");
+    }
+    Some(err)
+}
+
+pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &ParseSess) {
+    *sess.reached_eof.borrow_mut() |= unclosed_delims.iter()
+        .any(|unmatched_delim| unmatched_delim.found_delim.is_none());
+    for unmatched in unclosed_delims.drain(..) {
+        make_unclosed_delims_error(unmatched, sess).map(|mut e| e.emit());
     }
-    unclosed_delims.clear();
 }
diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs
index ab2b4519cb7..fcf3b4c0aa8 100644
--- a/src/libsyntax/parse/parser/diagnostics.rs
+++ b/src/libsyntax/parse/parser/diagnostics.rs
@@ -171,6 +171,12 @@ impl RecoverQPath for Expr {
     }
 }
 
+/// Control whether the closing delimiter should be consumed when calling `Parser::consume_block`.
+crate enum ConsumeClosingDelim {
+    Yes,
+    No,
+}
+
 impl<'a> Parser<'a> {
     pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> {
         self.span_fatal(self.token.span, m)
@@ -1105,8 +1111,8 @@ impl<'a> Parser<'a> {
             Ok(x) => x,
             Err(mut err) => {
                 err.emit();
-                // Recover from parse error.
-                self.consume_block(delim);
+                // Recover from parse error, callers expect the closing delim to be consumed.
+                self.consume_block(delim, ConsumeClosingDelim::Yes);
                 self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
             }
         }
@@ -1135,6 +1141,11 @@ impl<'a> Parser<'a> {
                  // Don't attempt to recover from this unclosed delimiter more than once.
                 let unmatched = self.unclosed_delims.remove(pos);
                 let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
+                if unmatched.found_delim.is_none() {
+                    // We encountered `Eof`, set this fact here to avoid complaining about missing
+                    // `fn main()` when we found place to suggest the closing brace.
+                    *self.sess.reached_eof.borrow_mut() = true;
+                }
 
                 // We want to suggest the inclusion of the closing delimiter where it makes
                 // the most sense, which is immediately after the last token:
@@ -1154,9 +1165,16 @@ impl<'a> Parser<'a> {
                     delim.to_string(),
                     Applicability::MaybeIncorrect,
                 );
-                err.emit();
-                self.expected_tokens.clear();  // reduce errors
-                Ok(true)
+                if unmatched.found_delim.is_none() {
+                    // Encountered `Eof` when lexing blocks. Do not recover here to avoid knockdown
+                    // errors which would be emitted elsewhere in the parser and let other error
+                    // recovery consume the rest of the file.
+                    Err(err)
+                } else {
+                    err.emit();
+                    self.expected_tokens.clear();  // Reduce the number of errors.
+                    Ok(true)
+                }
             }
             _ => Err(err),
         }
@@ -1164,7 +1182,12 @@ impl<'a> Parser<'a> {
 
     /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid.
     pub(super) fn eat_bad_pub(&mut self) {
-        if self.token.is_keyword(kw::Pub) {
+        // When `unclosed_delims` is populated, it means that the code being parsed is already
+        // quite malformed, which might mean that, for example, a pub struct definition could be
+        // parsed as being a trait item, which is invalid and this error would trigger
+        // unconditionally, resulting in misleading diagnostics. Because of this, we only attempt
+        // this nice to have recovery for code that is otherwise well formed.
+        if self.token.is_keyword(kw::Pub) && self.unclosed_delims.is_empty() {
             match self.parse_visibility(false) {
                 Ok(vis) => {
                     self.diagnostic()
@@ -1422,15 +1445,26 @@ impl<'a> Parser<'a> {
         Ok(param)
     }
 
-    pub(super) fn consume_block(&mut self, delim: token::DelimToken) {
+    pub(super) fn consume_block(
+        &mut self,
+        delim: token::DelimToken,
+        consume_close: ConsumeClosingDelim,
+    ) {
         let mut brace_depth = 0;
         loop {
             if self.eat(&token::OpenDelim(delim)) {
                 brace_depth += 1;
-            } else if self.eat(&token::CloseDelim(delim)) {
+            } else if self.check(&token::CloseDelim(delim)) {
                 if brace_depth == 0 {
+                    if let ConsumeClosingDelim::Yes = consume_close {
+                        // Some of the callers of this method expect to be able to parse the
+                        // closing delimiter themselves, so we leave it alone. Otherwise we advance
+                        // the parser.
+                        self.bump();
+                    }
                     return;
                 } else {
+                    self.bump();
                     brace_depth -= 1;
                     continue;
                 }
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index fe125336190..5b60e7e6dba 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -1,5 +1,5 @@
-use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode};
-use super::diagnostics::{Error, dummy_arg};
+use super::{Parser, PResult, PathStyle};
+use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim};
 
 use crate::maybe_whole;
 use crate::ptr::P;
@@ -339,7 +339,7 @@ impl<'a> Parser<'a> {
                 let ident = self.parse_ident().unwrap();
                 self.bump();  // `(`
                 let kw_name = self.recover_first_param();
-                self.consume_block(token::Paren);
+                self.consume_block(token::Paren, ConsumeClosingDelim::Yes);
                 let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
                     self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
                     self.bump();  // `{`
@@ -357,7 +357,7 @@ impl<'a> Parser<'a> {
                 let msg = format!("missing `{}` for {} definition", kw, kw_name);
                 let mut err = self.diagnostic().struct_span_err(sp, &msg);
                 if !ambiguous {
-                    self.consume_block(token::Brace);
+                    self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
                     let suggestion = format!("add `{}` here to parse `{}` as a public {}",
                                              kw,
                                              ident,
@@ -672,7 +672,8 @@ impl<'a> Parser<'a> {
                 Err(mut err) => {
                     err.emit();
                     if !at_end {
-                        self.recover_stmt_(SemiColonMode::Break, BlockMode::Break);
+                        self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                        break;
                     }
                 }
             }
@@ -861,7 +862,8 @@ impl<'a> Parser<'a> {
                     Err(mut e) => {
                         e.emit();
                         if !at_end {
-                            self.recover_stmt_(SemiColonMode::Break, BlockMode::Break);
+                            self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                            break;
                         }
                     }
                 }
@@ -1520,7 +1522,7 @@ impl<'a> Parser<'a> {
         if self.eat(&token::OpenDelim(token::Brace)) {
             while self.token != token::CloseDelim(token::Brace) {
                 let field = self.parse_struct_decl_field().map_err(|e| {
-                    self.recover_stmt();
+                    self.consume_block(token::Brace, ConsumeClosingDelim::No);
                     recovered = true;
                     e
                 });
@@ -1528,6 +1530,7 @@ impl<'a> Parser<'a> {
                     Ok(field) => fields.push(field),
                     Err(mut err) => {
                         err.emit();
+                        break;
                     }
                 }
             }
diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs
index 28a0868d5dd..323fe01f067 100644
--- a/src/libsyntax/sess.rs
+++ b/src/libsyntax/sess.rs
@@ -73,6 +73,8 @@ pub struct ParseSess {
     pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
     pub injected_crate_name: Once<Symbol>,
     crate gated_spans: GatedSpans,
+    /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
+    pub reached_eof: Lock<bool>,
 }
 
 impl ParseSess {
@@ -101,6 +103,7 @@ impl ParseSess {
             ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
             injected_crate_name: Once::new(),
             gated_spans: GatedSpans::default(),
+            reached_eof: Lock::new(false),
         }
     }
 
diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs
index a1184f757e2..b3c1f60b7eb 100644
--- a/src/test/ui/did_you_mean/issue-40006.rs
+++ b/src/test/ui/did_you_mean/issue-40006.rs
@@ -1,5 +1,4 @@
-impl dyn X { //~ ERROR cannot be made into an object
-//~^ ERROR missing
+impl dyn A { //~ ERROR missing
     Y
 }
 
@@ -7,10 +6,25 @@ struct S;
 
 trait X { //~ ERROR missing
     X() {}
-    fn xxx() { ### } //~ ERROR missing
-    //~^ ERROR expected
-    L = M; //~ ERROR missing
-    Z = { 2 + 3 }; //~ ERROR expected one of
+    fn xxx() { ### }
+    L = M;
+    Z = { 2 + 3 };
+    ::Y ();
+}
+
+trait A { //~ ERROR missing
+    X() {}
+}
+trait B {
+    fn xxx() { ### } //~ ERROR expected
+}
+trait C { //~ ERROR missing `fn`, `type`, or `const` for trait-item declaration
+    L = M;
+}
+trait D { //~ ERROR missing `fn`, `type`, or `const` for trait-item declaration
+    Z = { 2 + 3 };
+}
+trait E {
     ::Y (); //~ ERROR expected one of
 }
 
@@ -21,5 +35,5 @@ impl S {
 }
 
 fn main() {
-    S.hello_method();
+    S.hello_method(); //~ no method named `hello_method` found for type `S` in the current scope
 }
diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr
index 5b384045a48..f0baa175d63 100644
--- a/src/test/ui/did_you_mean/issue-40006.stderr
+++ b/src/test/ui/did_you_mean/issue-40006.stderr
@@ -1,70 +1,70 @@
 error: missing `fn`, `type`, or `const` for impl-item declaration
   --> $DIR/issue-40006.rs:1:13
    |
-LL |   impl dyn X {
+LL |   impl dyn A {
    |  _____________^
-LL | |
 LL | |     Y
    | |____^ missing `fn`, `type`, or `const`
 
 error: missing `fn`, `type`, or `const` for trait-item declaration
-  --> $DIR/issue-40006.rs:8:10
+  --> $DIR/issue-40006.rs:7:10
    |
 LL |   trait X {
    |  __________^
 LL | |     X() {}
    | |____^ missing `fn`, `type`, or `const`
 
+error: missing `fn`, `type`, or `const` for trait-item declaration
+  --> $DIR/issue-40006.rs:15:10
+   |
+LL |   trait A {
+   |  __________^
+LL | |     X() {}
+   | |____^ missing `fn`, `type`, or `const`
+
 error: expected `[`, found `#`
-  --> $DIR/issue-40006.rs:10:17
+  --> $DIR/issue-40006.rs:19:17
    |
 LL |     fn xxx() { ### }
    |                 ^ expected `[`
 
 error: missing `fn`, `type`, or `const` for trait-item declaration
-  --> $DIR/issue-40006.rs:10:21
+  --> $DIR/issue-40006.rs:21:10
    |
-LL |       fn xxx() { ### }
-   |  _____________________^
-LL | |
+LL |   trait C {
+   |  __________^
 LL | |     L = M;
    | |____^ missing `fn`, `type`, or `const`
 
 error: missing `fn`, `type`, or `const` for trait-item declaration
-  --> $DIR/issue-40006.rs:12:11
+  --> $DIR/issue-40006.rs:24:10
    |
-LL |       L = M;
-   |  ___________^
+LL |   trait D {
+   |  __________^
 LL | |     Z = { 2 + 3 };
    | |____^ missing `fn`, `type`, or `const`
 
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
-  --> $DIR/issue-40006.rs:13:18
-   |
-LL |     Z = { 2 + 3 };
-   |                  ^ expected one of 7 possible tokens here
-
 error: expected one of `!` or `::`, found `(`
-  --> $DIR/issue-40006.rs:14:9
+  --> $DIR/issue-40006.rs:28:9
    |
 LL |     ::Y ();
    |         ^ expected one of `!` or `::` here
 
 error: missing `fn`, `type`, or `const` for impl-item declaration
-  --> $DIR/issue-40006.rs:18:8
+  --> $DIR/issue-40006.rs:32:8
    |
 LL |     pub hello_method(&self) {
    |        ^ missing `fn`, `type`, or `const`
 
-error[E0038]: the trait `X` cannot be made into an object
-  --> $DIR/issue-40006.rs:1:6
+error[E0599]: no method named `hello_method` found for type `S` in the current scope
+  --> $DIR/issue-40006.rs:38:7
    |
-LL | impl dyn X {
-   |      ^^^^^ the trait `X` cannot be made into an object
+LL | struct S;
+   | --------- method `hello_method` not found for this
 ...
-LL |     fn xxx() { ### }
-   |        --- associated function `xxx` has no `self` parameter
+LL |     S.hello_method();
+   |       ^^^^^^^^^^^^ method not found in `S`
 
 error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0038`.
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-60075.rs b/src/test/ui/issues/issue-60075.rs
index 5788716a526..1f53a927932 100644
--- a/src/test/ui/issues/issue-60075.rs
+++ b/src/test/ui/issues/issue-60075.rs
@@ -5,8 +5,7 @@ trait T {
         let _ = if true {
         });
 //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
-//~^^ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
-//~^^^ ERROR 6:11: 6:12: expected identifier, found `;`
-//~^^^^ ERROR missing `fn`, `type`, or `const` for trait-item declaration
+//~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
+//~| ERROR expected identifier, found `;`
         Some(4)
     }
diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr
index ac97d32a6e1..961a546d8d6 100644
--- a/src/test/ui/issues/issue-60075.stderr
+++ b/src/test/ui/issues/issue-60075.stderr
@@ -19,17 +19,5 @@ error: expected identifier, found `;`
 LL |         });
    |           ^ expected identifier
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
-  --> $DIR/issue-60075.rs:6:12
-   |
-LL |           });
-   |  ____________^
-LL | |
-LL | |
-LL | |
-LL | |
-LL | |         Some(4)
-   | |________^ missing `fn`, `type`, or `const`
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser-recovery-1.rs b/src/test/ui/parser-recovery-1.rs
index 8126525c34f..21d36048e67 100644
--- a/src/test/ui/parser-recovery-1.rs
+++ b/src/test/ui/parser-recovery-1.rs
@@ -3,7 +3,6 @@
 // Test that we can recover from missing braces in the parser.
 
 trait Foo {
-//~^ ERROR `main` function not found
     fn bar() {
         let x = foo();
         //~^ ERROR cannot find function `foo` in this scope
diff --git a/src/test/ui/parser-recovery-1.stderr b/src/test/ui/parser-recovery-1.stderr
index ffe2b3322fc..83f8ef63c99 100644
--- a/src/test/ui/parser-recovery-1.stderr
+++ b/src/test/ui/parser-recovery-1.stderr
@@ -1,9 +1,8 @@
 error: this file contains an un-closed delimiter
-  --> $DIR/parser-recovery-1.rs:16:55
+  --> $DIR/parser-recovery-1.rs:15:55
    |
 LL | trait Foo {
    |           - un-closed delimiter
-LL |
 LL |     fn bar() {
    |              - this delimiter might not be properly closed...
 ...
@@ -14,36 +13,23 @@ LL | }
    |                                                       ^
 
 error: unexpected token: `;`
-  --> $DIR/parser-recovery-1.rs:13:15
+  --> $DIR/parser-recovery-1.rs:12:15
    |
 LL |     let x = y.;
    |               ^
 
 error[E0425]: cannot find function `foo` in this scope
-  --> $DIR/parser-recovery-1.rs:8:17
+  --> $DIR/parser-recovery-1.rs:7:17
    |
 LL |         let x = foo();
    |                 ^^^ not found in this scope
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/parser-recovery-1.rs:13:13
+  --> $DIR/parser-recovery-1.rs:12:13
    |
 LL |     let x = y.;
    |             ^ not found in this scope
 
-error[E0601]: `main` function not found in crate `parser_recovery_1`
-  --> $DIR/parser-recovery-1.rs:5:1
-   |
-LL | / trait Foo {
-LL | |
-LL | |     fn bar() {
-LL | |         let x = foo();
-...  |
-LL | |
-LL | | }
-   | |______________________________________________________^ consider adding a `main` function to `$DIR/parser-recovery-1.rs`
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0425, E0601.
-For more information about an error, try `rustc --explain E0425`.
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/parser/issue-2354.rs b/src/test/ui/parser/issue-2354.rs
index a14eb6e32fc..c4fc4716182 100644
--- a/src/test/ui/parser/issue-2354.rs
+++ b/src/test/ui/parser/issue-2354.rs
@@ -1,7 +1,4 @@
 fn foo() { //~ NOTE un-closed delimiter
-//~^ ERROR `main` function not found
-//~^^ NOTE main function must be defined
-//~^^^ NOTE you have one or more functions
   match Some(10) {
   //~^ NOTE this delimiter might not be properly closed...
       Some(y) => { panic!(); }
@@ -14,5 +11,5 @@ fn bar() {
     while (i < 1000) {}
 }
 
-fn main() {} //~ NOTE here is a function named `main`
-             //~ ERROR this file contains an un-closed delimiter
+fn main() {}
+//~ ERROR this file contains an un-closed delimiter
diff --git a/src/test/ui/parser/issue-2354.stderr b/src/test/ui/parser/issue-2354.stderr
index 038e3dcfa40..45199b02cb8 100644
--- a/src/test/ui/parser/issue-2354.stderr
+++ b/src/test/ui/parser/issue-2354.stderr
@@ -1,9 +1,8 @@
 error: this file contains an un-closed delimiter
-  --> $DIR/issue-2354.rs:18:66
+  --> $DIR/issue-2354.rs:15:53
    |
 LL | fn foo() {
    |          - un-closed delimiter
-...
 LL |   match Some(10) {
    |                  - this delimiter might not be properly closed...
 ...
@@ -11,28 +10,7 @@ LL | }
    | - ...as it matches this but it has different indentation
 ...
 LL |
-   |                                                                  ^
-
-error[E0601]: `main` function not found in crate `issue_2354`
-  --> $DIR/issue-2354.rs:1:1
-   |
-LL | / fn foo() {
-LL | |
-LL | |
-LL | |
-...  |
-LL | | fn main() {}
-LL | |
-   | |_________________________________________________________________^ the main function must be defined at the crate level (in `$DIR/issue-2354.rs`)
-   |
-note: here is a function named `main`
-  --> $DIR/issue-2354.rs:17:1
-   |
-LL | fn main() {}
-   | ^^^^^^^^^^^^
-   = note: you have one or more functions named `main` not defined at the crate level
-   = help: either move the `main` function definitions or attach the `#[main]` attribute to one of them
+   |                                                     ^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/parser/issue-62973.stderr b/src/test/ui/parser/issue-62973.stderr
index e73776dc7b4..82122ef0b6f 100644
--- a/src/test/ui/parser/issue-62973.stderr
+++ b/src/test/ui/parser/issue-62973.stderr
@@ -13,9 +13,11 @@ error: expected one of `,` or `}`, found `{`
   --> $DIR/issue-62973.rs:6:25
    |
 LL | fn p() { match s { v, E { [) {) }
-   |                -        ^ expected one of `,` or `}` here
-   |                |
-   |                while parsing this struct
+   |        -       -       -^ expected one of `,` or `}` here
+   |        |       |       |
+   |        |       |       help: `}` may belong here
+   |        |       while parsing this struct
+   |        unclosed delimiter
 
 error: struct literals are not allowed here
   --> $DIR/issue-62973.rs:6:16
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs
new file mode 100644
index 00000000000..8d89905909e
--- /dev/null
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs
@@ -0,0 +1,12 @@
+impl T for () { //~ ERROR cannot find trait `T` in this scope
+
+fn foo(&self) {}
+
+trait T { //~ ERROR expected one of
+    fn foo(&self);
+}
+
+pub(crate) struct Bar<T>();
+
+fn main() {}
+//~ ERROR this file contains an un-closed delimiter
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr
new file mode 100644
index 00000000000..9bf54181a07
--- /dev/null
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr
@@ -0,0 +1,33 @@
+error: this file contains an un-closed delimiter
+  --> $DIR/missing-close-brace-in-impl-trait.rs:12:53
+   |
+LL | impl T for () {
+   |               - un-closed delimiter
+...
+LL |
+   |                                                     ^
+
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `trait`
+  --> $DIR/missing-close-brace-in-impl-trait.rs:5:1
+   |
+LL | impl T for () {
+   |               - unclosed delimiter
+LL | 
+LL | fn foo(&self) {}
+   |                 -
+   |                 |
+   |                 expected one of 10 possible tokens here
+   |                 help: `}` may belong here
+LL | 
+LL | trait T {
+   | ^^^^^ unexpected token
+
+error[E0405]: cannot find trait `T` in this scope
+  --> $DIR/missing-close-brace-in-impl-trait.rs:1:6
+   |
+LL | impl T for () {
+   |      ^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs
new file mode 100644
index 00000000000..5b716b1467c
--- /dev/null
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs
@@ -0,0 +1,14 @@
+pub(crate) struct Bar<T> {
+  foo: T,
+
+trait T { //~ ERROR expected identifier, found keyword `trait`
+//~^ ERROR expected `:`, found `T`
+    fn foo(&self);
+}
+
+
+impl T for Bar<usize> {
+fn foo(&self) {}
+}
+
+fn main() {} //~ ERROR this file contains an un-closed delimiter
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr
new file mode 100644
index 00000000000..ce399dbbf45
--- /dev/null
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr
@@ -0,0 +1,28 @@
+error: this file contains an un-closed delimiter
+  --> $DIR/missing-close-brace-in-struct.rs:14:66
+   |
+LL | pub(crate) struct Bar<T> {
+   |                          - un-closed delimiter
+...
+LL | fn main() {}
+   |                                                                  ^
+
+error: expected identifier, found keyword `trait`
+  --> $DIR/missing-close-brace-in-struct.rs:4:1
+   |
+LL | trait T {
+   | ^^^^^ expected identifier, found keyword
+   |
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL | r#trait T {
+   | ^^^^^^^
+
+error: expected `:`, found `T`
+  --> $DIR/missing-close-brace-in-struct.rs:4:7
+   |
+LL | trait T {
+   |       ^ expected `:`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs
new file mode 100644
index 00000000000..79547195411
--- /dev/null
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs
@@ -0,0 +1,10 @@
+trait T {
+    fn foo(&self);
+
+pub(crate) struct Bar<T>(); //~ ERROR expected one of
+
+impl T for Bar<usize> {
+fn foo(&self) {}
+}
+
+fn main() {} //~ ERROR this file contains an un-closed delimiter
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
new file mode 100644
index 00000000000..4bfb4c1cb3a
--- /dev/null
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
@@ -0,0 +1,25 @@
+error: this file contains an un-closed delimiter
+  --> $DIR/missing-close-brace-in-trait.rs:10:66
+   |
+LL | trait T {
+   |         - un-closed delimiter
+...
+LL | fn main() {}
+   |                                                                  ^
+
+error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found keyword `pub`
+  --> $DIR/missing-close-brace-in-trait.rs:4:1
+   |
+LL | trait T {
+   |         - unclosed delimiter
+LL |     fn foo(&self);
+   |                   -
+   |                   |
+   |                   expected one of 7 possible tokens here
+   |                   help: `}` may belong here
+LL | 
+LL | pub(crate) struct Bar<T>();
+   | ^^^ unexpected token
+
+error: aborting due to 2 previous errors
+