@@ -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