about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2017-11-14 17:49:29 -0800
committerEsteban Küber <esteban@kuber.com.ar>2017-11-24 07:34:31 -0800
commit547873aa54e787cbb7c266fb6e7337ea4e8a9331 (patch)
tree5bcfc4954c7f0a54618959af49ff39ddd516c754 /src
parent1737d69c3b6632d56cd66144c9316ad643fb7507 (diff)
downloadrust-547873aa54e787cbb7c266fb6e7337ea4e8a9331.tar.gz
rust-547873aa54e787cbb7c266fb6e7337ea4e8a9331.zip
Account for missing keyword in fn/struct definition
Diffstat (limited to 'src')
-rw-r--r--src/libsyntax/parse/parser.rs53
-rw-r--r--src/test/ui/suggestions/pub-ident-fn.rs15
-rw-r--r--src/test/ui/suggestions/pub-ident-fn.stderr13
-rw-r--r--src/test/ui/suggestions/pub-ident-struct.rs13
-rw-r--r--src/test/ui/suggestions/pub-ident-struct.stderr13
5 files changed, 106 insertions, 1 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0b03429ea2e..fbc12872501 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -6236,7 +6236,58 @@ impl<'a> Parser<'a> {
             return Ok(Some(macro_def));
         }
 
-        self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility)
+        // Verify wether we have encountered a struct or method definition where the user forgot to
+        // add the `struct` or `fn` keyword after writing `pub`: `pub S {}`
+        if visibility == Visibility::Public && self.check_ident() {
+            // Keep the current state of the parser to rollback after an unsuccessful attempt to
+            // parse an entire method or struct body.
+            let parser_snapshot = self.clone();
+
+            // Space between `pub` keyword and the identifier
+            //
+            //     pub   S {}
+            //        ^^^ `sp` points here
+            let sp = self.prev_span.between(self.span);
+            if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
+                // possible public struct definition where `struct` was forgotten
+                let ident = self.parse_ident().unwrap();
+                match self.parse_record_struct_body() {
+                    Err(mut err) => {
+                        // couldn't parse a struct body, continue parsing as if it were a macro
+                        err.cancel();
+                        mem::replace(self, parser_snapshot);
+                    }
+                    Ok(_) => {
+                        let msg = format!("add `struct` here to parse `{}` as a public struct",
+                                          ident);
+                        let mut err = self.diagnostic()
+                            .struct_span_err(sp, "missing `struct` for struct definition");
+                        err.span_suggestion_short(sp, &msg, " struct ".into());
+                        return Err(err);
+                    }
+                }
+            } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
+                // possible public method definition where `fn` was forgotten
+                let ident = self.parse_ident().unwrap();
+                match self.parse_fn_decl(false)
+                    .and_then(|_| self.parse_where_clause())
+                    .and_then(|_| self.parse_inner_attrs_and_block()) {
+                    Err(mut err) => {
+                        // couldn't parse method arguments or body, continue parsing
+                        err.cancel();
+                        mem::replace(self, parser_snapshot);
+                    }
+                    Ok(_) => {
+                        let msg = format!("add `fn` here to parse `{}` as a public method", ident);
+                        let mut err = self.diagnostic()
+                            .struct_span_err(sp, "missing `fn` for method definition");
+                        err.span_suggestion_short(sp, &msg, " fn ".into());
+                        return Err(err);
+                    }
+                }
+            }
+        }
+        self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)
     }
 
     /// Parse a foreign item.
diff --git a/src/test/ui/suggestions/pub-ident-fn.rs b/src/test/ui/suggestions/pub-ident-fn.rs
new file mode 100644
index 00000000000..043cf9328c9
--- /dev/null
+++ b/src/test/ui/suggestions/pub-ident-fn.rs
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub   foo(s: usize) -> bool { true }
+
+fn main() {
+    foo(2);
+}
diff --git a/src/test/ui/suggestions/pub-ident-fn.stderr b/src/test/ui/suggestions/pub-ident-fn.stderr
new file mode 100644
index 00000000000..19d3db157c2
--- /dev/null
+++ b/src/test/ui/suggestions/pub-ident-fn.stderr
@@ -0,0 +1,13 @@
+error: missing `fn` for method definition
+  --> $DIR/pub-ident-fn.rs:11:4
+   |
+11 | pub   foo(s: usize) -> bool { true }
+   |    ^^^
+   |
+help: add `fn` here to parse `foo` as a public method
+   |
+11 | pub fn foo(s: usize) -> bool { true }
+   |     ^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/suggestions/pub-ident-struct.rs b/src/test/ui/suggestions/pub-ident-struct.rs
new file mode 100644
index 00000000000..3e14a36dbab
--- /dev/null
+++ b/src/test/ui/suggestions/pub-ident-struct.rs
@@ -0,0 +1,13 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub S {
+}
+fn main() {}
diff --git a/src/test/ui/suggestions/pub-ident-struct.stderr b/src/test/ui/suggestions/pub-ident-struct.stderr
new file mode 100644
index 00000000000..bae2f6a4f80
--- /dev/null
+++ b/src/test/ui/suggestions/pub-ident-struct.stderr
@@ -0,0 +1,13 @@
+error: missing `struct` for struct definition
+  --> $DIR/pub-ident-struct.rs:11:4
+   |
+11 | pub S {
+   |    ^
+   |
+help: add `struct` here to parse `S` as a public struct
+   |
+11 | pub struct S {
+   |     ^^^^^^
+
+error: aborting due to previous error
+