about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2021-09-15 19:32:03 -0500
committerAaron Hill <aa1ronham@gmail.com>2021-09-15 19:36:28 -0500
commitbd4c9676c76a1df1ea14c04fa0150e4048d5ba77 (patch)
tree45c728d240f87e915b5e0fbfa771bc890fbbc074
parent2c7bc5e33c25e29058cbafefe680da8d5e9220e9 (diff)
downloadrust-bd4c9676c76a1df1ea14c04fa0150e4048d5ba77.tar.gz
rust-bd4c9676c76a1df1ea14c04fa0150e4048d5ba77.zip
Fix linting when trailing macro expands to a trailing semi
When a macro is used in the trailing expression position of a block
(e.g. `fn foo() { my_macro!() }`), we currently parse it as an
expression, rather than a statement. As a result, we ended up
using the `NodeId` of the containing statement as our `lint_node_id`,
even though we don't normally do this for macro calls.

If such a macro expands to an expression with a `#[cfg]` attribute,
then the trailing statement can get removed entirely. This lead to
an ICE, since we were usng the `NodeId` of the expression to emit
a lint.

Ths commit makes us skip updating `lint_node_id` when handling
a macro in trailing expression position. This will cause us to
lint at the closest parent of the macro call.
-rw-r--r--compiler/rustc_expand/src/expand.rs15
-rw-r--r--src/test/ui/macros/lint-trailing-macro-call.rs16
-rw-r--r--src/test/ui/macros/lint-trailing-macro-call.stderr18
3 files changed, 43 insertions, 6 deletions
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 62066ca9657..d32593f34ad 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1386,14 +1386,17 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
         // See #78991 for an investigation of treating macros in this position
         // as statements, rather than expressions, during parsing.
-        if let StmtKind::Expr(expr) = &stmt.kind {
-            if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) {
+        let res = match &stmt.kind {
+            StmtKind::Expr(expr)
+                if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) =>
+            {
                 self.cx.current_expansion.is_trailing_mac = true;
+                // Don't use `assign_id` for this statement - it may get removed
+                // entirely due to a `#[cfg]` on the contained expression
+                noop_flat_map_stmt(stmt, self)
             }
-        }
-
-        let res = assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self));
-
+            _ => assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)),
+        };
         self.cx.current_expansion.is_trailing_mac = false;
         res
     }
diff --git a/src/test/ui/macros/lint-trailing-macro-call.rs b/src/test/ui/macros/lint-trailing-macro-call.rs
new file mode 100644
index 00000000000..f8e84756391
--- /dev/null
+++ b/src/test/ui/macros/lint-trailing-macro-call.rs
@@ -0,0 +1,16 @@
+// check-pass
+//
+// Ensures that we properly lint
+// a removed 'expression' resulting from a macro
+// in trailing expression position
+
+macro_rules! expand_it {
+    () => {
+        #[cfg(FALSE)] 25; //~  WARN trailing semicolon in macro
+                          //~| WARN this was previously
+    }
+}
+
+fn main() {
+    expand_it!()
+}
diff --git a/src/test/ui/macros/lint-trailing-macro-call.stderr b/src/test/ui/macros/lint-trailing-macro-call.stderr
new file mode 100644
index 00000000000..a98a559c8af
--- /dev/null
+++ b/src/test/ui/macros/lint-trailing-macro-call.stderr
@@ -0,0 +1,18 @@
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/lint-trailing-macro-call.rs:9:25
+   |
+LL |         #[cfg(FALSE)] 25;
+   |                         ^
+...
+LL |     expand_it!()
+   |     ------------ in this macro invocation
+   |
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: macro invocations at the end of a block are treated as expressions
+   = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it`
+   = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 1 warning emitted
+