diff --git a/compiler/rustc_hir/src/attrs/mod.rs b/compiler/rustc_hir/src/attrs/mod.rs index efd9c3853ee9..92dd77e80a51 100644 --- a/compiler/rustc_hir/src/attrs/mod.rs +++ b/compiler/rustc_hir/src/attrs/mod.rs @@ -77,6 +77,9 @@ macro_rules! find_attr { rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { break 'done Some($e); } + // FIXME: doesn't actually trigger in other crates :/ + // https://github.com/rust-lang/rust/issues/110613 + #[deny(unreachable_patterns)] _ => {} } } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 4c2b3cb97f76..7b97ff92e008 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -1,6 +1,7 @@ //! Some lints that are only useful in the compiler or crates that use compiler internals, such as //! Clippy. +use rustc_ast::{Pat, PatKind, Path}; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; @@ -12,10 +13,10 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::lints::{ - BadOptAccessDiag, DefaultHashTypesDiag, ImplicitSysrootCrateImportDiag, LintPassByHand, - NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag, - SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse, - TypeIrInherentUsage, TypeIrTraitUsage, + AttributeKindInFindAttr, BadOptAccessDiag, DefaultHashTypesDiag, + ImplicitSysrootCrateImportDiag, LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability, + QueryUntracked, SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag, + TykindKind, TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -621,3 +622,94 @@ fn is_whitelisted(crate_name: &str) -> bool { } } } + +declare_tool_lint! { + pub rustc::BAD_USE_OF_FIND_ATTR, + Allow, + "Forbid `AttributeKind::` as a prefix in `find_attr!` macros.", + report_in_external_macro: true +} +declare_lint_pass!(BadUseOfFindAttr => [BAD_USE_OF_FIND_ATTR]); + +impl EarlyLintPass for BadUseOfFindAttr { + fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &rustc_ast::Arm) { + fn path_contains_attribute_kind(cx: &EarlyContext<'_>, path: &Path) { + for segment in &path.segments { + if segment.ident.as_str() == "AttributeKind" { + cx.emit_span_lint( + BAD_USE_OF_FIND_ATTR, + segment.span(), + AttributeKindInFindAttr {}, + ); + } + } + } + + fn find_attr_kind_in_pat(cx: &EarlyContext<'_>, pat: &Pat) { + match &pat.kind { + PatKind::Struct(_, path, fields, _) => { + path_contains_attribute_kind(cx, path); + for field in fields { + find_attr_kind_in_pat(cx, &field.pat); + } + } + PatKind::TupleStruct(_, path, fields) => { + path_contains_attribute_kind(cx, path); + for field in fields { + find_attr_kind_in_pat(cx, &field); + } + } + PatKind::Or(options) => { + for pat in options { + find_attr_kind_in_pat(cx, pat); + } + } + PatKind::Path(_, path) => { + path_contains_attribute_kind(cx, path); + } + PatKind::Tuple(elems) => { + for pat in elems { + find_attr_kind_in_pat(cx, pat); + } + } + PatKind::Box(pat) => { + find_attr_kind_in_pat(cx, pat); + } + PatKind::Deref(pat) => { + find_attr_kind_in_pat(cx, pat); + } + PatKind::Ref(..) => { + find_attr_kind_in_pat(cx, pat); + } + PatKind::Slice(elems) => { + for pat in elems { + find_attr_kind_in_pat(cx, pat); + } + } + + PatKind::Guard(pat, ..) => { + find_attr_kind_in_pat(cx, pat); + } + PatKind::Paren(pat) => { + find_attr_kind_in_pat(cx, pat); + } + PatKind::Expr(..) + | PatKind::Range(..) + | PatKind::MacCall(..) + | PatKind::Rest + | PatKind::Missing + | PatKind::Err(..) + | PatKind::Ident(..) + | PatKind::Never + | PatKind::Wild => {} + } + } + + if let Some(expn_data) = arm.span.source_callee() + && let ExpnKind::Macro(_, name) = expn_data.kind + && name.as_str() == "find_attr" + { + find_attr_kind_in_pat(cx, &arm.pat); + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 58fa6562f2a6..a5c3a889826c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -665,6 +665,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_mod_pass(|_| Box::new(SymbolInternStringLiteral)); store.register_lints(&ImplicitSysrootCrateImport::lint_vec()); store.register_early_pass(|| Box::new(ImplicitSysrootCrateImport)); + store.register_lints(&BadUseOfFindAttr::lint_vec()); + store.register_early_pass(|| Box::new(BadUseOfFindAttr)); store.register_group( false, "rustc::internal", @@ -684,6 +686,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(SPAN_USE_EQ_CTXT), LintId::of(DIRECT_USE_OF_RUSTC_TYPE_IR), LintId::of(IMPLICIT_SYSROOT_CRATE_IMPORT), + LintId::of(BAD_USE_OF_FIND_ATTR), ], ); } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 3b34a217edfd..262a4121cc77 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1143,6 +1143,12 @@ pub(crate) struct ImplicitSysrootCrateImportDiag<'a> { pub name: &'a str, } +#[derive(LintDiagnostic)] +#[diag("use of `AttributeKind` in `find_attr!(...)` invocation")] +#[note("`find_attr!(...)` already imports `AttributeKind::*`")] +#[help("remote `AttributeKind`")] +pub(crate) struct AttributeKindInFindAttr {} + // let_underscore.rs #[derive(LintDiagnostic)] pub(crate) enum NonBindingLet { diff --git a/tests/ui-fulldeps/internal-lints/find_attr.rs b/tests/ui-fulldeps/internal-lints/find_attr.rs new file mode 100644 index 000000000000..00838132226f --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/find_attr.rs @@ -0,0 +1,24 @@ +//@ compile-flags: -Z unstable-options +//@ ignore-stage1 + +#![feature(rustc_private)] +#![deny(rustc::bad_use_of_find_attr)] + +extern crate rustc_hir; + +use rustc_hir::{attrs::AttributeKind, find_attr}; + +fn main() { + let attrs = &[]; + + find_attr!(attrs, AttributeKind::Inline(..)); + //~^ ERROR use of `AttributeKind` in `find_attr!(...)` invocation + find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecation {..}); + //~^ ERROR use of `AttributeKind` in `find_attr!(...)` invocation + //~| ERROR use of `AttributeKind` in `find_attr!(...)` invocation + + find_attr!(attrs, AttributeKind::Inline(..) => todo!()); + //~^ ERROR use of `AttributeKind` in `find_attr!(...)` invocation + find_attr!(attrs, AttributeKind::Inline(..) if true => todo!()); + //~^ ERROR use of `AttributeKind` in `find_attr!(...)` invocation +} diff --git a/tests/ui-fulldeps/internal-lints/find_attr.stderr b/tests/ui-fulldeps/internal-lints/find_attr.stderr new file mode 100644 index 000000000000..22c61563af70 --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/find_attr.stderr @@ -0,0 +1,52 @@ +error: use of `AttributeKind` in `find_attr!(...)` invocation + --> $DIR/find_attr.rs:14:23 + | +LL | find_attr!(attrs, AttributeKind::Inline(..)); + | ^^^^^^^^^^^^^ + | + = note: `find_attr!(...)` already imports `AttributeKind::*` + = help: remote `AttributeKind` +note: the lint level is defined here + --> $DIR/find_attr.rs:5:9 + | +LL | #![deny(rustc::bad_use_of_find_attr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: use of `AttributeKind` in `find_attr!(...)` invocation + --> $DIR/find_attr.rs:16:23 + | +LL | find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecation {..}); + | ^^^^^^^^^^^^^ + | + = note: `find_attr!(...)` already imports `AttributeKind::*` + = help: remote `AttributeKind` + +error: use of `AttributeKind` in `find_attr!(...)` invocation + --> $DIR/find_attr.rs:16:51 + | +LL | find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecation {..}); + | ^^^^^^^^^^^^^ + | + = note: `find_attr!(...)` already imports `AttributeKind::*` + = help: remote `AttributeKind` + +error: use of `AttributeKind` in `find_attr!(...)` invocation + --> $DIR/find_attr.rs:20:23 + | +LL | find_attr!(attrs, AttributeKind::Inline(..) => todo!()); + | ^^^^^^^^^^^^^ + | + = note: `find_attr!(...)` already imports `AttributeKind::*` + = help: remote `AttributeKind` + +error: use of `AttributeKind` in `find_attr!(...)` invocation + --> $DIR/find_attr.rs:22:23 + | +LL | find_attr!(attrs, AttributeKind::Inline(..) if true => todo!()); + | ^^^^^^^^^^^^^ + | + = note: `find_attr!(...)` already imports `AttributeKind::*` + = help: remote `AttributeKind` + +error: aborting due to 5 previous errors +