2626//! used to check when paths exist or do not.
2727//!
2828//! The full form of the `rustc_if_this_changed` annotation is
29- //! `#[rustc_if_this_changed(id)]`. The `"id"` is optional and
30- //! defaults to `"id"` if omitted.
29+ //! `#[rustc_if_this_changed("foo")]`, which will report a
30+ //! source node of `foo(def_id)`. The `"foo"` is optional and
31+ //! defaults to `"Hir"` if omitted.
3132//!
3233//! Example:
3334//!
3435//! ```
35- //! #[rustc_if_this_changed]
36+ //! #[rustc_if_this_changed(Hir) ]
3637//! fn foo() { }
3738//!
38- //! #[rustc_then_this_would_need(" trans" )] //~ ERROR no path from `foo`
39+ //! #[rustc_then_this_would_need(trans)] //~ ERROR no path from `foo`
3940//! fn bar() { }
4041//!
41- //! #[rustc_then_this_would_need(" trans" )] //~ ERROR OK
42+ //! #[rustc_then_this_would_need(trans)] //~ ERROR OK
4243//! fn baz() { foo(); }
4344//! ```
4445
@@ -47,7 +48,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode};
4748use rustc:: dep_graph:: debug:: { DepNodeFilter , EdgeFilter } ;
4849use rustc:: hir:: def_id:: DefId ;
4950use rustc:: ty:: TyCtxt ;
50- use rustc_data_structures:: fnv:: { FnvHashMap , FnvHashSet } ;
51+ use rustc_data_structures:: fnv:: FnvHashSet ;
5152use rustc_data_structures:: graph:: { Direction , INCOMING , OUTGOING , NodeIndex } ;
5253use rustc:: hir;
5354use rustc:: hir:: intravisit:: Visitor ;
@@ -61,7 +62,6 @@ use syntax_pos::Span;
6162
6263const IF_THIS_CHANGED : & ' static str = "rustc_if_this_changed" ;
6364const THEN_THIS_WOULD_NEED : & ' static str = "rustc_then_this_would_need" ;
64- const ID : & ' static str = "id" ;
6565
6666pub fn assert_dep_graph < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
6767 let _ignore = tcx. dep_graph . in_ignore ( ) ;
@@ -80,8 +80,9 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
8080 // Find annotations supplied by user (if any).
8181 let ( if_this_changed, then_this_would_need) = {
8282 let mut visitor = IfThisChanged { tcx : tcx,
83- if_this_changed : FnvHashMap ( ) ,
84- then_this_would_need : FnvHashMap ( ) } ;
83+ if_this_changed : vec ! [ ] ,
84+ then_this_would_need : vec ! [ ] } ;
85+ visitor. process_attrs ( ast:: CRATE_NODE_ID , & tcx. map . krate ( ) . attrs ) ;
8586 tcx. map . krate ( ) . visit_all_items ( & mut visitor) ;
8687 ( visitor. if_this_changed , visitor. then_this_would_need )
8788 } ;
@@ -97,58 +98,51 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
9798 check_paths ( tcx, & if_this_changed, & then_this_would_need) ;
9899}
99100
100- type SourceHashMap =
101- FnvHashMap < InternedString ,
102- FnvHashSet < ( Span , DefId , DepNode < DefId > ) > > ;
103- type TargetHashMap =
104- FnvHashMap < InternedString ,
105- FnvHashSet < ( Span , InternedString , ast:: NodeId , DepNode < DefId > ) > > ;
101+ type Sources = Vec < ( Span , DefId , DepNode < DefId > ) > ;
102+ type Targets = Vec < ( Span , InternedString , ast:: NodeId , DepNode < DefId > ) > ;
106103
107104struct IfThisChanged < ' a , ' tcx : ' a > {
108105 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
109- if_this_changed : SourceHashMap ,
110- then_this_would_need : TargetHashMap ,
106+ if_this_changed : Sources ,
107+ then_this_would_need : Targets ,
111108}
112109
113110impl < ' a , ' tcx > IfThisChanged < ' a , ' tcx > {
114- fn process_attrs ( & mut self , node_id : ast:: NodeId , def_id : DefId ) {
115- for attr in self . tcx . get_attrs ( def_id) . iter ( ) {
111+ fn argument ( & self , attr : & ast:: Attribute ) -> Option < InternedString > {
112+ let mut value = None ;
113+ for list_item in attr. meta_item_list ( ) . unwrap_or_default ( ) {
114+ match list_item. word ( ) {
115+ Some ( word) if value. is_none ( ) =>
116+ value = Some ( word. name ( ) . clone ( ) ) ,
117+ _ =>
118+ // FIXME better-encapsulate meta_item (don't directly access `node`)
119+ span_bug ! ( list_item. span( ) , "unexpected meta-item {:?}" , list_item. node) ,
120+ }
121+ }
122+ value
123+ }
124+
125+ fn process_attrs ( & mut self , node_id : ast:: NodeId , attrs : & [ ast:: Attribute ] ) {
126+ let def_id = self . tcx . map . local_def_id ( node_id) ;
127+ for attr in attrs {
116128 if attr. check_name ( IF_THIS_CHANGED ) {
117- let mut id = None ;
118- for list_item in attr. meta_item_list ( ) . unwrap_or_default ( ) {
119- match list_item. word ( ) {
120- Some ( word) if id. is_none ( ) => {
121- id = Some ( word. name ( ) . clone ( ) )
122- } ,
123- _ => {
124- // FIXME better-encapsulate meta_item (don't directly access `node`)
125- span_bug ! ( list_item. span( ) , "unexpected list-item {:?}" , list_item. node)
129+ let dep_node_interned = self . argument ( attr) ;
130+ let dep_node = match dep_node_interned {
131+ None => DepNode :: Hir ( def_id) ,
132+ Some ( ref n) => {
133+ match DepNode :: from_label_string ( & n[ ..] , def_id) {
134+ Ok ( n) => n,
135+ Err ( ( ) ) => {
136+ self . tcx . sess . span_fatal (
137+ attr. span ,
138+ & format ! ( "unrecognized DepNode variant {:?}" , n) ) ;
139+ }
126140 }
127141 }
128- }
129-
130- let id = id. unwrap_or ( InternedString :: new ( ID ) ) ;
131- self . if_this_changed . entry ( id)
132- . or_insert ( FnvHashSet ( ) )
133- . insert ( ( attr. span , def_id, DepNode :: Hir ( def_id) ) ) ;
142+ } ;
143+ self . if_this_changed . push ( ( attr. span , def_id, dep_node) ) ;
134144 } else if attr. check_name ( THEN_THIS_WOULD_NEED ) {
135- let mut dep_node_interned = None ;
136- let mut id = None ;
137- for list_item in attr. meta_item_list ( ) . unwrap_or_default ( ) {
138- match list_item. word ( ) {
139- Some ( word) if dep_node_interned. is_none ( ) => {
140- dep_node_interned = Some ( word. name ( ) . clone ( ) ) ;
141- } ,
142- Some ( word) if id. is_none ( ) => {
143- id = Some ( word. name ( ) . clone ( ) )
144- } ,
145- _ => {
146- // FIXME better-encapsulate meta_item (don't directly access `node`)
147- span_bug ! ( list_item. span( ) , "unexpected meta-item {:?}" , list_item. node)
148- }
149- }
150- }
151-
145+ let dep_node_interned = self . argument ( attr) ;
152146 let dep_node = match dep_node_interned {
153147 Some ( ref n) => {
154148 match DepNode :: from_label_string ( & n[ ..] , def_id) {
@@ -166,59 +160,49 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
166160 & format ! ( "missing DepNode variant" ) ) ;
167161 }
168162 } ;
169- let id = id. unwrap_or ( InternedString :: new ( ID ) ) ;
170- self . then_this_would_need
171- . entry ( id)
172- . or_insert ( FnvHashSet ( ) )
173- . insert ( ( attr. span , dep_node_interned. clone ( ) . unwrap ( ) , node_id, dep_node) ) ;
163+ self . then_this_would_need . push ( ( attr. span ,
164+ dep_node_interned. clone ( ) . unwrap ( ) ,
165+ node_id,
166+ dep_node) ) ;
174167 }
175168 }
176169 }
177170}
178171
179172impl < ' a , ' tcx > Visitor < ' tcx > for IfThisChanged < ' a , ' tcx > {
180173 fn visit_item ( & mut self , item : & ' tcx hir:: Item ) {
181- let def_id = self . tcx . map . local_def_id ( item. id ) ;
182- self . process_attrs ( item. id , def_id) ;
174+ self . process_attrs ( item. id , & item. attrs ) ;
183175 }
184176}
185177
186178fn check_paths < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
187- if_this_changed : & SourceHashMap ,
188- then_this_would_need : & TargetHashMap )
179+ if_this_changed : & Sources ,
180+ then_this_would_need : & Targets )
189181{
190182 // Return early here so as not to construct the query, which is not cheap.
191183 if if_this_changed. is_empty ( ) {
184+ for & ( target_span, _, _, _) in then_this_would_need {
185+ tcx. sess . span_err (
186+ target_span,
187+ & format ! ( "no #[rustc_if_this_changed] annotation detected" ) ) ;
188+
189+ }
192190 return ;
193191 }
194192 let query = tcx. dep_graph . query ( ) ;
195- for ( id, sources) in if_this_changed {
196- let targets = match then_this_would_need. get ( id) {
197- Some ( targets) => targets,
198- None => {
199- for & ( source_span, ..) in sources. iter ( ) . take ( 1 ) {
200- tcx. sess . span_err (
201- source_span,
202- & format ! ( "no targets for id `{}`" , id) ) ;
203- }
204- continue ;
205- }
206- } ;
207-
208- for & ( _, source_def_id, ref source_dep_node) in sources {
209- let dependents = query. transitive_successors ( source_dep_node) ;
210- for & ( target_span, ref target_pass, _, ref target_dep_node) in targets {
211- if !dependents. contains ( & target_dep_node) {
212- tcx. sess . span_err (
213- target_span,
214- & format ! ( "no path from `{}` to `{}`" ,
215- tcx. item_path_str( source_def_id) ,
216- target_pass) ) ;
217- } else {
218- tcx. sess . span_err (
219- target_span,
220- & format ! ( "OK" ) ) ;
221- }
193+ for & ( _, source_def_id, ref source_dep_node) in if_this_changed {
194+ let dependents = query. transitive_successors ( source_dep_node) ;
195+ for & ( target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need {
196+ if !dependents. contains ( & target_dep_node) {
197+ tcx. sess . span_err (
198+ target_span,
199+ & format ! ( "no path from `{}` to `{}`" ,
200+ tcx. item_path_str( source_def_id) ,
201+ target_pass) ) ;
202+ } else {
203+ tcx. sess . span_err (
204+ target_span,
205+ & format ! ( "OK" ) ) ;
222206 }
223207 }
224208 }
0 commit comments