From c560da8d5eb0019255d439c5c55bd318385f6caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Tue, 3 Dec 2024 21:18:24 +0000 Subject: [PATCH 1/4] 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 + | ``` --- compiler/rustc_ast/src/ast.rs | 4 ++ compiler/rustc_ast/src/attr/mod.rs | 1 + .../rustc_ast_passes/src/ast_validation.rs | 4 ++ compiler/rustc_expand/src/config.rs | 20 ++++++- compiler/rustc_feature/src/builtin_attrs.rs | 6 +++ compiler/rustc_lint/messages.ftl | 5 +- compiler/rustc_lint/src/early/diagnostics.rs | 4 +- compiler/rustc_lint/src/lints.rs | 4 +- compiler/rustc_lint_defs/src/lib.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 4 +- compiler/rustc_resolve/src/check_unused.rs | 1 + compiler/rustc_span/src/symbol.rs | 2 + .../editions/edition-extern-crate-allowed.rs | 2 +- .../edition-extern-crate-allowed.stderr | 8 ++- tests/ui/imports/extern-crate-used.rs | 2 +- tests/ui/imports/extern-crate-used.stderr | 9 +++- tests/ui/lint/unnecessary-extern-crate.rs | 12 ++--- tests/ui/lint/unnecessary-extern-crate.stderr | 53 ++++++++++++++----- .../lint/unused/lint-unused-extern-crate.rs | 4 +- .../unused/lint-unused-extern-crate.stderr | 19 +++++-- tests/ui/proc-macro/no-macro-use-attr.rs | 2 +- tests/ui/proc-macro/no-macro-use-attr.stderr | 8 ++- tests/ui/removing-extern-crate.fixed | 8 +-- tests/ui/removing-extern-crate.rs | 10 ++-- tests/ui/removing-extern-crate.stderr | 49 ++++++++++++----- .../extern-crate-idiomatic-in-2018.fixed | 2 +- .../extern-crate-idiomatic-in-2018.rs | 2 +- .../extern-crate-idiomatic-in-2018.stderr | 8 ++- ...-54400-unused-extern-crate-attr-span.fixed | 2 +- ...sue-54400-unused-extern-crate-attr-span.rs | 4 +- ...54400-unused-extern-crate-attr-span.stderr | 14 ++--- tests/ui/rust-2018/remove-extern-crate.fixed | 2 +- tests/ui/rust-2018/remove-extern-crate.rs | 2 +- tests/ui/rust-2018/remove-extern-crate.stderr | 9 +++- 34 files changed, 210 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1b831c454e6d..738ff4277108 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3143,6 +3143,10 @@ impl AttrItem { || self.path == sym::allow || self.path == sym::deny } + + pub fn is_cfg_placeholder(&self) -> bool { + self.path == sym::rustc_cfg_placeholder + } } /// `TraitRef`s appear in impls. diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 4d613085d793..6e41958d420c 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -233,6 +233,7 @@ impl Attribute { pub fn token_trees(&self) -> Vec<TokenTree> { match self.kind { + AttrKind::Normal(ref normal) if normal.item.is_cfg_placeholder() => vec![], AttrKind::Normal(ref normal) => normal .tokens .as_ref() diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 232d60be4eb2..a4c435c09c3c 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -339,6 +339,10 @@ impl<'a> AstValidator<'a> { sym::deny, sym::expect, sym::forbid, + // `cfg` and `cfg_attr` get replaced with an inert `rustc_cfg_placeholder` to + // keep the attribute "spot" in the AST. This allows suggestions to remove an + // item to provide a correct suggestion when `#[cfg_attr]`s are present. + sym::rustc_cfg_placeholder, sym::warn, ]; !arr.contains(&attr.name_or_empty()) && rustc_attr_parsing::is_builtin_attr(*attr) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 5570c0c38e83..fae60613d0f8 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -292,7 +292,25 @@ impl<'a> StripUnconfigured<'a> { } if !attr::cfg_matches(&cfg_predicate, &self.sess, self.lint_node_id, self.features) { - return vec![]; + // `cfg` and `cfg_attr` gets replaced with an inert `rustc_cfg_placeholder` to keep the + // attribute "spot" in the AST. This allows suggestions to remove an item to provide a + // correct suggestion when `#[cfg_attr]`s are present. + let item = ast::AttrItem { + unsafety: ast::Safety::Default, + path: ast::Path::from_ident(rustc_span::symbol::Ident::with_dummy_span( + sym::rustc_cfg_placeholder, + )), + args: ast::AttrArgs::Empty, + tokens: None, + }; + let kind = ast::AttrKind::Normal(P(ast::NormalAttr { item, tokens: None })); + let attr: ast::Attribute = ast::Attribute { + kind, + id: self.sess.psess.attr_id_generator.mk_attr_id(), + style: ast::AttrStyle::Outer, + span: cfg_attr.span, + }; + return vec![attr]; } if recursive { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 40857e0066ee..db7d9a3f8243 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -752,6 +752,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(Word, List: r#""...""#), DuplicatesOk, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), + // placeholder that replaces `cfg_attr` in the item's attribute list + ungated!( + rustc_cfg_placeholder, Normal, template!(Word /* irrelevant */), DuplicatesOk, + EncodeCrossCrate::No + ), + // ========================================================================== // Internal attributes, Diagnostics related: diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d51865810b9a..666999f81d6b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -945,8 +945,9 @@ lint_unused_doc_comment = unused doc comment .label = rustdoc does not generate documentation for macro invocations .help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion -lint_unused_extern_crate = unused extern crate - .suggestion = remove it +lint_unused_extern_crate = unused `extern crate` + .label = unused + .suggestion = remove the unused `extern crate` lint_unused_import_braces = braces around {$node} is unnecessary diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 40ca9e05d95d..279f452a305e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -292,8 +292,8 @@ pub(super) fn decorate_lint( BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => { lints::ByteSliceInPackedStructWithDerive { ty }.decorate_lint(diag); } - BuiltinLintDiag::UnusedExternCrate { removal_span } => { - lints::UnusedExternCrate { removal_span }.decorate_lint(diag); + BuiltinLintDiag::UnusedExternCrate { span, removal_span } => { + lints::UnusedExternCrate { span, removal_span }.decorate_lint(diag); } BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => { let suggestion_span = vis_span.between(ident_span); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 005863095729..ff64dc5dd35b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3001,7 +3001,9 @@ pub(crate) struct ByteSliceInPackedStructWithDerive { #[derive(LintDiagnostic)] #[diag(lint_unused_extern_crate)] pub(crate) struct UnusedExternCrate { - #[suggestion(code = "", applicability = "machine-applicable")] + #[label] + pub span: Span, + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub removal_span: Span, } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 46b4b1d43838..01b0b961974a 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -735,6 +735,7 @@ pub enum BuiltinLintDiag { ty: String, }, UnusedExternCrate { + span: Span, removal_span: Span, }, ExternCrateNotIdiomatic { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ece5a53aaa9c..a43392083783 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -286,6 +286,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::prelude_import | sym::panic_handler | sym::allow_internal_unsafe + | sym::rustc_cfg_placeholder // Inert, it's a placeholder in the AST. | sym::fundamental | sym::lang | sym::needs_allocator @@ -575,6 +576,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // conditional compilation sym::cfg, sym::cfg_attr, + sym::rustc_cfg_placeholder, // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`) sym::test, sym::ignore, @@ -2641,7 +2643,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`) // in where clauses. After that, only `self.check_attributes` should be enough. - const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg, sym::cfg_attr]; + const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg, sym::cfg_attr, sym::rustc_cfg_placeholder]; let spans = self .tcx .hir_attrs(where_predicate.hir_id) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 1c1e8494ffc7..31090d40679c 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -154,6 +154,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { extern_crate.id, span, BuiltinLintDiag::UnusedExternCrate { + span: extern_crate.span, removal_span: extern_crate.span_with_attributes, }, ); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a8bec35d819..c1a54c2d4092 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1745,6 +1745,8 @@ symbols! { rustc_autodiff, rustc_builtin_macro, rustc_capture_analysis, + // We ensure that the attribute can't be written by end users by adding `-` to the name. + rustc_cfg_placeholder: "rustc-cfg-placeholder", rustc_clean, rustc_coherence_is_core, rustc_coinductive, diff --git a/tests/ui/editions/edition-extern-crate-allowed.rs b/tests/ui/editions/edition-extern-crate-allowed.rs index 5e07417e5aa1..7798928a7c42 100644 --- a/tests/ui/editions/edition-extern-crate-allowed.rs +++ b/tests/ui/editions/edition-extern-crate-allowed.rs @@ -5,6 +5,6 @@ #![warn(rust_2018_idioms)] extern crate edition_extern_crate_allowed; -//~^ WARNING unused extern crate +//~^ WARNING unused `extern crate` fn main() {} diff --git a/tests/ui/editions/edition-extern-crate-allowed.stderr b/tests/ui/editions/edition-extern-crate-allowed.stderr index dde774c520d7..f816f172311c 100644 --- a/tests/ui/editions/edition-extern-crate-allowed.stderr +++ b/tests/ui/editions/edition-extern-crate-allowed.stderr @@ -1,8 +1,8 @@ -warning: unused extern crate +warning: unused `extern crate` --> $DIR/edition-extern-crate-allowed.rs:7:1 | LL | extern crate edition_extern_crate_allowed; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/edition-extern-crate-allowed.rs:5:9 @@ -10,6 +10,10 @@ note: the lint level is defined here LL | #![warn(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ = note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]` +help: remove the unused `extern crate` + | +LL - extern crate edition_extern_crate_allowed; + | warning: 1 warning emitted diff --git a/tests/ui/imports/extern-crate-used.rs b/tests/ui/imports/extern-crate-used.rs index b57dd02cd80c..9e2e1ca340f8 100644 --- a/tests/ui/imports/extern-crate-used.rs +++ b/tests/ui/imports/extern-crate-used.rs @@ -15,7 +15,7 @@ extern crate core as iso3; extern crate core as iso4; // Doesn't introduce its extern prelude entry, so it's still considered unused. -extern crate core; //~ ERROR unused extern crate +extern crate core; //~ ERROR unused `extern crate` mod m { use iso1::any as are_you_okay1; diff --git a/tests/ui/imports/extern-crate-used.stderr b/tests/ui/imports/extern-crate-used.stderr index 982da0c913ed..fcca4a4e1a7f 100644 --- a/tests/ui/imports/extern-crate-used.stderr +++ b/tests/ui/imports/extern-crate-used.stderr @@ -1,14 +1,19 @@ -error: unused extern crate +error: unused `extern crate` --> $DIR/extern-crate-used.rs:18:1 | LL | extern crate core; - | ^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/extern-crate-used.rs:6:9 | LL | #![deny(unused_extern_crates)] | ^^^^^^^^^^^^^^^^^^^^ +help: remove the unused `extern crate` + | +LL - extern crate core; +LL + + | error: aborting due to 1 previous error diff --git a/tests/ui/lint/unnecessary-extern-crate.rs b/tests/ui/lint/unnecessary-extern-crate.rs index 7f97a4c469ed..fb4edee029ec 100644 --- a/tests/ui/lint/unnecessary-extern-crate.rs +++ b/tests/ui/lint/unnecessary-extern-crate.rs @@ -4,10 +4,10 @@ #![feature(test)] extern crate core; -//~^ ERROR unused extern crate +//~^ ERROR unused `extern crate` //~| HELP remove extern crate core as x; -//~^ ERROR unused extern crate +//~^ ERROR unused `extern crate` //~| HELP remove extern crate proc_macro; @@ -29,11 +29,11 @@ mod foo { pub(super) extern crate alloc as d; extern crate core; - //~^ ERROR unused extern crate + //~^ ERROR unused `extern crate` //~| HELP remove extern crate core as x; - //~^ ERROR unused extern crate + //~^ ERROR unused `extern crate` //~| HELP remove pub extern crate test; @@ -42,11 +42,11 @@ mod foo { mod bar { extern crate core; - //~^ ERROR unused extern crate + //~^ ERROR unused `extern crate` //~| HELP remove extern crate core as x; - //~^ ERROR unused extern crate + //~^ ERROR unused `extern crate` //~| HELP remove pub(in crate::foo::bar) extern crate alloc as e; diff --git a/tests/ui/lint/unnecessary-extern-crate.stderr b/tests/ui/lint/unnecessary-extern-crate.stderr index 1fa4aa9c9a9c..1049476fa83b 100644 --- a/tests/ui/lint/unnecessary-extern-crate.stderr +++ b/tests/ui/lint/unnecessary-extern-crate.stderr @@ -1,44 +1,73 @@ -error: unused extern crate +error: unused `extern crate` --> $DIR/unnecessary-extern-crate.rs:6:1 | LL | extern crate core; - | ^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/unnecessary-extern-crate.rs:3:9 | LL | #![deny(unused_extern_crates)] | ^^^^^^^^^^^^^^^^^^^^ +help: remove the unused `extern crate` + | +LL - extern crate core; + | -error: unused extern crate +error: unused `extern crate` --> $DIR/unnecessary-extern-crate.rs:9:1 | LL | extern crate core as x; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core as x; + | -error: unused extern crate +error: unused `extern crate` --> $DIR/unnecessary-extern-crate.rs:31:5 | LL | extern crate core; - | ^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core; + | -error: unused extern crate +error: unused `extern crate` --> $DIR/unnecessary-extern-crate.rs:35:5 | LL | extern crate core as x; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core as x; + | -error: unused extern crate +error: unused `extern crate` --> $DIR/unnecessary-extern-crate.rs:44:9 | LL | extern crate core; - | ^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core; + | -error: unused extern crate +error: unused `extern crate` --> $DIR/unnecessary-extern-crate.rs:48:9 | LL | extern crate core as x; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core as x; + | error: aborting due to 6 previous errors diff --git a/tests/ui/lint/unused/lint-unused-extern-crate.rs b/tests/ui/lint/unused/lint-unused-extern-crate.rs index 58ce3a4f55c7..be506d85caf6 100644 --- a/tests/ui/lint/unused/lint-unused-extern-crate.rs +++ b/tests/ui/lint/unused/lint-unused-extern-crate.rs @@ -8,7 +8,7 @@ #![allow(unused_variables)] #![allow(deprecated)] -extern crate lint_unused_extern_crate5; //~ ERROR: unused extern crate +extern crate lint_unused_extern_crate5; //~ ERROR: unused `extern crate` pub extern crate lint_unused_extern_crate4; // no error, it is re-exported @@ -26,7 +26,7 @@ use other::*; mod foo { // Test that this is unused even though an earlier `extern crate` is used. - extern crate lint_unused_extern_crate2; //~ ERROR unused extern crate + extern crate lint_unused_extern_crate2; //~ ERROR unused `extern crate` } fn main() { diff --git a/tests/ui/lint/unused/lint-unused-extern-crate.stderr b/tests/ui/lint/unused/lint-unused-extern-crate.stderr index 46d8f3beeab4..c4ee8ed1d944 100644 --- a/tests/ui/lint/unused/lint-unused-extern-crate.stderr +++ b/tests/ui/lint/unused/lint-unused-extern-crate.stderr @@ -1,20 +1,31 @@ -error: unused extern crate +error: unused `extern crate` --> $DIR/lint-unused-extern-crate.rs:11:1 | LL | extern crate lint_unused_extern_crate5; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/lint-unused-extern-crate.rs:7:9 | LL | #![deny(unused_extern_crates)] | ^^^^^^^^^^^^^^^^^^^^ +help: remove the unused `extern crate` + | +LL - extern crate lint_unused_extern_crate5; +LL + + | -error: unused extern crate +error: unused `extern crate` --> $DIR/lint-unused-extern-crate.rs:29:5 | LL | extern crate lint_unused_extern_crate2; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate lint_unused_extern_crate2; +LL + + | error: aborting due to 2 previous errors diff --git a/tests/ui/proc-macro/no-macro-use-attr.rs b/tests/ui/proc-macro/no-macro-use-attr.rs index d44f51bfd8d4..03e01ee33d60 100644 --- a/tests/ui/proc-macro/no-macro-use-attr.rs +++ b/tests/ui/proc-macro/no-macro-use-attr.rs @@ -4,7 +4,7 @@ #![warn(unused_extern_crates)] extern crate test_macros; -//~^ WARN unused extern crate +//~^ WARN unused `extern crate` #[rustc_error] fn main() {} //~ ERROR fatal error triggered by #[rustc_error] diff --git a/tests/ui/proc-macro/no-macro-use-attr.stderr b/tests/ui/proc-macro/no-macro-use-attr.stderr index 3dda3cc7d5a5..dcc8c5333412 100644 --- a/tests/ui/proc-macro/no-macro-use-attr.stderr +++ b/tests/ui/proc-macro/no-macro-use-attr.stderr @@ -1,14 +1,18 @@ -warning: unused extern crate +warning: unused `extern crate` --> $DIR/no-macro-use-attr.rs:6:1 | LL | extern crate test_macros; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/no-macro-use-attr.rs:4:9 | LL | #![warn(unused_extern_crates)] | ^^^^^^^^^^^^^^^^^^^^ +help: remove the unused `extern crate` + | +LL - extern crate test_macros; + | error: fatal error triggered by #[rustc_error] --> $DIR/no-macro-use-attr.rs:10:1 diff --git a/tests/ui/removing-extern-crate.fixed b/tests/ui/removing-extern-crate.fixed index 477161fba804..9941337f72be 100644 --- a/tests/ui/removing-extern-crate.fixed +++ b/tests/ui/removing-extern-crate.fixed @@ -5,12 +5,12 @@ #![warn(rust_2018_idioms)] - //~ WARNING unused extern crate - //~ WARNING unused extern crate + //~ WARNING unused `extern crate` + //~ WARNING unused `extern crate` mod another { - //~ WARNING unused extern crate - //~ WARNING unused extern crate + //~ WARNING unused `extern crate` + //~ WARNING unused `extern crate` } fn main() {} diff --git a/tests/ui/removing-extern-crate.rs b/tests/ui/removing-extern-crate.rs index 0b819482c710..2e6bf7a9ada6 100644 --- a/tests/ui/removing-extern-crate.rs +++ b/tests/ui/removing-extern-crate.rs @@ -5,12 +5,14 @@ #![warn(rust_2018_idioms)] -extern crate removing_extern_crate as foo; //~ WARNING unused extern crate -extern crate core; //~ WARNING unused extern crate +#[cfg_attr(test, macro_use)] +extern crate removing_extern_crate as foo; //~ WARNING unused `extern crate` +extern crate core; //~ WARNING unused `extern crate` mod another { - extern crate removing_extern_crate as foo; //~ WARNING unused extern crate - extern crate core; //~ WARNING unused extern crate + #[cfg_attr(test, macro_use)] + extern crate removing_extern_crate as foo; //~ WARNING unused `extern crate` + extern crate core; //~ WARNING unused `extern crate` } fn main() {} diff --git a/tests/ui/removing-extern-crate.stderr b/tests/ui/removing-extern-crate.stderr index 4dddf160ce27..371eca06685c 100644 --- a/tests/ui/removing-extern-crate.stderr +++ b/tests/ui/removing-extern-crate.stderr @@ -1,8 +1,8 @@ -warning: unused extern crate - --> $DIR/removing-extern-crate.rs:8:1 +warning: unused `extern crate` + --> $DIR/removing-extern-crate.rs:9:1 | LL | extern crate removing_extern_crate as foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/removing-extern-crate.rs:6:9 @@ -10,24 +10,49 @@ note: the lint level is defined here 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 + + | -warning: unused extern crate - --> $DIR/removing-extern-crate.rs:9:1 +warning: unused `extern crate` + --> $DIR/removing-extern-crate.rs:10:1 | LL | extern crate core; - | ^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core; +LL + + | -warning: unused extern crate - --> $DIR/removing-extern-crate.rs:12:5 +warning: unused `extern crate` + --> $DIR/removing-extern-crate.rs:14:5 | LL | extern crate removing_extern_crate as foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - #[cfg_attr(test, macro_use)] +LL - extern crate removing_extern_crate as foo; +LL + + | -warning: unused extern crate - --> $DIR/removing-extern-crate.rs:13:5 +warning: unused `extern crate` + --> $DIR/removing-extern-crate.rs:15:5 | LL | extern crate core; - | ^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core; +LL + + | warning: 4 warnings emitted diff --git a/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed b/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed index ca8422c03a3a..3eeacbb2c058 100644 --- a/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed +++ b/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed @@ -9,7 +9,7 @@ #![deny(rust_2018_idioms)] #![allow(dead_code)] -//~^ ERROR unused extern crate +//~^ ERROR unused `extern crate` // Shouldn't suggest changing to `use`, as `bar` // would no longer be added to the prelude which could cause diff --git a/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.rs b/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.rs index 717e1a039825..b962bc8fdefe 100644 --- a/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.rs +++ b/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.rs @@ -10,7 +10,7 @@ #![allow(dead_code)] extern crate edition_lint_paths; -//~^ ERROR unused extern crate +//~^ ERROR unused `extern crate` // Shouldn't suggest changing to `use`, as `bar` // would no longer be added to the prelude which could cause diff --git a/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr b/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr index a68d99c14cea..6561b49e6019 100644 --- a/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr +++ b/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr @@ -1,8 +1,8 @@ -error: unused extern crate +error: unused `extern crate` --> $DIR/extern-crate-idiomatic-in-2018.rs:12:1 | LL | extern crate edition_lint_paths; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/extern-crate-idiomatic-in-2018.rs:9:9 @@ -10,6 +10,10 @@ note: the lint level is defined here LL | #![deny(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(unused_extern_crates)]` implied by `#[deny(rust_2018_idioms)]` +help: remove the unused `extern crate` + | +LL - extern crate edition_lint_paths; + | error: aborting due to 1 previous error diff --git a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed index 878d1dc72ccb..e82422be5ccc 100644 --- a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed +++ b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed @@ -8,6 +8,6 @@ // The suggestion span should include the attribute. -//~^ ERROR unused extern crate +//~^ ERROR unused `extern crate` fn main() {} diff --git a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs index 573942bd0955..57a05631cc8f 100644 --- a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs +++ b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs @@ -8,8 +8,8 @@ // The suggestion span should include the attribute. -#[cfg(not(FALSE))] //~ HELP remove it +#[cfg(not(FALSE))] //~ HELP remove extern crate edition_lint_paths; -//~^ ERROR unused extern crate +//~^ ERROR unused `extern crate` fn main() {} diff --git a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr index 038a9dd967b7..817ed89bc89b 100644 --- a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr +++ b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr @@ -1,11 +1,8 @@ -error: unused extern crate +error: unused `extern crate` --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:12:1 | -LL | / #[cfg(not(FALSE))] -LL | | extern crate edition_lint_paths; - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | |________________________________| - | help: remove it +LL | extern crate edition_lint_paths; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:6:9 @@ -13,6 +10,11 @@ note: the lint level is defined here LL | #![deny(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(unused_extern_crates)]` implied by `#[deny(rust_2018_idioms)]` +help: remove the unused `extern crate` + | +LL - #[cfg(not(FALSE))] +LL - extern crate edition_lint_paths; + | error: aborting due to 1 previous error diff --git a/tests/ui/rust-2018/remove-extern-crate.fixed b/tests/ui/rust-2018/remove-extern-crate.fixed index 19b1dc6fb013..0952c3b2aa9e 100644 --- a/tests/ui/rust-2018/remove-extern-crate.fixed +++ b/tests/ui/rust-2018/remove-extern-crate.fixed @@ -8,7 +8,7 @@ #![allow(dropping_copy_types)] #![allow(unused_imports)] - //~ WARNING unused extern crate + //~ WARNING unused `extern crate` // Shouldn't suggest changing to `use`, as `another_name` // would no longer be added to the prelude which could cause // compilation errors for imports that use `another_name` in other diff --git a/tests/ui/rust-2018/remove-extern-crate.rs b/tests/ui/rust-2018/remove-extern-crate.rs index 88ef858da147..59a3d4343c89 100644 --- a/tests/ui/rust-2018/remove-extern-crate.rs +++ b/tests/ui/rust-2018/remove-extern-crate.rs @@ -8,7 +8,7 @@ #![allow(dropping_copy_types)] #![allow(unused_imports)] -extern crate core; //~ WARNING unused extern crate +extern crate core; //~ WARNING unused `extern crate` // Shouldn't suggest changing to `use`, as `another_name` // would no longer be added to the prelude which could cause // compilation errors for imports that use `another_name` in other diff --git a/tests/ui/rust-2018/remove-extern-crate.stderr b/tests/ui/rust-2018/remove-extern-crate.stderr index cb090c621e9f..4c8fa017cf83 100644 --- a/tests/ui/rust-2018/remove-extern-crate.stderr +++ b/tests/ui/rust-2018/remove-extern-crate.stderr @@ -1,8 +1,8 @@ -warning: unused extern crate +warning: unused `extern crate` --> $DIR/remove-extern-crate.rs:11:1 | LL | extern crate core; - | ^^^^^^^^^^^^^^^^^^ help: remove it + | ^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here --> $DIR/remove-extern-crate.rs:7:9 @@ -10,6 +10,11 @@ note: the lint level is defined here LL | #![warn(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ = note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]` +help: remove the unused `extern crate` + | +LL - extern crate core; +LL + + | warning: `extern crate` is not idiomatic in the new edition --> $DIR/remove-extern-crate.rs:35:5 From 5a8cffadefb975a681a64894209cf80138b67f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Tue, 3 Dec 2024 21:39:35 +0000 Subject: [PATCH 2/4] Use the attribute placeholder if the `cfg_attr` couldn't be parsed --- compiler/rustc_expand/src/config.rs | 43 ++++++----- .../removing-extern-crate-malformed-cfg.fixed | 15 ++++ .../ui/removing-extern-crate-malformed-cfg.rs | 17 +++++ ...removing-extern-crate-malformed-cfg.stderr | 76 +++++++++++++++++++ 4 files changed, 131 insertions(+), 20 deletions(-) create mode 100644 tests/ui/removing-extern-crate-malformed-cfg.fixed create mode 100644 tests/ui/removing-extern-crate-malformed-cfg.rs create mode 100644 tests/ui/removing-extern-crate-malformed-cfg.stderr diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index fae60613d0f8..7d34c45efbba 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -265,6 +265,27 @@ impl<'a> StripUnconfigured<'a> { } } + /// `cfg` and `cfg_attr` gets replaced with an inert `rustc_cfg_placeholder` to keep the + /// attribute "spot" in the AST. This allows suggestions to remove an item to provide a + /// correct suggestion when `#[cfg_attr]`s are present. + fn mk_placeholder(&self, cfg_attr: &ast::Attribute) -> ast::Attribute { + let item = ast::AttrItem { + unsafety: ast::Safety::Default, + path: ast::Path::from_ident(rustc_span::symbol::Ident::with_dummy_span( + sym::rustc_cfg_placeholder, + )), + args: ast::AttrArgs::Empty, + tokens: None, + }; + let kind = ast::AttrKind::Normal(P(ast::NormalAttr { item, tokens: None })); + ast::Attribute { + kind, + id: self.sess.psess.attr_id_generator.mk_attr_id(), + style: cfg_attr.style, + span: cfg_attr.span, + } + } + /// Parse and expand a single `cfg_attr` attribute into a list of attributes /// when the configuration predicate is true, or otherwise expand into an /// empty list of attributes. @@ -278,7 +299,7 @@ impl<'a> StripUnconfigured<'a> { let Some((cfg_predicate, expanded_attrs)) = rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess) else { - return vec![]; + return vec![self.mk_placeholder(cfg_attr)]; }; // Lint on zero attributes in source. @@ -292,25 +313,7 @@ impl<'a> StripUnconfigured<'a> { } if !attr::cfg_matches(&cfg_predicate, &self.sess, self.lint_node_id, self.features) { - // `cfg` and `cfg_attr` gets replaced with an inert `rustc_cfg_placeholder` to keep the - // attribute "spot" in the AST. This allows suggestions to remove an item to provide a - // correct suggestion when `#[cfg_attr]`s are present. - let item = ast::AttrItem { - unsafety: ast::Safety::Default, - path: ast::Path::from_ident(rustc_span::symbol::Ident::with_dummy_span( - sym::rustc_cfg_placeholder, - )), - args: ast::AttrArgs::Empty, - tokens: None, - }; - let kind = ast::AttrKind::Normal(P(ast::NormalAttr { item, tokens: None })); - let attr: ast::Attribute = ast::Attribute { - kind, - id: self.sess.psess.attr_id_generator.mk_attr_id(), - style: ast::AttrStyle::Outer, - span: cfg_attr.span, - }; - return vec![attr]; + return vec![self.mk_placeholder(cfg_attr)]; } if recursive { diff --git a/tests/ui/removing-extern-crate-malformed-cfg.fixed b/tests/ui/removing-extern-crate-malformed-cfg.fixed new file mode 100644 index 000000000000..df9ca180a2dd --- /dev/null +++ b/tests/ui/removing-extern-crate-malformed-cfg.fixed @@ -0,0 +1,15 @@ +//@ edition:2018 +//@ aux-build:removing-extern-crate.rs +//@ run-rustfix + +#![warn(rust_2018_idioms)] + + //~ WARNING unused `extern crate` + //~ WARNING unused `extern crate` + +mod another { + //~ WARNING unused `extern crate` + //~ WARNING unused `extern crate` +} + +fn main() {} diff --git a/tests/ui/removing-extern-crate-malformed-cfg.rs b/tests/ui/removing-extern-crate-malformed-cfg.rs new file mode 100644 index 000000000000..bf362f157537 --- /dev/null +++ b/tests/ui/removing-extern-crate-malformed-cfg.rs @@ -0,0 +1,17 @@ +//@ edition:2018 +//@ aux-build:removing-extern-crate.rs +//@ run-rustfix + +#![warn(rust_2018_idioms)] + +#[cfg_attr(test, "macro_use")] //~ ERROR expected +extern crate removing_extern_crate as foo; //~ WARNING unused `extern crate` +extern crate core; //~ WARNING unused `extern crate` + +mod another { + #[cfg_attr(test)] //~ ERROR expected + extern crate removing_extern_crate as foo; //~ WARNING unused `extern crate` + extern crate core; //~ WARNING unused `extern crate` +} + +fn main() {} diff --git a/tests/ui/removing-extern-crate-malformed-cfg.stderr b/tests/ui/removing-extern-crate-malformed-cfg.stderr new file mode 100644 index 000000000000..4ab02ef8fc1e --- /dev/null +++ b/tests/ui/removing-extern-crate-malformed-cfg.stderr @@ -0,0 +1,76 @@ +error: expected identifier, found `"macro_use"` + --> $DIR/removing-extern-crate-malformed-cfg.rs:7:18 + | +LL | #[cfg_attr(test, "macro_use")] + | ^^^^^^^^^^^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute> + +error: expected one of `(`, `,`, `::`, or `=`, found `<eof>` + --> $DIR/removing-extern-crate-malformed-cfg.rs:12:16 + | +LL | #[cfg_attr(test)] + | ^^^^ expected one of `(`, `,`, `::`, or `=` + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute> + +warning: unused `extern crate` + --> $DIR/removing-extern-crate-malformed-cfg.rs:8:1 + | +LL | extern crate removing_extern_crate as foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused + | +note: the lint level is defined here + --> $DIR/removing-extern-crate-malformed-cfg.rs:5: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 + + | + +warning: unused `extern crate` + --> $DIR/removing-extern-crate-malformed-cfg.rs:9:1 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core; +LL + + | + +warning: unused `extern crate` + --> $DIR/removing-extern-crate-malformed-cfg.rs:13:5 + | +LL | extern crate removing_extern_crate as foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - #[cfg_attr(test)] +LL - extern crate removing_extern_crate as foo; +LL + + | + +warning: unused `extern crate` + --> $DIR/removing-extern-crate-malformed-cfg.rs:14:5 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ unused + | +help: remove the unused `extern crate` + | +LL - extern crate core; +LL + + | + +error: aborting due to 2 previous errors; 4 warnings emitted + From 9985925088e80292ccad0311883f091387eca362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Tue, 3 Dec 2024 23:29:09 +0000 Subject: [PATCH 3/4] Make clippy account for `rustc_cfg_placeholder` Avoid "duplicated attribute" lints firing on the cfg placeholder. --- .../clippy/clippy_lints/src/attrs/duplicated_attributes.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index 2ddbc7a6a76d..0f3888b07965 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -36,7 +36,12 @@ fn check_duplicated_attr( } let Some(ident) = attr.ident() else { return }; let name = ident.name; - if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented || name == sym::reason { + if name == sym::doc + || name == sym::cfg_attr + || name == sym::rustc_on_unimplemented + || name == sym::reason + || name == sym::rustc_cfg_placeholder + { // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg // conditions are the same. // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected. From 59e4c2c5e069e07698217370c57af1ad00861c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Tue, 10 Dec 2024 22:01:43 +0000 Subject: [PATCH 4/4] Add test for rustc-cfg-placeholder interaction with proc-macro Ensure that the cfg-placeholder isn't visible by proc-macros. --- .../proc-macro/auxiliary/cfg-placeholder.rs | 31 +++++++++++++++++++ ...ttr-placeholder-invisible-to-proc-macro.rs | 13 ++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/ui/proc-macro/auxiliary/cfg-placeholder.rs create mode 100644 tests/ui/proc-macro/cfg-attr-placeholder-invisible-to-proc-macro.rs diff --git a/tests/ui/proc-macro/auxiliary/cfg-placeholder.rs b/tests/ui/proc-macro/auxiliary/cfg-placeholder.rs new file mode 100644 index 000000000000..0aaf56293a9f --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/cfg-placeholder.rs @@ -0,0 +1,31 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn my_proc_macro(_: TokenStream, input: TokenStream) -> TokenStream { + if format!("{input:#?}").contains("my_attr1") { + panic!("found gated attribute my_attr1"); + } + if format!("{input:#?}").contains("placeholder") { + panic!("found placeholder attribute"); + } + if !format!("{input:#?}").contains("my_attr2") { + panic!("didn't if gated my_attr2"); + } + input +} + +#[proc_macro_attribute] +pub fn my_attr1(_: TokenStream, input: TokenStream) -> TokenStream { + panic!("my_attr1 was called"); + input +} + +#[proc_macro_attribute] +pub fn my_attr2(_: TokenStream, input: TokenStream) -> TokenStream { + if format!("{input:#?}").contains("my_attr1") { + panic!("found gated attribute my_attr1"); + } + input +} diff --git a/tests/ui/proc-macro/cfg-attr-placeholder-invisible-to-proc-macro.rs b/tests/ui/proc-macro/cfg-attr-placeholder-invisible-to-proc-macro.rs new file mode 100644 index 000000000000..62cac7878836 --- /dev/null +++ b/tests/ui/proc-macro/cfg-attr-placeholder-invisible-to-proc-macro.rs @@ -0,0 +1,13 @@ +// Ensure that `rustc-cfg-placeholder` isn't visible to proc-macros. +//@proc-macro: cfg-placeholder.rs +//@check-pass +#![feature(cfg_eval)] +#[macro_use] extern crate cfg_placeholder; + +#[cfg_eval] +#[my_proc_macro] +#[cfg_attr(FALSE, my_attr1)] +#[cfg_attr(all(), my_attr2)] +struct S {} + +fn main() {}