about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr_parsing/src')
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/body.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/dummy.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/link_attrs.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/loop_match.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/must_use.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/path.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/prototype.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs5
-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.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/test_attrs.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/transparency.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/util.rs33
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs281
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/lints.rs12
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs12
-rw-r--r--compiler/rustc_attr_parsing/src/target_checking.rs244
31 files changed, 402 insertions, 324 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index 4d995027814..096b81f8e26 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -6,10 +6,11 @@ use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
 use super::{CombineAttributeParser, ConvertFn};
-use crate::context::MaybeWarn::{Allow, Warn};
-use crate::context::{AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Warn};
 
 pub(crate) struct AllowInternalUnstableParser;
 impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs
index 88540384621..28681e09e4f 100644
--- a/compiler/rustc_attr_parsing/src/attributes/body.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/body.rs
@@ -5,8 +5,9 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use super::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::MaybeWarn::Allow;
-use crate::context::{AllowedTargets, Stage};
+use crate::context::Stage;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::Allow;
 
 pub(crate) struct CoroutineParser;
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 6ea073896c2..ea50805bb55 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -8,10 +8,11 @@ use super::{
     AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn,
     NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
 };
-use crate::context::MaybeWarn::{Allow, Warn};
-use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage};
+use crate::context::{AcceptContext, FinalizeContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Warn};
 
 pub(crate) struct OptimizeParser;
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index 00f949c82c5..0185cf5cc49 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -5,9 +5,11 @@ use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
 use super::{AcceptMapping, AttributeParser};
-use crate::context::MaybeWarn::Allow;
-use crate::context::{AllowedTargets, FinalizeContext, Stage};
+use crate::context::{FinalizeContext, Stage};
 use crate::session_diagnostics;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::Allow;
+
 #[derive(Default)]
 pub(crate) struct ConfusablesParser {
     confusables: ThinVec<Symbol>,
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index d3a61f3a653..f0c44fe3363 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -5,10 +5,12 @@ use rustc_span::{Span, Symbol, sym};
 
 use super::util::parse_version;
 use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::MaybeWarn::{Allow, Error};
-use crate::context::{AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Error};
+
 pub(crate) struct DeprecationParser;
 
 fn get<S: Stage>(
diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs
index 85842b1b5c5..7293cee842c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs
@@ -3,8 +3,10 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::target_checking::{ALL_TARGETS, AllowedTargets};
+
 pub(crate) struct DummyParser;
 impl<S: Stage> SingleAttributeParser<S> for DummyParser {
     const PATH: &[Symbol] = &[sym::rustc_dummy];
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index 33c21bad240..db991b4b5eb 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -10,9 +10,11 @@ use rustc_span::{Symbol, sym};
 
 use super::{AcceptContext, AttributeOrder, OnDuplicate};
 use crate::attributes::SingleAttributeParser;
-use crate::context::MaybeWarn::{Allow, Warn};
-use crate::context::{AllowedTargets, Stage};
+use crate::context::Stage;
 use crate::parser::ArgParser;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Warn};
+
 pub(crate) struct InlineParser;
 
 impl<S: Stage> SingleAttributeParser<S> for InlineParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
index 552b9dfabc2..80e1faebf14 100644
--- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
@@ -7,10 +7,14 @@ use rustc_span::{Span, Symbol, sym};
 use crate::attributes::{
     AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
 };
-use crate::context::MaybeWarn::Allow;
-use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage, parse_single_integer};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection};
+use crate::target_checking::Policy::Allow;
+use crate::target_checking::{ALL_TARGETS, AllowedTargets};
+
+use super::util::parse_single_integer;
+
 pub(crate) struct LinkNameParser;
 
 impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
index 2b586d4003c..2dd31df9a55 100644
--- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
@@ -3,8 +3,10 @@ use rustc_hir::{MethodKind, Target};
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::MaybeWarn::{Allow, Error};
-use crate::context::{AllowedTargets, Stage};
+use crate::context::Stage;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Error};
+
 pub(crate) struct AsPtrParser;
 impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser {
     const PATH: &[Symbol] = &[sym::rustc_as_ptr];
diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
index 242e2f2c1bc..25872a96735 100644
--- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
@@ -3,8 +3,10 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::MaybeWarn::Allow;
-use crate::context::{AllowedTargets, Stage};
+use crate::context::Stage;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::Allow;
+
 pub(crate) struct LoopMatchParser;
 impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser {
     const PATH: &[Symbol] = &[sym::loop_match];
diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
index 8928129c201..f0d14bb1a46 100644
--- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
@@ -6,10 +6,12 @@ use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
 use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate};
-use crate::context::MaybeWarn::{Allow, Error, Warn};
-use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage};
+use crate::context::{AcceptContext, FinalizeContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Error, Warn};
+
 pub(crate) struct MacroEscapeParser;
 impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
     const PATH: &[Symbol] = &[sym::macro_escape];
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 3d6e26a24b8..9c04a444e94 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -21,9 +21,10 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol};
 use thin_vec::ThinVec;
 
-use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage};
+use crate::context::{AcceptContext, FinalizeContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics::UnusedMultiple;
+use crate::target_checking::AllowedTargets;
 
 pub(crate) mod allow_unstable;
 pub(crate) mod body;
diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
index eb2b39298bc..92e5957bef5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
@@ -5,10 +5,12 @@ use rustc_hir::{MethodKind, Target};
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::MaybeWarn::{Allow, Error};
-use crate::context::{AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Error};
+
 pub(crate) struct MustUseParser;
 
 impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
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 589faf38f73..74f1c540769 100644
--- a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs
@@ -3,8 +3,10 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::MaybeWarn::Allow;
-use crate::context::{AllowedTargets, Stage};
+use crate::context::Stage;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::Allow;
+
 pub(crate) struct NoImplicitPreludeParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for NoImplicitPreludeParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
index 41e9ca4de41..4e6aec95e66 100644
--- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
@@ -3,8 +3,10 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::MaybeWarn::{Allow, Warn};
-use crate::context::{AllowedTargets, Stage};
+use crate::context::Stage;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Warn};
+
 pub(crate) struct NonExhaustiveParser;
 
 impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs
index f9191d1abed..f2d5736d1a3 100644
--- a/compiler/rustc_attr_parsing/src/attributes/path.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/path.rs
@@ -4,9 +4,11 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::MaybeWarn::{Allow, Error};
-use crate::context::{AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Error};
+
 pub(crate) struct PathParser;
 
 impl<S: Stage> SingleAttributeParser<S> for PathParser {
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 4624fa36287..19662d87f22 100644
--- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
@@ -7,9 +7,11 @@ use thin_vec::ThinVec;
 use crate::attributes::{
     AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
 };
-use crate::context::MaybeWarn::{Allow, Warn};
-use crate::context::{AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Warn};
+
 pub(crate) struct ProcMacroParser;
 impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
     const PATH: &[Symbol] = &[sym::proc_macro];
diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs
index fb1e47298b4..0ef36bc7e4c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs
@@ -7,8 +7,10 @@ use rustc_span::{Span, Symbol, sym};
 
 use super::{AttributeOrder, OnDuplicate};
 use crate::attributes::SingleAttributeParser;
-use crate::context::{AcceptContext, AllowedTargets, MaybeWarn, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::Allow;
 
 pub(crate) struct CustomMirParser;
 
@@ -19,8 +21,7 @@ impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
 
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
 
-    const ALLOWED_TARGETS: AllowedTargets =
-        AllowedTargets::AllowList(&[MaybeWarn::Allow(Target::Fn)]);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
 
     const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]);
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 7ab58ed9347..cd4a98f9ec8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -6,11 +6,12 @@ use rustc_hir::{MethodKind, Target};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 
 use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext};
-use crate::context::MaybeWarn::Allow;
-use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
 use crate::session_diagnostics;
 use crate::session_diagnostics::IncorrectReprFormatGenericCause;
+use crate::target_checking::Policy::Allow;
+use crate::target_checking::{ALL_TARGETS, AllowedTargets};
 /// Parse #[repr(...)] forms.
 ///
 /// Valid repr contents: any of the primitive integral type names (see
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index efd7b650e44..282312e1f9b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -4,9 +4,13 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::MaybeWarn::Allow;
-use crate::context::{AcceptContext, AllowedTargets, Stage, parse_single_integer};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::Allow;
+
+use super::util::parse_single_integer;
+
 pub(crate) struct RustcLayoutScalarValidRangeStart;
 
 impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs
index d4ad861a3a2..c9cb1857389 100644
--- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs
@@ -2,7 +2,9 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol, sym};
 
 use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
-use crate::context::{ALL_TARGETS, AllowedTargets, Stage};
+use crate::context::Stage;
+use crate::target_checking::{ALL_TARGETS, AllowedTargets};
+
 pub(crate) struct MayDangleParser;
 impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser {
     const PATH: &[Symbol] = &[sym::may_dangle];
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index c7a809d7d88..7ecad4c0120 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -12,10 +12,11 @@ use rustc_span::{Ident, Span, Symbol, sym};
 use super::util::parse_version;
 use super::{AcceptMapping, AttributeParser, OnDuplicate};
 use crate::attributes::NoArgsAttributeParser;
-use crate::context::MaybeWarn::Allow;
-use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage};
+use crate::context::{AcceptContext, FinalizeContext, Stage};
 use crate::parser::{ArgParser, MetaItemParser};
 use crate::session_diagnostics::{self, UnsupportedLiteralReason};
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::Allow;
 
 macro_rules! reject_outside_std {
     ($cx: ident) => {
diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
index 164c680b8a8..1ac4959f5fc 100644
--- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
@@ -5,9 +5,11 @@ use rustc_hir::lints::AttributeLintKind;
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::MaybeWarn::{Allow, Error};
-use crate::context::{AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::{Allow, Error};
+
 pub(crate) struct IgnoreParser;
 
 impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index ee9d7ba99cd..f7550e1f4ad 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -8,9 +8,11 @@ use rustc_span::{Span, Symbol, sym};
 use crate::attributes::{
     AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
 };
-use crate::context::MaybeWarn::{Allow, Warn};
-use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::target_checking::Policy::{Allow, Warn};
+use crate::target_checking::{ALL_TARGETS, AllowedTargets};
+
 pub(crate) struct SkipDuringMethodDispatchParser;
 impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
     const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
index 0ffcf434b52..1d98cf200fa 100644
--- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -5,9 +5,11 @@ use rustc_span::hygiene::Transparency;
 use rustc_span::{Symbol, sym};
 
 use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::MaybeWarn::Allow;
-use crate::context::{AcceptContext, AllowedTargets, Stage};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
+use crate::target_checking::AllowedTargets;
+use crate::target_checking::Policy::Allow;
+
 pub(crate) struct TransparencyParser;
 
 // FIXME(jdonszelmann): make these proper diagnostics
diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs
index 10134915b27..ef9701cb7cb 100644
--- a/compiler/rustc_attr_parsing/src/attributes/util.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/util.rs
@@ -1,8 +1,12 @@
+use rustc_ast::LitKind;
 use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name};
 use rustc_feature::is_builtin_attr_name;
 use rustc_hir::RustcVersion;
 use rustc_span::{Symbol, sym};
 
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+
 /// Parse a rustc version number written inside string literal in an attribute,
 /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
 /// not accepted in this position, unlike when parsing CFG_RELEASE.
@@ -56,3 +60,32 @@ pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>(
     }
     false
 }
+
+/// Parse a single integer.
+///
+/// Used by attributes that take a single integer as argument, such as
+/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
+/// `cx` is the context given to the attribute.
+/// `args` is the parser for the attribute arguments.
+pub(crate) fn parse_single_integer<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    args: &ArgParser<'_>,
+) -> Option<u128> {
+    let Some(list) = args.list() else {
+        cx.expected_list(cx.attr_span);
+        return None;
+    };
+    let Some(single) = list.single() else {
+        cx.expected_single_argument(list.span);
+        return None;
+    };
+    let Some(lit) = single.lit() else {
+        cx.expected_integer_literal(single.span());
+        return None;
+    };
+    let LitKind::Int(num, _ty) = lit.kind else {
+        cx.expected_integer_literal(single.span());
+        return None;
+    };
+    Some(num.0)
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index c0d3bc99ba9..90fef7a7fad 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -3,16 +3,13 @@ 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, AttrStyle, LitKind, MetaItemLit, NodeId};
+use rustc_ast::{self as ast, AttrStyle, 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, MethodKind, Target,
-};
+use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, Target};
 use rustc_session::Session;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 
@@ -65,11 +62,9 @@ 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, InvalidTarget, UnknownMetaItem,
-};
+use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
+use crate::target_checking::AllowedTargets;
 
 type GroupType<S> = LazyLock<GroupTypeInner<S>>;
 
@@ -667,69 +662,11 @@ 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> {
     pub(crate) tools: Vec<Symbol>,
-    features: Option<&'sess Features>,
+    pub(crate) features: Option<&'sess Features>,
     sess: &'sess Session,
     stage: S,
 
@@ -917,9 +854,9 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
                     let parser = MetaItemParser::from_attr(n, self.dcx());
                     let path = parser.path();
                     let args = parser.args();
-                    let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
+                    let path_parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
 
-                    if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
+                    if let Some(accepts) = S::parsers().accepters.get(path_parts.as_slice()) {
                         for accept in accepts {
                             let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
                                 shared: SharedContext {
@@ -937,44 +874,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
                             (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,
-                                        });
-                                    }
-                                }
+                                self.check_target(
+                                    path.get_attribute_path(),
+                                    attr.span,
+                                    &accept.allowed_targets,
+                                    target,
+                                    target_id,
+                                    &mut emit_lint,
+                                );
                             }
                         }
                     } else {
@@ -1062,161 +969,3 @@ 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));
-        }
-        if !features.extern_types() {
-            allowed_targets.retain(|t| !matches!(t, Target::ForeignTy));
-        }
-    }
-
-    // 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
-/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
-/// `cx` is the context given to the attribute.
-/// `args` is the parser for the attribute arguments.
-pub(crate) fn parse_single_integer<S: Stage>(
-    cx: &mut AcceptContext<'_, '_, S>,
-    args: &ArgParser<'_>,
-) -> Option<u128> {
-    let Some(list) = args.list() else {
-        cx.expected_list(cx.attr_span);
-        return None;
-    };
-    let Some(single) = list.single() else {
-        cx.expected_single_argument(list.span);
-        return None;
-    };
-    let Some(lit) = single.lit() else {
-        cx.expected_integer_literal(single.span());
-        return None;
-    };
-    let LitKind::Int(num, _ty) = lit.kind else {
-        cx.expected_integer_literal(single.span());
-        return None;
-    };
-    Some(num.0)
-}
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index fc1377e5314..667cc024f59 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -89,6 +89,7 @@ pub(crate) mod context;
 mod lints;
 pub mod parser;
 mod session_diagnostics;
+mod target_checking;
 
 pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
 pub use attributes::cfg_old::*;
diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs
index 2813fef3148..7030f28f23c 100644
--- a/compiler/rustc_attr_parsing/src/lints.rs
+++ b/compiler/rustc_attr_parsing/src/lints.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 use rustc_errors::{DiagArgValue, LintEmitter};
 use rustc_hir::lints::{AttributeLint, AttributeLintKind};
 use rustc_hir::{HirId, Target};
@@ -35,12 +37,12 @@ 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
+        AttributeLintKind::InvalidTarget { name, target, 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
+                if name.segments[0].name == sym::deprecated
                     && ![Target::Closure, Target::Expression, Target::Statement, Target::Arm]
-                        .contains(&target)
+                        .contains(target)
                 {
                     rustc_session::lint::builtin::USELESS_DEPRECATED
                 } else {
@@ -51,7 +53,9 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi
                 session_diagnostics::InvalidTargetLint {
                     name,
                     target: target.plural_name(),
-                    applied: applied.clone(),
+                    applied: DiagArgValue::StrListSepByAnd(
+                        applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(),
+                    ),
                     only,
                     attr_span: *span,
                 },
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index aec970a3ce9..2993881f717 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -484,10 +484,10 @@ pub(crate) struct EmptyAttributeList {
 #[diag(attr_parsing_invalid_target_lint)]
 #[warning]
 #[help]
-pub(crate) struct InvalidTargetLint {
-    pub name: Symbol,
-    pub target: &'static str,
-    pub applied: String,
+pub(crate) struct InvalidTargetLint<'a> {
+    pub name: &'a AttrPath,
+    pub target: &'a str,
+    pub applied: DiagArgValue,
     pub only: &'static str,
     #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
     pub attr_span: Span,
@@ -500,9 +500,9 @@ pub(crate) struct InvalidTarget {
     #[primary_span]
     #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
     pub span: Span,
-    pub name: Symbol,
+    pub name: AttrPath,
     pub target: &'static str,
-    pub applied: String,
+    pub applied: DiagArgValue,
     pub only: &'static str,
 }
 
diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs
new file mode 100644
index 00000000000..08ce1d5b047
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/target_checking.rs
@@ -0,0 +1,244 @@
+use std::borrow::Cow;
+
+use rustc_errors::DiagArgValue;
+use rustc_feature::Features;
+use rustc_hir::lints::{AttributeLint, AttributeLintKind};
+use rustc_hir::{AttrPath, MethodKind, Target};
+use rustc_span::Span;
+
+use crate::AttributeParser;
+use crate::context::Stage;
+use crate::session_diagnostics::InvalidTarget;
+
+#[derive(Debug)]
+pub(crate) enum AllowedTargets {
+    AllowList(&'static [Policy]),
+    AllowListWarnRest(&'static [Policy]),
+}
+
+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(&Policy::Allow(target)) {
+                    AllowedResult::Allowed
+                } else if list.contains(&Policy::Warn(target)) {
+                    AllowedResult::Warn
+                } else {
+                    AllowedResult::Error
+                }
+            }
+            AllowedTargets::AllowListWarnRest(list) => {
+                if list.contains(&Policy::Allow(target)) {
+                    AllowedResult::Allowed
+                } else if list.contains(&Policy::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 {
+            Policy::Allow(target) => Some(*target),
+            Policy::Warn(_) => None,
+            Policy::Error(_) => None,
+        })
+        .collect()
+    }
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub(crate) enum Policy {
+    Allow(Target),
+    Warn(Target),
+    Error(Target),
+}
+
+impl<S: Stage> AttributeParser<'_, S> {
+    pub(crate) fn check_target(
+        &self,
+        attr_name: AttrPath,
+        attr_span: Span,
+        allowed_targets: &AllowedTargets,
+        target: Target,
+        target_id: S::Id,
+        mut emit_lint: impl FnMut(AttributeLint<S::Id>),
+    ) {
+        match allowed_targets.is_allowed(target) {
+            AllowedResult::Allowed => {}
+            AllowedResult::Warn => {
+                let allowed_targets = 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: attr_name,
+                        target,
+                        only: if only { "only " } else { "" },
+                        applied,
+                    },
+                });
+            }
+            AllowedResult::Error => {
+                let allowed_targets = allowed_targets.allowed_targets();
+                let (applied, only) =
+                    allowed_targets_applied(allowed_targets, target, self.features);
+                self.dcx().emit_err(InvalidTarget {
+                    span: attr_span,
+                    name: attr_name,
+                    target: target.plural_name(),
+                    only: if only { "only " } else { "" },
+                    applied: DiagArgValue::StrListSepByAnd(
+                        applied.into_iter().map(Cow::Owned).collect(),
+                    ),
+                });
+            }
+        }
+    }
+}
+
+/// 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>,
+) -> (Vec<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()))
+            .map(|i| i.to_string())
+            .collect(),
+        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 [Policy] = {
+    use Policy::Allow;
+    &[
+        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 }),
+    ]
+};