22use std:: fmt;
33use std:: fmt:: Debug ;
44
5- pub use rustc_ast:: attr:: data_structures:: * ;
65use rustc_macros:: { Decodable , Encodable , HashStable , PrintAttribute } ;
76use rustc_span:: { DesugaringKind , Span , Symbol , kw} ;
87use thin_vec:: ThinVec ;
@@ -13,8 +12,9 @@ use crate::attrs::PrintAttribute;
1312#[ derive( Clone , Default , Debug , HashStable , Encodable , Decodable , PrintAttribute ) ]
1413pub struct Directive {
1514 pub is_rustc_attr : bool ,
16- pub condition : Option < OnUnimplementedCondition > ,
17- pub subcommands : ThinVec < Directive > ,
15+ /// This is never nested more than once, i.e. the directives in this
16+ /// thinvec have no filters of their own.
17+ pub filters : ThinVec < ( OnUnimplementedCondition , Directive ) > ,
1818 pub message : Option < ( Span , FormatString ) > ,
1919 pub label : Option < ( Span , FormatString ) > ,
2020 pub notes : ThinVec < FormatString > ,
@@ -28,11 +28,8 @@ impl Directive {
2828 /// We can't check this while parsing the attribute because `rustc_attr_parsing` doesn't have
2929 /// access to the item an attribute is on. Instead we later call this function in `check_attr`.
3030 pub fn visit_params ( & self , visit : & mut impl FnMut ( Symbol , Span ) ) {
31- if let Some ( condition) = & self . condition {
32- condition. visit_params ( visit) ;
33- }
34-
35- for subcommand in & self . subcommands {
31+ for ( filter, subcommand) in & self . filters {
32+ filter. visit_params ( visit) ;
3633 subcommand. visit_params ( visit) ;
3734 }
3835
@@ -62,53 +59,25 @@ impl Directive {
6259 "Directive::eval({self:?}, this={this}, options={condition_options:?}, args ={args:?})"
6360 ) ;
6461
65- let Some ( condition_options) = condition_options else {
62+ let mut ret = CustomDiagnostic :: default ( ) ;
63+
64+ if let Some ( condition_options) = condition_options {
65+ for ( filter, directive) in & self . filters {
66+ if filter. matches_predicate ( condition_options) {
67+ debug ! ( "eval: {filter:?} succeeded" ) ;
68+ ret. update ( directive, args) ;
69+ } else {
70+ debug ! ( "eval: skipping {filter:?} due to condition" ) ;
71+ }
72+ }
73+ } else {
6674 debug_assert ! (
6775 !self . is_rustc_attr,
6876 "Directive::eval called for `rustc_on_unimplemented` without `condition_options`"
6977 ) ;
70- return CustomDiagnostic {
71- label : self . label . as_ref ( ) . map ( |l| l. 1 . format ( args) ) ,
72- message : self . message . as_ref ( ) . map ( |m| m. 1 . format ( args) ) ,
73- notes : self . notes . iter ( ) . map ( |n| n. format ( args) ) . collect ( ) ,
74- parent_label : None ,
75- } ;
7678 } ;
77- let mut message = None ;
78- let mut label = None ;
79- let mut notes = Vec :: new ( ) ;
80- let mut parent_label = None ;
81-
82- for command in self . subcommands . iter ( ) . chain ( Some ( self ) ) . rev ( ) {
83- debug ! ( ?command) ;
84- if let Some ( ref condition) = command. condition
85- && !condition. matches_predicate ( condition_options)
86- {
87- debug ! ( "eval: skipping {command:?} due to condition" ) ;
88- continue ;
89- }
90- debug ! ( "eval: {command:?} succeeded" ) ;
91- if let Some ( ref message_) = command. message {
92- message = Some ( message_. clone ( ) ) ;
93- }
94-
95- if let Some ( ref label_) = command. label {
96- label = Some ( label_. clone ( ) ) ;
97- }
98-
99- notes. extend ( command. notes . clone ( ) ) ;
100-
101- if let Some ( ref parent_label_) = command. parent_label {
102- parent_label = Some ( parent_label_. clone ( ) ) ;
103- }
104- }
105-
106- CustomDiagnostic {
107- label : label. map ( |l| l. 1 . format ( args) ) ,
108- message : message. map ( |m| m. 1 . format ( args) ) ,
109- notes : notes. into_iter ( ) . map ( |n| n. format ( args) ) . collect ( ) ,
110- parent_label : parent_label. map ( |e_s| e_s. format ( args) ) ,
111- }
79+ ret. update ( self , args) ;
80+ ret
11281 }
11382}
11483
@@ -121,6 +90,22 @@ pub struct CustomDiagnostic {
12190 pub parent_label : Option < String > ,
12291}
12392
93+ impl CustomDiagnostic {
94+ fn update ( & mut self , di : & Directive , args : & FormatArgs ) {
95+ if self . message . is_none ( ) {
96+ self . message = di. message . as_ref ( ) . map ( |m| m. 1 . format ( args) ) ;
97+ }
98+ if self . label . is_none ( ) {
99+ self . label = di. label . as_ref ( ) . map ( |l| l. 1 . format ( args) ) ;
100+ }
101+ if self . parent_label . is_none ( ) {
102+ self . parent_label = di. parent_label . as_ref ( ) . map ( |p| p. format ( args) ) ;
103+ }
104+
105+ self . notes . extend ( di. notes . iter ( ) . map ( |n| n. format ( args) ) )
106+ }
107+ }
108+
124109/// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
125110/// either as string pieces or dynamic arguments.
126111#[ derive( Clone , Debug , HashStable , Encodable , Decodable , PrintAttribute ) ]
0 commit comments