1- use rustc_hir:: attrs:: LintAttrIdsInformation ;
1+ use rustc_hir:: HashIgnoredAttrId ;
2+ use rustc_hir:: attrs:: { LintAttrIdsInformation , LintAttributeKind } ;
23use rustc_hir:: lints:: { AttributeLintKind , RenamedLintSuggestion } ;
34use rustc_middle:: bug;
45use rustc_session:: lint:: CheckLintNameResult ;
56use rustc_session:: lint:: builtin:: { RENAMED_AND_REMOVED_LINTS , UNKNOWN_LINTS } ;
7+
68use super :: prelude:: * ;
79use crate :: session_diagnostics:: UnknownToolInScopedLint ;
10+ use crate :: target_checking:: Policy ;
11+
12+ const ALLOWED_TARGETS : & ' static [ Policy ] = & [
13+ Allow ( Target :: ExternCrate ) ,
14+ Allow ( Target :: Use ) ,
15+ Allow ( Target :: Static ) ,
16+ Allow ( Target :: Const ) ,
17+ Allow ( Target :: Fn ) ,
18+ Allow ( Target :: Closure ) ,
19+ Allow ( Target :: Mod ) ,
20+ Allow ( Target :: ForeignMod ) ,
21+ Allow ( Target :: GlobalAsm ) ,
22+ Allow ( Target :: TyAlias ) ,
23+ Allow ( Target :: Enum ) ,
24+ Allow ( Target :: Variant ) ,
25+ Allow ( Target :: Struct ) ,
26+ Allow ( Target :: Field ) ,
27+ Allow ( Target :: Union ) ,
28+ Allow ( Target :: Trait ) ,
29+ Allow ( Target :: TraitAlias ) ,
30+ Allow ( Target :: Impl { of_trait : false } ) ,
31+ Allow ( Target :: Impl { of_trait : true } ) ,
32+ Allow ( Target :: Expression ) ,
33+ Allow ( Target :: Statement ) ,
34+ Allow ( Target :: Arm ) ,
35+ Allow ( Target :: AssocConst ) ,
36+ Allow ( Target :: Method ( MethodKind :: Inherent ) ) ,
37+ Allow ( Target :: Method ( MethodKind :: Trait { body : false } ) ) ,
38+ Allow ( Target :: Method ( MethodKind :: Trait { body : true } ) ) ,
39+ Allow ( Target :: Method ( MethodKind :: TraitImpl ) ) ,
40+ Allow ( Target :: AssocTy ) ,
41+ Allow ( Target :: ForeignFn ) ,
42+ Allow ( Target :: ForeignStatic ) ,
43+ Allow ( Target :: ForeignTy ) ,
44+ Allow ( Target :: MacroDef ) ,
45+ Allow ( Target :: Param ) ,
46+ Allow ( Target :: PatField ) ,
47+ Allow ( Target :: ExprField ) ,
48+ Allow ( Target :: MacroCall ) ,
49+ Allow ( Target :: Crate ) ,
50+ Allow ( Target :: Delegation { mac : false } ) ,
51+ Allow ( Target :: Delegation { mac : true } ) ,
52+ ]
53+ ;
854
955#[ derive( Default ) ]
1056pub ( crate ) struct AllowParser {
1157 lint_ids : ThinVec < LintAttrIdsInformation > ,
1258 reason : Option < Symbol > ,
1359 errored : bool ,
60+ attr_span : Option < Span > ,
1461}
1562
1663// Needs to be manually impl:ed as `AttributeParser`, because otherwise deduplication occurs
@@ -22,6 +69,7 @@ impl<S: Stage> AttributeParser<S> for AllowParser {
2269 "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
2370 ) ,
2471 |this, cx, args| {
72+ this. attr_span = Some ( cx. attr_span ) ;
2573 validate_lint_attr (
2674 cx,
2775 args,
@@ -34,20 +82,27 @@ impl<S: Stage> AttributeParser<S> for AllowParser {
3482 ) ] ;
3583
3684 fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
37- if !self . errored {
38- Some ( AttributeKind :: Allow { lint_ids : self . lint_ids , reason : self . reason } )
85+ if !self . errored && !self . attr_span . is_none ( ) {
86+ Some ( AttributeKind :: LintAttribute {
87+ lint_groups : self . lint_ids ,
88+ reason : self . reason ,
89+ kind : LintAttributeKind :: Allow ,
90+ attr_span : self . attr_span . unwrap ( ) ,
91+ } )
3992 } else {
4093 None
4194 }
4295 }
4396
44- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALL_TARGETS ) ;
97+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
4598}
4699#[ derive( Default ) ]
47100pub ( crate ) struct DenyParser {
48101 lint_ids : ThinVec < LintAttrIdsInformation > ,
49102 reason : Option < Symbol > ,
50103 errored : bool ,
104+ attr_span : Option < Span > ,
105+
51106}
52107impl < S : Stage > AttributeParser < S > for DenyParser {
53108 const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
@@ -57,6 +112,7 @@ impl<S: Stage> AttributeParser<S> for DenyParser {
57112 "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
58113 ) ,
59114 |this, cx, args| {
115+ this. attr_span = Some ( cx. attr_span ) ;
60116 validate_lint_attr (
61117 cx,
62118 args,
@@ -69,21 +125,27 @@ impl<S: Stage> AttributeParser<S> for DenyParser {
69125 ) ] ;
70126
71127 fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
72- if !self . errored {
73- Some ( AttributeKind :: Deny { lint_ids : self . lint_ids , reason : self . reason } )
128+ if !self . errored && !self . attr_span . is_none ( ) {
129+ Some ( AttributeKind :: LintAttribute {
130+ lint_groups : self . lint_ids ,
131+ reason : self . reason ,
132+ kind : LintAttributeKind :: Deny , attr_span : self . attr_span . unwrap ( ) ,
133+ } )
74134 } else {
75135 None
76136 }
77137 }
78138
79- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALL_TARGETS ) ;
139+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
80140}
81141
82142#[ derive( Default ) ]
83143pub ( crate ) struct ForbidParser {
84144 lint_ids : ThinVec < LintAttrIdsInformation > ,
85145 reason : Option < Symbol > ,
86146 errored : bool ,
147+ attr_span : Option < Span > ,
148+
87149}
88150impl < S : Stage > AttributeParser < S > for ForbidParser {
89151 const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
@@ -93,6 +155,7 @@ impl<S: Stage> AttributeParser<S> for ForbidParser {
93155 "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
94156 ) ,
95157 |this, cx, args| {
158+ this. attr_span = Some ( cx. attr_span ) ;
96159 validate_lint_attr (
97160 cx,
98161 args,
@@ -106,21 +169,26 @@ impl<S: Stage> AttributeParser<S> for ForbidParser {
106169
107170 fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
108171 if !self . errored {
109- Some ( AttributeKind :: Forbid { lint_ids : self . lint_ids , reason : self . reason } )
172+ Some ( AttributeKind :: LintAttribute {
173+ lint_groups : self . lint_ids ,
174+ reason : self . reason ,
175+ kind : LintAttributeKind :: Forbid , attr_span : self . attr_span . unwrap ( ) ,
176+ } )
110177 } else {
111178 None
112179 }
113180 }
114181
115- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALL_TARGETS ) ;
182+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
116183}
117184
118-
119185#[ derive( Default ) ]
120186pub ( crate ) struct WarnParser {
121187 lint_ids : ThinVec < LintAttrIdsInformation > ,
122188 reason : Option < Symbol > ,
123189 errored : bool ,
190+ attr_span : Option < Span > ,
191+
124192}
125193impl < S : Stage > AttributeParser < S > for WarnParser {
126194 const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
@@ -130,6 +198,7 @@ impl<S: Stage> AttributeParser<S> for WarnParser {
130198 "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
131199 ) ,
132200 |this, cx, args| {
201+ this. attr_span = Some ( cx. attr_span ) ;
133202 validate_lint_attr (
134203 cx,
135204 args,
@@ -142,21 +211,27 @@ impl<S: Stage> AttributeParser<S> for WarnParser {
142211 ) ] ;
143212
144213 fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
145- if !self . errored {
146- Some ( AttributeKind :: Warn { lint_ids : self . lint_ids , reason : self . reason } )
214+ if !self . errored && !self . attr_span . is_none ( ) {
215+ Some ( AttributeKind :: LintAttribute {
216+ lint_groups : self . lint_ids ,
217+ reason : self . reason ,
218+ kind : LintAttributeKind :: Warn , attr_span : self . attr_span . unwrap ( ) ,
219+ } )
147220 } else {
148221 None
149222 }
150223 }
151224
152- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALL_TARGETS ) ;
225+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
153226}
154227
155228#[ derive( Default ) ]
156229pub ( crate ) struct ExpectParser {
157230 lint_ids : ThinVec < LintAttrIdsInformation > ,
158231 reason : Option < Symbol > ,
159232 errored : bool ,
233+ attr_span : Option < Span > ,
234+
160235}
161236impl < S : Stage > AttributeParser < S > for ExpectParser {
162237 const ATTRIBUTES : AcceptMapping < Self , S > = & [ (
@@ -166,6 +241,7 @@ impl<S: Stage> AttributeParser<S> for ExpectParser {
166241 "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
167242 ) ,
168243 |this, cx, args| {
244+ this. attr_span = Some ( cx. attr_span ) ;
169245 validate_lint_attr (
170246 cx,
171247 args,
@@ -177,17 +253,23 @@ impl<S: Stage> AttributeParser<S> for ExpectParser {
177253 } ,
178254 ) ] ;
179255
180- fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
181- if !self . errored {
182- Some ( AttributeKind :: Expect { lint_ids : self . lint_ids , reason : self . reason , } )
256+ fn finalize ( self , cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
257+ if !self . errored && !self . attr_span . is_none ( ) {
258+ Some ( AttributeKind :: LintAttribute {
259+ lint_groups : self . lint_ids ,
260+ reason : self . reason ,
261+ kind : LintAttributeKind :: Expect ( HashIgnoredAttrId { attr_id : cx. attr_id } ) ,
262+ attr_span : self . attr_span . unwrap ( ) ,
263+ } )
183264 } else {
184265 None
185266 }
186267 }
187268
188- const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALL_TARGETS ) ;
269+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALLOWED_TARGETS ) ;
189270}
190271
272+ #[ inline( always) ]
191273fn validate_lint_attr < S : Stage > (
192274 cx : & mut AcceptContext < ' _ , ' _ , S > ,
193275 args : & ArgParser ,
@@ -196,23 +278,25 @@ fn validate_lint_attr<S: Stage>(
196278 reason : & mut Option < Symbol > ,
197279 attr_name : Symbol ,
198280) {
199-
200281 let Some ( list) = args. list ( ) . map ( MetaItemListParser :: mixed) else {
201282 cx. expected_list ( cx. inner_span , args) ;
202283 return ;
203284 } ;
204285 let mut list = list. peekable ( ) ;
205286
206287 let mut skip_empty_check = false ;
288+ let mut lint_index = 0 ;
289+
207290 while let Some ( item) = list. next ( ) {
208291 let Some ( meta_item) = item. meta_item ( ) else {
209292 cx. expected_string_literal ( item. span ( ) , item. lit ( ) ) ;
210293 * errored = true ;
211294 continue ;
212295 } ;
296+
213297 if let Some ( args) = meta_item. word_is ( sym:: reason) {
214298 if reason. is_some ( ) {
215- // TODO check if this check is already present
299+ // TODO check if this check is already present
216300 cx. duplicate_key ( meta_item. span ( ) , sym:: reason) ;
217301 * errored = true ;
218302 }
@@ -250,18 +334,23 @@ fn validate_lint_attr<S: Stage>(
250334 rest. into_iter ( ) . map ( |ident| ident. to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "::" ) ;
251335 ( Some ( tool. name ) , Some ( tool. span ) , name)
252336 } ;
253- let original_name = Symbol :: intern ( & tool_name. map ( |tool|format ! ( "{tool}::{}" , & name) ) . unwrap_or ( name. clone ( ) ) ) ;
254-
255- if let Some ( ids) = check_lint ( cx, original_name, & name, tool_name, tool_span, meta_item. span ( ) ) {
337+ let original_name = Symbol :: intern (
338+ & tool_name. map ( |tool| format ! ( "{tool}::{}" , & name) ) . unwrap_or ( name. clone ( ) ) ,
339+ ) ;
340+
341+ if let Some ( ids) =
342+ check_lint ( cx, original_name, & name, tool_name, tool_span, meta_item. span ( ) , lint_index )
343+ {
256344 lint_ids. extend ( ids) ;
257345 } else {
258346 // Since external tool lints aren't directly checked by rustc, we don't store these ids
259347 // inside the parsed attr, but this still means that something *does* exist in it, so we shouldn't warn
260348 skip_empty_check = true ;
261349 }
350+ lint_index += 1 ;
262351 }
263352 }
264- if !skip_empty_check && lint_ids. is_empty ( ) {
353+ if !skip_empty_check && ! * errored && lint_ids. is_empty ( ) {
265354 cx. warn_empty_attribute ( cx. attr_span ) ;
266355 }
267356}
@@ -273,6 +362,7 @@ fn check_lint<S: Stage>(
273362 tool_name : Option < Symbol > ,
274363 tool_span : Option < Span > ,
275364 span : Span ,
365+ lint_index : usize
276366) -> Option < Vec < LintAttrIdsInformation > > {
277367 let Some ( lint_store) = & cx. sess . lint_store else {
278368 bug ! ( "lint_store required while parsing attributes" ) ;
@@ -281,14 +371,18 @@ fn check_lint<S: Stage>(
281371 match lint_store. check_lint_name ( lint_name, tool_name, & cx. tools ) {
282372 CheckLintNameResult :: Ok ( ids) => {
283373 for id in ids {
284- lint_ids. push ( LintAttrIdsInformation { name : Symbol :: intern ( & id. to_string ( ) ) , original_name, span, tool_name} ) ;
374+ lint_ids. push ( LintAttrIdsInformation {
375+ name : Symbol :: intern ( & id. to_string ( ) ) ,
376+ original_name,
377+ span,
378+ tool_name,
379+ lint_index,
380+ } ) ;
285381 }
286382 }
287383 CheckLintNameResult :: Tool ( ids, new_lint_name) => {
288384 let _name = match new_lint_name {
289- None => {
290- original_name
291- }
385+ None => original_name,
292386 Some ( new_lint_name) => {
293387 let new_lint_name = Symbol :: intern ( & new_lint_name) ;
294388 cx. emit_lint (
@@ -304,7 +398,13 @@ fn check_lint<S: Stage>(
304398 }
305399 } ;
306400 for id in ids {
307- lint_ids. push ( LintAttrIdsInformation { name : Symbol :: intern ( & id. to_string ( ) ) , original_name, span, tool_name} ) ;
401+ lint_ids. push ( LintAttrIdsInformation {
402+ name : Symbol :: intern ( & id. to_string ( ) ) ,
403+ original_name,
404+ span,
405+ tool_name,
406+ lint_index
407+ } ) ;
308408 }
309409 }
310410
@@ -317,7 +417,6 @@ fn check_lint<S: Stage>(
317417 }
318418
319419 CheckLintNameResult :: NoTool => {
320- dbg ! ( & cx. tools) ;
321420 cx. emit_err ( UnknownToolInScopedLint {
322421 span : tool_span,
323422 tool_name : tool_name. unwrap ( ) ,
@@ -351,7 +450,7 @@ fn check_lint<S: Stage>(
351450
352451 for id in ids {
353452 let name = Symbol :: intern ( & id. to_string ( ) ) ;
354- lint_ids. push ( LintAttrIdsInformation { name, original_name, span, tool_name} ) ;
453+ lint_ids. push ( LintAttrIdsInformation { name, original_name, span, tool_name, lint_index } ) ;
355454 }
356455 }
357456
0 commit comments