about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr_parsing')
-rw-r--r--compiler/rustc_attr_parsing/Cargo.toml1
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs22
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/body.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs77
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs29
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/dummy.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs20
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/link_attrs.rs32
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs27
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/loop_match.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs19
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs21
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/must_use.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs13
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/path.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs12
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs17
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/semantics.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs43
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/test_attrs.rs9
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs26
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/transparency.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs243
-rw-r--r--compiler/rustc_attr_parsing/src/lints.rs23
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs23
29 files changed, 666 insertions, 56 deletions
diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml
index cec9d62e656..bac89373b67 100644
--- a/compiler/rustc_attr_parsing/Cargo.toml
+++ b/compiler/rustc_attr_parsing/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
+itertools = "0.12"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index de22ea322c7..4fb66a81652 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -10,6 +10,12 @@ attr_parsing_empty_attribute =
     unused attribute
     .suggestion = remove this attribute
 
+attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target}
+    .help = `#[{$name}]` can {$only}be applied to {$applied}
+attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target}
+    .warn = {-attr_parsing_previously_accepted}
+    .help = `#[{$name}]` can {$only}be applied to {$applied}
+
 attr_parsing_empty_confusables =
     expected at least one confusable name
 attr_parsing_expected_one_cfg_pattern =
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index b3393e93de8..4d995027814 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -2,10 +2,12 @@ use std::iter;
 
 use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::AttributeKind;
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
 use super::{CombineAttributeParser, ConvertFn};
-use crate::context::{AcceptContext, Stage};
+use crate::context::MaybeWarn::{Allow, Warn};
+use crate::context::{AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
 
@@ -15,6 +17,12 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
     type Item = (Symbol, Span);
     const CONVERT: ConvertFn<Self::Item> =
         |items, span| AttributeKind::AllowInternalUnstable(items, span);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::MacroDef),
+        Allow(Target::Fn),
+        Warn(Target::Field),
+        Warn(Target::Arm),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
 
     fn extend<'c>(
@@ -32,6 +40,11 @@ impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
     const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
     type Item = (Symbol, Span);
     const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Impl { of_trait: true }),
+        Allow(Target::Trait),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
 
     fn extend<'c>(
@@ -53,6 +66,13 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
     type Item = Symbol;
     const CONVERT: ConvertFn<Self::Item> =
         |items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
 
     fn extend<'c>(
diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs
index ab9330216f6..88540384621 100644
--- a/compiler/rustc_attr_parsing/src/attributes/body.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/body.rs
@@ -1,15 +1,18 @@
 //! Attributes that can be found in function body.
 
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use super::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::Stage;
+use crate::context::MaybeWarn::Allow;
+use crate::context::{AllowedTargets, Stage};
 
 pub(crate) struct CoroutineParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for CoroutineParser {
     const PATH: &[Symbol] = &[sym::coroutine];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
     const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span);
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index a9f77195d1b..6ea073896c2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -1,5 +1,6 @@
 use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy};
+use rustc_hir::{MethodKind, Target};
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
 
@@ -7,7 +8,8 @@ use super::{
     AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn,
     NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
 };
-use crate::context::{AcceptContext, FinalizeContext, Stage};
+use crate::context::MaybeWarn::{Allow, Warn};
+use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
 
@@ -17,6 +19,13 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
     const PATH: &[Symbol] = &[sym::optimize];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Closure),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Inherent)),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
@@ -49,6 +58,15 @@ pub(crate) struct ColdParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
     const PATH: &[Symbol] = &[sym::cold];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::ForeignFn),
+        Allow(Target::Closure),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
 }
 
@@ -58,6 +76,17 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
     const PATH: &[Symbol] = &[sym::coverage];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Closure),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Impl { of_trait: true }),
+        Allow(Target::Impl { of_trait: false }),
+        Allow(Target::Mod),
+        Allow(Target::Crate),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
@@ -97,6 +126,16 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
     const PATH: &[rustc_span::Symbol] = &[sym::export_name];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Static),
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Warn(Target::Field),
+        Warn(Target::Arm),
+        Warn(Target::MacroDef),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
@@ -138,6 +177,12 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
                 this.span = Some(cx.attr_span);
             }
         })];
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+    ]);
 
     fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         // FIXME(jdonszelmann): upgrade this list to *parsed* attributes
@@ -230,6 +275,18 @@ pub(crate) struct TrackCallerParser;
 impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
     const PATH: &[Symbol] = &[sym::track_caller];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::ForeignFn),
+        Allow(Target::Closure),
+        Warn(Target::MacroDef),
+        Warn(Target::Arm),
+        Warn(Target::Field),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
 }
 
@@ -237,6 +294,12 @@ pub(crate) struct NoMangleParser;
 impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
     const PATH: &[Symbol] = &[sym::no_mangle];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
+        Allow(Target::Fn),
+        Allow(Target::Static),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
 }
 
@@ -310,6 +373,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
             }
         },
     )];
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]);
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker`
@@ -373,4 +437,15 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
         }
         features
     }
+
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Warn(Target::Statement),
+        Warn(Target::Field),
+        Warn(Target::Arm),
+        Warn(Target::MacroDef),
+    ]);
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index edd22172ca2..00f949c82c5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -1,12 +1,13 @@
 use rustc_feature::template;
 use rustc_hir::attrs::AttributeKind;
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
 use super::{AcceptMapping, AttributeParser};
-use crate::context::{FinalizeContext, Stage};
+use crate::context::MaybeWarn::Allow;
+use crate::context::{AllowedTargets, FinalizeContext, Stage};
 use crate::session_diagnostics;
-
 #[derive(Default)]
 pub(crate) struct ConfusablesParser {
     confusables: ThinVec<Symbol>,
@@ -41,6 +42,8 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
             this.first_span.get_or_insert(cx.attr_span);
         },
     )];
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.confusables.is_empty() {
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index e57ea8bbb5c..8101c91460f 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -1,13 +1,14 @@
 use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
 use super::util::parse_version;
 use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
+use crate::context::MaybeWarn::{Allow, Error};
+use crate::context::{AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
-
 pub(crate) struct DeprecationParser;
 
 fn get<S: Stage>(
@@ -38,6 +39,30 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
     const PATH: &[Symbol] = &[sym::deprecated];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
+        Allow(Target::Fn),
+        Allow(Target::Mod),
+        Allow(Target::Struct),
+        Allow(Target::Enum),
+        Allow(Target::Union),
+        Allow(Target::Const),
+        Allow(Target::Static),
+        Allow(Target::MacroDef),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::TyAlias),
+        Allow(Target::Use),
+        Allow(Target::ForeignFn),
+        Allow(Target::Field),
+        Allow(Target::Trait),
+        Allow(Target::AssocTy),
+        Allow(Target::AssocConst),
+        Allow(Target::Variant),
+        Allow(Target::Impl { of_trait: false }), //FIXME This does not make sense
+        Allow(Target::Crate),
+        Error(Target::WherePredicate),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(
         Word,
         List: &[r#"since = "version""#, r#"note = "reason""#, r#"since = "version", note = "reason""#],
diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs
index bbcd9ab530c..85842b1b5c5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs
@@ -3,14 +3,14 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
+use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
-
 pub(crate) struct DummyParser;
 impl<S: Stage> SingleAttributeParser<S> for DummyParser {
     const PATH: &[Symbol] = &[sym::rustc_dummy];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
     const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
 
     fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser<'_>) -> Option<AttributeKind> {
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index e9a45f20bff..6a659a95b85 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -5,19 +5,34 @@
 use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::{AttributeKind, InlineAttr};
 use rustc_hir::lints::AttributeLintKind;
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{Symbol, sym};
 
 use super::{AcceptContext, AttributeOrder, OnDuplicate};
 use crate::attributes::SingleAttributeParser;
-use crate::context::Stage;
+use crate::context::MaybeWarn::{Allow, Warn};
+use crate::context::{AllowedTargets, Stage};
 use crate::parser::ArgParser;
-
 pub(crate) struct InlineParser;
 
 impl<S: Stage> SingleAttributeParser<S> for InlineParser {
     const PATH: &'static [Symbol] = &[sym::inline];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Closure),
+        Allow(Target::Delegation { mac: false }),
+        Warn(Target::Method(MethodKind::Trait { body: false })),
+        Warn(Target::ForeignFn),
+        Warn(Target::Field),
+        Warn(Target::MacroDef),
+        Warn(Target::Arm),
+        Warn(Target::AssocConst),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(
         Word,
         List: &["always", "never"],
@@ -63,6 +78,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
     const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
     const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
index e4ced2e37c5..552b9dfabc2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
@@ -1,21 +1,26 @@
 use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
 use rustc_hir::attrs::{AttributeKind, Linkage};
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{
     AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
 };
-use crate::context::{AcceptContext, Stage, parse_single_integer};
+use crate::context::MaybeWarn::Allow;
+use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage, parse_single_integer};
 use crate::parser::ArgParser;
 use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection};
-
 pub(crate) struct LinkNameParser;
 
 impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
     const PATH: &[Symbol] = &[sym::link_name];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
+        Allow(Target::ForeignFn),
+        Allow(Target::ForeignStatic),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(
         NameValueStr: "name",
         "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
@@ -41,6 +46,8 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
     const PATH: &[Symbol] = &[sym::link_section];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowListWarnRest(&[Allow(Target::Static), Allow(Target::Fn)]);
     const TEMPLATE: AttributeTemplate = template!(
         NameValueStr: "name",
         "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
@@ -70,6 +77,7 @@ pub(crate) struct ExportStableParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
     const PATH: &[Symbol] = &[sym::export_stable];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
 }
 
@@ -77,6 +85,7 @@ pub(crate) struct FfiConstParser;
 impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
     const PATH: &[Symbol] = &[sym::ffi_const];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
 }
 
@@ -84,6 +93,7 @@ pub(crate) struct FfiPureParser;
 impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
     const PATH: &[Symbol] = &[sym::ffi_pure];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
 }
 
@@ -91,6 +101,12 @@ pub(crate) struct StdInternalSymbolParser;
 impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
     const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::ForeignFn),
+        Allow(Target::Static),
+        Allow(Target::ForeignStatic),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
 }
 
@@ -100,6 +116,8 @@ impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
     const PATH: &[Symbol] = &[sym::link_ordinal];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
     const TEMPLATE: AttributeTemplate = template!(
         List: &["ordinal"],
         "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
@@ -138,6 +156,16 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
 
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Static),
+        Allow(Target::ForeignStatic),
+        Allow(Target::ForeignFn),
+    ]);
 
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: [
         "available_externally",
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
index 9530fec07d6..2b586d4003c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
@@ -1,13 +1,21 @@
 use rustc_hir::attrs::AttributeKind;
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::Stage;
-
+use crate::context::MaybeWarn::{Allow, Error};
+use crate::context::{AllowedTargets, Stage};
 pub(crate) struct AsPtrParser;
 impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser {
     const PATH: &[Symbol] = &[sym::rustc_as_ptr];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr;
 }
 
@@ -15,6 +23,11 @@ pub(crate) struct PubTransparentParser;
 impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser {
     const PATH: &[Symbol] = &[sym::rustc_pub_transparent];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Struct),
+        Allow(Target::Enum),
+        Allow(Target::Union),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent;
 }
 
@@ -22,6 +35,11 @@ pub(crate) struct PassByValueParser;
 impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser {
     const PATH: &[Symbol] = &[sym::rustc_pass_by_value];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Struct),
+        Allow(Target::Enum),
+        Allow(Target::TyAlias),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue;
 }
 
@@ -29,5 +47,10 @@ pub(crate) struct AutomaticallyDerivedParser;
 impl<S: Stage> NoArgsAttributeParser<S> for AutomaticallyDerivedParser {
     const PATH: &[Symbol] = &[sym::automatically_derived];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
+        Allow(Target::Impl { of_trait: true }),
+        Error(Target::Crate),
+        Error(Target::WherePredicate),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::AutomaticallyDerived;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
index 868c113a6d1..242e2f2c1bc 100644
--- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
@@ -1,13 +1,15 @@
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::Stage;
-
+use crate::context::MaybeWarn::Allow;
+use crate::context::{AllowedTargets, Stage};
 pub(crate) struct LoopMatchParser;
 impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser {
     const PATH: &[Symbol] = &[sym::loop_match];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch;
 }
 
@@ -15,5 +17,6 @@ pub(crate) struct ConstContinueParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ConstContinueParser {
     const PATH: &[Symbol] = &[sym::const_continue];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
index a1166bf9ac5..c9b5dd35fa1 100644
--- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
@@ -1,18 +1,20 @@
 use rustc_errors::DiagArgValue;
 use rustc_feature::{AttributeTemplate, template};
+use rustc_hir::Target;
 use rustc_hir::attrs::{AttributeKind, MacroUseArgs};
 use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
 use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate};
-use crate::context::{AcceptContext, FinalizeContext, Stage};
+use crate::context::MaybeWarn::{Allow, Error, Warn};
+use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
-
 pub(crate) struct MacroEscapeParser;
 impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
     const PATH: &[Symbol] = &[sym::macro_escape];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS;
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::MacroEscape;
 }
 
@@ -35,6 +37,12 @@ const MACRO_USE_TEMPLATE: AttributeTemplate = template!(
     Word, List: &["name1, name2, ..."],
     "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
 );
+const MACRO_USE_ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
+    Allow(Target::Mod),
+    Allow(Target::ExternCrate),
+    Allow(Target::Crate),
+    Error(Target::WherePredicate),
+]);
 
 impl<S: Stage> AttributeParser<S> for MacroUseParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[(
@@ -111,6 +119,7 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
             }
         },
     )];
+    const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS;
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
@@ -122,5 +131,11 @@ pub(crate) struct AllowInternalUnsafeParser;
 impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
     const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::MacroDef),
+        Warn(Target::Field),
+        Warn(Target::Arm),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index f7946ade6d2..ed5d1d92b8c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -21,7 +21,7 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol};
 use thin_vec::ThinVec;
 
-use crate::context::{AcceptContext, FinalizeContext, Stage};
+use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics::UnusedMultiple;
 
@@ -80,6 +80,8 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
     /// If an attribute has this symbol, the `accept` function will be called on it.
     const ATTRIBUTES: AcceptMapping<Self, S>;
 
+    const ALLOWED_TARGETS: AllowedTargets;
+
     /// The parser has gotten a chance to accept the attributes on an item,
     /// here it can produce an attribute.
     ///
@@ -116,6 +118,8 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
     /// and this specified whether to, for example, warn or error on the other one.
     const ON_DUPLICATE: OnDuplicate<S>;
 
+    const ALLOWED_TARGETS: AllowedTargets;
+
     /// The template this attribute parser should implement. Used for diagnostics.
     const TEMPLATE: AttributeTemplate;
 
@@ -163,6 +167,7 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
             }
         },
     )];
+    const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         Some(self.1?.0)
@@ -247,6 +252,7 @@ pub(crate) enum AttributeOrder {
 pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
     const PATH: &[Symbol];
     const ON_DUPLICATE: OnDuplicate<S>;
+    const ALLOWED_TARGETS: AllowedTargets;
 
     /// Create the [`AttributeKind`] given attribute's [`Span`].
     const CREATE: fn(Span) -> AttributeKind;
@@ -264,6 +270,7 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without
     const PATH: &[Symbol] = T::PATH;
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
+    const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
     const TEMPLATE: AttributeTemplate = template!(Word);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
@@ -293,6 +300,8 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
     ///  where `x` is a vec of these individual reprs.
     const CONVERT: ConvertFn<Self::Item>;
 
+    const ALLOWED_TARGETS: AllowedTargets;
+
     /// The template this attribute parser should implement. Used for diagnostics.
     const TEMPLATE: AttributeTemplate;
 
@@ -324,15 +333,13 @@ impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
 }
 
 impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
-    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
-        T::PATH,
-        <T as CombineAttributeParser<S>>::TEMPLATE,
-        |group: &mut Combine<T, S>, cx, args| {
+    const ATTRIBUTES: AcceptMapping<Self, S> =
+        &[(T::PATH, T::TEMPLATE, |group: &mut Combine<T, S>, cx, args| {
             // Keep track of the span of the first attribute, for diagnostics
             group.first_span.get_or_insert(cx.attr_span);
             group.items.extend(T::extend(cx, args))
-        },
-    )];
+        })];
+    const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if let Some(first_span) = self.first_span {
diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
index c88bb5a69e5..b6cfc780590 100644
--- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
@@ -4,16 +4,16 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
+use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
-
 pub(crate) struct MustUseParser;
 
 impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
     const PATH: &[Symbol] = &[sym::must_use];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
     const TEMPLATE: AttributeTemplate = template!(
         Word, NameValueStr: "reason",
         "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
diff --git a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs
index 40f8d00685e..589faf38f73 100644
--- a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs
@@ -1,13 +1,16 @@
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::Stage;
-
+use crate::context::MaybeWarn::Allow;
+use crate::context::{AllowedTargets, Stage};
 pub(crate) struct NoImplicitPreludeParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for NoImplicitPreludeParser {
     const PATH: &[rustc_span::Symbol] = &[sym::no_implicit_prelude];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Allow(Target::Crate)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoImplicitPrelude;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
index 361ac8e959d..41e9ca4de41 100644
--- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
@@ -1,13 +1,22 @@
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::Stage;
-
+use crate::context::MaybeWarn::{Allow, Warn};
+use crate::context::{AllowedTargets, Stage};
 pub(crate) struct NonExhaustiveParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser {
     const PATH: &[Symbol] = &[sym::non_exhaustive];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Enum),
+        Allow(Target::Struct),
+        Allow(Target::Variant),
+        Warn(Target::Field),
+        Warn(Target::Arm),
+        Warn(Target::MacroDef),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs
index c1c3de8cbfc..f9191d1abed 100644
--- a/compiler/rustc_attr_parsing/src/attributes/path.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/path.rs
@@ -1,17 +1,20 @@
 use rustc_feature::{AttributeTemplate, template};
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
+use crate::context::MaybeWarn::{Allow, Error};
+use crate::context::{AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
-
 pub(crate) struct PathParser;
 
 impl<S: Stage> SingleAttributeParser<S> for PathParser {
     const PATH: &[Symbol] = &[sym::path];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Error(Target::Crate)]);
     const TEMPLATE: AttributeTemplate = template!(
         NameValueStr: "file",
         "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
index b267980914c..4624fa36287 100644
--- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
@@ -1,4 +1,5 @@
 use rustc_feature::{AttributeTemplate, template};
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
@@ -6,13 +7,15 @@ use thin_vec::ThinVec;
 use crate::attributes::{
     AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
 };
-use crate::context::{AcceptContext, Stage};
+use crate::context::MaybeWarn::{Allow, Warn};
+use crate::context::{AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
-
 pub(crate) struct ProcMacroParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
     const PATH: &[Symbol] = &[sym::proc_macro];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro;
 }
 
@@ -20,6 +23,8 @@ pub(crate) struct ProcMacroAttributeParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
     const PATH: &[Symbol] = &[sym::proc_macro_attribute];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute;
 }
 
@@ -28,6 +33,8 @@ impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
     const PATH: &[Symbol] = &[sym::proc_macro_derive];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]);
     const TEMPLATE: AttributeTemplate = template!(
         List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
         "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
@@ -48,6 +55,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
     const PATH: &[Symbol] = &[sym::rustc_builtin_macro];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
     const TEMPLATE: AttributeTemplate =
         template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]);
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 996d2af5f37..7ab58ed9347 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -2,14 +2,15 @@ use rustc_abi::Align;
 use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
 use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::{AttributeKind, IntType, ReprAttr};
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 
 use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext};
-use crate::context::{AcceptContext, Stage};
+use crate::context::MaybeWarn::Allow;
+use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage};
 use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
 use crate::session_diagnostics;
 use crate::session_diagnostics::IncorrectReprFormatGenericCause;
-
 /// Parse #[repr(...)] forms.
 ///
 /// Valid repr contents: any of the primitive integral type names (see
@@ -60,6 +61,10 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
 
         reprs
     }
+
+    //FIXME Still checked fully in `check_attr.rs`
+    //This one is slightly more complicated because the allowed targets depend on the arguments
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
 }
 
 macro_rules! int_pat {
@@ -318,6 +323,14 @@ impl AlignParser {
 
 impl<S: Stage> AttributeParser<S> for AlignParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::TraitImpl)),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::ForeignFn),
+    ]);
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         let (align, span) = self.0?;
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index 1a668b4416f..efd7b650e44 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -1,17 +1,19 @@
 use rustc_feature::{AttributeTemplate, template};
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage, parse_single_integer};
+use crate::context::MaybeWarn::Allow;
+use crate::context::{AcceptContext, AllowedTargets, Stage, parse_single_integer};
 use crate::parser::ArgParser;
-
 pub(crate) struct RustcLayoutScalarValidRangeStart;
 
 impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
     const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
     const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
@@ -26,6 +28,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd {
     const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
     const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
@@ -40,6 +43,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {
     const PATH: &[rustc_span::Symbol] = &[sym::rustc_object_lifetime_default];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
     const TEMPLATE: AttributeTemplate = template!(Word);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs
index 70a8a002099..d4ad861a3a2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs
@@ -2,11 +2,11 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::Stage;
-
+use crate::context::{ALL_TARGETS, AllowedTargets, Stage};
 pub(crate) struct MayDangleParser;
 impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser {
     const PATH: &[Symbol] = &[sym::may_dangle];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
     const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index c6707f5048b..5a26178f84b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -4,15 +4,16 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_feature::template;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::{
-    DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, StableSince,
-    UnstableReason, VERSION_PLACEHOLDER,
+    DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
+    StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_span::{Ident, Span, Symbol, sym};
 
 use super::util::parse_version;
 use super::{AcceptMapping, AttributeParser, OnDuplicate};
 use crate::attributes::NoArgsAttributeParser;
-use crate::context::{AcceptContext, FinalizeContext, Stage};
+use crate::context::MaybeWarn::Allow;
+use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage};
 use crate::parser::{ArgParser, MetaItemParser};
 use crate::session_diagnostics::{self, UnsupportedLiteralReason};
 
@@ -26,6 +27,35 @@ macro_rules! reject_outside_std {
     };
 }
 
+const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+    Allow(Target::Fn),
+    Allow(Target::Struct),
+    Allow(Target::Enum),
+    Allow(Target::Union),
+    Allow(Target::Method(MethodKind::Inherent)),
+    Allow(Target::Method(MethodKind::Trait { body: false })),
+    Allow(Target::Method(MethodKind::Trait { body: true })),
+    Allow(Target::Method(MethodKind::TraitImpl)),
+    Allow(Target::Impl { of_trait: false }),
+    Allow(Target::Impl { of_trait: true }),
+    Allow(Target::MacroDef),
+    Allow(Target::Crate),
+    Allow(Target::Mod),
+    Allow(Target::Use), // FIXME I don't think this does anything?
+    Allow(Target::Const),
+    Allow(Target::AssocConst),
+    Allow(Target::AssocTy),
+    Allow(Target::Trait),
+    Allow(Target::TraitAlias),
+    Allow(Target::TyAlias),
+    Allow(Target::Variant),
+    Allow(Target::Field),
+    Allow(Target::Param),
+    Allow(Target::Static),
+    Allow(Target::ForeignFn),
+    Allow(Target::ForeignStatic),
+]);
+
 #[derive(Default)]
 pub(crate) struct StabilityParser {
     allowed_through_unstable_modules: Option<Symbol>,
@@ -87,6 +117,7 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
             },
         ),
     ];
+    const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
 
     fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if let Some(atum) = self.allowed_through_unstable_modules {
@@ -142,6 +173,7 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
             }
         },
     )];
+    const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         let (stability, span) = self.stability?;
@@ -154,6 +186,10 @@ pub(crate) struct ConstStabilityIndirectParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser {
     const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect;
 }
 
@@ -213,6 +249,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
             this.promotable = true;
         }),
     ];
+    const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
 
     fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.promotable {
diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
index 3267855fb0d..8b666c3868b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
@@ -1,18 +1,21 @@
 use rustc_feature::{AttributeTemplate, template};
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::lints::AttributeLintKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
+use crate::context::MaybeWarn::{Allow, Error};
+use crate::context::{AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
-
 pub(crate) struct IgnoreParser;
 
 impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
     const PATH: &[Symbol] = &[sym::ignore];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
     const TEMPLATE: AttributeTemplate = template!(
         Word, NameValueStr: "reason",
         "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
@@ -54,6 +57,8 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
     const PATH: &[Symbol] = &[sym::should_panic];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
     const TEMPLATE: AttributeTemplate = template!(
         Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
         "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index 8514d799aa4..ee9d7ba99cd 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -2,19 +2,21 @@ use core::mem;
 
 use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::AttributeKind;
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{
     AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
 };
-use crate::context::{AcceptContext, Stage};
+use crate::context::MaybeWarn::{Allow, Warn};
+use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
-
 pub(crate) struct SkipDuringMethodDispatchParser;
 impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
     const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
 
     const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]);
 
@@ -58,6 +60,7 @@ pub(crate) struct ParenSugarParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ParenSugarParser {
     const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::ParenSugar;
 }
 
@@ -65,6 +68,7 @@ pub(crate) struct TypeConstParser;
 impl<S: Stage> NoArgsAttributeParser<S> for TypeConstParser {
     const PATH: &[Symbol] = &[sym::type_const];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocConst)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst;
 }
 
@@ -74,6 +78,12 @@ pub(crate) struct MarkerParser;
 impl<S: Stage> NoArgsAttributeParser<S> for MarkerParser {
     const PATH: &[Symbol] = &[sym::marker];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Trait),
+        Warn(Target::Field),
+        Warn(Target::Arm),
+        Warn(Target::MacroDef),
+    ]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::Marker;
 }
 
@@ -81,6 +91,7 @@ pub(crate) struct DenyExplicitImplParser;
 impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
     const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
 }
 
@@ -88,6 +99,7 @@ pub(crate) struct DoNotImplementViaObjectParser;
 impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
     const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
 }
 
@@ -98,6 +110,7 @@ pub(crate) struct ConstTraitParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ConstTraitParser {
     const PATH: &[Symbol] = &[sym::const_trait];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstTrait;
 }
 
@@ -107,6 +120,7 @@ pub(crate) struct SpecializationTraitParser;
 impl<S: Stage> NoArgsAttributeParser<S> for SpecializationTraitParser {
     const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::SpecializationTrait;
 }
 
@@ -114,6 +128,7 @@ pub(crate) struct UnsafeSpecializationMarkerParser;
 impl<S: Stage> NoArgsAttributeParser<S> for UnsafeSpecializationMarkerParser {
     const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker;
 }
 
@@ -123,6 +138,7 @@ pub(crate) struct CoinductiveParser;
 impl<S: Stage> NoArgsAttributeParser<S> for CoinductiveParser {
     const PATH: &[Symbol] = &[sym::rustc_coinductive];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::Coinductive;
 }
 
@@ -130,6 +146,8 @@ pub(crate) struct AllowIncoherentImplParser;
 impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
     const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
 }
 
@@ -137,6 +155,7 @@ pub(crate) struct CoherenceIsCoreParser;
 impl<S: Stage> NoArgsAttributeParser<S> for CoherenceIsCoreParser {
     const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore;
 }
 
@@ -144,6 +163,8 @@ pub(crate) struct FundamentalParser;
 impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
     const PATH: &[Symbol] = &[sym::fundamental];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::Struct), Allow(Target::Trait)]);
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental;
 }
 
@@ -151,5 +172,6 @@ pub(crate) struct PointeeParser;
 impl<S: Stage> NoArgsAttributeParser<S> for PointeeParser {
     const PATH: &[Symbol] = &[sym::pointee];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
index d4d68eb8b27..0ffcf434b52 100644
--- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -1,12 +1,13 @@
 use rustc_feature::{AttributeTemplate, template};
+use rustc_hir::Target;
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::hygiene::Transparency;
 use rustc_span::{Symbol, sym};
 
 use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
+use crate::context::MaybeWarn::Allow;
+use crate::context::{AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
-
 pub(crate) struct TransparencyParser;
 
 // FIXME(jdonszelmann): make these proper diagnostics
@@ -18,6 +19,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| {
         cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
     });
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
     const TEMPLATE: AttributeTemplate =
         template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
 
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 6045a8b28a2..bebe3350c4e 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -3,13 +3,16 @@ use std::collections::BTreeMap;
 use std::ops::{Deref, DerefMut};
 use std::sync::LazyLock;
 
+use itertools::Itertools;
 use private::Sealed;
 use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId};
 use rustc_errors::{DiagCtxtHandle, Diagnostic};
 use rustc_feature::{AttributeTemplate, Features};
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::lints::{AttributeLint, AttributeLintKind};
-use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
+use rustc_hir::{
+    AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, MethodKind, Target,
+};
 use rustc_session::Session;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 
@@ -61,8 +64,11 @@ use crate::attributes::traits::{
 };
 use crate::attributes::transparency::TransparencyParser;
 use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
+use crate::context::MaybeWarn::{Allow, Error, Warn};
 use crate::parser::{ArgParser, MetaItemParser, PathParser};
-use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
+use crate::session_diagnostics::{
+    AttributeParseError, AttributeParseErrorReason, InvalidTarget, UnknownMetaItem,
+};
 
 type GroupType<S> = LazyLock<GroupTypeInner<S>>;
 
@@ -74,6 +80,7 @@ struct GroupTypeInner<S: Stage> {
 struct GroupTypeInnerAccept<S: Stage> {
     template: AttributeTemplate,
     accept_fn: AcceptFn<S>,
+    allowed_targets: AllowedTargets,
 }
 
 type AcceptFn<S> =
@@ -121,7 +128,8 @@ macro_rules! attribute_parsers {
                                 STATE_OBJECT.with_borrow_mut(|s| {
                                     accept_fn(s, cx, args)
                                 })
-                            })
+                            }),
+                            allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
                         });
                     }
 
@@ -643,6 +651,64 @@ impl ShouldEmit {
     }
 }
 
+#[derive(Debug)]
+pub(crate) enum AllowedTargets {
+    AllowList(&'static [MaybeWarn]),
+    AllowListWarnRest(&'static [MaybeWarn]),
+}
+
+pub(crate) enum AllowedResult {
+    Allowed,
+    Warn,
+    Error,
+}
+
+impl AllowedTargets {
+    pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult {
+        match self {
+            AllowedTargets::AllowList(list) => {
+                if list.contains(&Allow(target)) {
+                    AllowedResult::Allowed
+                } else if list.contains(&Warn(target)) {
+                    AllowedResult::Warn
+                } else {
+                    AllowedResult::Error
+                }
+            }
+            AllowedTargets::AllowListWarnRest(list) => {
+                if list.contains(&Allow(target)) {
+                    AllowedResult::Allowed
+                } else if list.contains(&Error(target)) {
+                    AllowedResult::Error
+                } else {
+                    AllowedResult::Warn
+                }
+            }
+        }
+    }
+
+    pub(crate) fn allowed_targets(&self) -> Vec<Target> {
+        match self {
+            AllowedTargets::AllowList(list) => list,
+            AllowedTargets::AllowListWarnRest(list) => list,
+        }
+        .iter()
+        .filter_map(|target| match target {
+            Allow(target) => Some(*target),
+            Warn(_) => None,
+            Error(_) => None,
+        })
+        .collect()
+    }
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub(crate) enum MaybeWarn {
+    Allow(Target),
+    Warn(Target),
+    Error(Target),
+}
+
 /// Context created once, for example as part of the ast lowering
 /// context, through which all attributes can be lowered.
 pub struct AttributeParser<'sess, S: Stage = Late> {
@@ -691,6 +757,7 @@ impl<'sess> AttributeParser<'sess, Early> {
             attrs,
             target_span,
             target_node_id,
+            Target::Crate, // Does not matter, we're not going to emit errors anyways
             OmitDoc::Skip,
             std::convert::identity,
             |_lint| {
@@ -777,6 +844,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
         attrs: &[ast::Attribute],
         target_span: Span,
         target_id: S::Id,
+        target: Target,
         omit_doc: OmitDoc,
 
         lower_span: impl Copy + Fn(Span) -> Span,
@@ -848,7 +916,48 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
                                 attr_path: path.get_attribute_path(),
                             };
 
-                            (accept.accept_fn)(&mut cx, args)
+                            (accept.accept_fn)(&mut cx, args);
+
+                            if self.stage.should_emit().should_emit() {
+                                match accept.allowed_targets.is_allowed(target) {
+                                    AllowedResult::Allowed => {}
+                                    AllowedResult::Warn => {
+                                        let allowed_targets =
+                                            accept.allowed_targets.allowed_targets();
+                                        let (applied, only) = allowed_targets_applied(
+                                            allowed_targets,
+                                            target,
+                                            self.features,
+                                        );
+                                        emit_lint(AttributeLint {
+                                            id: target_id,
+                                            span: attr.span,
+                                            kind: AttributeLintKind::InvalidTarget {
+                                                name: parts[0],
+                                                target,
+                                                only: if only { "only " } else { "" },
+                                                applied,
+                                            },
+                                        });
+                                    }
+                                    AllowedResult::Error => {
+                                        let allowed_targets =
+                                            accept.allowed_targets.allowed_targets();
+                                        let (applied, only) = allowed_targets_applied(
+                                            allowed_targets,
+                                            target,
+                                            self.features,
+                                        );
+                                        self.dcx().emit_err(InvalidTarget {
+                                            span: attr.span,
+                                            name: parts[0],
+                                            target: target.plural_name(),
+                                            only: if only { "only " } else { "" },
+                                            applied,
+                                        });
+                                    }
+                                }
+                            }
                         }
                     } else {
                         // If we're here, we must be compiling a tool attribute... Or someone
@@ -936,6 +1045,132 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
     }
 }
 
+/// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to.
+/// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string
+pub(crate) fn allowed_targets_applied(
+    mut allowed_targets: Vec<Target>,
+    target: Target,
+    features: Option<&Features>,
+) -> (String, bool) {
+    // Remove unstable targets from `allowed_targets` if their features are not enabled
+    if let Some(features) = features {
+        if !features.fn_delegation() {
+            allowed_targets.retain(|t| !matches!(t, Target::Delegation { .. }));
+        }
+        if !features.stmt_expr_attributes() {
+            allowed_targets.retain(|t| !matches!(t, Target::Expression | Target::Statement));
+        }
+    }
+
+    // We define groups of "similar" targets.
+    // If at least two of the targets are allowed, and the `target` is not in the group,
+    // we collapse the entire group to a single entry to simplify the target list
+    const FUNCTION_LIKE: &[Target] = &[
+        Target::Fn,
+        Target::Closure,
+        Target::ForeignFn,
+        Target::Method(MethodKind::Inherent),
+        Target::Method(MethodKind::Trait { body: false }),
+        Target::Method(MethodKind::Trait { body: true }),
+        Target::Method(MethodKind::TraitImpl),
+    ];
+    const METHOD_LIKE: &[Target] = &[
+        Target::Method(MethodKind::Inherent),
+        Target::Method(MethodKind::Trait { body: false }),
+        Target::Method(MethodKind::Trait { body: true }),
+        Target::Method(MethodKind::TraitImpl),
+    ];
+    const IMPL_LIKE: &[Target] =
+        &[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }];
+    const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum];
+
+    let mut added_fake_targets = Vec::new();
+    filter_targets(
+        &mut allowed_targets,
+        FUNCTION_LIKE,
+        "functions",
+        target,
+        &mut added_fake_targets,
+    );
+    filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets);
+    filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets);
+    filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets);
+
+    // If there is now only 1 target left, show that as the only possible target
+    (
+        added_fake_targets
+            .iter()
+            .copied()
+            .chain(allowed_targets.iter().map(|t| t.plural_name()))
+            .join(", "),
+        allowed_targets.len() + added_fake_targets.len() == 1,
+    )
+}
+
+fn filter_targets(
+    allowed_targets: &mut Vec<Target>,
+    target_group: &'static [Target],
+    target_group_name: &'static str,
+    target: Target,
+    added_fake_targets: &mut Vec<&'static str>,
+) {
+    if target_group.contains(&target) {
+        return;
+    }
+    if allowed_targets.iter().filter(|at| target_group.contains(at)).count() < 2 {
+        return;
+    }
+    allowed_targets.retain(|t| !target_group.contains(t));
+    added_fake_targets.push(target_group_name);
+}
+
+/// This is the list of all targets to which a attribute can be applied
+/// This is used for:
+/// - `rustc_dummy`, which can be applied to all targets
+/// - Attributes that are not parted to the new target system yet can use this list as a placeholder
+pub(crate) const ALL_TARGETS: &'static [MaybeWarn] = &[
+    Allow(Target::ExternCrate),
+    Allow(Target::Use),
+    Allow(Target::Static),
+    Allow(Target::Const),
+    Allow(Target::Fn),
+    Allow(Target::Closure),
+    Allow(Target::Mod),
+    Allow(Target::ForeignMod),
+    Allow(Target::GlobalAsm),
+    Allow(Target::TyAlias),
+    Allow(Target::Enum),
+    Allow(Target::Variant),
+    Allow(Target::Struct),
+    Allow(Target::Field),
+    Allow(Target::Union),
+    Allow(Target::Trait),
+    Allow(Target::TraitAlias),
+    Allow(Target::Impl { of_trait: false }),
+    Allow(Target::Impl { of_trait: true }),
+    Allow(Target::Expression),
+    Allow(Target::Statement),
+    Allow(Target::Arm),
+    Allow(Target::AssocConst),
+    Allow(Target::Method(MethodKind::Inherent)),
+    Allow(Target::Method(MethodKind::Trait { body: false })),
+    Allow(Target::Method(MethodKind::Trait { body: true })),
+    Allow(Target::Method(MethodKind::TraitImpl)),
+    Allow(Target::AssocTy),
+    Allow(Target::ForeignFn),
+    Allow(Target::ForeignStatic),
+    Allow(Target::ForeignTy),
+    Allow(Target::MacroDef),
+    Allow(Target::Param),
+    Allow(Target::PatField),
+    Allow(Target::ExprField),
+    Allow(Target::WherePredicate),
+    Allow(Target::MacroCall),
+    Allow(Target::Crate),
+    Allow(Target::Delegation { mac: false }),
+    Allow(Target::Delegation { mac: true }),
+];
+
 /// Parse a single integer.
 ///
 /// Used by attributes that take a single integer as argument, such as
diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs
index 22f5531bc80..733225bab59 100644
--- a/compiler/rustc_attr_parsing/src/lints.rs
+++ b/compiler/rustc_attr_parsing/src/lints.rs
@@ -1,6 +1,7 @@
 use rustc_errors::{DiagArgValue, LintEmitter};
-use rustc_hir::HirId;
 use rustc_hir::lints::{AttributeLint, AttributeLintKind};
+use rustc_hir::{HirId, Target};
+use rustc_span::sym;
 
 use crate::session_diagnostics;
 
@@ -34,5 +35,25 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi
             *first_span,
             session_diagnostics::EmptyAttributeList { attr_span: *first_span },
         ),
+        &AttributeLintKind::InvalidTarget { name, target, ref applied, only } => lint_emitter
+            .emit_node_span_lint(
+                // This check is here because `deprecated` had its own lint group and removing this would be a breaking change
+                if name == sym::deprecated
+                    && ![Target::Closure, Target::Expression, Target::Statement, Target::Arm]
+                        .contains(&target)
+                {
+                    rustc_session::lint::builtin::USELESS_DEPRECATED
+                } else {
+                    rustc_session::lint::builtin::UNUSED_ATTRIBUTES
+                },
+                *id,
+                *span,
+                session_diagnostics::InvalidTargetLint {
+                    name,
+                    target: target.plural_name(),
+                    applied: applied.clone(),
+                    only,
+                },
+            ),
     }
 }
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 41179844152..95e85667cd6 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -480,6 +480,29 @@ pub(crate) struct EmptyAttributeList {
     pub attr_span: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(attr_parsing_invalid_target_lint)]
+#[warning]
+#[help]
+pub(crate) struct InvalidTargetLint {
+    pub name: Symbol,
+    pub target: &'static str,
+    pub applied: String,
+    pub only: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[help]
+#[diag(attr_parsing_invalid_target)]
+pub(crate) struct InvalidTarget {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+    pub target: &'static str,
+    pub applied: String,
+    pub only: &'static str,
+}
+
 #[derive(Diagnostic)]
 #[diag(attr_parsing_invalid_alignment_value, code = E0589)]
 pub(crate) struct InvalidAlignmentValue {