about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2017-03-24 23:00:21 -0700
committerEsteban Küber <esteban@kuber.com.ar>2017-03-24 23:06:00 -0700
commit57009caabd2a45a6efa4d36149feec39ab0a0658 (patch)
treefbf7cad105ada8a7db30f266ce8b6313eeb62174 /src/libsyntax/parse
parentc62e532f3de4c0254b772c36fe629b2042efd107 (diff)
downloadrust-57009caabd2a45a6efa4d36149feec39ab0a0658.tar.gz
rust-57009caabd2a45a6efa4d36149feec39ab0a0658.zip
Identify missing item category in `impl`s
```rust
struct S;
impl S {
    pub hello_method(&self) {
        println!("Hello");
    }
}
fn main() { S.hello_method(); }
```

```rust
error: can't qualify macro invocation with `pub`
 --> file.rs:3:4
  |
3 |     pub hello_method(&self) {
  |     ^^^-            - expected `!` here for a macro invocation
  |        |
  |        did you mean to write `fn` here for a method declaration?
  |
  = help: try adjusting the macro to put `pub` inside the invocation
```
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs62
1 files changed, 47 insertions, 15 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index df4ccc94c04..a19339f8cc1 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -4660,25 +4660,30 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) {
-        match *visa {
-            Visibility::Inherited => (),
+    fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) {
+        if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) {
+            err.emit();
+        }
+    }
+
+    fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> {
+        match *vis {
+            Visibility::Inherited => Ok(()),
             _ => {
                 let is_macro_rules: bool = match self.token {
                     token::Ident(sid) => sid.name == Symbol::intern("macro_rules"),
                     _ => false,
                 };
                 if is_macro_rules {
-                    self.diagnostic().struct_span_err(span, "can't qualify macro_rules \
-                                                             invocation with `pub`")
-                                     .help("did you mean #[macro_export]?")
-                                     .emit();
+                    let mut err = self.diagnostic()
+                        .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
+                    err.help("did you mean #[macro_export]?");
+                    Err(err)
                 } else {
-                    self.diagnostic().struct_span_err(span, "can't qualify macro \
-                                                             invocation with `pub`")
-                                     .help("try adjusting the macro to put `pub` \
-                                            inside the invocation")
-                                     .emit();
+                    let mut err = self.diagnostic()
+                        .struct_span_err(sp, "can't qualify macro invocation with `pub`");
+                    err.help("try adjusting the macro to put `pub` inside the invocation");
+                    Err(err)
                 }
             }
         }
@@ -4689,14 +4694,41 @@ impl<'a> Parser<'a> {
                          -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
         // code copied from parse_macro_use_or_failure... abstraction!
         if self.token.is_path_start() {
-            // method macro.
+            // Method macro.
 
             let prev_span = self.prev_span;
-            self.complain_if_pub_macro(&vis, prev_span);
+            // Before complaining about trying to set a macro as `pub`,
+            // check if `!` comes after the path.
+            let err = self.complain_if_pub_macro_diag(&vis, prev_span);
 
             let lo = self.span.lo;
             let pth = self.parse_path(PathStyle::Mod)?;
-            self.expect(&token::Not)?;
+            let bang_err = self.expect(&token::Not);
+            if let Err(mut err) = err {
+                if let Err(mut bang_err) = bang_err {
+                    // Given this code `pub path(`, it seems like this is not setting the
+                    // visibility of a macro invocation, but rather a mistyped method declaration.
+                    // Keep the macro diagnostic, but also provide a hint that `fn` might be
+                    // missing. Don't complain about the missing `!` as a separate diagnostic, add
+                    // label in the appropriate place as part of one unified diagnostic.
+                    //
+                    // x |     pub path(&self) {
+                    //   |     ^^^-    - expected `!` here for a macro invocation
+                    //   |        |
+                    //   |        did you mean to write `fn` here for a method declaration?
+
+                    bang_err.cancel();
+                    err.span_label(self.span, &"expected `!` here for a macro invocation");
+                    //     pub  path(
+                    //        ^^ `sp` below will point to this
+                    let sp = mk_sp(prev_span.hi, self.prev_span.lo);
+                    err.span_label(sp,
+                                   &"did you mean to write `fn` here for a method declaration?");
+                }
+                return Err(err);
+            } else if let Err(bang_err) = bang_err {
+                return Err(bang_err);
+            }
 
             // eat a matched-delimiter token tree:
             let (delim, tts) = self.expect_delimited_token_tree()?;