Skip to content

Compute a better lint_node_id during expansion #87146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_builtin_macros/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,15 +455,15 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
ecx.parse_sess().buffer_lint(
lint::builtin::BAD_ASM_STYLE,
find_span(".intel_syntax"),
ecx.resolver.lint_node_id(ecx.current_expansion.id),
ecx.current_expansion.lint_node_id,
"avoid using `.intel_syntax`, Intel syntax is the default",
);
}
if template_str.contains(".att_syntax") {
ecx.parse_sess().buffer_lint(
lint::builtin::BAD_ASM_STYLE,
find_span(".att_syntax"),
ecx.resolver.lint_node_id(ecx.current_expansion.id),
ecx.current_expansion.lint_node_id,
"avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/source_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ pub fn expand_include<'cx>(
}
}

Box::new(ExpandResult { p, node_id: cx.resolver.lint_node_id(cx.current_expansion.id) })
Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id })
}

// include_str! : read the given file, insert it as a literal string expr
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ use std::rc::Rc;

crate use rustc_span::hygiene::MacroKind;

// When adding new variants, make sure to
// adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector`
// to use `assign_id!`
#[derive(Debug, Clone)]
pub enum Annotatable {
Item(P<ast::Item>),
Expand Down Expand Up @@ -869,9 +872,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;
Expand Down Expand Up @@ -926,6 +926,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> =
Expand Down Expand Up @@ -971,6 +973,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(),
Expand Down
103 changes: 83 additions & 20 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_ast::ptr::P;
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs};
use rustc_ast::{AstLike, Block, Inline, ItemKind, Local, MacArgs};
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
Expand Down Expand Up @@ -1098,6 +1098,43 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
}
}

/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
/// for an AST node that supports attributes
/// (see the `Annotatable` enum)
/// 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);
Expand All @@ -1118,12 +1155,19 @@ 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
}
});
}

// This is needed in order to set `lint_node_id` for `let` statements
fn visit_local(&mut self, local: &mut P<Local>) {
assign_id!(self, &mut local.id, || noop_visit_local(local, self));
}

fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
let mut arm = configure!(self, arm);

Expand All @@ -1133,7 +1177,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]> {
Expand All @@ -1145,7 +1189,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]> {
Expand All @@ -1157,7 +1201,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]> {
Expand All @@ -1169,7 +1213,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]> {
Expand All @@ -1181,7 +1225,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]> {
Expand All @@ -1193,7 +1237,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>> {
Expand All @@ -1214,9 +1258,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
})
})
}
})
Expand Down Expand Up @@ -1266,6 +1312,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
}

// The placeholder expander gives ids to statements, so we avoid folding the id here.
// We don't use `assign_id!` - it will be called when we visit statement's contents
// (e.g. an expression, item, or local)
let ast::Stmt { id, kind, span } = stmt;
noop_flat_map_stmt_kind(kind, self)
.into_iter()
Expand Down Expand Up @@ -1377,7 +1425,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;
Expand All @@ -1387,7 +1435,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)
}
}
}
}
Expand All @@ -1411,7 +1464,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))
}
}
}

Expand All @@ -1434,7 +1489,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))
}
}
}

Expand Down Expand Up @@ -1478,7 +1535,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
))
}
}
}

Expand All @@ -1498,13 +1560,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();
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_expand/src/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
});
}
Expand Down
22 changes: 18 additions & 4 deletions compiler/rustc_lint/src/early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
})
}

fn visit_expr_field(&mut self, f: &'a ast::ExprField) {
self.with_lint_attrs(f.id, &f.attrs, |cx| {
ast_visit::walk_expr_field(cx, f);
})
}

fn visit_stmt(&mut self, s: &'a ast::Stmt) {
// Add the statement's lint attributes to our
// current state when checking the statement itself.
Expand Down Expand Up @@ -204,8 +210,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
}

fn visit_arm(&mut self, a: &'a ast::Arm) {
run_early_pass!(self, check_arm, a);
ast_visit::walk_arm(self, a);
self.with_lint_attrs(a.id, &a.attrs, |cx| {
run_early_pass!(cx, check_arm, a);
ast_visit::walk_arm(cx, a);
})
}

fn visit_expr_post(&mut self, e: &'a ast::Expr) {
Expand Down Expand Up @@ -389,9 +397,15 @@ pub fn check_ast_crate<T: EarlyLintPass>(
// All of the buffered lints should have been emitted at this point.
// If not, that means that we somehow buffered a lint for a node id
// that was not lint-checked (perhaps it doesn't exist?). This is a bug.
for (_id, lints) in buffered.map {
for (id, lints) in buffered.map {
for early_lint in lints {
sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
sess.delay_span_bug(
early_lint.span,
&format!(
"failed to process buffered lint here (dummy = {})",
id == ast::DUMMY_NODE_ID
),
);
}
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,15 @@ impl<HCX> ToStableHashKey<HCX> for LintId {
}

// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency
#[derive(PartialEq)]
#[derive(PartialEq, Debug)]
pub enum ExternDepSpec {
Json(Json),
Raw(String),
}

// This could be a closure, but then implementing derive trait
// becomes hacky (and it gets allocated).
#[derive(PartialEq)]
#[derive(PartialEq, Debug)]
pub enum BuiltinLintDiagnostics {
Normal,
BareTraitObject(Span, /* is_global */ bool),
Expand Down
Loading