3939//! previous revision to compare things to.
4040//!
4141
42+ use std:: collections:: HashSet ;
43+ use std:: vec:: Vec ;
4244use rustc:: dep_graph:: DepNode ;
4345use rustc:: hir;
4446use rustc:: hir:: def_id:: DefId ;
@@ -54,6 +56,8 @@ use rustc::ty::TyCtxt;
5456const LABEL : & ' static str = "label" ;
5557const CFG : & ' static str = "cfg" ;
5658
59+ type Labels = HashSet < String > ;
60+
5761pub fn check_dirty_clean_annotations < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
5862 // can't add `#[rustc_dirty]` etc without opting in to this feature
5963 if !tcx. sess . features . borrow ( ) . rustc_attrs {
@@ -87,23 +91,46 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
8791}
8892
8993impl < ' 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 {
9295 for item in attr. meta_item_list ( ) . unwrap_or_else ( Vec :: new) {
9396 if item. check_name ( LABEL ) {
9497 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) ) ;
102113 }
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) ) ;
103119 }
104120 }
121+ out
122+ }
105123
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
107134 }
108135
109136 fn dep_node_str ( & self , dep_node : & DepNode ) -> String {
@@ -150,12 +177,18 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
150177 if attr. check_name ( ATTR_DIRTY ) {
151178 if check_config ( self . tcx , attr) {
152179 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+ }
154184 }
155185 } else if attr. check_name ( ATTR_CLEAN ) {
156186 if check_config ( self . tcx , attr) {
157187 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+ }
159192 }
160193 }
161194 }
0 commit comments