@@ -46,6 +46,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode};
4646use  rustc:: hir; 
4747use  rustc:: hir:: def_id:: DefId ; 
4848use  rustc:: hir:: itemlikevisit:: ItemLikeVisitor ; 
49+ use  rustc:: hir:: intravisit; 
4950use  syntax:: ast:: { self ,  Attribute ,  NestedMetaItem } ; 
5051use  rustc_data_structures:: fx:: { FxHashSet ,  FxHashMap } ; 
5152use  syntax_pos:: Span ; 
@@ -73,17 +74,32 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
7374    let  query = tcx. dep_graph . query ( ) ; 
7475    debug ! ( "query-nodes: {:?}" ,  query. nodes( ) ) ; 
7576    let  krate = tcx. hir . krate ( ) ; 
76-     krate . visit_all_item_likes ( & mut  DirtyCleanVisitor  { 
77+     let   mut  dirty_clean_visitor =  DirtyCleanVisitor  { 
7778        tcx :  tcx, 
7879        query :  & query, 
7980        dirty_inputs :  dirty_inputs, 
80-     } ) ; 
81+         checked_attrs :  FxHashSet ( ) , 
82+     } ; 
83+     krate. visit_all_item_likes ( & mut  dirty_clean_visitor) ; 
84+ 
85+     let  mut  all_attrs = FindAllAttrs  { 
86+         tcx :  tcx, 
87+         attr_names :  vec ! [ ATTR_DIRTY ,  ATTR_CLEAN ] , 
88+         found_attrs :  vec ! [ ] , 
89+     } ; 
90+     intravisit:: walk_crate ( & mut  all_attrs,  krate) ; 
91+ 
92+     // Note that we cannot use the existing "unused attribute"-infrastructure 
93+     // here, since that is running before trans. This is also the reason why 
94+     // all trans-specific attributes are `Whitelisted` in syntax::feature_gate. 
95+     all_attrs. report_unchecked_attrs ( & dirty_clean_visitor. checked_attrs ) ; 
8196} 
8297
8398pub  struct  DirtyCleanVisitor < ' a ,  ' tcx : ' a >  { 
8499    tcx :  TyCtxt < ' a ,  ' tcx ,  ' tcx > , 
85100    query :  & ' a  DepGraphQuery < DefId > , 
86101    dirty_inputs :  FxHashSet < DepNode < DefId > > , 
102+     checked_attrs :  FxHashSet < ast:: AttrId > , 
87103} 
88104
89105impl < ' a ,  ' tcx >  DirtyCleanVisitor < ' a ,  ' tcx >  { 
@@ -109,7 +125,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
109125        dep_node. map_def ( |& def_id| Some ( self . tcx . item_path_str ( def_id) ) ) . unwrap ( ) 
110126    } 
111127
112-     fn  assert_dirty ( & self ,  item :   & hir :: Item ,  dep_node :  DepNode < DefId > )  { 
128+     fn  assert_dirty ( & self ,  item_span :   Span ,  dep_node :  DepNode < DefId > )  { 
113129        debug ! ( "assert_dirty({:?})" ,  dep_node) ; 
114130
115131        match  dep_node { 
@@ -121,7 +137,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
121137                if  !self . dirty_inputs . contains ( & dep_node)  { 
122138                    let  dep_node_str = self . dep_node_str ( & dep_node) ; 
123139                    self . tcx . sess . span_err ( 
124-                         item . span , 
140+                         item_span , 
125141                        & format ! ( "`{:?}` not found in dirty set, but should be dirty" , 
126142                                 dep_node_str) ) ; 
127143                } 
@@ -132,14 +148,14 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
132148                if  self . query . contains_node ( & dep_node)  { 
133149                    let  dep_node_str = self . dep_node_str ( & dep_node) ; 
134150                    self . tcx . sess . span_err ( 
135-                         item . span , 
151+                         item_span , 
136152                        & format ! ( "`{:?}` found in dep graph, but should be dirty" ,  dep_node_str) ) ; 
137153                } 
138154            } 
139155        } 
140156    } 
141157
142-     fn  assert_clean ( & self ,  item :   & hir :: Item ,  dep_node :  DepNode < DefId > )  { 
158+     fn  assert_clean ( & self ,  item_span :   Span ,  dep_node :  DepNode < DefId > )  { 
143159        debug ! ( "assert_clean({:?})" ,  dep_node) ; 
144160
145161        match  dep_node { 
@@ -150,7 +166,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
150166                if  self . dirty_inputs . contains ( & dep_node)  { 
151167                    let  dep_node_str = self . dep_node_str ( & dep_node) ; 
152168                    self . tcx . sess . span_err ( 
153-                         item . span , 
169+                         item_span , 
154170                        & format ! ( "`{:?}` found in dirty-node set, but should be clean" , 
155171                                 dep_node_str) ) ; 
156172                } 
@@ -160,35 +176,43 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
160176                if  !self . query . contains_node ( & dep_node)  { 
161177                    let  dep_node_str = self . dep_node_str ( & dep_node) ; 
162178                    self . tcx . sess . span_err ( 
163-                         item . span , 
179+                         item_span , 
164180                        & format ! ( "`{:?}` not found in dep graph, but should be clean" , 
165181                                 dep_node_str) ) ; 
166182                } 
167183            } 
168184        } 
169185    } 
170- } 
171186
172- impl < ' a ,  ' tcx >  ItemLikeVisitor < ' tcx >  for  DirtyCleanVisitor < ' a ,  ' tcx >  { 
173-     fn  visit_item ( & mut  self ,  item :  & ' tcx  hir:: Item )  { 
174-         let  def_id = self . tcx . hir . local_def_id ( item. id ) ; 
187+     fn  check_item ( & mut  self ,  item_id :  ast:: NodeId ,  item_span :  Span )  { 
188+         let  def_id = self . tcx . hir . local_def_id ( item_id) ; 
175189        for  attr in  self . tcx . get_attrs ( def_id) . iter ( )  { 
176190            if  attr. check_name ( ATTR_DIRTY )  { 
177191                if  check_config ( self . tcx ,  attr)  { 
178-                     self . assert_dirty ( item,  self . dep_node ( attr,  def_id) ) ; 
192+                     self . checked_attrs . insert ( attr. id ) ; 
193+                     self . assert_dirty ( item_span,  self . dep_node ( attr,  def_id) ) ; 
179194                } 
180195            }  else  if  attr. check_name ( ATTR_CLEAN )  { 
181196                if  check_config ( self . tcx ,  attr)  { 
182-                     self . assert_clean ( item,  self . dep_node ( attr,  def_id) ) ; 
197+                     self . checked_attrs . insert ( attr. id ) ; 
198+                     self . assert_clean ( item_span,  self . dep_node ( attr,  def_id) ) ; 
183199                } 
184200            } 
185201        } 
186202    } 
203+ } 
204+ 
205+ impl < ' a ,  ' tcx >  ItemLikeVisitor < ' tcx >  for  DirtyCleanVisitor < ' a ,  ' tcx >  { 
206+     fn  visit_item ( & mut  self ,  item :  & ' tcx  hir:: Item )  { 
207+         self . check_item ( item. id ,  item. span ) ; 
208+     } 
187209
188-     fn  visit_trait_item ( & mut  self ,  _trait_item :  & hir:: TraitItem )  { 
210+     fn  visit_trait_item ( & mut  self ,  item :  & hir:: TraitItem )  { 
211+         self . check_item ( item. id ,  item. span ) ; 
189212    } 
190213
191-     fn  visit_impl_item ( & mut  self ,  _impl_item :  & hir:: ImplItem )  { 
214+     fn  visit_impl_item ( & mut  self ,  item :  & hir:: ImplItem )  { 
215+         self . check_item ( item. id ,  item. span ) ; 
192216    } 
193217} 
194218
@@ -201,46 +225,69 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
201225
202226    tcx. dep_graph . with_ignore ( ||{ 
203227        let  krate = tcx. hir . krate ( ) ; 
204-         krate . visit_all_item_likes ( & mut  DirtyCleanMetadataVisitor  { 
228+         let   mut  dirty_clean_visitor =  DirtyCleanMetadataVisitor  { 
205229            tcx :  tcx, 
206230            prev_metadata_hashes :  prev_metadata_hashes, 
207231            current_metadata_hashes :  current_metadata_hashes, 
208-         } ) ; 
232+             checked_attrs :  FxHashSet ( ) , 
233+         } ; 
234+         krate. visit_all_item_likes ( & mut  dirty_clean_visitor) ; 
235+ 
236+         let  mut  all_attrs = FindAllAttrs  { 
237+             tcx :  tcx, 
238+             attr_names :  vec ! [ ATTR_DIRTY_METADATA ,  ATTR_CLEAN_METADATA ] , 
239+             found_attrs :  vec ! [ ] , 
240+         } ; 
241+         intravisit:: walk_crate ( & mut  all_attrs,  krate) ; 
242+ 
243+         // Note that we cannot use the existing "unused attribute"-infrastructure 
244+         // here, since that is running before trans. This is also the reason why 
245+         // all trans-specific attributes are `Whitelisted` in syntax::feature_gate. 
246+         all_attrs. report_unchecked_attrs ( & dirty_clean_visitor. checked_attrs ) ; 
209247    } ) ; 
210248} 
211249
212250pub  struct  DirtyCleanMetadataVisitor < ' a ,  ' tcx : ' a ,  ' m >  { 
213251    tcx :  TyCtxt < ' a ,  ' tcx ,  ' tcx > , 
214252    prev_metadata_hashes :  & ' m  FxHashMap < DefId ,  Fingerprint > , 
215253    current_metadata_hashes :  & ' m  FxHashMap < DefId ,  Fingerprint > , 
254+     checked_attrs :  FxHashSet < ast:: AttrId > , 
216255} 
217256
218257impl < ' a ,  ' tcx ,  ' m >  ItemLikeVisitor < ' tcx >  for  DirtyCleanMetadataVisitor < ' a ,  ' tcx ,  ' m >  { 
219258    fn  visit_item ( & mut  self ,  item :  & ' tcx  hir:: Item )  { 
220-         let  def_id = self . tcx . hir . local_def_id ( item. id ) ; 
259+         self . check_item ( item. id ,  item. span ) ; 
260+     } 
261+ 
262+     fn  visit_trait_item ( & mut  self ,  item :  & hir:: TraitItem )  { 
263+         self . check_item ( item. id ,  item. span ) ; 
264+     } 
265+ 
266+     fn  visit_impl_item ( & mut  self ,  item :  & hir:: ImplItem )  { 
267+         self . check_item ( item. id ,  item. span ) ; 
268+     } 
269+ } 
270+ 
271+ impl < ' a ,  ' tcx ,  ' m >  DirtyCleanMetadataVisitor < ' a ,  ' tcx ,  ' m >  { 
272+ 
273+     fn  check_item ( & mut  self ,  item_id :  ast:: NodeId ,  item_span :  Span )  { 
274+         let  def_id = self . tcx . hir . local_def_id ( item_id) ; 
221275
222276        for  attr in  self . tcx . get_attrs ( def_id) . iter ( )  { 
223277            if  attr. check_name ( ATTR_DIRTY_METADATA )  { 
224278                if  check_config ( self . tcx ,  attr)  { 
225-                     self . assert_state ( false ,  def_id,  item. span ) ; 
279+                     self . checked_attrs . insert ( attr. id ) ; 
280+                     self . assert_state ( false ,  def_id,  item_span) ; 
226281                } 
227282            }  else  if  attr. check_name ( ATTR_CLEAN_METADATA )  { 
228283                if  check_config ( self . tcx ,  attr)  { 
229-                     self . assert_state ( true ,  def_id,  item. span ) ; 
284+                     self . checked_attrs . insert ( attr. id ) ; 
285+                     self . assert_state ( true ,  def_id,  item_span) ; 
230286                } 
231287            } 
232288        } 
233289    } 
234290
235-     fn  visit_trait_item ( & mut  self ,  _trait_item :  & hir:: TraitItem )  { 
236-     } 
237- 
238-     fn  visit_impl_item ( & mut  self ,  _impl_item :  & hir:: ImplItem )  { 
239-     } 
240- } 
241- 
242- impl < ' a ,  ' tcx ,  ' m >  DirtyCleanMetadataVisitor < ' a ,  ' tcx ,  ' m >  { 
243- 
244291    fn  assert_state ( & self ,  should_be_clean :  bool ,  def_id :  DefId ,  span :  Span )  { 
245292        let  item_path = self . tcx . item_path_str ( def_id) ; 
246293        debug ! ( "assert_state({})" ,  item_path) ; 
@@ -274,7 +321,7 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
274321/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan 
275322/// for a `cfg="foo"` attribute and check whether we have a cfg 
276323/// flag called `foo`. 
277- fn  check_config ( tcx :  TyCtxt ,  attr :  & ast :: Attribute )  -> bool  { 
324+ fn  check_config ( tcx :  TyCtxt ,  attr :  & Attribute )  -> bool  { 
278325    debug ! ( "check_config(attr={:?})" ,  attr) ; 
279326    let  config = & tcx. sess . parse_sess . config ; 
280327    debug ! ( "check_config: config={:?}" ,  config) ; 
@@ -304,3 +351,47 @@ fn expect_associated_value(tcx: TyCtxt, item: &NestedMetaItem) -> ast::Name {
304351        tcx. sess . span_fatal ( item. span ,  & msg) ; 
305352    } 
306353} 
354+ 
355+ 
356+ // A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from 
357+ // the HIR. It is used to verfiy that we really ran checks for all annotated 
358+ // nodes. 
359+ pub  struct  FindAllAttrs < ' a ,  ' tcx : ' a >  { 
360+     tcx :  TyCtxt < ' a ,  ' tcx ,  ' tcx > , 
361+     attr_names :  Vec < & ' static  str > , 
362+     found_attrs :  Vec < & ' tcx  Attribute > , 
363+ } 
364+ 
365+ impl < ' a ,  ' tcx >  FindAllAttrs < ' a ,  ' tcx >  { 
366+ 
367+     fn  is_active_attr ( & mut  self ,  attr :  & Attribute )  -> bool  { 
368+         for  attr_name in  & self . attr_names  { 
369+             if  attr. check_name ( attr_name)  && check_config ( self . tcx ,  attr)  { 
370+                 return  true ; 
371+             } 
372+         } 
373+ 
374+         false 
375+     } 
376+ 
377+     fn  report_unchecked_attrs ( & self ,  checked_attrs :  & FxHashSet < ast:: AttrId > )  { 
378+         for  attr in  & self . found_attrs  { 
379+             if  !checked_attrs. contains ( & attr. id )  { 
380+                 self . tcx . sess . span_err ( attr. span ,  & format ! ( "found unchecked \  
381+                      #[rustc_dirty]/#[rustc_clean] attribute") ) ; 
382+             } 
383+         } 
384+     } 
385+ } 
386+ 
387+ impl < ' a ,  ' tcx >  intravisit:: Visitor < ' tcx >  for  FindAllAttrs < ' a ,  ' tcx >  { 
388+     fn  nested_visit_map < ' this > ( & ' this  mut  self )  -> intravisit:: NestedVisitorMap < ' this ,  ' tcx >  { 
389+         intravisit:: NestedVisitorMap :: All ( & self . tcx . hir ) 
390+     } 
391+ 
392+     fn  visit_attribute ( & mut  self ,  attr :  & ' tcx  Attribute )  { 
393+         if  self . is_active_attr ( attr)  { 
394+             self . found_attrs . push ( attr) ; 
395+         } 
396+     } 
397+ } 
0 commit comments