diff options
17 files changed, 302 insertions, 96 deletions
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..921c4ed0f0a 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; @@ -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.span_diagnostic) { + 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..5dbe4d95a85 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; @@ -1370,20 +1370,29 @@ impl<'a> Parser<'a> { } } +crate fn make_unclosed_delims_error( + unmatched: UnmatchedBrace, + handler: &errors::Handler, +) -> 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 = handler.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>, 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(); + for unmatched in unclosed_delims.drain(..) { + make_unclosed_delims_error(unmatched, handler).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..be1441d1c3f 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()) } } @@ -1154,9 +1160,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 +1177,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 +1440,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/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/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..66f43889cec --- /dev/null +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs @@ -0,0 +1,13 @@ +impl T for () { //~ ERROR `main` function not found +//~^ 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..52c00758b37 --- /dev/null +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr @@ -0,0 +1,46 @@ +error: this file contains an un-closed delimiter + --> $DIR/missing-close-brace-in-impl-trait.rs:13:53 + | +LL | impl T for () { + | - un-closed delimiter +... +LL | + | ^ + +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `trait` + --> $DIR/missing-close-brace-in-impl-trait.rs:6:1 + | +LL | impl T for () { + | - unclosed delimiter +... +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[E0601]: `main` function not found in crate `missing_close_brace_in_impl_trait` + --> $DIR/missing-close-brace-in-impl-trait.rs:1:1 + | +LL | / impl T for () { +LL | | +LL | | +LL | | fn foo(&self) {} +... | +LL | | fn main() {} +LL | | + | |____________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-impl-trait.rs` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0405, E0601. +For more information about an 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..8f42897914a --- /dev/null +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs @@ -0,0 +1,14 @@ +pub(crate) struct Bar<T> { //~ ERROR `main` function not found + 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..e0d5eb90aa1 --- /dev/null +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr @@ -0,0 +1,41 @@ +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[E0601]: `main` function not found in crate `missing_close_brace_in_struct` + --> $DIR/missing-close-brace-in-struct.rs:1:1 + | +LL | / pub(crate) struct Bar<T> { +LL | | foo: T, +LL | | +LL | | trait T { +... | +LL | | +LL | | fn main() {} + | |_________________________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-struct.rs` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0601`. 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..46b9cab66e9 --- /dev/null +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs @@ -0,0 +1,11 @@ +trait T { +//~^ ERROR `main` function not found in crate `missing_close_brace_in_trait` + 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..7de6c1d0cdd --- /dev/null +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr @@ -0,0 +1,39 @@ +error: this file contains an un-closed delimiter + --> $DIR/missing-close-brace-in-trait.rs:11:66 + | +LL | trait T { + | - un-closed delimiter +... +LL | fn main() {} + | ^ + +error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` + --> $DIR/missing-close-brace-in-trait.rs:5:1 + | +LL | trait T { + | - unclosed delimiter +LL | +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[E0601]: `main` function not found in crate `missing_close_brace_in_trait` + --> $DIR/missing-close-brace-in-trait.rs:1:1 + | +LL | / trait T { +LL | | +LL | | fn foo(&self); +LL | | +... | +LL | | +LL | | fn main() {} + | |_________________________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-trait.rs` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0601`. |
