26
26
//! used to check when paths exist or do not.
27
27
//!
28
28
//! 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.
31
32
//!
32
33
//! Example:
33
34
//!
34
35
//! ```
35
- //! #[rustc_if_this_changed]
36
+ //! #[rustc_if_this_changed(Hir) ]
36
37
//! fn foo() { }
37
38
//!
38
- //! #[rustc_then_this_would_need(" trans" )] //~ ERROR no path from `foo`
39
+ //! #[rustc_then_this_would_need(trans)] //~ ERROR no path from `foo`
39
40
//! fn bar() { }
40
41
//!
41
- //! #[rustc_then_this_would_need(" trans" )] //~ ERROR OK
42
+ //! #[rustc_then_this_would_need(trans)] //~ ERROR OK
42
43
//! fn baz() { foo(); }
43
44
//! ```
44
45
@@ -47,7 +48,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode};
47
48
use rustc:: dep_graph:: debug:: { DepNodeFilter , EdgeFilter } ;
48
49
use rustc:: hir:: def_id:: DefId ;
49
50
use rustc:: ty:: TyCtxt ;
50
- use rustc_data_structures:: fnv:: { FnvHashMap , FnvHashSet } ;
51
+ use rustc_data_structures:: fnv:: FnvHashSet ;
51
52
use rustc_data_structures:: graph:: { Direction , INCOMING , OUTGOING , NodeIndex } ;
52
53
use rustc:: hir;
53
54
use rustc:: hir:: intravisit:: Visitor ;
@@ -61,7 +62,6 @@ use syntax_pos::Span;
61
62
62
63
const IF_THIS_CHANGED : & ' static str = "rustc_if_this_changed" ;
63
64
const THEN_THIS_WOULD_NEED : & ' static str = "rustc_then_this_would_need" ;
64
- const ID : & ' static str = "id" ;
65
65
66
66
pub fn assert_dep_graph < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
67
67
let _ignore = tcx. dep_graph . in_ignore ( ) ;
@@ -80,8 +80,9 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
80
80
// Find annotations supplied by user (if any).
81
81
let ( if_this_changed, then_this_would_need) = {
82
82
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 ) ;
85
86
tcx. map . krate ( ) . visit_all_items ( & mut visitor) ;
86
87
( visitor. if_this_changed , visitor. then_this_would_need )
87
88
} ;
@@ -97,58 +98,51 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
97
98
check_paths ( tcx, & if_this_changed, & then_this_would_need) ;
98
99
}
99
100
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 > ) > ;
106
103
107
104
struct IfThisChanged < ' a , ' tcx : ' a > {
108
105
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 ,
111
108
}
112
109
113
110
impl < ' 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 {
116
128
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
+ }
126
140
}
127
141
}
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) ) ;
134
144
} 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) ;
152
146
let dep_node = match dep_node_interned {
153
147
Some ( ref n) => {
154
148
match DepNode :: from_label_string ( & n[ ..] , def_id) {
@@ -166,59 +160,49 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
166
160
& format ! ( "missing DepNode variant" ) ) ;
167
161
}
168
162
} ;
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) ) ;
174
167
}
175
168
}
176
169
}
177
170
}
178
171
179
172
impl < ' a , ' tcx > Visitor < ' tcx > for IfThisChanged < ' a , ' tcx > {
180
173
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 ) ;
183
175
}
184
176
}
185
177
186
178
fn 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 )
189
181
{
190
182
// Return early here so as not to construct the query, which is not cheap.
191
183
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
+ }
192
190
return ;
193
191
}
194
192
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" ) ) ;
222
206
}
223
207
}
224
208
}
0 commit comments