about summary refs log tree commit diff
path: root/compiler/rustc_expand/src
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2021-07-14 18:24:12 -0500
committerAaron Hill <aa1ronham@gmail.com>2021-07-17 23:03:56 -0500
commitddd544856ecd181ee02490d12f723be549d3ecb3 (patch)
tree36bec16c3a8132f356fdb4713a63aac33e0471a9 /compiler/rustc_expand/src
parenteb0b95b55a0b38d91e834dd30902b67627ed2eb0 (diff)
downloadrust-ddd544856ecd181ee02490d12f723be549d3ecb3.tar.gz
rust-ddd544856ecd181ee02490d12f723be549d3ecb3.zip
Compute a better `lint_node_id` during expansion
When we need to emit a lint at a macro invocation, we currently use the
`NodeId` of its parent definition (e.g. the enclosing function). This
means that any `#[allow]` / `#[deny]` attributes placed 'closer' to the
macro (e.g. on an enclosing block or statement) will have no effect.

This commit computes a better `lint_node_id` in `InvocationCollector`.
When we visit/flat_map an AST node, we assign it a `NodeId` (earlier
than we normally would), and store than `NodeId` in current
`ExpansionData`. When we collect a macro invocation, the current
`lint_node_id` gets cloned along with our `ExpansionData`, allowing it
to be used if we need to emit a lint later on.

This improves the handling of `#[allow]` / `#[deny]` for
`SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` and some `asm!`-related lints.
The 'legacy derive helpers' lint retains its current behavior
(I've inlined the now-removed `lint_node_id` function), since
there isn't an `ExpansionData` readily available.
Diffstat (limited to 'compiler/rustc_expand/src')
-rw-r--r--compiler/rustc_expand/src/base.rs6
-rw-r--r--compiler/rustc_expand/src/expand.rs100
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs3
3 files changed, 82 insertions, 27 deletions
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 497be2d9318..03ded6465d0 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -869,9 +869,6 @@ pub trait ResolverExpand {
 
     fn check_unused_macros(&mut self);
 
-    /// Some parent node that is close enough to the given macro call.
-    fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId;
-
     // Resolver interfaces for specific built-in macros.
     /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
     fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool;
@@ -926,6 +923,8 @@ pub struct ExpansionData {
     pub module: Rc<ModuleData>,
     pub dir_ownership: DirOwnership,
     pub prior_type_ascription: Option<(Span, bool)>,
+    /// Some parent node that is close to this macro call
+    pub lint_node_id: NodeId,
 }
 
 type OnExternModLoaded<'a> =
@@ -971,6 +970,7 @@ impl<'a> ExtCtxt<'a> {
                 module: Default::default(),
                 dir_ownership: DirOwnership::Owned { relative: None },
                 prior_type_ascription: None,
+                lint_node_id: ast::CRATE_NODE_ID,
             },
             force_mode: false,
             expansions: FxHashMap::default(),
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index b9d40962411..f79e9648ab6 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1098,6 +1098,41 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     }
 }
 
+/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
+/// This method assigns a `NodeId`, and sets that `NodeId`
+/// as our current 'lint node id'. If a macro call is found
+/// inside this AST node, we will use this AST node's `NodeId`
+/// to emit lints associated with that macro (allowing
+/// `#[allow]` / `#[deny]` to be applied close to
+/// the macro invocation).
+///
+/// Do *not* call this for a macro AST node
+/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
+/// at these AST nodes, since they are removed and
+/// replaced with the result of macro expansion.
+///
+/// All other `NodeId`s are assigned by `visit_id`.
+/// * `self` is the 'self' parameter for the current method,
+/// * `id` is a mutable reference to the `NodeId` field
+///    of the current AST node.
+/// * `closure` is a closure that executes the
+///   `noop_visit_*` / `noop_flat_map_*` method
+///   for the current AST node.
+macro_rules! assign_id {
+    ($self:ident, $id:expr, $closure:expr) => {{
+        let old_id = $self.cx.current_expansion.lint_node_id;
+        if $self.monotonic {
+            debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
+            let new_id = $self.cx.resolver.next_node_id();
+            *$id = new_id;
+            $self.cx.current_expansion.lint_node_id = new_id;
+        }
+        let ret = ($closure)();
+        $self.cx.current_expansion.lint_node_id = old_id;
+        ret
+    }};
+}
+
 impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
         self.cfg.configure_expr(expr);
@@ -1118,7 +1153,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 self.check_attributes(&expr.attrs);
                 self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner()
             } else {
-                ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
+                assign_id!(self, &mut expr.id, || {
+                    ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
+                });
                 expr
             }
         });
@@ -1133,7 +1170,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 .make_arms();
         }
 
-        noop_flat_map_arm(arm, self)
+        assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self))
     }
 
     fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
@@ -1145,7 +1182,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 .make_expr_fields();
         }
 
-        noop_flat_map_expr_field(field, self)
+        assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self))
     }
 
     fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
@@ -1157,7 +1194,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 .make_pat_fields();
         }
 
-        noop_flat_map_pat_field(fp, self)
+        assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self))
     }
 
     fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
@@ -1169,7 +1206,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 .make_params();
         }
 
-        noop_flat_map_param(p, self)
+        assign_id!(self, &mut p.id, || noop_flat_map_param(p, self))
     }
 
     fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
@@ -1181,7 +1218,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 .make_field_defs();
         }
 
-        noop_flat_map_field_def(sf, self)
+        assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self))
     }
 
     fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
@@ -1193,7 +1230,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 .make_variants();
         }
 
-        noop_flat_map_variant(variant, self)
+        assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self))
     }
 
     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
@@ -1214,9 +1251,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     .make_opt_expr()
                     .map(|expr| expr.into_inner())
             } else {
-                Some({
-                    noop_visit_expr(&mut expr, self);
-                    expr
+                assign_id!(self, &mut expr.id, || {
+                    Some({
+                        noop_visit_expr(&mut expr, self);
+                        expr
+                    })
                 })
             }
         })
@@ -1225,7 +1264,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
         match pat.kind {
             PatKind::MacCall(_) => {}
-            _ => return noop_visit_pat(pat, self),
+            _ => {
+                return assign_id!(self, &mut pat.id, || noop_visit_pat(pat, self));
+            }
         }
 
         visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) {
@@ -1278,7 +1319,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
             &mut self.cx.current_expansion.dir_ownership,
             DirOwnership::UnownedViaBlock,
         );
-        noop_visit_block(block, self);
+        assign_id!(self, &mut block.id, || noop_visit_block(block, self));
         self.cx.current_expansion.dir_ownership = orig_dir_ownership;
     }
 
@@ -1377,7 +1418,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 let orig_dir_ownership =
                     mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership);
 
-                let result = noop_flat_map_item(item, self);
+                let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self));
 
                 // Restore the module info.
                 self.cx.current_expansion.dir_ownership = orig_dir_ownership;
@@ -1387,7 +1428,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
             }
             _ => {
                 item.attrs = attrs;
-                noop_flat_map_item(item, self)
+                // The crate root is special - don't assign an ID to it.
+                if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) {
+                    assign_id!(self, &mut item.id, || noop_flat_map_item(item, self))
+                } else {
+                    noop_flat_map_item(item, self)
+                }
             }
         }
     }
@@ -1411,7 +1457,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     _ => unreachable!(),
                 })
             }
-            _ => noop_flat_map_assoc_item(item, self),
+            _ => {
+                assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
+            }
         }
     }
 
@@ -1434,14 +1482,16 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     _ => unreachable!(),
                 })
             }
-            _ => noop_flat_map_assoc_item(item, self),
+            _ => {
+                assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
+            }
         }
     }
 
     fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
         match ty.kind {
             ast::TyKind::MacCall(_) => {}
-            _ => return noop_visit_ty(ty, self),
+            _ => return assign_id!(self, &mut ty.id, || noop_visit_ty(ty, self)),
         };
 
         visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) {
@@ -1478,7 +1528,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     _ => unreachable!(),
                 })
             }
-            _ => noop_flat_map_foreign_item(foreign_item, self),
+            _ => {
+                assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item(
+                    foreign_item,
+                    self
+                ))
+            }
         }
     }
 
@@ -1498,13 +1553,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 .make_generic_params();
         }
 
-        noop_flat_map_generic_param(param, self)
+        assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self))
     }
 
     fn visit_id(&mut self, id: &mut ast::NodeId) {
-        if self.monotonic {
-            debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
-            *id = self.cx.resolver.next_node_id()
+        // We may have already assigned a `NodeId`
+        // by calling `assign_id`
+        if self.monotonic && *id == ast::DUMMY_NODE_ID {
+            *id = self.cx.resolver.next_node_id();
         }
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 8b68c94e61a..7f985af364d 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -289,7 +289,6 @@ fn generic_extension<'cx>(
 
                 let mut p = Parser::new(sess, tts, false, None);
                 p.last_type_ascription = cx.current_expansion.prior_type_ascription;
-                let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id);
 
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
@@ -301,7 +300,7 @@ fn generic_extension<'cx>(
                     // macro leaves unparsed tokens.
                     site_span: sp,
                     macro_ident: name,
-                    lint_node_id,
+                    lint_node_id: cx.current_expansion.lint_node_id,
                     arm_span,
                 });
             }