about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs27
-rw-r--r--src/libsyntax/tokenstream.rs25
-rw-r--r--src/libsyntax_ext/format.rs2
-rw-r--r--src/test/ui/codemap_tests/bad-format-args.stderr12
-rw-r--r--src/test/ui/macros/missing-comma.rs20
-rw-r--r--src/test/ui/macros/missing-comma.stderr16
6 files changed, 92 insertions, 10 deletions
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index c9ec2c7d1e8..e7e94614ac8 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -174,7 +174,32 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
     }
 
     let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers"));
-    cx.span_err(best_fail_spot.substitute_dummy(sp), &best_fail_msg);
+    let mut err = cx.struct_span_err(best_fail_spot.substitute_dummy(sp), &best_fail_msg);
+
+    // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
+    if let Some((arg, comma_span)) = arg.add_comma() {
+        for lhs in lhses { // try each arm's matchers
+            let lhs_tt = match *lhs {
+                quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
+                _ => cx.span_bug(sp, "malformed macro lhs")
+            };
+            match TokenTree::parse(cx, lhs_tt, arg.clone()) {
+                Success(_) => {
+                    if comma_span == DUMMY_SP {
+                        err.note("you might be missing a comma");
+                    } else {
+                        err.span_suggestion_short(
+                            comma_span,
+                            "missing comma here",
+                            ",".to_string(),
+                        );
+                    }
+                }
+                _ => {}
+            }
+        }
+    }
+    err.emit();
     cx.trace_macros_diag();
     DummyResult::any(sp)
 }
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 1a4236b280b..f84b5307a11 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -182,6 +182,31 @@ pub struct TokenStream {
     kind: TokenStreamKind,
 }
 
+impl TokenStream {
+    /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream`
+    /// separating the two arguments with a comma for diagnostic suggestions.
+    pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> {
+        // Used to suggest if a user writes `println!("{}" a);`
+        if let TokenStreamKind::Stream(ref slice) = self.kind {
+            if slice.len() == 2 {
+                let comma_span = match slice[0] {
+                    TokenStream { kind: TokenStreamKind::Tree(TokenTree::Token(sp, _)) } |
+                    TokenStream { kind: TokenStreamKind::Tree(TokenTree::Delimited(sp, _)) } => {
+                        sp.shrink_to_hi()
+                    }
+                    _ => DUMMY_SP,
+                };
+                let comma = TokenStream {
+                    kind: TokenStreamKind::Tree(TokenTree::Token(comma_span, token::Comma)),
+                };
+                let slice = RcSlice::new(vec![slice[0].clone(), comma, slice[1].clone()]);
+                return Some((TokenStream { kind: TokenStreamKind::Stream(slice) }, comma_span));
+            }
+        }
+        None
+    }
+}
+
 #[derive(Clone, Debug)]
 enum TokenStreamKind {
     Empty,
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 46c85497ee7..53f8fe2b0c2 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -147,7 +147,7 @@ fn parse_args(ecx: &mut ExtCtxt,
     let mut named = false;
     while p.token != token::Eof {
         if !p.eat(&token::Comma) {
-            ecx.span_err(sp, "expected token: `,`");
+            ecx.span_err(p.span, "expected token: `,`");
             return None;
         }
         if p.token == token::Eof {
diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr
index d0cdeb2178f..1c801f2a790 100644
--- a/src/test/ui/codemap_tests/bad-format-args.stderr
+++ b/src/test/ui/codemap_tests/bad-format-args.stderr
@@ -7,20 +7,16 @@ LL |     format!(); //~ ERROR requires at least a format string argument
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: expected token: `,`
-  --> $DIR/bad-format-args.rs:13:5
+  --> $DIR/bad-format-args.rs:13:16
    |
 LL |     format!("" 1); //~ ERROR expected token: `,`
-   |     ^^^^^^^^^^^^^^
-   |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+   |                ^
 
 error: expected token: `,`
-  --> $DIR/bad-format-args.rs:14:5
+  --> $DIR/bad-format-args.rs:14:19
    |
 LL |     format!("", 1 1); //~ ERROR expected token: `,`
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+   |                   ^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/macros/missing-comma.rs b/src/test/ui/macros/missing-comma.rs
new file mode 100644
index 00000000000..ac82171a4e8
--- /dev/null
+++ b/src/test/ui/macros/missing-comma.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 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.
+
+macro_rules! foo {
+    ($a:ident, $b:ident) => ()
+}
+
+fn main() {
+    println!("{}" a);
+    //~^ ERROR expected token: `,`
+    foo!(a b);
+    //~^ ERROR no rules expected the token `b`
+}
diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr
new file mode 100644
index 00000000000..3467032d9b5
--- /dev/null
+++ b/src/test/ui/macros/missing-comma.stderr
@@ -0,0 +1,16 @@
+error: expected token: `,`
+  --> $DIR/missing-comma.rs:16:19
+   |
+LL |     println!("{}" a);
+   |                   ^
+
+error: no rules expected the token `b`
+  --> $DIR/missing-comma.rs:18:12
+   |
+LL |     foo!(a b);
+   |           -^
+   |           |
+   |           help: missing comma here
+
+error: aborting due to 2 previous errors
+