diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 8ed7bbf6e1276..4ecaf742fab04 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -892,7 +892,7 @@ pub fn parse_ast_fragment<'a>( let mut stmts = SmallVec::new(); // Won't make progress on a `}`. while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) { - if let Some(stmt) = this.parse_full_stmt()? { + if let Some(stmt) = this.parse_full_stmt(false)? { stmts.push(stmt); } } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d7d6fcd05b795..a0cbd67e3d441 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -30,7 +30,7 @@ impl<'a> Parser<'a> { fn parse_item_(&mut self, req_name: ReqName) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; - self.parse_item_common(attrs, true, false, req_name) + self.parse_item_common(attrs, true, false, req_name, true) } pub(super) fn parse_item_common( @@ -39,6 +39,7 @@ impl<'a> Parser<'a> { mac_allowed: bool, attrs_allowed: bool, req_name: ReqName, + mod_stmt: bool, ) -> PResult<'a, Option> { maybe_whole!(self, NtItem, |item| { let mut item = item; @@ -49,9 +50,9 @@ impl<'a> Parser<'a> { let mut unclosed_delims = vec![]; let (mut item, tokens) = self.collect_tokens(|this| { - let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name); + let i = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name, mod_stmt); unclosed_delims.append(&mut this.unclosed_delims); - item + i })?; self.unclosed_delims.append(&mut unclosed_delims); @@ -83,11 +84,13 @@ impl<'a> Parser<'a> { mac_allowed: bool, attrs_allowed: bool, req_name: ReqName, + mod_stmt: bool, ) -> PResult<'a, Option> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; let mut def = self.parse_defaultness(); - let kind = self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, req_name)?; + let kind = + self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, req_name, mod_stmt)?; if let Some((ident, kind)) = kind { self.error_on_unconsumed_default(def, &kind); let span = lo.to(self.prev_span); @@ -148,6 +151,7 @@ impl<'a> Parser<'a> { vis: &Visibility, def: &mut Defaultness, req_name: ReqName, + mod_stmt: bool, ) -> PResult<'a, Option> { let mut def = || mem::replace(def, Defaultness::Final); @@ -212,9 +216,13 @@ impl<'a> Parser<'a> { } else if vis.node.is_pub() && self.isnt_macro_invocation() { self.recover_missing_kw_before_item()?; return Ok(None); - } else if macros_allowed && self.token.is_path_start() { + } else if let Some(kind) = if macros_allowed && self.token.is_path_start() { + self.parse_item_macro(vis, mod_stmt)? + } else { + None + } { // MACRO INVOCATION ITEM - (Ident::invalid(), ItemKind::Mac(self.parse_item_macro(vis)?)) + (Ident::invalid(), ItemKind::Mac(kind)) } else { return Ok(None); }; @@ -333,13 +341,36 @@ impl<'a> Parser<'a> { } /// Parses an item macro, e.g., `item!();`. - fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, Mac> { - let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` - self.expect(&token::Not)?; // `!` + fn parse_item_macro(&mut self, vis: &Visibility, mod_stmt: bool) -> PResult<'a, Option> { + let parse_prefix = |p: &mut Self| -> PResult<'a, ast::Path> { + let path = p.parse_path(PathStyle::Mod)?; // `foo::bar` + p.expect(&token::Not)?; // `!` + Ok(path) + }; + let path = if mod_stmt { + // We're in statement-as-module-item recovery mode. + // To avoid "stealing" syntax from e.g. `x.f()` as a module-level statement, + // we backtrack if we failed to parse `$path!`; after we have, we commit firmly. + // This is only done when `mod_stmt` holds to avoid backtracking inside functions. + let snapshot = self.clone(); + match parse_prefix(self) { + Ok(path) => path, + Err(mut err) => { + // Assert that this is only for diagnostics! + // This is a safeguard against breaking LL(k) accidentally in the spec, + // assuming no one has gated the syntax with something like `#[cfg(FALSE)]`. + err.delay_as_bug(); + *self = snapshot; + return Ok(None); + } + } + } else { + parse_prefix(self)? + }; let args = self.parse_mac_args()?; // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`. self.eat_semi_for_macro_if_needed(&args); self.complain_if_pub_macro(vis, false); - Ok(Mac { path, args, prior_type_ascription: self.last_type_ascription }) + Ok(Some(Mac { path, args, prior_type_ascription: self.last_type_ascription })) } /// Recover if we parsed attributes and expected an item but there was none. diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 9dba813c9a721..918c3d32be6d1 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -4,12 +4,15 @@ use super::Parser; use crate::{new_sub_parser_from_file, DirectoryOwnership}; -use rustc_errors::PResult; -use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP}; +use rustc_ast_pretty::pprust; +use rustc_errors::{Applicability, PResult}; +use rustc_span::source_map::{respan, FileName, MultiSpan, SourceMap, Span, DUMMY_SP}; use rustc_span::symbol::sym; use syntax::ast::{self, Attribute, Crate, Ident, ItemKind, Mod}; use syntax::attr; +use syntax::ptr::P; use syntax::token::{self, TokenKind}; +use syntax::visit::Visitor; use std::path::{self, Path, PathBuf}; @@ -75,9 +78,12 @@ impl<'a> Parser<'a> { /// Given a termination token, parses all of the items in a module. fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { let mut items = vec![]; - while let Some(item) = self.parse_item()? { - items.push(item); - self.maybe_consume_incorrect_semicolon(&items); + let mut stuck = false; + while let Some(res) = self.parse_item_in_mod(term, &mut stuck)? { + if let Some(item) = res { + items.push(item); + self.maybe_consume_incorrect_semicolon(&items); + } } if !self.eat(term) { @@ -95,6 +101,138 @@ impl<'a> Parser<'a> { Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) } + fn parse_item_in_mod( + &mut self, + term: &TokenKind, + stuck: &mut bool, + ) -> PResult<'a, Option>>> { + match self.parse_item()? { + // We just made progress and we might have statements following this item. + i @ Some(_) => { + *stuck = false; + Ok(Some(i)) + } + // No progress and the previous attempt at statements failed, so terminate the loop. + None if *stuck => Ok(None), + None => Ok(self.recover_stmts_as_item(term, stuck)?.then_some(None)), + } + } + + /// Parse a contiguous list of statements until we reach the terminating token or EOF. + /// When any statements were parsed, perform recovery and suggest wrapping the statements + /// inside a function. If `stuck` becomes `true`, then this method should not be called + /// unless we have advanced the cursor. + fn recover_stmts_as_item(&mut self, term: &TokenKind, stuck: &mut bool) -> PResult<'a, bool> { + let lo = self.token.span; + let mut stmts = vec![]; + while ![term, &token::Eof].contains(&&self.token.kind) { + let old_expected = std::mem::take(&mut self.expected_tokens); + let snapshot = self.clone(); + let stmt = self.parse_full_stmt(true); + self.expected_tokens = old_expected; // Restore expected tokens to before recovery. + match stmt { + Ok(None) => break, + Ok(Some(stmt)) => stmts.push(stmt), + Err(mut err) => { + // We couldn't parse as a statement. Rewind to the last one we could for. + // Also notify the caller that we made no progress, meaning that the method + // should not be called again to avoid non-termination. + err.cancel(); + *self = snapshot; + *stuck = true; + break; + } + } + } + + let recovered = !stmts.is_empty(); + if recovered { + // We parsed some statements and have recovered, so let's emit an error. + self.error_stmts_as_item_suggest_fn(lo, stmts); + } + Ok(recovered) + } + + fn error_stmts_as_item_suggest_fn(&self, lo: Span, stmts: Vec) { + use syntax::ast::*; + + let span = lo.to(self.prev_span); + let spans: MultiSpan = match &*stmts { + [] | [_] => span.into(), + [x, .., y] => vec![x.span, y.span].into(), + }; + + // Perform coarse grained inference about returns. + // We use this to tell whether `main` is an acceptable name + // and if `-> _` or `-> Result<_, _>` should be used instead of defaulting to unit. + #[derive(Default)] + struct RetInfer(bool, bool, bool); + let RetInfer(has_ret_unit, has_ret_expr, has_try_expr) = { + impl Visitor<'_> for RetInfer { + fn visit_expr_post(&mut self, expr: &Expr) { + match expr.kind { + ExprKind::Ret(None) => self.0 = true, // `return` + ExprKind::Ret(Some(_)) => self.1 = true, // `return $expr` + ExprKind::Try(_) => self.2 = true, // `expr?` + _ => {} + } + } + } + let mut visitor = RetInfer::default(); + for stmt in &stmts { + visitor.visit_stmt(stmt); + } + if let StmtKind::Expr(_) = &stmts.last().unwrap().kind { + visitor.1 = true; // The tail expression. + } + visitor + }; + + // For the function name, use `main` if we are in `main.rs`, and `my_function` otherwise. + let use_main = (has_ret_unit || has_try_expr) + && self.directory.path.file_stem() == Some(std::ffi::OsStr::new("main")); + let ident = Ident::from_str_and_span(if use_main { "main" } else { "my_function" }, span); + + // Construct the return type; either default, `-> _`, or `-> Result<_, _>`. + let output = match (has_ret_unit, has_ret_expr, has_try_expr) { + // `-> ()`; We either had `return;`, so return type is unit, or nothing was returned. + (true, _, _) | (false, false, false) => FnRetTy::Default(span), + // `-> Result<_, _>`; We had `?` somewhere so `-> Result<_, _>` is a good bet. + (_, _, true) => { + let arg = GenericArg::Type(self.mk_ty(span, TyKind::Infer)); + let args = [arg.clone(), arg].to_vec(); + let args = AngleBracketedArgs { span, constraints: vec![], args }; + let mut path = Path::from_ident(Ident::from_str_and_span("Result", span)); + path.segments[0].args = Some(P(GenericArgs::AngleBracketed(args))); + FnRetTy::Ty(self.mk_ty(span, TyKind::Path(None, path))) + } + // `-> _`; We had `return $expr;` so it's probably not `()` as return type. + (_, true, _) => FnRetTy::Ty(self.mk_ty(span, TyKind::Infer)), + }; + + // Finalize the AST for the function item: `fn $ident() $output { $stmts }`. + let sig = FnSig { header: FnHeader::default(), decl: P(FnDecl { inputs: vec![], output }) }; + let body = self.mk_block(stmts, BlockCheckMode::Default, span); + let kind = ItemKind::Fn(Defaultness::Final, sig, Generics::default(), Some(body)); + let vis = respan(span, VisibilityKind::Inherited); + let item = Item { span, ident, vis, kind, attrs: vec![], id: DUMMY_NODE_ID, tokens: None }; + + // Emit the error with a suggestion to wrap the statements in the function. + let mut err = self.struct_span_err(spans, "statements cannot reside in modules"); + err.span_suggestion_verbose( + span, + "consider moving the statements into a function", + pprust::item_to_string(&item), + Applicability::HasPlaceholders, + ); + err.note("the program entry point starts in `fn main() { ... }`, defined in `main.rs`"); + err.note( + "for more on functions and how to structure your program, \ + see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html", + ); + err.emit(); + } + fn submod_path( &mut self, id: ast::Ident, diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index d2a6f0b7fcf0c..47f6e5b7b6d06 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -22,14 +22,14 @@ impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. pub fn parse_stmt(&mut self) -> PResult<'a, Option> { - Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| { + Ok(self.parse_stmt_without_recovery(false).unwrap_or_else(|mut e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None })) } - fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option> { + fn parse_stmt_without_recovery(&mut self, module_stmt: bool) -> PResult<'a, Option> { maybe_whole!(self, NtStmt, |x| Some(x)); let attrs = self.parse_outer_attributes()?; @@ -56,7 +56,10 @@ impl<'a> Parser<'a> { // that starts like a path (1 token), but it fact not a path. // Also, we avoid stealing syntax from `parse_item_`. self.parse_stmt_path_start(lo, attrs)? - } else if let Some(item) = self.parse_stmt_item(attrs.clone())? { + } else if let Some(item) = + // When parsing the statement as a module (recovery), avoid parsing items. + if module_stmt { None } else { self.parse_stmt_item(attrs.clone())? } + { // FIXME: Bad copy of attrs self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) } else if self.token == token::Semi { @@ -89,7 +92,7 @@ impl<'a> Parser<'a> { fn parse_stmt_item(&mut self, attrs: Vec) -> PResult<'a, Option> { let old = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); - let item = self.parse_item_common(attrs.clone(), false, true, |_| true)?; + let item = self.parse_item_common(attrs.clone(), false, true, |_| true, false)?; self.directory.ownership = old; Ok(item) } @@ -275,7 +278,7 @@ impl<'a> Parser<'a> { // bar; // // which is valid in other languages, but not Rust. - match self.parse_stmt_without_recovery() { + match self.parse_stmt_without_recovery(true) { Ok(Some(stmt)) => { if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) || do_not_suggest_help @@ -334,7 +337,7 @@ impl<'a> Parser<'a> { if self.token == token::Eof { break; } - let stmt = match self.parse_full_stmt() { + let stmt = match self.parse_full_stmt(false) { Err(mut err) => { self.maybe_annotate_with_ascription(&mut err, false); err.emit(); @@ -354,20 +357,23 @@ impl<'a> Parser<'a> { } /// Parses a statement, including the trailing semicolon. - pub fn parse_full_stmt(&mut self) -> PResult<'a, Option> { + pub fn parse_full_stmt(&mut self, module_stmt: bool) -> PResult<'a, Option> { // Skip looking for a trailing semicolon when we have an interpolated statement. maybe_whole!(self, NtStmt, |x| Some(x)); - let mut stmt = match self.parse_stmt_without_recovery()? { + let mut stmt = match self.parse_stmt_without_recovery(module_stmt)? { Some(stmt) => stmt, None => return Ok(None), }; let mut eat_semi = true; match stmt.kind { - // Expression without semicolon. StmtKind::Expr(ref expr) - if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => + // Expression without semicolon. + if self.token != token::Eof + && classify::expr_requires_semi_to_be_stmt(expr) + // Do not error here if in `module_stmt` recovery mode. + && !module_stmt => { // Just check for errors and recover; do not eat semicolon yet. if let Err(mut e) = diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs index 74f304d81a0f1..813c9a1dcf388 100644 --- a/src/test/ui/did_you_mean/issue-40006.rs +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -1,11 +1,11 @@ impl dyn A { - Y -} //~ ERROR expected one of `!` or `::`, found `}` + Y //~ ERROR non-item in item list +} struct S; trait X { - X() {} //~ ERROR expected one of `!` or `::`, found `(` + X() {} //~ ERROR non-item in item list fn xxx() { ### } L = M; Z = { 2 + 3 }; @@ -13,19 +13,19 @@ trait X { } trait A { - X() {} //~ ERROR expected one of `!` or `::`, found `(` + X() {} //~ ERROR non-item in item list } trait B { fn xxx() { ### } //~ ERROR expected } trait C { - L = M; //~ ERROR expected one of `!` or `::`, found `=` + L = M; //~ ERROR non-item in item list } trait D { - Z = { 2 + 3 }; //~ ERROR expected one of `!` or `::`, found `=` + Z = { 2 + 3 }; //~ ERROR non-item in item list } trait E { - ::Y (); //~ ERROR expected one of + ::Y (); //~ ERROR non-item in item list } impl S { diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 613d7eee59480..787fb2e57e6c6 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,36 +1,33 @@ -error: expected one of `!` or `::`, found `}` - --> $DIR/issue-40006.rs:3:1 +error: non-item in item list + --> $DIR/issue-40006.rs:2:5 | LL | impl dyn A { - | - while parsing this item list starting here + | - item list starts here LL | Y - | - expected one of `!` or `::` + | ^ non-item starts here LL | } - | ^ - | | - | unexpected token - | the item list ends here + | - item list ends here -error: expected one of `!` or `::`, found `(` - --> $DIR/issue-40006.rs:8:6 +error: non-item in item list + --> $DIR/issue-40006.rs:8:5 | LL | trait X { - | - while parsing this item list starting here + | - item list starts here LL | X() {} - | ^ expected one of `!` or `::` + | ^ non-item starts here ... LL | } - | - the item list ends here + | - item list ends here -error: expected one of `!` or `::`, found `(` - --> $DIR/issue-40006.rs:16:6 +error: non-item in item list + --> $DIR/issue-40006.rs:16:5 | LL | trait A { - | - while parsing this item list starting here + | - item list starts here LL | X() {} - | ^ expected one of `!` or `::` + | ^ non-item starts here LL | } - | - the item list ends here + | - item list ends here error: expected `[`, found `#` --> $DIR/issue-40006.rs:19:17 @@ -38,35 +35,35 @@ error: expected `[`, found `#` LL | fn xxx() { ### } | ^ expected `[` -error: expected one of `!` or `::`, found `=` - --> $DIR/issue-40006.rs:22:7 +error: non-item in item list + --> $DIR/issue-40006.rs:22:5 | LL | trait C { - | - while parsing this item list starting here + | - item list starts here LL | L = M; - | ^ expected one of `!` or `::` + | ^ non-item starts here LL | } - | - the item list ends here + | - item list ends here -error: expected one of `!` or `::`, found `=` - --> $DIR/issue-40006.rs:25:7 +error: non-item in item list + --> $DIR/issue-40006.rs:25:5 | LL | trait D { - | - while parsing this item list starting here + | - item list starts here LL | Z = { 2 + 3 }; - | ^ expected one of `!` or `::` + | ^ non-item starts here LL | } - | - the item list ends here + | - item list ends here -error: expected one of `!` or `::`, found `(` - --> $DIR/issue-40006.rs:28:9 +error: non-item in item list + --> $DIR/issue-40006.rs:28:5 | LL | trait E { - | - while parsing this item list starting here + | - item list starts here LL | ::Y (); - | ^ expected one of `!` or `::` + | ^^ non-item starts here LL | } - | - the item list ends here + | - item list ends here error: missing `fn` for method definition --> $DIR/issue-40006.rs:32:8 diff --git a/src/test/ui/feature-gates/feature-gate-extern_prelude.rs b/src/test/ui/feature-gates/feature-gate-extern_prelude.rs index 237099e790107..ba9dc4a7c7d0f 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_prelude.rs +++ b/src/test/ui/feature-gates/feature-gate-extern_prelude.rs @@ -1 +1 @@ -can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-` +can-only-test-this-in-run-make-fulldeps //~ ERROR expected item, found `can` diff --git a/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr b/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr index d72e47e9ed8ff..22e335e5aed3c 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr +++ b/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr @@ -1,8 +1,8 @@ -error: expected one of `!` or `::`, found `-` - --> $DIR/feature-gate-extern_prelude.rs:1:4 +error: expected item, found `can` + --> $DIR/feature-gate-extern_prelude.rs:1:1 | LL | can-only-test-this-in-run-make-fulldeps - | ^ expected one of `!` or `::` + | ^^^ expected item error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21146.rs b/src/test/ui/issues/issue-21146.rs index 19eaffc3edd4a..32987fcf53cdf 100644 --- a/src/test/ui/issues/issue-21146.rs +++ b/src/test/ui/issues/issue-21146.rs @@ -1,3 +1,3 @@ -// error-pattern: expected one of `!` or `::`, found `` +// error-pattern: expected item, found `parse_error` include!("auxiliary/issue-21146-inc.rs"); fn main() {} diff --git a/src/test/ui/issues/issue-21146.stderr b/src/test/ui/issues/issue-21146.stderr index c71fda3d63fe9..f2667ce406f5c 100644 --- a/src/test/ui/issues/issue-21146.stderr +++ b/src/test/ui/issues/issue-21146.stderr @@ -1,8 +1,8 @@ -error: expected one of `!` or `::`, found `` +error: expected item, found `parse_error` --> $DIR/auxiliary/issue-21146-inc.rs:3:1 | LL | parse_error - | ^^^^^^^^^^^ expected one of `!` or `::` + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-49040.rs b/src/test/ui/issues/issue-49040.rs index b7a541dd6642a..5cd4955a9bed3 100644 --- a/src/test/ui/issues/issue-49040.rs +++ b/src/test/ui/issues/issue-49040.rs @@ -1,3 +1,3 @@ -#![allow(unused_variables)]; //~ ERROR expected item, found `;` +#![allow(unused_variables)]; //~ ERROR statements cannot reside in modules //~^ ERROR `main` function fn foo() {} diff --git a/src/test/ui/issues/issue-49040.stderr b/src/test/ui/issues/issue-49040.stderr index 4134d6aa54468..99ea38fadff00 100644 --- a/src/test/ui/issues/issue-49040.stderr +++ b/src/test/ui/issues/issue-49040.stderr @@ -1,8 +1,15 @@ -error: expected item, found `;` +error: statements cannot reside in modules --> $DIR/issue-49040.rs:1:28 | LL | #![allow(unused_variables)]; - | ^ help: remove this semicolon + | ^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | #![allow(unused_variables)]fn my_function() { } + | ^^^^^^^^^^^^^^^^^^^^ error[E0601]: `main` function not found in crate `issue_49040` --> $DIR/issue-49040.rs:1:1 @@ -10,7 +17,7 @@ error[E0601]: `main` function not found in crate `issue_49040` LL | / #![allow(unused_variables)]; LL | | LL | | fn foo() {} - | |__^ consider adding a `main` function to `$DIR/issue-49040.rs` + | |___________^ consider adding a `main` function to `$DIR/issue-49040.rs` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-62554.stderr b/src/test/ui/issues/issue-62554.stderr index 935d3842cdf61..66b7c6b2b0edb 100644 --- a/src/test/ui/issues/issue-62554.stderr +++ b/src/test/ui/issues/issue-62554.stderr @@ -60,12 +60,6 @@ LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s | -- ^^^^^^^^^^^ expected `{` | | | this `if` expression has a condition, but no block - | -help: try placing this code inside a block - | -LL | fn foo(u: u8) { if u8 { macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { -LL | } - | error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/class-implements-bad-trait.stderr b/src/test/ui/parser/class-implements-bad-trait.stderr index 3a4dea95d5ddc..cb27722a65b2b 100644 --- a/src/test/ui/parser/class-implements-bad-trait.stderr +++ b/src/test/ui/parser/class-implements-bad-trait.stderr @@ -1,8 +1,36 @@ -error: expected one of `!` or `::`, found `cat` - --> $DIR/class-implements-bad-trait.rs:2:7 +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` + --> $DIR/class-implements-bad-trait.rs:4:21 | -LL | class cat : nonexistent { - | ^^^ expected one of `!` or `::` +LL | new(in_x : usize) { self.meows = in_x; } + | ^ expected one of `.`, `;`, `?`, `}`, or an operator -error: aborting due to previous error +error: statements cannot reside in modules + --> $DIR/class-implements-bad-trait.rs:2:1 + | +LL | class cat : nonexistent { + | _^^^^^___________________^ +LL | | let meows: usize; +LL | | new(in_x : usize) { self.meows = in_x; } +LL | | } + | |_^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() -> _ { +LL | class; +LL | cat: nonexistent; +LL | { let meows: usize; (/*ERROR*/) } +LL | } + | + +error[E0425]: cannot find function `cat` in this scope + --> $DIR/class-implements-bad-trait.rs:8:14 + | +LL | let nyan = cat(0); + | ^^^ not found in this scope + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser/extern-no-fn.rs b/src/test/ui/parser/extern-no-fn.rs index d9f35e0eb5cfc..2a87950250cb8 100644 --- a/src/test/ui/parser/extern-no-fn.rs +++ b/src/test/ui/parser/extern-no-fn.rs @@ -1,5 +1,5 @@ extern { - f(); //~ ERROR expected one of `!` or `::`, found `(` + f(); //~ ERROR non-item in item list } fn main() { diff --git a/src/test/ui/parser/extern-no-fn.stderr b/src/test/ui/parser/extern-no-fn.stderr index 0151cb4235b0d..7ac5bab3ace1a 100644 --- a/src/test/ui/parser/extern-no-fn.stderr +++ b/src/test/ui/parser/extern-no-fn.stderr @@ -1,12 +1,12 @@ -error: expected one of `!` or `::`, found `(` - --> $DIR/extern-no-fn.rs:2:6 +error: non-item in item list + --> $DIR/extern-no-fn.rs:2:5 | LL | extern { - | - while parsing this item list starting here + | - item list starts here LL | f(); - | ^ expected one of `!` or `::` + | ^ non-item starts here LL | } - | - the item list ends here + | - item list ends here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-21153.rs b/src/test/ui/parser/issue-21153.rs index bf5fdb1f3c6b0..f75fce4d0796b 100644 --- a/src/test/ui/parser/issue-21153.rs +++ b/src/test/ui/parser/issue-21153.rs @@ -1,6 +1,6 @@ trait MyTrait: Iterator { Item = T; - //~^ ERROR expected one of `!` or `::`, found `=` + //~^ ERROR non-item in item list } fn main() {} diff --git a/src/test/ui/parser/issue-21153.stderr b/src/test/ui/parser/issue-21153.stderr index cbfa9ded3c393..c84d373738cd4 100644 --- a/src/test/ui/parser/issue-21153.stderr +++ b/src/test/ui/parser/issue-21153.stderr @@ -1,13 +1,13 @@ -error: expected one of `!` or `::`, found `=` - --> $DIR/issue-21153.rs:2:10 +error: non-item in item list + --> $DIR/issue-21153.rs:2:5 | LL | trait MyTrait: Iterator { - | - while parsing this item list starting here + | - item list starts here LL | Item = T; - | ^ expected one of `!` or `::` + | ^^^^ non-item starts here LL | LL | } - | - the item list ends here + | - item list ends here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-62913.rs b/src/test/ui/parser/issue-62913.rs index 0db06f636c3ec..523945bcf5279 100644 --- a/src/test/ui/parser/issue-62913.rs +++ b/src/test/ui/parser/issue-62913.rs @@ -1,4 +1,5 @@ "\u\\" //~^ ERROR incorrect unicode escape sequence //~| ERROR invalid trailing slash in literal -//~| ERROR expected item, found `"\u\\"` +//~| ERROR statements cannot reside in modules +//~| ERROR `main` function not found diff --git a/src/test/ui/parser/issue-62913.stderr b/src/test/ui/parser/issue-62913.stderr index f72174f8929b8..c019fa620e469 100644 --- a/src/test/ui/parser/issue-62913.stderr +++ b/src/test/ui/parser/issue-62913.stderr @@ -12,11 +12,25 @@ error: invalid trailing slash in literal LL | "\u\" | ^ -error: expected item, found `"\u\"` +error: statements cannot reside in modules --> $DIR/issue-62913.rs:1:1 | LL | "\u\" - | ^^^^^^ expected item + | ^^^^^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() -> _ { "\u\" } + | + +error[E0601]: `main` function not found in crate `issue_62913` + --> $DIR/issue-62913.rs:1:1 + | +LL | "\u\" + | ^^^^^^ consider adding a `main` function to `$DIR/issue-62913.rs` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/parser/module-statement-recovery/main.rs b/src/test/ui/parser/module-statement-recovery/main.rs new file mode 100644 index 0000000000000..d8b49b7aa2784 --- /dev/null +++ b/src/test/ui/parser/module-statement-recovery/main.rs @@ -0,0 +1,23 @@ +fn main() {} + +fn foo() {} + +let x = 0; //~ ERROR statements cannot reside in modules +x; +x; +x; +x; +x; +x; +foo()?; +Ok(42u16) + +struct X; + +if true {} //~ ERROR statements cannot reside in modules + +enum E {} + +x.y(); //~ ERROR statements cannot reside in modules +let x = 0; +x; diff --git a/src/test/ui/parser/module-statement-recovery/main.stderr b/src/test/ui/parser/module-statement-recovery/main.stderr new file mode 100644 index 0000000000000..bb7c2650213ea --- /dev/null +++ b/src/test/ui/parser/module-statement-recovery/main.stderr @@ -0,0 +1,52 @@ +error: statements cannot reside in modules + --> $DIR/main.rs:5:1 + | +LL | let x = 0; + | ^^^^^^^^^^ +... +LL | Ok(42u16) + | ^^^^^^^^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() -> Result<_, _> { +LL | let x = 0; +LL | x; +LL | x; +LL | x; +LL | x; + ... + +error: statements cannot reside in modules + --> $DIR/main.rs:17:1 + | +LL | if true {} + | ^^^^^^^^^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() -> _ { if true { } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: statements cannot reside in modules + --> $DIR/main.rs:21:1 + | +LL | x.y(); + | ^^^^^^ +LL | let x = 0; +LL | x; + | ^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() { x.y(); let x = 0; x; } + | + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/module-statement-recovery/recover-statements-not-main.rs b/src/test/ui/parser/module-statement-recovery/recover-statements-not-main.rs new file mode 100644 index 0000000000000..d8b49b7aa2784 --- /dev/null +++ b/src/test/ui/parser/module-statement-recovery/recover-statements-not-main.rs @@ -0,0 +1,23 @@ +fn main() {} + +fn foo() {} + +let x = 0; //~ ERROR statements cannot reside in modules +x; +x; +x; +x; +x; +x; +foo()?; +Ok(42u16) + +struct X; + +if true {} //~ ERROR statements cannot reside in modules + +enum E {} + +x.y(); //~ ERROR statements cannot reside in modules +let x = 0; +x; diff --git a/src/test/ui/parser/module-statement-recovery/recover-statements-not-main.stderr b/src/test/ui/parser/module-statement-recovery/recover-statements-not-main.stderr new file mode 100644 index 0000000000000..b3cb7c83f1354 --- /dev/null +++ b/src/test/ui/parser/module-statement-recovery/recover-statements-not-main.stderr @@ -0,0 +1,52 @@ +error: statements cannot reside in modules + --> $DIR/recover-statements-not-main.rs:5:1 + | +LL | let x = 0; + | ^^^^^^^^^^ +... +LL | Ok(42u16) + | ^^^^^^^^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() -> Result<_, _> { +LL | let x = 0; +LL | x; +LL | x; +LL | x; +LL | x; + ... + +error: statements cannot reside in modules + --> $DIR/recover-statements-not-main.rs:17:1 + | +LL | if true {} + | ^^^^^^^^^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() -> _ { if true { } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: statements cannot reside in modules + --> $DIR/recover-statements-not-main.rs:21:1 + | +LL | x.y(); + | ^^^^^^ +LL | let x = 0; +LL | x; + | ^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() { x.y(); let x = 0; x; } + | + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/underscore_item_not_const.rs b/src/test/ui/parser/underscore_item_not_const.rs index c01ac4752e075..85dccee12d978 100644 --- a/src/test/ui/parser/underscore_item_not_const.rs +++ b/src/test/ui/parser/underscore_item_not_const.rs @@ -11,6 +11,8 @@ use _ as g; //~ ERROR expected identifier, found reserved identifier `_` trait _ {} //~ ERROR expected identifier, found reserved identifier `_` trait _ = Copy; //~ ERROR expected identifier, found reserved identifier `_` macro_rules! _ { () => {} } //~ ERROR expected identifier, found reserved identifier `_` -union _ { f: u8 } //~ ERROR expected one of `!` or `::`, found reserved identifier `_` +union _ { f: u8 } +//~^ ERROR statements cannot reside in modules +//~| ERROR expected item, found reserved identifier `_` fn main() {} diff --git a/src/test/ui/parser/underscore_item_not_const.stderr b/src/test/ui/parser/underscore_item_not_const.stderr index 0bc7642dd1964..14fc5905d8e3e 100644 --- a/src/test/ui/parser/underscore_item_not_const.stderr +++ b/src/test/ui/parser/underscore_item_not_const.stderr @@ -64,11 +64,24 @@ error: expected identifier, found reserved identifier `_` LL | macro_rules! _ { () => {} } | ^ expected identifier, found reserved identifier -error: expected one of `!` or `::`, found reserved identifier `_` +error: statements cannot reside in modules + --> $DIR/underscore_item_not_const.rs:14:1 + | +LL | union _ { f: u8 } + | ^^^^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | fn my_function() -> _ { union } _ { f: u8 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected item, found reserved identifier `_` --> $DIR/underscore_item_not_const.rs:14:7 | LL | union _ { f: u8 } - | ^ expected one of `!` or `::` + | ^ expected item -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors diff --git a/src/test/ui/pub/pub-restricted-error-fn.rs b/src/test/ui/pub/pub-restricted-error-fn.rs index fc1aeae2b0cf4..ea65416a3df69 100644 --- a/src/test/ui/pub/pub-restricted-error-fn.rs +++ b/src/test/ui/pub/pub-restricted-error-fn.rs @@ -1,2 +1,4 @@ -pub(crate) () fn foo() {} //~ ERROR visibility `pub(crate)` is not followed by an item -//~^ ERROR expected item, found `(` +pub(crate) () fn foo() {} +//~^ ERROR visibility `pub(crate)` is not followed by an item +//~| ERROR statements cannot reside in modules +//~| ERROR `main` function not found diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr index 0511a821a7afd..3240791356869 100644 --- a/src/test/ui/pub/pub-restricted-error-fn.stderr +++ b/src/test/ui/pub/pub-restricted-error-fn.stderr @@ -6,11 +6,25 @@ LL | pub(crate) () fn foo() {} | = help: you likely meant to define an item, e.g., `pub(crate) fn foo() {}` -error: expected item, found `(` +error: statements cannot reside in modules --> $DIR/pub-restricted-error-fn.rs:1:12 | LL | pub(crate) () fn foo() {} - | ^ expected item + | ^^ + | + = note: the program entry point starts in `fn main() { ... }`, defined in `main.rs` + = note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html +help: consider moving the statements into a function + | +LL | pub(crate) fn my_function() -> _ { () } fn foo() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0601]: `main` function not found in crate `pub_restricted_error_fn` + --> $DIR/pub-restricted-error-fn.rs:1:1 + | +LL | pub(crate) () fn foo() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/pub-restricted-error-fn.rs` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0601`.