Skip to content

Commit ddd5448

Browse files
committed
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.
1 parent eb0b95b commit ddd5448

File tree

10 files changed

+139
-65
lines changed

10 files changed

+139
-65
lines changed

compiler/rustc_builtin_macros/src/asm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,15 +455,15 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
455455
ecx.parse_sess().buffer_lint(
456456
lint::builtin::BAD_ASM_STYLE,
457457
find_span(".intel_syntax"),
458-
ecx.resolver.lint_node_id(ecx.current_expansion.id),
458+
ecx.current_expansion.lint_node_id,
459459
"avoid using `.intel_syntax`, Intel syntax is the default",
460460
);
461461
}
462462
if template_str.contains(".att_syntax") {
463463
ecx.parse_sess().buffer_lint(
464464
lint::builtin::BAD_ASM_STYLE,
465465
find_span(".att_syntax"),
466-
ecx.resolver.lint_node_id(ecx.current_expansion.id),
466+
ecx.current_expansion.lint_node_id,
467467
"avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
468468
);
469469
}

compiler/rustc_builtin_macros/src/source_util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ pub fn expand_include<'cx>(
159159
}
160160
}
161161

162-
Box::new(ExpandResult { p, node_id: cx.resolver.lint_node_id(cx.current_expansion.id) })
162+
Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id })
163163
}
164164

165165
// include_str! : read the given file, insert it as a literal string expr

compiler/rustc_expand/src/base.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -869,9 +869,6 @@ pub trait ResolverExpand {
869869

870870
fn check_unused_macros(&mut self);
871871

872-
/// Some parent node that is close enough to the given macro call.
873-
fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId;
874-
875872
// Resolver interfaces for specific built-in macros.
876873
/// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
877874
fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool;
@@ -926,6 +923,8 @@ pub struct ExpansionData {
926923
pub module: Rc<ModuleData>,
927924
pub dir_ownership: DirOwnership,
928925
pub prior_type_ascription: Option<(Span, bool)>,
926+
/// Some parent node that is close to this macro call
927+
pub lint_node_id: NodeId,
929928
}
930929

931930
type OnExternModLoaded<'a> =
@@ -971,6 +970,7 @@ impl<'a> ExtCtxt<'a> {
971970
module: Default::default(),
972971
dir_ownership: DirOwnership::Owned { relative: None },
973972
prior_type_ascription: None,
973+
lint_node_id: ast::CRATE_NODE_ID,
974974
},
975975
force_mode: false,
976976
expansions: FxHashMap::default(),

compiler/rustc_expand/src/expand.rs

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,41 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
10981098
}
10991099
}
11001100

1101+
/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
1102+
/// This method assigns a `NodeId`, and sets that `NodeId`
1103+
/// as our current 'lint node id'. If a macro call is found
1104+
/// inside this AST node, we will use this AST node's `NodeId`
1105+
/// to emit lints associated with that macro (allowing
1106+
/// `#[allow]` / `#[deny]` to be applied close to
1107+
/// the macro invocation).
1108+
///
1109+
/// Do *not* call this for a macro AST node
1110+
/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
1111+
/// at these AST nodes, since they are removed and
1112+
/// replaced with the result of macro expansion.
1113+
///
1114+
/// All other `NodeId`s are assigned by `visit_id`.
1115+
/// * `self` is the 'self' parameter for the current method,
1116+
/// * `id` is a mutable reference to the `NodeId` field
1117+
/// of the current AST node.
1118+
/// * `closure` is a closure that executes the
1119+
/// `noop_visit_*` / `noop_flat_map_*` method
1120+
/// for the current AST node.
1121+
macro_rules! assign_id {
1122+
($self:ident, $id:expr, $closure:expr) => {{
1123+
let old_id = $self.cx.current_expansion.lint_node_id;
1124+
if $self.monotonic {
1125+
debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
1126+
let new_id = $self.cx.resolver.next_node_id();
1127+
*$id = new_id;
1128+
$self.cx.current_expansion.lint_node_id = new_id;
1129+
}
1130+
let ret = ($closure)();
1131+
$self.cx.current_expansion.lint_node_id = old_id;
1132+
ret
1133+
}};
1134+
}
1135+
11011136
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
11021137
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
11031138
self.cfg.configure_expr(expr);
@@ -1118,7 +1153,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
11181153
self.check_attributes(&expr.attrs);
11191154
self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner()
11201155
} else {
1121-
ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
1156+
assign_id!(self, &mut expr.id, || {
1157+
ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
1158+
});
11221159
expr
11231160
}
11241161
});
@@ -1133,7 +1170,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
11331170
.make_arms();
11341171
}
11351172

1136-
noop_flat_map_arm(arm, self)
1173+
assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self))
11371174
}
11381175

11391176
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> {
11451182
.make_expr_fields();
11461183
}
11471184

1148-
noop_flat_map_expr_field(field, self)
1185+
assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self))
11491186
}
11501187

11511188
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> {
11571194
.make_pat_fields();
11581195
}
11591196

1160-
noop_flat_map_pat_field(fp, self)
1197+
assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self))
11611198
}
11621199

11631200
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> {
11691206
.make_params();
11701207
}
11711208

1172-
noop_flat_map_param(p, self)
1209+
assign_id!(self, &mut p.id, || noop_flat_map_param(p, self))
11731210
}
11741211

11751212
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> {
11811218
.make_field_defs();
11821219
}
11831220

1184-
noop_flat_map_field_def(sf, self)
1221+
assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self))
11851222
}
11861223

11871224
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> {
11931230
.make_variants();
11941231
}
11951232

1196-
noop_flat_map_variant(variant, self)
1233+
assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self))
11971234
}
11981235

11991236
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> {
12141251
.make_opt_expr()
12151252
.map(|expr| expr.into_inner())
12161253
} else {
1217-
Some({
1218-
noop_visit_expr(&mut expr, self);
1219-
expr
1254+
assign_id!(self, &mut expr.id, || {
1255+
Some({
1256+
noop_visit_expr(&mut expr, self);
1257+
expr
1258+
})
12201259
})
12211260
}
12221261
})
@@ -1225,7 +1264,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
12251264
fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
12261265
match pat.kind {
12271266
PatKind::MacCall(_) => {}
1228-
_ => return noop_visit_pat(pat, self),
1267+
_ => {
1268+
return assign_id!(self, &mut pat.id, || noop_visit_pat(pat, self));
1269+
}
12291270
}
12301271

12311272
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> {
12781319
&mut self.cx.current_expansion.dir_ownership,
12791320
DirOwnership::UnownedViaBlock,
12801321
);
1281-
noop_visit_block(block, self);
1322+
assign_id!(self, &mut block.id, || noop_visit_block(block, self));
12821323
self.cx.current_expansion.dir_ownership = orig_dir_ownership;
12831324
}
12841325

@@ -1377,7 +1418,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
13771418
let orig_dir_ownership =
13781419
mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership);
13791420

1380-
let result = noop_flat_map_item(item, self);
1421+
let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self));
13811422

13821423
// Restore the module info.
13831424
self.cx.current_expansion.dir_ownership = orig_dir_ownership;
@@ -1387,7 +1428,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
13871428
}
13881429
_ => {
13891430
item.attrs = attrs;
1390-
noop_flat_map_item(item, self)
1431+
// The crate root is special - don't assign an ID to it.
1432+
if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) {
1433+
assign_id!(self, &mut item.id, || noop_flat_map_item(item, self))
1434+
} else {
1435+
noop_flat_map_item(item, self)
1436+
}
13911437
}
13921438
}
13931439
}
@@ -1411,7 +1457,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
14111457
_ => unreachable!(),
14121458
})
14131459
}
1414-
_ => noop_flat_map_assoc_item(item, self),
1460+
_ => {
1461+
assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
1462+
}
14151463
}
14161464
}
14171465

@@ -1434,14 +1482,16 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
14341482
_ => unreachable!(),
14351483
})
14361484
}
1437-
_ => noop_flat_map_assoc_item(item, self),
1485+
_ => {
1486+
assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
1487+
}
14381488
}
14391489
}
14401490

14411491
fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
14421492
match ty.kind {
14431493
ast::TyKind::MacCall(_) => {}
1444-
_ => return noop_visit_ty(ty, self),
1494+
_ => return assign_id!(self, &mut ty.id, || noop_visit_ty(ty, self)),
14451495
};
14461496

14471497
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> {
14781528
_ => unreachable!(),
14791529
})
14801530
}
1481-
_ => noop_flat_map_foreign_item(foreign_item, self),
1531+
_ => {
1532+
assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item(
1533+
foreign_item,
1534+
self
1535+
))
1536+
}
14821537
}
14831538
}
14841539

@@ -1498,13 +1553,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
14981553
.make_generic_params();
14991554
}
15001555

1501-
noop_flat_map_generic_param(param, self)
1556+
assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self))
15021557
}
15031558

15041559
fn visit_id(&mut self, id: &mut ast::NodeId) {
1505-
if self.monotonic {
1506-
debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
1507-
*id = self.cx.resolver.next_node_id()
1560+
// We may have already assigned a `NodeId`
1561+
// by calling `assign_id`
1562+
if self.monotonic && *id == ast::DUMMY_NODE_ID {
1563+
*id = self.cx.resolver.next_node_id();
15081564
}
15091565
}
15101566
}

compiler/rustc_expand/src/mbe/macro_rules.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,6 @@ fn generic_extension<'cx>(
289289

290290
let mut p = Parser::new(sess, tts, false, None);
291291
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
292-
let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id);
293292

294293
// Let the context choose how to interpret the result.
295294
// Weird, but useful for X-macros.
@@ -301,7 +300,7 @@ fn generic_extension<'cx>(
301300
// macro leaves unparsed tokens.
302301
site_span: sp,
303302
macro_ident: name,
304-
lint_node_id,
303+
lint_node_id: cx.current_expansion.lint_node_id,
305304
arm_span,
306305
});
307306
}

compiler/rustc_lint_defs/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,15 @@ impl<HCX> ToStableHashKey<HCX> for LintId {
274274
}
275275

276276
// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency
277-
#[derive(PartialEq)]
277+
#[derive(PartialEq, Debug)]
278278
pub enum ExternDepSpec {
279279
Json(Json),
280280
Raw(String),
281281
}
282282

283283
// This could be a closure, but then implementing derive trait
284284
// becomes hacky (and it gets allocated).
285-
#[derive(PartialEq)]
285+
#[derive(PartialEq, Debug)]
286286
pub enum BuiltinLintDiagnostics {
287287
Normal,
288288
BareTraitObject(Span, /* is_global */ bool),

compiler/rustc_resolve/src/macros.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
281281
// Derives are not included when `invocations` are collected, so we have to add them here.
282282
let parent_scope = &ParentScope { derives, ..parent_scope };
283283
let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion();
284-
let node_id = self.lint_node_id(eager_expansion_root);
284+
let node_id = invoc.expansion_data.lint_node_id;
285285
let (ext, res) = self.smart_resolve_macro_path(
286286
path,
287287
kind,
@@ -348,14 +348,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
348348
}
349349
}
350350

351-
fn lint_node_id(&self, expn_id: LocalExpnId) -> NodeId {
352-
// FIXME - make this more precise. This currently returns the NodeId of the
353-
// nearest closing item - we should try to return the closest parent of the ExpnId
354-
self.invocation_parents
355-
.get(&expn_id)
356-
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0])
357-
}
358-
359351
fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool {
360352
self.containers_deriving_copy.contains(&expn_id)
361353
}
@@ -1105,9 +1097,13 @@ impl<'a> Resolver<'a> {
11051097
let seg = Segment::from_ident(ident);
11061098
check_consistency(self, &[seg], ident.span, kind, initial_res, res);
11071099
if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) {
1100+
let node_id = self
1101+
.invocation_parents
1102+
.get(&parent_scope.expansion)
1103+
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]);
11081104
self.lint_buffer.buffer_lint_with_diagnostic(
11091105
LEGACY_DERIVE_HELPERS,
1110-
self.lint_node_id(parent_scope.expansion),
1106+
node_id,
11111107
ident.span,
11121108
"derive helper attribute is used before it is introduced",
11131109
BuiltinLintDiagnostics::LegacyDeriveHelpers(binding.span),

src/test/ui/asm/inline-syntax.x86_64.stderr

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
1-
warning: avoid using `.intel_syntax`, Intel syntax is the default
2-
--> $DIR/inline-syntax.rs:57:14
3-
|
4-
LL | global_asm!(".intel_syntax noprefix", "nop");
5-
| ^^^^^^^^^^^^^^^^^^^^^^
6-
|
7-
= note: `#[warn(bad_asm_style)]` on by default
8-
91
warning: avoid using `.intel_syntax`, Intel syntax is the default
102
--> $DIR/inline-syntax.rs:31:15
113
|
124
LL | asm!(".intel_syntax noprefix", "nop");
135
| ^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(bad_asm_style)]` on by default
148

159
warning: avoid using `.intel_syntax`, Intel syntax is the default
1610
--> $DIR/inline-syntax.rs:34:15
@@ -42,5 +36,11 @@ warning: avoid using `.intel_syntax`, Intel syntax is the default
4236
LL | .intel_syntax noprefix
4337
| ^^^^^^^^^^^^^^^^^^^^^^
4438

39+
warning: avoid using `.intel_syntax`, Intel syntax is the default
40+
--> $DIR/inline-syntax.rs:57:14
41+
|
42+
LL | global_asm!(".intel_syntax noprefix", "nop");
43+
| ^^^^^^^^^^^^^^^^^^^^^^
44+
4545
warning: 7 warnings emitted
4646

0 commit comments

Comments
 (0)