about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-26 15:54:47 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-03-27 07:02:50 +0100
commit6c643a070c1f725159e626697f13b45b72f23069 (patch)
treeb3584cd88c7d297611e6e03045434fd81d962935
parent3b1d7351186a073c72e4be3c7d7b7ab8f1f10c58 (diff)
downloadrust-6c643a070c1f725159e626697f13b45b72f23069.tar.gz
rust-6c643a070c1f725159e626697f13b45b72f23069.zip
suggest semi on expr mac!() good as stmt mac!().
-rw-r--r--src/librustc_expand/mbe/macro_rules.rs19
-rw-r--r--src/test/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs15
-rw-r--r--src/test/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr34
-rw-r--r--src/test/ui/macros/macro-in-expression-context-2.stderr6
4 files changed, 73 insertions, 1 deletions
diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs
index b9477be57dd..0e70fdbd9c1 100644
--- a/src/librustc_expand/mbe/macro_rules.rs
+++ b/src/librustc_expand/mbe/macro_rules.rs
@@ -86,6 +86,7 @@ fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Pa
 fn emit_frag_parse_err(
     mut e: DiagnosticBuilder<'_>,
     parser: &Parser<'_>,
+    orig_parser: &mut Parser<'_>,
     site_span: Span,
     macro_ident: ast::Ident,
     arm_span: Span,
@@ -118,6 +119,21 @@ fn emit_frag_parse_err(
         AstFragmentKind::Pat if macro_ident.name == sym::vec => {
             suggest_slice_pat(&mut e, site_span, parser);
         }
+        // Try a statement if an expression is wanted but failed and suggest adding `;` to call.
+        AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) {
+            Err(mut err) => err.cancel(),
+            Ok(_) => {
+                e.note(
+                    "the macro call doesn't expand to an expression, but it can expand to a statement",
+                );
+                e.span_suggestion_verbose(
+                    site_span.shrink_to_hi(),
+                    "add `;` to interpret the expansion as a statement",
+                    ";".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        },
         _ => annotate_err_with_kind(&mut e, kind, site_span),
     };
     e.emit();
@@ -126,10 +142,11 @@ fn emit_frag_parse_err(
 impl<'a> ParserAnyMacro<'a> {
     crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
         let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
+        let snapshot = &mut parser.clone();
         let fragment = match parse_ast_fragment(parser, kind) {
             Ok(f) => f,
             Err(err) => {
-                emit_frag_parse_err(err, parser, site_span, macro_ident, arm_span, kind);
+                emit_frag_parse_err(err, parser, snapshot, site_span, macro_ident, arm_span, kind);
                 return kind.dummy(site_span);
             }
         };
diff --git a/src/test/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs b/src/test/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs
new file mode 100644
index 00000000000..d7813936554
--- /dev/null
+++ b/src/test/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs
@@ -0,0 +1,15 @@
+macro_rules! make_item {
+    ($a:ident) => {
+        struct $a;
+    }; //~^ ERROR expected expression
+       //~| ERROR expected expression
+}
+
+fn a() {
+    make_item!(A)
+}
+fn b() {
+    make_item!(B)
+}
+
+fn main() {}
diff --git a/src/test/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr b/src/test/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr
new file mode 100644
index 00000000000..c8d69640071
--- /dev/null
+++ b/src/test/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr
@@ -0,0 +1,34 @@
+error: expected expression, found keyword `struct`
+  --> $DIR/issue-34421-mac-expr-bad-stmt-good-add-semi.rs:3:9
+   |
+LL |         struct $a;
+   |         ^^^^^^ expected expression
+...
+LL |     make_item!(A)
+   |     ------------- in this macro invocation
+   |
+   = note: the macro call doesn't expand to an expression, but it can expand to a statement
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `;` to interpret the expansion as a statement
+   |
+LL |     make_item!(A);
+   |                  ^
+
+error: expected expression, found keyword `struct`
+  --> $DIR/issue-34421-mac-expr-bad-stmt-good-add-semi.rs:3:9
+   |
+LL |         struct $a;
+   |         ^^^^^^ expected expression
+...
+LL |     make_item!(B)
+   |     ------------- in this macro invocation
+   |
+   = note: the macro call doesn't expand to an expression, but it can expand to a statement
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `;` to interpret the expansion as a statement
+   |
+LL |     make_item!(B);
+   |                  ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/macros/macro-in-expression-context-2.stderr b/src/test/ui/macros/macro-in-expression-context-2.stderr
index 672871c49ca..8f966096393 100644
--- a/src/test/ui/macros/macro-in-expression-context-2.stderr
+++ b/src/test/ui/macros/macro-in-expression-context-2.stderr
@@ -6,6 +6,12 @@ LL | macro_rules! empty { () => () }
 ...
 LL |         _ => { empty!() }
    |                ^^^^^^^^ expected expression
+   |
+   = note: the macro call doesn't expand to an expression, but it can expand to a statement
+help: add `;` to interpret the expansion as a statement
+   |
+LL |         _ => { empty!(); }
+   |                        ^
 
 error: aborting due to previous error