Skip to content

Commit c560da8

Browse files
committed
Replace cfg_attr in AST with rustc-cfg-placeholder for accurate span tracking
Previously, when evaluating a `#[cfg_attr(..)]` to false, the entire attribute was removed from the AST. Afterwards, we insert in its place a `#[rustc-cfg-placeholder]` attribute so that checks for attributes can still know about their placement. This is particularly relevant when we suggest removing items with `cfg_attr`s (fix #56328). We use `rustc-cfg-placeholder` as it is an ident that can't be written by the end user to begin with. We tweak the wording of the existing "unused `extern crate`" lint. ``` warning: unused `extern crate` --> $DIR/removing-extern-crate.rs:9:1 | LL | extern crate removing_extern_crate as foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/removing-extern-crate.rs:6:9 | LL | #![warn(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ = note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]` help: remove the unused `extern crate` | LL - #[cfg_attr(test, macro_use)] LL - extern crate removing_extern_crate as foo; LL + | ```
1 parent f7b4354 commit c560da8

34 files changed

+210
-77
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3143,6 +3143,10 @@ impl AttrItem {
31433143
|| self.path == sym::allow
31443144
|| self.path == sym::deny
31453145
}
3146+
3147+
pub fn is_cfg_placeholder(&self) -> bool {
3148+
self.path == sym::rustc_cfg_placeholder
3149+
}
31463150
}
31473151

31483152
/// `TraitRef`s appear in impls.

compiler/rustc_ast/src/attr/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ impl Attribute {
233233

234234
pub fn token_trees(&self) -> Vec<TokenTree> {
235235
match self.kind {
236+
AttrKind::Normal(ref normal) if normal.item.is_cfg_placeholder() => vec![],
236237
AttrKind::Normal(ref normal) => normal
237238
.tokens
238239
.as_ref()

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ impl<'a> AstValidator<'a> {
339339
sym::deny,
340340
sym::expect,
341341
sym::forbid,
342+
// `cfg` and `cfg_attr` get replaced with an inert `rustc_cfg_placeholder` to
343+
// keep the attribute "spot" in the AST. This allows suggestions to remove an
344+
// item to provide a correct suggestion when `#[cfg_attr]`s are present.
345+
sym::rustc_cfg_placeholder,
342346
sym::warn,
343347
];
344348
!arr.contains(&attr.name_or_empty()) && rustc_attr_parsing::is_builtin_attr(*attr)

compiler/rustc_expand/src/config.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,25 @@ impl<'a> StripUnconfigured<'a> {
292292
}
293293

294294
if !attr::cfg_matches(&cfg_predicate, &self.sess, self.lint_node_id, self.features) {
295-
return vec![];
295+
// `cfg` and `cfg_attr` gets replaced with an inert `rustc_cfg_placeholder` to keep the
296+
// attribute "spot" in the AST. This allows suggestions to remove an item to provide a
297+
// correct suggestion when `#[cfg_attr]`s are present.
298+
let item = ast::AttrItem {
299+
unsafety: ast::Safety::Default,
300+
path: ast::Path::from_ident(rustc_span::symbol::Ident::with_dummy_span(
301+
sym::rustc_cfg_placeholder,
302+
)),
303+
args: ast::AttrArgs::Empty,
304+
tokens: None,
305+
};
306+
let kind = ast::AttrKind::Normal(P(ast::NormalAttr { item, tokens: None }));
307+
let attr: ast::Attribute = ast::Attribute {
308+
kind,
309+
id: self.sess.psess.attr_id_generator.mk_attr_id(),
310+
style: ast::AttrStyle::Outer,
311+
span: cfg_attr.span,
312+
};
313+
return vec![attr];
296314
}
297315

298316
if recursive {

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
752752
template!(Word, List: r#""...""#), DuplicatesOk,
753753
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
754754
),
755+
// placeholder that replaces `cfg_attr` in the item's attribute list
756+
ungated!(
757+
rustc_cfg_placeholder, Normal, template!(Word /* irrelevant */), DuplicatesOk,
758+
EncodeCrossCrate::No
759+
),
760+
755761

756762
// ==========================================================================
757763
// Internal attributes, Diagnostics related:

compiler/rustc_lint/messages.ftl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -945,8 +945,9 @@ lint_unused_doc_comment = unused doc comment
945945
.label = rustdoc does not generate documentation for macro invocations
946946
.help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion
947947
948-
lint_unused_extern_crate = unused extern crate
949-
.suggestion = remove it
948+
lint_unused_extern_crate = unused `extern crate`
949+
.label = unused
950+
.suggestion = remove the unused `extern crate`
950951
951952
lint_unused_import_braces = braces around {$node} is unnecessary
952953

compiler/rustc_lint/src/early/diagnostics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,8 @@ pub(super) fn decorate_lint(
292292
BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => {
293293
lints::ByteSliceInPackedStructWithDerive { ty }.decorate_lint(diag);
294294
}
295-
BuiltinLintDiag::UnusedExternCrate { removal_span } => {
296-
lints::UnusedExternCrate { removal_span }.decorate_lint(diag);
295+
BuiltinLintDiag::UnusedExternCrate { span, removal_span } => {
296+
lints::UnusedExternCrate { span, removal_span }.decorate_lint(diag);
297297
}
298298
BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => {
299299
let suggestion_span = vis_span.between(ident_span);

compiler/rustc_lint/src/lints.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3001,7 +3001,9 @@ pub(crate) struct ByteSliceInPackedStructWithDerive {
30013001
#[derive(LintDiagnostic)]
30023002
#[diag(lint_unused_extern_crate)]
30033003
pub(crate) struct UnusedExternCrate {
3004-
#[suggestion(code = "", applicability = "machine-applicable")]
3004+
#[label]
3005+
pub span: Span,
3006+
#[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
30053007
pub removal_span: Span,
30063008
}
30073009

compiler/rustc_lint_defs/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ pub enum BuiltinLintDiag {
735735
ty: String,
736736
},
737737
UnusedExternCrate {
738+
span: Span,
738739
removal_span: Span,
739740
},
740741
ExternCrateNotIdiomatic {

compiler/rustc_passes/src/check_attr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
286286
| sym::prelude_import
287287
| sym::panic_handler
288288
| sym::allow_internal_unsafe
289+
| sym::rustc_cfg_placeholder // Inert, it's a placeholder in the AST.
289290
| sym::fundamental
290291
| sym::lang
291292
| sym::needs_allocator
@@ -575,6 +576,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
575576
// conditional compilation
576577
sym::cfg,
577578
sym::cfg_attr,
579+
sym::rustc_cfg_placeholder,
578580
// testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`)
579581
sym::test,
580582
sym::ignore,
@@ -2641,7 +2643,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
26412643
// only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed
26422644
// if we allow more attributes (e.g., tool attributes and `allow/deny/warn`)
26432645
// in where clauses. After that, only `self.check_attributes` should be enough.
2644-
const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg, sym::cfg_attr];
2646+
const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg, sym::cfg_attr, sym::rustc_cfg_placeholder];
26452647
let spans = self
26462648
.tcx
26472649
.hir_attrs(where_predicate.hir_id)

0 commit comments

Comments
 (0)