diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2021-07-14 18:24:12 -0500 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2021-07-17 23:03:56 -0500 |
| commit | ddd544856ecd181ee02490d12f723be549d3ecb3 (patch) | |
| tree | 36bec16c3a8132f356fdb4713a63aac33e0471a9 /compiler/rustc_expand/src | |
| parent | eb0b95b55a0b38d91e834dd30902b67627ed2eb0 (diff) | |
| download | rust-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.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/expand.rs | 100 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/mbe/macro_rules.rs | 3 |
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, }); } |
