Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3d8877b

Browse files
committedFeb 24, 2020
Auto merge of #69445 - Centril:soyuz, r=<try>
EXPERIMENT: Recover on stmts/exprs at module level, suggesting to wrap in function TODO: write description r? @petrochenkov @estebank
2 parents 834bc56 + 0748f60 commit 3d8877b

28 files changed

+596
-203
lines changed
 

‎src/librustc_expand/expand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ pub fn parse_ast_fragment<'a>(
887887
let mut stmts = SmallVec::new();
888888
// Won't make progress on a `}`.
889889
while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) {
890-
if let Some(stmt) = this.parse_full_stmt()? {
890+
if let Some(stmt) = this.parse_full_stmt(false)? {
891891
stmts.push(stmt);
892892
}
893893
}

‎src/librustc_parse/parser/item.rs

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl<'a> Parser<'a> {
3030

3131
fn parse_item_(&mut self, req_name: ReqName) -> PResult<'a, Option<Item>> {
3232
let attrs = self.parse_outer_attributes()?;
33-
self.parse_item_common(attrs, true, false, req_name)
33+
self.parse_item_common(attrs, true, false, req_name, true)
3434
}
3535

3636
pub(super) fn parse_item_common(
@@ -39,6 +39,7 @@ impl<'a> Parser<'a> {
3939
mac_allowed: bool,
4040
attrs_allowed: bool,
4141
req_name: ReqName,
42+
mod_stmt: bool,
4243
) -> PResult<'a, Option<Item>> {
4344
maybe_whole!(self, NtItem, |item| {
4445
let mut item = item;
@@ -49,9 +50,9 @@ impl<'a> Parser<'a> {
4950

5051
let mut unclosed_delims = vec![];
5152
let (mut item, tokens) = self.collect_tokens(|this| {
52-
let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
53+
let i = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name, mod_stmt);
5354
unclosed_delims.append(&mut this.unclosed_delims);
54-
item
55+
i
5556
})?;
5657
self.unclosed_delims.append(&mut unclosed_delims);
5758

@@ -83,11 +84,13 @@ impl<'a> Parser<'a> {
8384
mac_allowed: bool,
8485
attrs_allowed: bool,
8586
req_name: ReqName,
87+
mod_stmt: bool,
8688
) -> PResult<'a, Option<Item>> {
8789
let lo = self.token.span;
8890
let vis = self.parse_visibility(FollowedByType::No)?;
8991
let mut def = self.parse_defaultness();
90-
let kind = self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, req_name)?;
92+
let kind =
93+
self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, req_name, mod_stmt)?;
9194
if let Some((ident, kind)) = kind {
9295
self.error_on_unconsumed_default(def, &kind);
9396
let span = lo.to(self.prev_span);
@@ -148,6 +151,7 @@ impl<'a> Parser<'a> {
148151
vis: &Visibility,
149152
def: &mut Defaultness,
150153
req_name: ReqName,
154+
mod_stmt: bool,
151155
) -> PResult<'a, Option<ItemInfo>> {
152156
let mut def = || mem::replace(def, Defaultness::Final);
153157

@@ -212,9 +216,13 @@ impl<'a> Parser<'a> {
212216
} else if vis.node.is_pub() && self.isnt_macro_invocation() {
213217
self.recover_missing_kw_before_item()?;
214218
return Ok(None);
215-
} else if macros_allowed && self.token.is_path_start() {
219+
} else if let Some(kind) = if macros_allowed && self.token.is_path_start() {
220+
self.parse_item_macro(vis, mod_stmt)?
221+
} else {
222+
None
223+
} {
216224
// MACRO INVOCATION ITEM
217-
(Ident::invalid(), ItemKind::Mac(self.parse_item_macro(vis)?))
225+
(Ident::invalid(), ItemKind::Mac(kind))
218226
} else {
219227
return Ok(None);
220228
};
@@ -333,13 +341,36 @@ impl<'a> Parser<'a> {
333341
}
334342

335343
/// Parses an item macro, e.g., `item!();`.
336-
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, Mac> {
337-
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
338-
self.expect(&token::Not)?; // `!`
344+
fn parse_item_macro(&mut self, vis: &Visibility, mod_stmt: bool) -> PResult<'a, Option<Mac>> {
345+
let parse_prefix = |p: &mut Self| -> PResult<'a, ast::Path> {
346+
let path = p.parse_path(PathStyle::Mod)?; // `foo::bar`
347+
p.expect(&token::Not)?; // `!`
348+
Ok(path)
349+
};
350+
let path = if mod_stmt {
351+
// We're in statement-as-module-item recovery mode.
352+
// To avoid "stealing" syntax from e.g. `x.f()` as a module-level statement,
353+
// we backtrack if we failed to parse `$path!`; after we have, we commit firmly.
354+
// This is only done when `mod_stmt` holds to avoid backtracking inside functions.
355+
let snapshot = self.clone();
356+
match parse_prefix(self) {
357+
Ok(path) => path,
358+
Err(mut err) => {
359+
// Assert that this is only for diagnostics!
360+
// This is a safeguard against breaking LL(k) accidentally in the spec,
361+
// assuming no one has gated the syntax with something like `#[cfg(FALSE)]`.
362+
err.delay_as_bug();
363+
*self = snapshot;
364+
return Ok(None);
365+
}
366+
}
367+
} else {
368+
parse_prefix(self)?
369+
};
339370
let args = self.parse_mac_args()?; // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
340371
self.eat_semi_for_macro_if_needed(&args);
341372
self.complain_if_pub_macro(vis, false);
342-
Ok(Mac { path, args, prior_type_ascription: self.last_type_ascription })
373+
Ok(Some(Mac { path, args, prior_type_ascription: self.last_type_ascription }))
343374
}
344375

345376
/// Recover if we parsed attributes and expected an item but there was none.
@@ -647,7 +678,8 @@ impl<'a> Parser<'a> {
647678

648679
/// Parses associated items.
649680
fn parse_assoc_item(&mut self, req_name: ReqName) -> PResult<'a, Option<Option<P<AssocItem>>>> {
650-
Ok(self.parse_item_(req_name)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
681+
let item = self.parse_item_(req_name)?;
682+
Ok(item.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
651683
let kind = match kind {
652684
ItemKind::Mac(a) => AssocItemKind::Macro(a),
653685
ItemKind::Fn(a, b, c, d) => AssocItemKind::Fn(a, b, c, d),
@@ -836,7 +868,8 @@ impl<'a> Parser<'a> {
836868
pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
837869
maybe_whole!(self, NtForeignItem, |item| Some(Some(item)));
838870

839-
Ok(self.parse_item_(|_| true)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
871+
let item = self.parse_item_(|_| true)?;
872+
Ok(item.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
840873
let kind = match kind {
841874
ItemKind::Mac(a) => ForeignItemKind::Macro(a),
842875
ItemKind::Fn(a, b, c, d) => ForeignItemKind::Fn(a, b, c, d),

‎src/librustc_parse/parser/module.rs

Lines changed: 143 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ use super::Parser;
44

55
use crate::{new_sub_parser_from_file, DirectoryOwnership};
66

7-
use rustc_errors::PResult;
8-
use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP};
7+
use rustc_ast_pretty::pprust;
8+
use rustc_errors::{Applicability, PResult};
9+
use rustc_span::source_map::{respan, FileName, MultiSpan, SourceMap, Span, DUMMY_SP};
910
use rustc_span::symbol::sym;
1011
use syntax::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
1112
use syntax::attr;
13+
use syntax::ptr::P;
1214
use syntax::token::{self, TokenKind};
15+
use syntax::visit::Visitor;
1316

1417
use std::path::{self, Path, PathBuf};
1518

@@ -75,9 +78,12 @@ impl<'a> Parser<'a> {
7578
/// Given a termination token, parses all of the items in a module.
7679
fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
7780
let mut items = vec![];
78-
while let Some(item) = self.parse_item()? {
79-
items.push(item);
80-
self.maybe_consume_incorrect_semicolon(&items);
81+
let mut stuck = false;
82+
while let Some(res) = self.parse_item_in_mod(term, &mut stuck)? {
83+
if let Some(item) = res {
84+
items.push(item);
85+
self.maybe_consume_incorrect_semicolon(&items);
86+
}
8187
}
8288

8389
if !self.eat(term) {
@@ -95,6 +101,138 @@ impl<'a> Parser<'a> {
95101
Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
96102
}
97103

104+
fn parse_item_in_mod(
105+
&mut self,
106+
term: &TokenKind,
107+
stuck: &mut bool,
108+
) -> PResult<'a, Option<Option<P<ast::Item>>>> {
109+
match self.parse_item()? {
110+
// We just made progress and we might have statements following this item.
111+
i @ Some(_) => {
112+
*stuck = false;
113+
Ok(Some(i))
114+
}
115+
// No progress and the previous attempt at statements failed, so terminate the loop.
116+
None if *stuck => Ok(None),
117+
None => Ok(self.recover_stmts_as_item(term, stuck)?.then_some(None)),
118+
}
119+
}
120+
121+
/// Parse a contiguous list of statements until we reach the terminating token or EOF.
122+
/// When any statements were parsed, perform recovery and suggest wrapping the statements
123+
/// inside a function. If `stuck` becomes `true`, then this method should not be called
124+
/// unless we have advanced the cursor.
125+
fn recover_stmts_as_item(&mut self, term: &TokenKind, stuck: &mut bool) -> PResult<'a, bool> {
126+
let lo = self.token.span;
127+
let mut stmts = vec![];
128+
while ![term, &token::Eof].contains(&&self.token.kind) {
129+
let old_expected = std::mem::take(&mut self.expected_tokens);
130+
let snapshot = self.clone();
131+
let stmt = self.parse_full_stmt(true);
132+
self.expected_tokens = old_expected; // Restore expected tokens to before recovery.
133+
match stmt {
134+
Ok(None) => break,
135+
Ok(Some(stmt)) => stmts.push(stmt),
136+
Err(mut err) => {
137+
// We couldn't parse as a statement. Rewind to the last one we could for.
138+
// Also notify the caller that we made no progress, meaning that the method
139+
// should not be called again to avoid non-termination.
140+
err.cancel();
141+
*self = snapshot;
142+
*stuck = true;
143+
break;
144+
}
145+
}
146+
}
147+
148+
let recovered = !stmts.is_empty();
149+
if recovered {
150+
// We parsed some statements and have recovered, so let's emit an error.
151+
self.error_stmts_as_item_suggest_fn(lo, stmts);
152+
}
153+
Ok(recovered)
154+
}
155+
156+
fn error_stmts_as_item_suggest_fn(&self, lo: Span, stmts: Vec<ast::Stmt>) {
157+
use syntax::ast::*;
158+
159+
let span = lo.to(self.prev_span);
160+
let spans: MultiSpan = match &*stmts {
161+
[] | [_] => span.into(),
162+
[x, .., y] => vec![x.span, y.span].into(),
163+
};
164+
165+
// Perform coarse grained inference about returns.
166+
// We use this to tell whether `main` is an acceptable name
167+
// and if `-> _` or `-> Result<_, _>` should be used instead of defaulting to unit.
168+
#[derive(Default)]
169+
struct RetInfer(bool, bool, bool);
170+
let RetInfer(has_ret_unit, has_ret_expr, has_try_expr) = {
171+
impl Visitor<'_> for RetInfer {
172+
fn visit_expr_post(&mut self, expr: &Expr) {
173+
match expr.kind {
174+
ExprKind::Ret(None) => self.0 = true, // `return`
175+
ExprKind::Ret(Some(_)) => self.1 = true, // `return $expr`
176+
ExprKind::Try(_) => self.2 = true, // `expr?`
177+
_ => {}
178+
}
179+
}
180+
}
181+
let mut visitor = RetInfer::default();
182+
for stmt in &stmts {
183+
visitor.visit_stmt(stmt);
184+
}
185+
if let StmtKind::Expr(_) = &stmts.last().unwrap().kind {
186+
visitor.1 = true; // The tail expression.
187+
}
188+
visitor
189+
};
190+
191+
// For the function name, use `main` if we are in `main.rs`, and `my_function` otherwise.
192+
let use_main = (has_ret_unit || has_try_expr)
193+
&& self.directory.path.file_stem() == Some(std::ffi::OsStr::new("main"));
194+
let ident = Ident::from_str_and_span(if use_main { "main" } else { "my_function" }, span);
195+
196+
// Construct the return type; either default, `-> _`, or `-> Result<_, _>`.
197+
let output = match (has_ret_unit, has_ret_expr, has_try_expr) {
198+
// `-> ()`; We either had `return;`, so return type is unit, or nothing was returned.
199+
(true, _, _) | (false, false, false) => FnRetTy::Default(span),
200+
// `-> Result<_, _>`; We had `?` somewhere so `-> Result<_, _>` is a good bet.
201+
(_, _, true) => {
202+
let arg = GenericArg::Type(self.mk_ty(span, TyKind::Infer));
203+
let args = [arg.clone(), arg].to_vec();
204+
let args = AngleBracketedArgs { span, constraints: vec![], args };
205+
let mut path = Path::from_ident(Ident::from_str_and_span("Result", span));
206+
path.segments[0].args = Some(P(GenericArgs::AngleBracketed(args)));
207+
FnRetTy::Ty(self.mk_ty(span, TyKind::Path(None, path)))
208+
}
209+
// `-> _`; We had `return $expr;` so it's probably not `()` as return type.
210+
(_, true, _) => FnRetTy::Ty(self.mk_ty(span, TyKind::Infer)),
211+
};
212+
213+
// Finalize the AST for the function item: `fn $ident() $output { $stmts }`.
214+
let sig = FnSig { header: FnHeader::default(), decl: P(FnDecl { inputs: vec![], output }) };
215+
let body = self.mk_block(stmts, BlockCheckMode::Default, span);
216+
let kind = ItemKind::Fn(Defaultness::Final, sig, Generics::default(), Some(body));
217+
let vis = respan(span, VisibilityKind::Inherited);
218+
let item = Item { span, ident, vis, kind, attrs: vec![], id: DUMMY_NODE_ID, tokens: None };
219+
220+
// Emit the error with a suggestion to wrap the statements in the function.
221+
let mut err = self.struct_span_err(spans, "statements cannot reside in modules");
222+
err.span_suggestion_verbose(
223+
span,
224+
"consider moving the statements into a function",
225+
pprust::item_to_string(&item),
226+
Applicability::HasPlaceholders,
227+
);
228+
err.note("the program entry point starts in `fn main() { ... }`, defined in `main.rs`");
229+
err.note(
230+
"for more on functions and how to structure your program, \
231+
see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html",
232+
);
233+
err.emit();
234+
}
235+
98236
fn submod_path(
99237
&mut self,
100238
id: ast::Ident,

‎src/librustc_parse/parser/stmt.rs

Lines changed: 98 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -22,74 +22,49 @@ impl<'a> Parser<'a> {
2222
/// Parses a statement. This stops just before trailing semicolons on everything but items.
2323
/// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
2424
pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
25-
Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| {
25+
Ok(self.parse_stmt_without_recovery(false).unwrap_or_else(|mut e| {
2626
e.emit();
2727
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
2828
None
2929
}))
3030
}
3131

32-
fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> {
32+
fn parse_stmt_without_recovery(&mut self, module_stmt: bool) -> PResult<'a, Option<Stmt>> {
3333
maybe_whole!(self, NtStmt, |x| Some(x));
3434

3535
let attrs = self.parse_outer_attributes()?;
3636
let lo = self.token.span;
3737

38-
if self.eat_keyword(kw::Let) {
39-
return self.parse_local_mk(lo, attrs.into()).map(Some);
40-
}
41-
if self.is_kw_followed_by_ident(kw::Mut) {
42-
return self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut");
43-
}
44-
if self.is_kw_followed_by_ident(kw::Auto) {
38+
let stmt = if self.eat_keyword(kw::Let) {
39+
self.parse_local_mk(lo, attrs.into())?
40+
} else if self.is_kw_followed_by_ident(kw::Mut) {
41+
self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
42+
} else if self.is_kw_followed_by_ident(kw::Auto) {
4543
self.bump(); // `auto`
4644
let msg = "write `let` instead of `auto` to introduce a new variable";
47-
return self.recover_stmt_local(lo, attrs.into(), msg, "let");
48-
}
49-
if self.is_kw_followed_by_ident(sym::var) {
45+
self.recover_stmt_local(lo, attrs.into(), msg, "let")?
46+
} else if self.is_kw_followed_by_ident(sym::var) {
5047
self.bump(); // `var`
5148
let msg = "write `let` instead of `var` to introduce a new variable";
52-
return self.recover_stmt_local(lo, attrs.into(), msg, "let");
53-
}
54-
55-
// Starts like a simple path, being careful to avoid contextual keywords,
56-
// e.g., `union`, items with `crate` visibility, or `auto trait` items.
57-
// We aim to parse an arbitrary path `a::b` but not something that starts like a path
58-
// (1 token), but it fact not a path. Also, we avoid stealing syntax from `parse_item_`.
59-
if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_path_start_item()
49+
self.recover_stmt_local(lo, attrs.into(), msg, "let")?
50+
} else if self.token.is_path_start()
51+
&& !self.token.is_qpath_start()
52+
&& !self.is_path_start_item()
6053
{
61-
let path = self.parse_path(PathStyle::Expr)?;
62-
63-
if self.eat(&token::Not) {
64-
return self.parse_stmt_mac(lo, attrs.into(), path);
65-
}
66-
67-
let expr = if self.check(&token::OpenDelim(token::Brace)) {
68-
self.parse_struct_expr(lo, path, AttrVec::new())?
69-
} else {
70-
let hi = self.prev_span;
71-
self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
72-
};
73-
74-
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
75-
let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
76-
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
77-
})?;
78-
return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr))));
79-
}
80-
81-
// FIXME: Bad copy of attrs
82-
let old_directory_ownership =
83-
mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
84-
let item = self.parse_item_common(attrs.clone(), false, true, |_| true)?;
85-
self.directory.ownership = old_directory_ownership;
86-
87-
if let Some(item) = item {
88-
return Ok(Some(self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))));
54+
// We have avoided contextual keywords like `union`, items with `crate` visibility,
55+
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
56+
// that starts like a path (1 token), but it fact not a path.
57+
// Also, we avoid stealing syntax from `parse_item_`.
58+
self.parse_stmt_path_start(lo, attrs)?
59+
} else if let Some(item) =
60+
// When parsing the statement as a module (recovery), avoid parsing items.
61+
if module_stmt { None } else { self.parse_stmt_item(attrs.clone())? }
62+
{
63+
// FIXME: Bad copy of attrs
64+
self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
8965
}
90-
9166
// Do not attempt to parse an expression if we're done here.
92-
if self.token == token::Semi {
67+
else if self.token == token::Semi {
9368
self.error_outer_attrs(&attrs);
9469
self.bump();
9570
let mut last_semi = lo;
@@ -104,27 +79,49 @@ impl<'a> Parser<'a> {
10479
ExprKind::Tup(Vec::new()),
10580
AttrVec::new(),
10681
));
107-
return Ok(Some(self.mk_stmt(lo.to(last_semi), kind)));
108-
}
109-
110-
if self.token == token::CloseDelim(token::Brace) {
82+
self.mk_stmt(lo.to(last_semi), kind)
83+
} else if self.token != token::CloseDelim(token::Brace) {
84+
// Remainder are line-expr stmts.
85+
let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
86+
self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
87+
} else {
11188
self.error_outer_attrs(&attrs);
11289
return Ok(None);
90+
};
91+
Ok(Some(stmt))
92+
}
93+
94+
fn parse_stmt_item(&mut self, attrs: Vec<Attribute>) -> PResult<'a, Option<ast::Item>> {
95+
let old = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
96+
let item = self.parse_item_common(attrs.clone(), false, true, |_| true, false)?;
97+
self.directory.ownership = old;
98+
Ok(item)
99+
}
100+
101+
fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, Stmt> {
102+
let path = self.parse_path(PathStyle::Expr)?;
103+
104+
if self.eat(&token::Not) {
105+
return self.parse_stmt_mac(lo, attrs.into(), path);
113106
}
114107

115-
// Remainder are line-expr stmts.
116-
let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
117-
Ok(Some(self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))))
108+
let expr = if self.check(&token::OpenDelim(token::Brace)) {
109+
self.parse_struct_expr(lo, path, AttrVec::new())?
110+
} else {
111+
let hi = self.prev_span;
112+
self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
113+
};
114+
115+
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
116+
let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
117+
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
118+
})?;
119+
Ok(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr)))
118120
}
119121

120122
/// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
121123
/// At this point, the `!` token after the path has already been eaten.
122-
fn parse_stmt_mac(
123-
&mut self,
124-
lo: Span,
125-
attrs: AttrVec,
126-
path: ast::Path,
127-
) -> PResult<'a, Option<Stmt>> {
124+
fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> {
128125
let args = self.parse_mac_args()?;
129126
let delim = args.delim();
130127
let hi = self.prev_span;
@@ -145,7 +142,7 @@ impl<'a> Parser<'a> {
145142
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
146143
StmtKind::Expr(e)
147144
};
148-
Ok(Some(self.mk_stmt(lo.to(hi), kind)))
145+
Ok(self.mk_stmt(lo.to(hi), kind))
149146
}
150147

151148
/// Error on outer attributes in this context.
@@ -167,12 +164,12 @@ impl<'a> Parser<'a> {
167164
attrs: AttrVec,
168165
msg: &str,
169166
sugg: &str,
170-
) -> PResult<'a, Option<Stmt>> {
167+
) -> PResult<'a, Stmt> {
171168
let stmt = self.parse_local_mk(lo, attrs)?;
172169
self.struct_span_err(lo, "invalid variable declaration")
173170
.span_suggestion(lo, msg, sugg.to_string(), Applicability::MachineApplicable)
174171
.emit();
175-
Ok(Some(stmt))
172+
Ok(stmt)
176173
}
177174

178175
fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
@@ -282,7 +279,7 @@ impl<'a> Parser<'a> {
282279
// bar;
283280
//
284281
// which is valid in other languages, but not Rust.
285-
match self.parse_stmt_without_recovery() {
282+
match self.parse_stmt_without_recovery(true) {
286283
Ok(Some(stmt)) => {
287284
if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
288285
|| do_not_suggest_help
@@ -341,7 +338,7 @@ impl<'a> Parser<'a> {
341338
if self.token == token::Eof {
342339
break;
343340
}
344-
let stmt = match self.parse_full_stmt() {
341+
let stmt = match self.parse_full_stmt(false) {
345342
Err(mut err) => {
346343
self.maybe_annotate_with_ascription(&mut err, false);
347344
err.emit();
@@ -361,47 +358,50 @@ impl<'a> Parser<'a> {
361358
}
362359

363360
/// Parses a statement, including the trailing semicolon.
364-
pub fn parse_full_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
361+
pub fn parse_full_stmt(&mut self, module_stmt: bool) -> PResult<'a, Option<Stmt>> {
365362
// Skip looking for a trailing semicolon when we have an interpolated statement.
366363
maybe_whole!(self, NtStmt, |x| Some(x));
367364

368-
let mut stmt = match self.parse_stmt_without_recovery()? {
365+
let mut stmt = match self.parse_stmt_without_recovery(module_stmt)? {
369366
Some(stmt) => stmt,
370367
None => return Ok(None),
371368
};
372369

373370
let mut eat_semi = true;
374371
match stmt.kind {
375-
StmtKind::Expr(ref expr) if self.token != token::Eof => {
376-
// expression without semicolon
377-
if classify::expr_requires_semi_to_be_stmt(expr) {
378-
// Just check for errors and recover; do not eat semicolon yet.
379-
if let Err(mut e) =
380-
self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)])
381-
{
382-
if let TokenKind::DocComment(..) = self.token.kind {
383-
if let Ok(snippet) = self.span_to_snippet(self.token.span) {
384-
let sp = self.token.span;
385-
let marker = &snippet[..3];
386-
let (comment_marker, doc_comment_marker) = marker.split_at(2);
387-
388-
e.span_suggestion(
389-
sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
390-
&format!(
391-
"add a space before `{}` to use a regular comment",
392-
doc_comment_marker,
393-
),
394-
format!("{} {}", comment_marker, doc_comment_marker),
395-
Applicability::MaybeIncorrect,
396-
);
397-
}
372+
StmtKind::Expr(ref expr)
373+
// Expression without semicolon.
374+
if self.token != token::Eof
375+
&& classify::expr_requires_semi_to_be_stmt(expr)
376+
// Do not error here if in `module_stmt` recovery mode.
377+
&& !module_stmt =>
378+
{
379+
// Just check for errors and recover; do not eat semicolon yet.
380+
if let Err(mut e) =
381+
self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)])
382+
{
383+
if let TokenKind::DocComment(..) = self.token.kind {
384+
if let Ok(snippet) = self.span_to_snippet(self.token.span) {
385+
let sp = self.token.span;
386+
let marker = &snippet[..3];
387+
let (comment_marker, doc_comment_marker) = marker.split_at(2);
388+
389+
e.span_suggestion(
390+
sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
391+
&format!(
392+
"add a space before `{}` to use a regular comment",
393+
doc_comment_marker,
394+
),
395+
format!("{} {}", comment_marker, doc_comment_marker),
396+
Applicability::MaybeIncorrect,
397+
);
398398
}
399-
e.emit();
400-
self.recover_stmt();
401-
// Don't complain about type errors in body tail after parse error (#57383).
402-
let sp = expr.span.to(self.prev_span);
403-
stmt.kind = StmtKind::Expr(self.mk_expr_err(sp));
404399
}
400+
e.emit();
401+
self.recover_stmt();
402+
// Don't complain about type errors in body tail after parse error (#57383).
403+
let sp = expr.span.to(self.prev_span);
404+
stmt.kind = StmtKind::Expr(self.mk_expr_err(sp));
405405
}
406406
}
407407
StmtKind::Local(..) => {

‎src/test/ui/did_you_mean/issue-40006.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
impl dyn A {
2-
Y
3-
} //~ ERROR expected one of `!` or `::`, found `}`
2+
Y //~ ERROR non-item in item list
3+
}
44

55
struct S;
66

77
trait X {
8-
X() {} //~ ERROR expected one of `!` or `::`, found `(`
8+
X() {} //~ ERROR non-item in item list
99
fn xxx() { ### }
1010
L = M;
1111
Z = { 2 + 3 };
1212
::Y ();
1313
}
1414

1515
trait A {
16-
X() {} //~ ERROR expected one of `!` or `::`, found `(`
16+
X() {} //~ ERROR non-item in item list
1717
}
1818
trait B {
1919
fn xxx() { ### } //~ ERROR expected
2020
}
2121
trait C {
22-
L = M; //~ ERROR expected one of `!` or `::`, found `=`
22+
L = M; //~ ERROR non-item in item list
2323
}
2424
trait D {
25-
Z = { 2 + 3 }; //~ ERROR expected one of `!` or `::`, found `=`
25+
Z = { 2 + 3 }; //~ ERROR non-item in item list
2626
}
2727
trait E {
28-
::Y (); //~ ERROR expected one of
28+
::Y (); //~ ERROR non-item in item list
2929
}
3030

3131
impl S {

‎src/test/ui/did_you_mean/issue-40006.stderr

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,69 @@
1-
error: expected one of `!` or `::`, found `}`
2-
--> $DIR/issue-40006.rs:3:1
1+
error: non-item in item list
2+
--> $DIR/issue-40006.rs:2:5
33
|
44
LL | impl dyn A {
5-
| - while parsing this item list starting here
5+
| - item list starts here
66
LL | Y
7-
| - expected one of `!` or `::`
7+
| ^ non-item starts here
88
LL | }
9-
| ^
10-
| |
11-
| unexpected token
12-
| the item list ends here
9+
| - item list ends here
1310

14-
error: expected one of `!` or `::`, found `(`
15-
--> $DIR/issue-40006.rs:8:6
11+
error: non-item in item list
12+
--> $DIR/issue-40006.rs:8:5
1613
|
1714
LL | trait X {
18-
| - while parsing this item list starting here
15+
| - item list starts here
1916
LL | X() {}
20-
| ^ expected one of `!` or `::`
17+
| ^ non-item starts here
2118
...
2219
LL | }
23-
| - the item list ends here
20+
| - item list ends here
2421

25-
error: expected one of `!` or `::`, found `(`
26-
--> $DIR/issue-40006.rs:16:6
22+
error: non-item in item list
23+
--> $DIR/issue-40006.rs:16:5
2724
|
2825
LL | trait A {
29-
| - while parsing this item list starting here
26+
| - item list starts here
3027
LL | X() {}
31-
| ^ expected one of `!` or `::`
28+
| ^ non-item starts here
3229
LL | }
33-
| - the item list ends here
30+
| - item list ends here
3431

3532
error: expected `[`, found `#`
3633
--> $DIR/issue-40006.rs:19:17
3734
|
3835
LL | fn xxx() { ### }
3936
| ^ expected `[`
4037

41-
error: expected one of `!` or `::`, found `=`
42-
--> $DIR/issue-40006.rs:22:7
38+
error: non-item in item list
39+
--> $DIR/issue-40006.rs:22:5
4340
|
4441
LL | trait C {
45-
| - while parsing this item list starting here
42+
| - item list starts here
4643
LL | L = M;
47-
| ^ expected one of `!` or `::`
44+
| ^ non-item starts here
4845
LL | }
49-
| - the item list ends here
46+
| - item list ends here
5047

51-
error: expected one of `!` or `::`, found `=`
52-
--> $DIR/issue-40006.rs:25:7
48+
error: non-item in item list
49+
--> $DIR/issue-40006.rs:25:5
5350
|
5451
LL | trait D {
55-
| - while parsing this item list starting here
52+
| - item list starts here
5653
LL | Z = { 2 + 3 };
57-
| ^ expected one of `!` or `::`
54+
| ^ non-item starts here
5855
LL | }
59-
| - the item list ends here
56+
| - item list ends here
6057

61-
error: expected one of `!` or `::`, found `(`
62-
--> $DIR/issue-40006.rs:28:9
58+
error: non-item in item list
59+
--> $DIR/issue-40006.rs:28:5
6360
|
6461
LL | trait E {
65-
| - while parsing this item list starting here
62+
| - item list starts here
6663
LL | ::Y ();
67-
| ^ expected one of `!` or `::`
64+
| ^^ non-item starts here
6865
LL | }
69-
| - the item list ends here
66+
| - item list ends here
7067

7168
error: missing `fn` for method definition
7269
--> $DIR/issue-40006.rs:32:8
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-`
1+
can-only-test-this-in-run-make-fulldeps //~ ERROR expected item, found `can`
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected one of `!` or `::`, found `-`
2-
--> $DIR/feature-gate-extern_prelude.rs:1:4
1+
error: expected item, found `can`
2+
--> $DIR/feature-gate-extern_prelude.rs:1:1
33
|
44
LL | can-only-test-this-in-run-make-fulldeps
5-
| ^ expected one of `!` or `::`
5+
| ^^^ expected item
66

77
error: aborting due to previous error
88

‎src/test/ui/issues/issue-21146.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
// error-pattern: expected one of `!` or `::`, found `<eof>`
1+
// error-pattern: expected item, found `parse_error`
22
include!("auxiliary/issue-21146-inc.rs");
33
fn main() {}

‎src/test/ui/issues/issue-21146.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected one of `!` or `::`, found `<eof>`
1+
error: expected item, found `parse_error`
22
--> $DIR/auxiliary/issue-21146-inc.rs:3:1
33
|
44
LL | parse_error
5-
| ^^^^^^^^^^^ expected one of `!` or `::`
5+
| ^^^^^^^^^^^
66

77
error: aborting due to previous error
88

‎src/test/ui/issues/issue-49040.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
#![allow(unused_variables)]; //~ ERROR expected item, found `;`
1+
#![allow(unused_variables)]; //~ ERROR statements cannot reside in modules
22
//~^ ERROR `main` function
33
fn foo() {}

‎src/test/ui/issues/issue-49040.stderr

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1-
error: expected item, found `;`
1+
error: statements cannot reside in modules
22
--> $DIR/issue-49040.rs:1:28
33
|
44
LL | #![allow(unused_variables)];
5-
| ^ help: remove this semicolon
5+
| ^
6+
|
7+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
8+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
9+
help: consider moving the statements into a function
10+
|
11+
LL | #![allow(unused_variables)]fn my_function() { }
12+
| ^^^^^^^^^^^^^^^^^^^^
613

714
error[E0601]: `main` function not found in crate `issue_49040`
815
--> $DIR/issue-49040.rs:1:1
916
|
1017
LL | / #![allow(unused_variables)];
1118
LL | |
1219
LL | | fn foo() {}
13-
| |__^ consider adding a `main` function to `$DIR/issue-49040.rs`
20+
| |___________^ consider adding a `main` function to `$DIR/issue-49040.rs`
1421

1522
error: aborting due to 2 previous errors
1623

‎src/test/ui/issues/issue-62554.stderr

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,6 @@ LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s
6060
| -- ^^^^^^^^^^^ expected `{`
6161
| |
6262
| this `if` expression has a condition, but no block
63-
|
64-
help: try placing this code inside a block
65-
|
66-
LL | fn foo(u: u8) { if u8 { macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
67-
LL | }
68-
|
6963

7064
error: aborting due to 6 previous errors
7165

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,36 @@
1-
error: expected one of `!` or `::`, found `cat`
2-
--> $DIR/class-implements-bad-trait.rs:2:7
1+
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
2+
--> $DIR/class-implements-bad-trait.rs:4:21
33
|
4-
LL | class cat : nonexistent {
5-
| ^^^ expected one of `!` or `::`
4+
LL | new(in_x : usize) { self.meows = in_x; }
5+
| ^ expected one of `.`, `;`, `?`, `}`, or an operator
66

7-
error: aborting due to previous error
7+
error: statements cannot reside in modules
8+
--> $DIR/class-implements-bad-trait.rs:2:1
9+
|
10+
LL | class cat : nonexistent {
11+
| _^^^^^___________________^
12+
LL | | let meows: usize;
13+
LL | | new(in_x : usize) { self.meows = in_x; }
14+
LL | | }
15+
| |_^
16+
|
17+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
18+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
19+
help: consider moving the statements into a function
20+
|
21+
LL | fn my_function() -> _ {
22+
LL | class;
23+
LL | cat: nonexistent;
24+
LL | { let meows: usize; (/*ERROR*/) }
25+
LL | }
26+
|
27+
28+
error[E0425]: cannot find function `cat` in this scope
29+
--> $DIR/class-implements-bad-trait.rs:8:14
30+
|
31+
LL | let nyan = cat(0);
32+
| ^^^ not found in this scope
33+
34+
error: aborting due to 3 previous errors
835

36+
For more information about this error, try `rustc --explain E0425`.

‎src/test/ui/parser/extern-no-fn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
extern {
2-
f(); //~ ERROR expected one of `!` or `::`, found `(`
2+
f(); //~ ERROR non-item in item list
33
}
44

55
fn main() {
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
error: expected one of `!` or `::`, found `(`
2-
--> $DIR/extern-no-fn.rs:2:6
1+
error: non-item in item list
2+
--> $DIR/extern-no-fn.rs:2:5
33
|
44
LL | extern {
5-
| - while parsing this item list starting here
5+
| - item list starts here
66
LL | f();
7-
| ^ expected one of `!` or `::`
7+
| ^ non-item starts here
88
LL | }
9-
| - the item list ends here
9+
| - item list ends here
1010

1111
error: aborting due to previous error
1212

‎src/test/ui/parser/issue-21153.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
trait MyTrait<T>: Iterator {
22
Item = T;
3-
//~^ ERROR expected one of `!` or `::`, found `=`
3+
//~^ ERROR non-item in item list
44
}
55

66
fn main() {}

‎src/test/ui/parser/issue-21153.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
error: expected one of `!` or `::`, found `=`
2-
--> $DIR/issue-21153.rs:2:10
1+
error: non-item in item list
2+
--> $DIR/issue-21153.rs:2:5
33
|
44
LL | trait MyTrait<T>: Iterator {
5-
| - while parsing this item list starting here
5+
| - item list starts here
66
LL | Item = T;
7-
| ^ expected one of `!` or `::`
7+
| ^^^^ non-item starts here
88
LL |
99
LL | }
10-
| - the item list ends here
10+
| - item list ends here
1111

1212
error: aborting due to previous error
1313

‎src/test/ui/parser/issue-62913.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"\u\\"
22
//~^ ERROR incorrect unicode escape sequence
33
//~| ERROR invalid trailing slash in literal
4-
//~| ERROR expected item, found `"\u\\"`
4+
//~| ERROR statements cannot reside in modules
5+
//~| ERROR `main` function not found

‎src/test/ui/parser/issue-62913.stderr

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,25 @@ error: invalid trailing slash in literal
1212
LL | "\u\"
1313
| ^
1414

15-
error: expected item, found `"\u\"`
15+
error: statements cannot reside in modules
1616
--> $DIR/issue-62913.rs:1:1
1717
|
1818
LL | "\u\"
19-
| ^^^^^^ expected item
19+
| ^^^^^^
20+
|
21+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
22+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
23+
help: consider moving the statements into a function
24+
|
25+
LL | fn my_function() -> _ { "\u\" }
26+
|
27+
28+
error[E0601]: `main` function not found in crate `issue_62913`
29+
--> $DIR/issue-62913.rs:1:1
30+
|
31+
LL | "\u\"
32+
| ^^^^^^ consider adding a `main` function to `$DIR/issue-62913.rs`
2033

21-
error: aborting due to 3 previous errors
34+
error: aborting due to 4 previous errors
2235

36+
For more information about this error, try `rustc --explain E0601`.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
fn main() {}
2+
3+
fn foo() {}
4+
5+
let x = 0; //~ ERROR statements cannot reside in modules
6+
x;
7+
x;
8+
x;
9+
x;
10+
x;
11+
x;
12+
foo()?;
13+
Ok(42u16)
14+
15+
struct X;
16+
17+
if true {} //~ ERROR statements cannot reside in modules
18+
19+
enum E {}
20+
21+
x.y(); //~ ERROR statements cannot reside in modules
22+
let x = 0;
23+
x;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: statements cannot reside in modules
2+
--> $DIR/main.rs:5:1
3+
|
4+
LL | let x = 0;
5+
| ^^^^^^^^^^
6+
...
7+
LL | Ok(42u16)
8+
| ^^^^^^^^^
9+
|
10+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
11+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
12+
help: consider moving the statements into a function
13+
|
14+
LL | fn my_function() -> Result<_, _> {
15+
LL | let x = 0;
16+
LL | x;
17+
LL | x;
18+
LL | x;
19+
LL | x;
20+
...
21+
22+
error: statements cannot reside in modules
23+
--> $DIR/main.rs:17:1
24+
|
25+
LL | if true {}
26+
| ^^^^^^^^^^
27+
|
28+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
29+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
30+
help: consider moving the statements into a function
31+
|
32+
LL | fn my_function() -> _ { if true { } }
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
35+
error: statements cannot reside in modules
36+
--> $DIR/main.rs:21:1
37+
|
38+
LL | x.y();
39+
| ^^^^^^
40+
LL | let x = 0;
41+
LL | x;
42+
| ^^
43+
|
44+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
45+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
46+
help: consider moving the statements into a function
47+
|
48+
LL | fn my_function() { x.y(); let x = 0; x; }
49+
|
50+
51+
error: aborting due to 3 previous errors
52+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
fn main() {}
2+
3+
fn foo() {}
4+
5+
let x = 0; //~ ERROR statements cannot reside in modules
6+
x;
7+
x;
8+
x;
9+
x;
10+
x;
11+
x;
12+
foo()?;
13+
Ok(42u16)
14+
15+
struct X;
16+
17+
if true {} //~ ERROR statements cannot reside in modules
18+
19+
enum E {}
20+
21+
x.y(); //~ ERROR statements cannot reside in modules
22+
let x = 0;
23+
x;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: statements cannot reside in modules
2+
--> $DIR/recover-statements-not-main.rs:5:1
3+
|
4+
LL | let x = 0;
5+
| ^^^^^^^^^^
6+
...
7+
LL | Ok(42u16)
8+
| ^^^^^^^^^
9+
|
10+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
11+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
12+
help: consider moving the statements into a function
13+
|
14+
LL | fn my_function() -> Result<_, _> {
15+
LL | let x = 0;
16+
LL | x;
17+
LL | x;
18+
LL | x;
19+
LL | x;
20+
...
21+
22+
error: statements cannot reside in modules
23+
--> $DIR/recover-statements-not-main.rs:17:1
24+
|
25+
LL | if true {}
26+
| ^^^^^^^^^^
27+
|
28+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
29+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
30+
help: consider moving the statements into a function
31+
|
32+
LL | fn my_function() -> _ { if true { } }
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
35+
error: statements cannot reside in modules
36+
--> $DIR/recover-statements-not-main.rs:21:1
37+
|
38+
LL | x.y();
39+
| ^^^^^^
40+
LL | let x = 0;
41+
LL | x;
42+
| ^^
43+
|
44+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
45+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
46+
help: consider moving the statements into a function
47+
|
48+
LL | fn my_function() { x.y(); let x = 0; x; }
49+
|
50+
51+
error: aborting due to 3 previous errors
52+

‎src/test/ui/parser/underscore_item_not_const.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use _ as g; //~ ERROR expected identifier, found reserved identifier `_`
1111
trait _ {} //~ ERROR expected identifier, found reserved identifier `_`
1212
trait _ = Copy; //~ ERROR expected identifier, found reserved identifier `_`
1313
macro_rules! _ { () => {} } //~ ERROR expected identifier, found reserved identifier `_`
14-
union _ { f: u8 } //~ ERROR expected one of `!` or `::`, found reserved identifier `_`
14+
union _ { f: u8 }
15+
//~^ ERROR statements cannot reside in modules
16+
//~| ERROR expected item, found reserved identifier `_`
1517

1618
fn main() {}

‎src/test/ui/parser/underscore_item_not_const.stderr

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,24 @@ error: expected identifier, found reserved identifier `_`
6464
LL | macro_rules! _ { () => {} }
6565
| ^ expected identifier, found reserved identifier
6666

67-
error: expected one of `!` or `::`, found reserved identifier `_`
67+
error: statements cannot reside in modules
68+
--> $DIR/underscore_item_not_const.rs:14:1
69+
|
70+
LL | union _ { f: u8 }
71+
| ^^^^^
72+
|
73+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
74+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
75+
help: consider moving the statements into a function
76+
|
77+
LL | fn my_function() -> _ { union } _ { f: u8 }
78+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
79+
80+
error: expected item, found reserved identifier `_`
6881
--> $DIR/underscore_item_not_const.rs:14:7
6982
|
7083
LL | union _ { f: u8 }
71-
| ^ expected one of `!` or `::`
84+
| ^ expected item
7285

73-
error: aborting due to 12 previous errors
86+
error: aborting due to 13 previous errors
7487

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
pub(crate) () fn foo() {} //~ ERROR visibility `pub(crate)` is not followed by an item
2-
//~^ ERROR expected item, found `(`
1+
pub(crate) () fn foo() {}
2+
//~^ ERROR visibility `pub(crate)` is not followed by an item
3+
//~| ERROR statements cannot reside in modules
4+
//~| ERROR `main` function not found

‎src/test/ui/pub/pub-restricted-error-fn.stderr

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,25 @@ LL | pub(crate) () fn foo() {}
66
|
77
= help: you likely meant to define an item, e.g., `pub(crate) fn foo() {}`
88

9-
error: expected item, found `(`
9+
error: statements cannot reside in modules
1010
--> $DIR/pub-restricted-error-fn.rs:1:12
1111
|
1212
LL | pub(crate) () fn foo() {}
13-
| ^ expected item
13+
| ^^
14+
|
15+
= note: the program entry point starts in `fn main() { ... }`, defined in `main.rs`
16+
= note: for more on functions and how to structure your program, see https://doc.rust-lang.org/book/ch03-03-how-functions-work.html
17+
help: consider moving the statements into a function
18+
|
19+
LL | pub(crate) fn my_function() -> _ { () } fn foo() {}
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21+
22+
error[E0601]: `main` function not found in crate `pub_restricted_error_fn`
23+
--> $DIR/pub-restricted-error-fn.rs:1:1
24+
|
25+
LL | pub(crate) () fn foo() {}
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/pub-restricted-error-fn.rs`
1427

15-
error: aborting due to 2 previous errors
28+
error: aborting due to 3 previous errors
1629

30+
For more information about this error, try `rustc --explain E0601`.

0 commit comments

Comments
 (0)
Please sign in to comment.