39
39
//! previous revision to compare things to.
40
40
//!
41
41
42
+ use std:: collections:: HashSet ;
43
+ use std:: vec:: Vec ;
42
44
use rustc:: dep_graph:: DepNode ;
43
45
use rustc:: hir;
44
46
use rustc:: hir:: def_id:: DefId ;
@@ -54,6 +56,8 @@ use rustc::ty::TyCtxt;
54
56
const LABEL : & ' static str = "label" ;
55
57
const CFG : & ' static str = "cfg" ;
56
58
59
+ type Labels = HashSet < String > ;
60
+
57
61
pub fn check_dirty_clean_annotations < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
58
62
// can't add `#[rustc_dirty]` etc without opting in to this feature
59
63
if !tcx. sess . features . borrow ( ) . rustc_attrs {
@@ -87,23 +91,46 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
87
91
}
88
92
89
93
impl < ' a , ' tcx > DirtyCleanVisitor < ' a , ' tcx > {
90
- fn dep_node ( & self , attr : & Attribute , def_id : DefId ) -> DepNode {
91
- let def_path_hash = self . tcx . def_path_hash ( def_id) ;
94
+ fn labels ( & self , attr : & Attribute ) -> Labels {
92
95
for item in attr. meta_item_list ( ) . unwrap_or_else ( Vec :: new) {
93
96
if item. check_name ( LABEL ) {
94
97
let value = expect_associated_value ( self . tcx , & item) ;
95
- match DepNode :: from_label_string ( & value. as_str ( ) , def_path_hash) {
96
- Ok ( dep_node) => return dep_node,
97
- Err ( ( ) ) => {
98
- self . tcx . sess . span_fatal (
99
- item. span ,
100
- & format ! ( "dep-node label `{}` not recognized" , value) ) ;
101
- }
98
+ return self . resolve_labels ( & item, value. as_str ( ) . as_ref ( ) ) ;
99
+ }
100
+ }
101
+ self . tcx . sess . span_fatal ( attr. span , "no `label` found" ) ;
102
+ }
103
+
104
+ fn resolve_labels ( & self , item : & NestedMetaItem , value : & str ) -> Labels {
105
+ let mut out: Labels = HashSet :: new ( ) ;
106
+ for label in value. split ( ',' ) {
107
+ let label = label. trim ( ) ;
108
+ if DepNode :: has_label_string ( label) {
109
+ if out. contains ( label) {
110
+ self . tcx . sess . span_fatal (
111
+ item. span ,
112
+ & format ! ( "dep-node label `{}` is repeated" , label) ) ;
102
113
}
114
+ out. insert ( label. to_string ( ) ) ;
115
+ } else {
116
+ self . tcx . sess . span_fatal (
117
+ item. span ,
118
+ & format ! ( "dep-node label `{}` not recognized" , label) ) ;
103
119
}
104
120
}
121
+ out
122
+ }
105
123
106
- self . tcx . sess . span_fatal ( attr. span , "no `label` found" ) ;
124
+ fn dep_nodes ( & self , labels : & Labels , def_id : DefId ) -> Vec < DepNode > {
125
+ let mut out = Vec :: with_capacity ( labels. len ( ) ) ;
126
+ let def_path_hash = self . tcx . def_path_hash ( def_id) ;
127
+ for label in labels. iter ( ) {
128
+ match DepNode :: from_label_string ( label, def_path_hash) {
129
+ Ok ( dep_node) => out. push ( dep_node) ,
130
+ Err ( ( ) ) => unreachable ! ( ) ,
131
+ }
132
+ }
133
+ out
107
134
}
108
135
109
136
fn dep_node_str ( & self , dep_node : & DepNode ) -> String {
@@ -150,12 +177,18 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
150
177
if attr. check_name ( ATTR_DIRTY ) {
151
178
if check_config ( self . tcx , attr) {
152
179
self . checked_attrs . insert ( attr. id ) ;
153
- self . assert_dirty ( item_span, self . dep_node ( attr, def_id) ) ;
180
+ let labels = self . labels ( attr) ;
181
+ for dep_node in self . dep_nodes ( & labels, def_id) {
182
+ self . assert_dirty ( item_span, dep_node) ;
183
+ }
154
184
}
155
185
} else if attr. check_name ( ATTR_CLEAN ) {
156
186
if check_config ( self . tcx , attr) {
157
187
self . checked_attrs . insert ( attr. id ) ;
158
- self . assert_clean ( item_span, self . dep_node ( attr, def_id) ) ;
188
+ let labels = self . labels ( attr) ;
189
+ for dep_node in self . dep_nodes ( & labels, def_id) {
190
+ self . assert_clean ( item_span, dep_node) ;
191
+ }
159
192
}
160
193
}
161
194
}
0 commit comments