@@ -2,6 +2,7 @@ use crate::context::{CheckLintNameResult, LintStore};
22use  crate :: late:: unerased_lint_store; 
33use  rustc_ast as  ast; 
44use  rustc_ast:: unwrap_or; 
5+ use  rustc_ast:: NestedMetaItem ; 
56use  rustc_ast_pretty:: pprust; 
67use  rustc_data_structures:: fx:: FxHashMap ; 
78use  rustc_errors:: { struct_span_err,  Applicability ,  DiagnosticBuilder } ; 
@@ -247,44 +248,18 @@ impl<'s> LintLevelsBuilder<'s> {
247248
248249            // Before processing the lint names, look for a reason (RFC 2383) 
249250            // at the end. 
250-             let  mut  reason = None ; 
251251            let  tail_li = & metas[ metas. len ( )  - 1 ] ; 
252-             if  let  Some ( item)  = tail_li. meta_item ( )  { 
253-                 match  item. kind  { 
254-                     ast:: MetaItemKind :: Word  => { }  // actual lint names handled later 
255-                     ast:: MetaItemKind :: NameValue ( ref  name_value)  => { 
256-                         if  item. path  == sym:: reason { 
257-                             // FIXME (#55112): issue unused-attributes lint if we thereby 
258-                             // don't have any lint names (`#[level(reason = "foo")]`) 
259-                             if  let  ast:: LitKind :: Str ( rationale,  _)  = name_value. kind  { 
260-                                 if  !self . sess . features_untracked ( ) . lint_reasons  { 
261-                                     feature_err ( 
262-                                         & self . sess . parse_sess , 
263-                                         sym:: lint_reasons, 
264-                                         item. span , 
265-                                         "lint reasons are experimental" , 
266-                                     ) 
267-                                     . emit ( ) ; 
268-                                 } 
269-                                 reason = Some ( rationale) ; 
270-                             }  else  { 
271-                                 bad_attr ( name_value. span ) 
272-                                     . span_label ( name_value. span ,  "reason must be a string literal" ) 
273-                                     . emit ( ) ; 
274-                             } 
275-                             // found reason, reslice meta list to exclude it 
276-                             metas. pop ( ) . unwrap ( ) ; 
277-                         }  else  { 
278-                             bad_attr ( item. span ) 
279-                                 . span_label ( item. span ,  "bad attribute argument" ) 
280-                                 . emit ( ) ; 
281-                         } 
282-                     } 
283-                     ast:: MetaItemKind :: List ( _)  => { 
284-                         bad_attr ( item. span ) . span_label ( item. span ,  "bad attribute argument" ) . emit ( ) ; 
285-                     } 
252+             let  reason = match  try_parse_reason_metadata ( tail_li,  self . sess )  { 
253+                 ParseLintReasonResult :: Ok ( reason)  => { 
254+                     metas. pop ( ) . unwrap ( ) ; 
255+                     Some ( reason) 
286256                } 
287-             } 
257+                 ParseLintReasonResult :: MalformedReason  => { 
258+                     metas. pop ( ) . unwrap ( ) ; 
259+                     None 
260+                 } 
261+                 ParseLintReasonResult :: NotFound  => None , 
262+             } ; 
288263
289264            for  li in  metas { 
290265                let  sp = li. span ( ) ; 
@@ -568,6 +543,57 @@ impl<'s> LintLevelsBuilder<'s> {
568543    } 
569544} 
570545
546+ pub ( crate )  enum  ParseLintReasonResult  { 
547+     /// The reason was found and is returned as part of this value. 
548+ Ok ( Symbol ) , 
549+     /// Indicates that the reason field was found but was malformed. 
550+ MalformedReason , 
551+     /// The checked item is not a reason field. 
552+ NotFound , 
553+ } 
554+ 
555+ pub ( crate )  fn  try_parse_reason_metadata ( 
556+     item :  & NestedMetaItem , 
557+     sess :  & Session , 
558+ )  -> ParseLintReasonResult  { 
559+     let  bad_attr = |span| struct_span_err ! ( sess,  span,  E0452 ,  "malformed lint attribute input" ) ; 
560+     if  let  Some ( item)  = item. meta_item ( )  { 
561+         match  item. kind  { 
562+             ast:: MetaItemKind :: Word  => { }  // actual lint names handled later 
563+             ast:: MetaItemKind :: NameValue ( ref  name_value)  => { 
564+                 if  item. path  == sym:: reason { 
565+                     // FIXME (#55112): issue unused-attributes lint if we thereby 
566+                     // don't have any lint names (`#[level(reason = "foo")]`) 
567+                     if  let  ast:: LitKind :: Str ( rationale,  _)  = name_value. kind  { 
568+                         if  !sess. features_untracked ( ) . lint_reasons  { 
569+                             feature_err ( 
570+                                 & sess. parse_sess , 
571+                                 sym:: lint_reasons, 
572+                                 item. span , 
573+                                 "lint reasons are experimental" , 
574+                             ) 
575+                             . emit ( ) ; 
576+                         } 
577+                         return  ParseLintReasonResult :: Ok ( rationale) ; 
578+                     }  else  { 
579+                         bad_attr ( name_value. span ) 
580+                             . span_label ( name_value. span ,  "reason must be a string literal" ) 
581+                             . emit ( ) ; 
582+                         return  ParseLintReasonResult :: MalformedReason ; 
583+                     } 
584+                 }  else  { 
585+                     bad_attr ( item. span ) . span_label ( item. span ,  "bad attribute argument" ) . emit ( ) ; 
586+                 } 
587+             } 
588+             ast:: MetaItemKind :: List ( _)  => { 
589+                 bad_attr ( item. span ) . span_label ( item. span ,  "bad attribute argument" ) . emit ( ) ; 
590+             } 
591+         } 
592+     } 
593+ 
594+     ParseLintReasonResult :: NotFound 
595+ } 
596+ 
571597pub  fn  is_known_lint_tool ( m_item :  Symbol ,  sess :  & Session ,  attrs :  & [ ast:: Attribute ] )  -> bool  { 
572598    if  [ sym:: clippy,  sym:: rustc,  sym:: rustdoc] . contains ( & m_item)  { 
573599        return  true ; 
0 commit comments