Skip to content

Commit 547873a

Browse files
committed
Account for missing keyword in fn/struct definition
1 parent 1737d69 commit 547873a

File tree

5 files changed

+106
-1
lines changed

5 files changed

+106
-1
lines changed

src/libsyntax/parse/parser.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6236,7 +6236,58 @@ impl<'a> Parser<'a> {
62366236
return Ok(Some(macro_def));
62376237
}
62386238

6239-
self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility)
6239+
// Verify wether we have encountered a struct or method definition where the user forgot to
6240+
// add the `struct` or `fn` keyword after writing `pub`: `pub S {}`
6241+
if visibility == Visibility::Public && self.check_ident() {
6242+
// Keep the current state of the parser to rollback after an unsuccessful attempt to
6243+
// parse an entire method or struct body.
6244+
let parser_snapshot = self.clone();
6245+
6246+
// Space between `pub` keyword and the identifier
6247+
//
6248+
// pub S {}
6249+
// ^^^ `sp` points here
6250+
let sp = self.prev_span.between(self.span);
6251+
if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
6252+
// possible public struct definition where `struct` was forgotten
6253+
let ident = self.parse_ident().unwrap();
6254+
match self.parse_record_struct_body() {
6255+
Err(mut err) => {
6256+
// couldn't parse a struct body, continue parsing as if it were a macro
6257+
err.cancel();
6258+
mem::replace(self, parser_snapshot);
6259+
}
6260+
Ok(_) => {
6261+
let msg = format!("add `struct` here to parse `{}` as a public struct",
6262+
ident);
6263+
let mut err = self.diagnostic()
6264+
.struct_span_err(sp, "missing `struct` for struct definition");
6265+
err.span_suggestion_short(sp, &msg, " struct ".into());
6266+
return Err(err);
6267+
}
6268+
}
6269+
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
6270+
// possible public method definition where `fn` was forgotten
6271+
let ident = self.parse_ident().unwrap();
6272+
match self.parse_fn_decl(false)
6273+
.and_then(|_| self.parse_where_clause())
6274+
.and_then(|_| self.parse_inner_attrs_and_block()) {
6275+
Err(mut err) => {
6276+
// couldn't parse method arguments or body, continue parsing
6277+
err.cancel();
6278+
mem::replace(self, parser_snapshot);
6279+
}
6280+
Ok(_) => {
6281+
let msg = format!("add `fn` here to parse `{}` as a public method", ident);
6282+
let mut err = self.diagnostic()
6283+
.struct_span_err(sp, "missing `fn` for method definition");
6284+
err.span_suggestion_short(sp, &msg, " fn ".into());
6285+
return Err(err);
6286+
}
6287+
}
6288+
}
6289+
}
6290+
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)
62406291
}
62416292

62426293
/// Parse a foreign item.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub foo(s: usize) -> bool { true }
12+
13+
fn main() {
14+
foo(2);
15+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: missing `fn` for method definition
2+
--> $DIR/pub-ident-fn.rs:11:4
3+
|
4+
11 | pub foo(s: usize) -> bool { true }
5+
| ^^^
6+
|
7+
help: add `fn` here to parse `foo` as a public method
8+
|
9+
11 | pub fn foo(s: usize) -> bool { true }
10+
| ^^
11+
12+
error: aborting due to previous error
13+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub S {
12+
}
13+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: missing `struct` for struct definition
2+
--> $DIR/pub-ident-struct.rs:11:4
3+
|
4+
11 | pub S {
5+
| ^
6+
|
7+
help: add `struct` here to parse `S` as a public struct
8+
|
9+
11 | pub struct S {
10+
| ^^^^^^
11+
12+
error: aborting due to previous error
13+

0 commit comments

Comments
 (0)