@@ -3,16 +3,13 @@ use std::collections::BTreeMap;
33use std:: ops:: { Deref , DerefMut } ;
44use std:: sync:: LazyLock ;
55
6- use itertools:: Itertools ;
76use private:: Sealed ;
8- use rustc_ast:: { self as ast, LitKind , MetaItemLit , NodeId } ;
7+ use rustc_ast:: { self as ast, MetaItemLit , NodeId } ;
98use rustc_errors:: { DiagCtxtHandle , Diagnostic } ;
109use rustc_feature:: { AttributeTemplate , Features } ;
1110use rustc_hir:: attrs:: AttributeKind ;
1211use rustc_hir:: lints:: { AttributeLint , AttributeLintKind } ;
13- use rustc_hir:: {
14- AttrArgs , AttrItem , AttrPath , Attribute , HashIgnoredAttrId , HirId , MethodKind , Target ,
15- } ;
12+ use rustc_hir:: { AttrArgs , AttrItem , AttrPath , Attribute , HashIgnoredAttrId , HirId , Target } ;
1613use rustc_session:: Session ;
1714use rustc_span:: { DUMMY_SP , ErrorGuaranteed , Span , Symbol , sym} ;
1815
@@ -64,11 +61,9 @@ use crate::attributes::traits::{
6461} ;
6562use crate :: attributes:: transparency:: TransparencyParser ;
6663use crate :: attributes:: { AttributeParser as _, Combine , Single , WithoutArgs } ;
67- use crate :: context:: MaybeWarn :: { Allow , Error , Warn } ;
6864use crate :: parser:: { ArgParser , MetaItemParser , PathParser } ;
69- use crate :: session_diagnostics:: {
70- AttributeParseError , AttributeParseErrorReason , InvalidTarget , UnknownMetaItem ,
71- } ;
65+ use crate :: session_diagnostics:: { AttributeParseError , AttributeParseErrorReason , UnknownMetaItem } ;
66+ use crate :: target_checking:: AllowedTargets ;
7267
7368type GroupType < S > = LazyLock < GroupTypeInner < S > > ;
7469
@@ -651,69 +646,11 @@ impl ShouldEmit {
651646 }
652647}
653648
654- #[ derive( Debug ) ]
655- pub ( crate ) enum AllowedTargets {
656- AllowList ( & ' static [ MaybeWarn ] ) ,
657- AllowListWarnRest ( & ' static [ MaybeWarn ] ) ,
658- }
659-
660- pub ( crate ) enum AllowedResult {
661- Allowed ,
662- Warn ,
663- Error ,
664- }
665-
666- impl AllowedTargets {
667- pub ( crate ) fn is_allowed ( & self , target : Target ) -> AllowedResult {
668- match self {
669- AllowedTargets :: AllowList ( list) => {
670- if list. contains ( & Allow ( target) ) {
671- AllowedResult :: Allowed
672- } else if list. contains ( & Warn ( target) ) {
673- AllowedResult :: Warn
674- } else {
675- AllowedResult :: Error
676- }
677- }
678- AllowedTargets :: AllowListWarnRest ( list) => {
679- if list. contains ( & Allow ( target) ) {
680- AllowedResult :: Allowed
681- } else if list. contains ( & Error ( target) ) {
682- AllowedResult :: Error
683- } else {
684- AllowedResult :: Warn
685- }
686- }
687- }
688- }
689-
690- pub ( crate ) fn allowed_targets ( & self ) -> Vec < Target > {
691- match self {
692- AllowedTargets :: AllowList ( list) => list,
693- AllowedTargets :: AllowListWarnRest ( list) => list,
694- }
695- . iter ( )
696- . filter_map ( |target| match target {
697- Allow ( target) => Some ( * target) ,
698- Warn ( _) => None ,
699- Error ( _) => None ,
700- } )
701- . collect ( )
702- }
703- }
704-
705- #[ derive( Debug , Eq , PartialEq ) ]
706- pub ( crate ) enum MaybeWarn {
707- Allow ( Target ) ,
708- Warn ( Target ) ,
709- Error ( Target ) ,
710- }
711-
712649/// Context created once, for example as part of the ast lowering
713650/// context, through which all attributes can be lowered.
714651pub struct AttributeParser < ' sess , S : Stage = Late > {
715652 pub ( crate ) tools : Vec < Symbol > ,
716- features : Option < & ' sess Features > ,
653+ pub ( crate ) features : Option < & ' sess Features > ,
717654 sess : & ' sess Session ,
718655 stage : S ,
719656
@@ -900,9 +837,9 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
900837 let parser = MetaItemParser :: from_attr ( n, self . dcx ( ) ) ;
901838 let path = parser. path ( ) ;
902839 let args = parser. args ( ) ;
903- let parts = path. segments ( ) . map ( |i| i. name ) . collect :: < Vec < _ > > ( ) ;
840+ let path_parts = path. segments ( ) . map ( |i| i. name ) . collect :: < Vec < _ > > ( ) ;
904841
905- if let Some ( accepts) = S :: parsers ( ) . accepters . get ( parts . as_slice ( ) ) {
842+ if let Some ( accepts) = S :: parsers ( ) . accepters . get ( path_parts . as_slice ( ) ) {
906843 for accept in accepts {
907844 let mut cx: AcceptContext < ' _ , ' sess , S > = AcceptContext {
908845 shared : SharedContext {
@@ -919,44 +856,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
919856 ( accept. accept_fn ) ( & mut cx, args) ;
920857
921858 if self . stage . should_emit ( ) . should_emit ( ) {
922- match accept. allowed_targets . is_allowed ( target) {
923- AllowedResult :: Allowed => { }
924- AllowedResult :: Warn => {
925- let allowed_targets =
926- accept. allowed_targets . allowed_targets ( ) ;
927- let ( applied, only) = allowed_targets_applied (
928- allowed_targets,
929- target,
930- self . features ,
931- ) ;
932- emit_lint ( AttributeLint {
933- id : target_id,
934- span : attr. span ,
935- kind : AttributeLintKind :: InvalidTarget {
936- name : parts[ 0 ] ,
937- target,
938- only : if only { "only " } else { "" } ,
939- applied,
940- } ,
941- } ) ;
942- }
943- AllowedResult :: Error => {
944- let allowed_targets =
945- accept. allowed_targets . allowed_targets ( ) ;
946- let ( applied, only) = allowed_targets_applied (
947- allowed_targets,
948- target,
949- self . features ,
950- ) ;
951- self . dcx ( ) . emit_err ( InvalidTarget {
952- span : attr. span ,
953- name : parts[ 0 ] ,
954- target : target. plural_name ( ) ,
955- only : if only { "only " } else { "" } ,
956- applied,
957- } ) ;
958- }
959- }
859+ self . check_target (
860+ path. get_attribute_path ( ) ,
861+ attr. span ,
862+ & accept. allowed_targets ,
863+ target,
864+ target_id,
865+ & mut emit_lint,
866+ ) ;
960867 }
961868 }
962869 } else {
@@ -1044,158 +951,3 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
1044951 }
1045952 }
1046953}
1047-
1048- /// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to.
1049- /// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string
1050- pub ( crate ) fn allowed_targets_applied (
1051- mut allowed_targets : Vec < Target > ,
1052- target : Target ,
1053- features : Option < & Features > ,
1054- ) -> ( String , bool ) {
1055- // Remove unstable targets from `allowed_targets` if their features are not enabled
1056- if let Some ( features) = features {
1057- if !features. fn_delegation ( ) {
1058- allowed_targets. retain ( |t| !matches ! ( t, Target :: Delegation { .. } ) ) ;
1059- }
1060- if !features. stmt_expr_attributes ( ) {
1061- allowed_targets. retain ( |t| !matches ! ( t, Target :: Expression | Target :: Statement ) ) ;
1062- }
1063- }
1064-
1065- // We define groups of "similar" targets.
1066- // If at least two of the targets are allowed, and the `target` is not in the group,
1067- // we collapse the entire group to a single entry to simplify the target list
1068- const FUNCTION_LIKE : & [ Target ] = & [
1069- Target :: Fn ,
1070- Target :: Closure ,
1071- Target :: ForeignFn ,
1072- Target :: Method ( MethodKind :: Inherent ) ,
1073- Target :: Method ( MethodKind :: Trait { body : false } ) ,
1074- Target :: Method ( MethodKind :: Trait { body : true } ) ,
1075- Target :: Method ( MethodKind :: TraitImpl ) ,
1076- ] ;
1077- const METHOD_LIKE : & [ Target ] = & [
1078- Target :: Method ( MethodKind :: Inherent ) ,
1079- Target :: Method ( MethodKind :: Trait { body : false } ) ,
1080- Target :: Method ( MethodKind :: Trait { body : true } ) ,
1081- Target :: Method ( MethodKind :: TraitImpl ) ,
1082- ] ;
1083- const IMPL_LIKE : & [ Target ] =
1084- & [ Target :: Impl { of_trait : false } , Target :: Impl { of_trait : true } ] ;
1085- const ADT_LIKE : & [ Target ] = & [ Target :: Struct , Target :: Enum ] ;
1086-
1087- let mut added_fake_targets = Vec :: new ( ) ;
1088- filter_targets (
1089- & mut allowed_targets,
1090- FUNCTION_LIKE ,
1091- "functions" ,
1092- target,
1093- & mut added_fake_targets,
1094- ) ;
1095- filter_targets ( & mut allowed_targets, METHOD_LIKE , "methods" , target, & mut added_fake_targets) ;
1096- filter_targets ( & mut allowed_targets, IMPL_LIKE , "impl blocks" , target, & mut added_fake_targets) ;
1097- filter_targets ( & mut allowed_targets, ADT_LIKE , "data types" , target, & mut added_fake_targets) ;
1098-
1099- // If there is now only 1 target left, show that as the only possible target
1100- (
1101- added_fake_targets
1102- . iter ( )
1103- . copied ( )
1104- . chain ( allowed_targets. iter ( ) . map ( |t| t. plural_name ( ) ) )
1105- . join ( ", " ) ,
1106- allowed_targets. len ( ) + added_fake_targets. len ( ) == 1 ,
1107- )
1108- }
1109-
1110- fn filter_targets (
1111- allowed_targets : & mut Vec < Target > ,
1112- target_group : & ' static [ Target ] ,
1113- target_group_name : & ' static str ,
1114- target : Target ,
1115- added_fake_targets : & mut Vec < & ' static str > ,
1116- ) {
1117- if target_group. contains ( & target) {
1118- return ;
1119- }
1120- if allowed_targets. iter ( ) . filter ( |at| target_group. contains ( at) ) . count ( ) < 2 {
1121- return ;
1122- }
1123- allowed_targets. retain ( |t| !target_group. contains ( t) ) ;
1124- added_fake_targets. push ( target_group_name) ;
1125- }
1126-
1127- /// This is the list of all targets to which a attribute can be applied
1128- /// This is used for:
1129- /// - `rustc_dummy`, which can be applied to all targets
1130- /// - Attributes that are not parted to the new target system yet can use this list as a placeholder
1131- pub ( crate ) const ALL_TARGETS : & ' static [ MaybeWarn ] = & [
1132- Allow ( Target :: ExternCrate ) ,
1133- Allow ( Target :: Use ) ,
1134- Allow ( Target :: Static ) ,
1135- Allow ( Target :: Const ) ,
1136- Allow ( Target :: Fn ) ,
1137- Allow ( Target :: Closure ) ,
1138- Allow ( Target :: Mod ) ,
1139- Allow ( Target :: ForeignMod ) ,
1140- Allow ( Target :: GlobalAsm ) ,
1141- Allow ( Target :: TyAlias ) ,
1142- Allow ( Target :: Enum ) ,
1143- Allow ( Target :: Variant ) ,
1144- Allow ( Target :: Struct ) ,
1145- Allow ( Target :: Field ) ,
1146- Allow ( Target :: Union ) ,
1147- Allow ( Target :: Trait ) ,
1148- Allow ( Target :: TraitAlias ) ,
1149- Allow ( Target :: Impl { of_trait : false } ) ,
1150- Allow ( Target :: Impl { of_trait : true } ) ,
1151- Allow ( Target :: Expression ) ,
1152- Allow ( Target :: Statement ) ,
1153- Allow ( Target :: Arm ) ,
1154- Allow ( Target :: AssocConst ) ,
1155- Allow ( Target :: Method ( MethodKind :: Inherent ) ) ,
1156- Allow ( Target :: Method ( MethodKind :: Trait { body : false } ) ) ,
1157- Allow ( Target :: Method ( MethodKind :: Trait { body : true } ) ) ,
1158- Allow ( Target :: Method ( MethodKind :: TraitImpl ) ) ,
1159- Allow ( Target :: AssocTy ) ,
1160- Allow ( Target :: ForeignFn ) ,
1161- Allow ( Target :: ForeignStatic ) ,
1162- Allow ( Target :: ForeignTy ) ,
1163- Allow ( Target :: MacroDef ) ,
1164- Allow ( Target :: Param ) ,
1165- Allow ( Target :: PatField ) ,
1166- Allow ( Target :: ExprField ) ,
1167- Allow ( Target :: WherePredicate ) ,
1168- Allow ( Target :: MacroCall ) ,
1169- Allow ( Target :: Crate ) ,
1170- Allow ( Target :: Delegation { mac : false } ) ,
1171- Allow ( Target :: Delegation { mac : true } ) ,
1172- ] ;
1173-
1174- /// Parse a single integer.
1175- ///
1176- /// Used by attributes that take a single integer as argument, such as
1177- /// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
1178- /// `cx` is the context given to the attribute.
1179- /// `args` is the parser for the attribute arguments.
1180- pub ( crate ) fn parse_single_integer < S : Stage > (
1181- cx : & mut AcceptContext < ' _ , ' _ , S > ,
1182- args : & ArgParser < ' _ > ,
1183- ) -> Option < u128 > {
1184- let Some ( list) = args. list ( ) else {
1185- cx. expected_list ( cx. attr_span ) ;
1186- return None ;
1187- } ;
1188- let Some ( single) = list. single ( ) else {
1189- cx. expected_single_argument ( list. span ) ;
1190- return None ;
1191- } ;
1192- let Some ( lit) = single. lit ( ) else {
1193- cx. expected_integer_literal ( single. span ( ) ) ;
1194- return None ;
1195- } ;
1196- let LitKind :: Int ( num, _ty) = lit. kind else {
1197- cx. expected_integer_literal ( single. span ( ) ) ;
1198- return None ;
1199- } ;
1200- Some ( num. 0 )
1201- }
0 commit comments