11//! Contains the data structures used by the diagnostic attribute family.
2- use std:: fmt;
3- use std:: fmt:: Debug ;
2+ use std:: fmt:: { self , Debug } ;
43
5- use rustc_macros:: { Decodable , Encodable , StableHash } ;
4+ use rustc_macros:: { Decodable , Encodable , StableHash , Walkable } ;
5+ use rustc_span:: def_id:: DefId ;
66use rustc_span:: { DesugaringKind , Span , Symbol , kw} ;
77use thin_vec:: ThinVec ;
88use tracing:: debug;
99
10- #[ derive( Clone , Default , Debug , StableHash , Encodable , Decodable ) ]
10+ use crate :: { NodeId , Path } ;
11+
12+ #[ derive( Clone , Default , Debug , StableHash , Encodable , Decodable , Walkable ) ]
1113pub struct Directive {
1214 pub is_rustc_attr : bool ,
1315 /// This is never nested more than once, i.e. the directives in this
1416 /// thinvec have no filters of their own.
1517 pub filters : ThinVec < ( Filter , Directive ) > ,
18+ #[ visitable( ignore) ]
1619 pub message : Option < ( Span , FormatString ) > ,
20+ #[ visitable( ignore) ]
1721 pub label : Option < ( Span , FormatString ) > ,
22+ #[ visitable( ignore) ]
1823 pub notes : ThinVec < FormatString > ,
24+ #[ visitable( ignore) ]
1925 pub parent_label : Option < FormatString > ,
2026}
2127
@@ -47,6 +53,16 @@ impl Directive {
4753 }
4854 }
4955
56+ pub fn resolve_predicates ( & mut self , resolve : & mut impl FnMut ( NodeId , & Path ) -> Option < DefId > ) {
57+ for ( Filter { pred, .. } , nested_dir) in & mut self . filters {
58+ debug_assert ! (
59+ nested_dir. filters. is_empty( ) ,
60+ "can't have filters beyond the root directive"
61+ ) ;
62+ pred. resolve_predicates ( resolve) ;
63+ }
64+ }
65+
5066 pub fn eval (
5167 & self ,
5268 filter_options : Option < & FilterOptions > ,
@@ -234,19 +250,31 @@ pub enum FormatArg {
234250}
235251
236252/// Represents the `on` filter in `#[rustc_on_unimplemented]`.
237- #[ derive( Clone , Debug , StableHash , Encodable , Decodable ) ]
253+ #[ derive( Clone , Debug , StableHash , Encodable , Decodable , Walkable ) ]
238254pub struct Filter {
239255 pub span : Span ,
240256 pub pred : Predicate ,
241257}
258+
242259impl Filter {
243260 pub fn matches_predicate ( & self , options : & FilterOptions ) -> bool {
244261 self . pred . eval ( & mut |p| match p {
245262 FlagOrNv :: Flag ( b) => options. has_flag ( * b) ,
246- FlagOrNv :: NameValue ( NameValue { name, value } ) => {
263+ FlagOrNv :: NameValue ( NameValue :: String { name, value } ) => {
247264 let value = value. format ( & options. generic_args ) ;
248265 options. contains ( * name, value)
249266 }
267+ FlagOrNv :: NameValue ( NameValue :: Path { .. } ) => {
268+ unreachable ! ( "should have been removed during ast lowering" )
269+ }
270+ FlagOrNv :: NameValue ( NameValue :: DefId { name, def_id } ) => {
271+ if let Some ( def_id) = def_id {
272+ options. contains_defid ( * name, * def_id)
273+ } else {
274+ // we've already errored during ast lowering
275+ false
276+ }
277+ }
250278 } )
251279 }
252280
@@ -259,10 +287,10 @@ impl Filter {
259287///
260288/// It is similar to the predicate in the `cfg` attribute,
261289/// and may contain nested predicates.
262- #[ derive( Clone , Debug , StableHash , Encodable , Decodable ) ]
290+ #[ derive( Clone , Debug , StableHash , Encodable , Decodable , Walkable ) ]
263291pub enum Predicate {
264292 /// A condition like `on(crate_local)`.
265- Flag ( Flag ) ,
293+ Flag ( # [ visitable ( ignore ) ] Flag ) ,
266294 /// A match, like `on(Rhs = "Whatever")`.
267295 Match ( NameValue ) ,
268296 /// Negation, like `on(not($pred))`.
@@ -294,6 +322,41 @@ impl Predicate {
294322 }
295323 }
296324 }
325+
326+ pub fn visit_predicates ( & self , visit : & mut impl FnMut ( NodeId , & Path ) ) {
327+ match self {
328+ Predicate :: Flag ( _) | Predicate :: Match ( NameValue :: String { .. } ) => { }
329+ Predicate :: Match ( NameValue :: Path { name : _, value, id } ) => {
330+ visit ( * id, value) ;
331+ }
332+ Predicate :: Match ( NameValue :: DefId { .. } ) => {
333+ unreachable ! ( )
334+ }
335+ Predicate :: Not ( not) => not. visit_predicates ( visit) ,
336+ Predicate :: All ( preds) | Predicate :: Any ( preds) => {
337+ preds. iter ( ) . for_each ( |pred| pred. visit_predicates ( visit) )
338+ }
339+ }
340+ }
341+
342+ pub fn resolve_predicates ( & mut self , resolve : & mut impl FnMut ( NodeId , & Path ) -> Option < DefId > ) {
343+ match self {
344+ Predicate :: Flag ( _) | Predicate :: Match ( NameValue :: String { .. } ) => { }
345+ Predicate :: Match ( NameValue :: Path { name, value, id } ) => {
346+ let def_id = resolve ( * id, value) ;
347+ * self = Predicate :: Match ( NameValue :: DefId { name : * name, def_id } ) ;
348+ }
349+ Predicate :: Match ( NameValue :: DefId { .. } ) => {
350+ if cfg ! ( debug_assertions) {
351+ unreachable ! ( "predicate was resolved twice" )
352+ }
353+ }
354+ Predicate :: Not ( not) => not. resolve_predicates ( resolve) ,
355+ Predicate :: All ( preds) | Predicate :: Any ( preds) => {
356+ preds. iter_mut ( ) . for_each ( |pred| pred. resolve_predicates ( resolve) )
357+ }
358+ }
359+ }
297360}
298361
299362/// Represents a `MetaWord` in an `on`-filter.
@@ -312,21 +375,39 @@ pub enum Flag {
312375/// A `MetaNameValueStr` in an `on`-filter.
313376///
314377/// For example, `#[rustc_on_unimplemented(on(name = "value", message = "hello"))]`.
315- #[ derive( Clone , Debug , StableHash , Encodable , Decodable ) ]
316- pub struct NameValue {
317- pub name : Name ,
378+ #[ derive( Clone , Debug , StableHash , Encodable , Decodable , Walkable ) ]
379+ pub enum NameValue {
318380 /// Something like `"&str"` or `"alloc::string::String"`,
319381 /// in which case it just contains a single string piece.
320382 /// But if it is something like `"&[{A}]"` then it must be formatted later.
321- pub value : FilterFormatString ,
383+ String {
384+ #[ visitable( ignore) ]
385+ name : Name ,
386+ #[ visitable( ignore) ]
387+ value : FilterFormatString ,
388+ } ,
389+ Path {
390+ #[ visitable( ignore) ]
391+ name : Name ,
392+ id : NodeId ,
393+ value : Path ,
394+ } ,
395+ DefId {
396+ #[ visitable( ignore) ]
397+ name : Name ,
398+ #[ visitable( ignore) ]
399+ def_id : Option < DefId > ,
400+ } ,
322401}
323402
324403impl NameValue {
325404 pub fn visit_params ( & self , span : Span , visit : & mut impl FnMut ( Symbol , Span ) ) {
326- if let Name :: GenericArg ( arg) = self . name {
327- visit ( arg, span) ;
405+ if let NameValue :: String { name, value } = self {
406+ if let Name :: GenericArg ( arg) = name {
407+ visit ( * arg, span) ;
408+ }
409+ value. visit_params ( span, visit) ;
328410 }
329- self . value . visit_params ( span, visit) ;
330411 }
331412}
332413
@@ -357,14 +438,14 @@ pub struct FilterFormatString {
357438}
358439
359440impl FilterFormatString {
360- fn format ( & self , generic_args : & [ ( Symbol , String ) ] ) -> String {
441+ fn format ( & self , generic_args : & [ ( Symbol , String , Option < DefId > ) ] ) -> String {
361442 let mut ret = String :: new ( ) ;
362443
363444 for piece in & self . pieces {
364445 match piece {
365446 LitOrArg :: Lit ( s) => ret. push_str ( s. as_str ( ) ) ,
366- LitOrArg :: Arg ( s) => match generic_args. iter ( ) . find ( |( k, _) | k == s) {
367- Some ( ( _, val) ) => ret. push_str ( val) ,
447+ LitOrArg :: Arg ( s) => match generic_args. iter ( ) . find ( |( k, _, _ ) | k == s) {
448+ Some ( ( _, val, _ ) ) => ret. push_str ( val) ,
368449 None => {
369450 let _ = std:: fmt:: write ( & mut ret, format_args ! ( "{{{s}}}" ) ) ;
370451 }
@@ -416,21 +497,21 @@ pub enum LitOrArg {
416497///
417498/// ```rust,ignore (just an example)
418499/// FilterOptions {
419- /// self_types: ["u32", "{integral}"],
500+ /// self_types: [( "u32", None), ( "{integral}", None), ("Type", Some(<defid>)) ],
420501/// from_desugaring: Some("QuestionMark"),
421502/// cause: None,
422503/// crate_local: false,
423504/// direct: true,
424- /// generic_args: [("Self","u32"),
425- /// ("R", "core::option::Option<core::convert::Infallible>"),
426- /// ("R", "core::option::Option<T>" ),
505+ /// generic_args: [("Self","u32", <defid> ),
506+ /// ("R", "core::option::Option<core::convert::Infallible>", Some(<defid>) ),
507+ /// ("R", "core::option::Option<T>", Some(<defid>) ),
427508/// ],
428509/// }
429510/// ```
430511#[ derive( Debug ) ]
431512pub struct FilterOptions {
432513 /// All the self types that may apply.
433- pub self_types : Vec < String > ,
514+ pub self_types : Vec < ( String , Option < DefId > ) > ,
434515 // The kind of compiler desugaring.
435516 pub from_desugaring : Option < DesugaringKind > ,
436517 /// Match on a variant of rustc_infer's `ObligationCauseCode`.
@@ -439,23 +520,45 @@ pub struct FilterOptions {
439520 /// Is the obligation "directly" user-specified, rather than derived?
440521 pub direct : bool ,
441522 // A list of the generic arguments and their reified types.
442- pub generic_args : Vec < ( Symbol , String ) > ,
523+ pub generic_args : Vec < ( Symbol , String , Option < DefId > ) > ,
443524}
444525
445526impl FilterOptions {
446- pub fn has_flag ( & self , name : Flag ) -> bool {
527+ fn has_flag ( & self , name : Flag ) -> bool {
447528 match name {
448529 Flag :: CrateLocal => self . crate_local ,
449530 Flag :: Direct => self . direct ,
450531 Flag :: FromDesugaring => self . from_desugaring . is_some ( ) ,
451532 }
452533 }
453- pub fn contains ( & self , name : Name , value : String ) -> bool {
534+ fn contains ( & self , name : Name , value : String ) -> bool {
454535 match name {
455- Name :: SelfUpper => self . self_types . contains ( & value) ,
536+ Name :: SelfUpper => {
537+ self . self_types . iter ( ) . any ( |( type_name, _this_def_id) | * type_name == value)
538+ }
456539 Name :: FromDesugaring => self . from_desugaring . is_some_and ( |ds| ds. matches ( & value) ) ,
457540 Name :: Cause => self . cause == Some ( value) ,
458- Name :: GenericArg ( arg) => self . generic_args . contains ( & ( arg, value) ) ,
541+ Name :: GenericArg ( generic) => self
542+ . generic_args
543+ . iter ( )
544+ . any ( |( this_name, typename, _) | * this_name == generic && * typename == value) ,
545+ }
546+ }
547+
548+ fn contains_defid ( & self , name : Name , def_id : DefId ) -> bool {
549+ match name {
550+ Name :: SelfUpper => {
551+ self . self_types . iter ( ) . any ( |( _type_name, this_def_id) | * this_def_id == Some ( def_id) )
552+ }
553+
554+ Name :: GenericArg ( generic) => {
555+ self . generic_args . iter ( ) . any ( |( this_name, _type_name, this_def_id) | {
556+ * this_name == generic && * this_def_id == Some ( def_id)
557+ } )
558+ }
559+ Name :: FromDesugaring | Name :: Cause => {
560+ unreachable ! ( "these can only refer to strings and are never resolved" )
561+ }
459562 }
460563 }
461564}
0 commit comments