24
24
//! Errors are reported if we are in the suitable configuration but
25
25
//! the required condition is not met.
26
26
27
+ use super :: directory:: RetracedDefIdDirectory ;
28
+ use super :: load:: DirtyNodes ;
27
29
use rustc:: dep_graph:: { DepGraphQuery , DepNode } ;
28
30
use rustc:: hir;
29
31
use rustc:: hir:: def_id:: DefId ;
30
32
use rustc:: hir:: intravisit:: Visitor ;
33
+ use rustc_data_structures:: fnv:: FnvHashSet ;
31
34
use syntax:: ast:: { self , Attribute , MetaItem } ;
32
35
use syntax:: attr:: AttrMetaMethods ;
33
36
use syntax:: parse:: token:: InternedString ;
@@ -38,19 +41,33 @@ const CLEAN: &'static str = "rustc_clean";
38
41
const LABEL : & ' static str = "label" ;
39
42
const CFG : & ' static str = "cfg" ;
40
43
41
- pub fn check_dirty_clean_annotations < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
44
+ pub fn check_dirty_clean_annotations < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
45
+ dirty_inputs : & DirtyNodes ,
46
+ retraced : & RetracedDefIdDirectory ) {
47
+ // can't add `#[rustc_dirty]` etc without opting in to this feature
48
+ if !tcx. sess . features . borrow ( ) . rustc_attrs {
49
+ return ;
50
+ }
51
+
42
52
let _ignore = tcx. dep_graph . in_ignore ( ) ;
53
+ let dirty_inputs: FnvHashSet < DepNode < DefId > > =
54
+ dirty_inputs. iter ( )
55
+ . filter_map ( |d| retraced. map ( d) )
56
+ . collect ( ) ;
43
57
let query = tcx. dep_graph . query ( ) ;
58
+ debug ! ( "query-nodes: {:?}" , query. nodes( ) ) ;
44
59
let krate = tcx. map . krate ( ) ;
45
60
krate. visit_all_items ( & mut DirtyCleanVisitor {
46
61
tcx : tcx,
47
62
query : & query,
63
+ dirty_inputs : dirty_inputs,
48
64
} ) ;
49
65
}
50
66
51
67
pub struct DirtyCleanVisitor < ' a , ' tcx : ' a > {
52
68
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
53
69
query : & ' a DepGraphQuery < DefId > ,
70
+ dirty_inputs : FnvHashSet < DepNode < DefId > > ,
54
71
}
55
72
56
73
impl < ' a , ' tcx > DirtyCleanVisitor < ' a , ' tcx > {
@@ -81,10 +98,13 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
81
98
return true ;
82
99
}
83
100
}
101
+ return false ;
84
102
}
85
103
}
86
- debug ! ( "check_config: no match found" ) ;
87
- return false ;
104
+
105
+ self . tcx . sess . span_fatal (
106
+ attr. span ,
107
+ & format ! ( "no cfg attribute" ) ) ;
88
108
}
89
109
90
110
fn dep_node ( & self , attr : & Attribute , def_id : DefId ) -> DepNode < DefId > {
@@ -105,29 +125,59 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
105
125
self . tcx . sess . span_fatal ( attr. span , "no `label` found" ) ;
106
126
}
107
127
108
- fn dep_node_str ( & self , dep_node : DepNode < DefId > ) -> DepNode < String > {
128
+ fn dep_node_str ( & self , dep_node : & DepNode < DefId > ) -> DepNode < String > {
109
129
dep_node. map_def ( |& def_id| Some ( self . tcx . item_path_str ( def_id) ) ) . unwrap ( )
110
130
}
111
131
112
132
fn assert_dirty ( & self , item : & hir:: Item , dep_node : DepNode < DefId > ) {
113
133
debug ! ( "assert_dirty({:?})" , dep_node) ;
114
134
115
- if self . query . contains_node ( & dep_node) {
116
- let dep_node_str = self . dep_node_str ( dep_node) ;
117
- self . tcx . sess . span_err (
118
- item. span ,
119
- & format ! ( "`{:?}` found in dep graph, but should be dirty" , dep_node_str) ) ;
135
+ match dep_node {
136
+ DepNode :: Hir ( _) => {
137
+ // HIR nodes are inputs, so if we are asserting that the HIR node is
138
+ // dirty, we check the dirty input set.
139
+ if !self . dirty_inputs . contains ( & dep_node) {
140
+ let dep_node_str = self . dep_node_str ( & dep_node) ;
141
+ self . tcx . sess . span_err (
142
+ item. span ,
143
+ & format ! ( "`{:?}` not found in dirty set, but should be dirty" , dep_node_str) ) ;
144
+ }
145
+ }
146
+ _ => {
147
+ // Other kinds of nodes would be targets, so check if
148
+ // the dep-graph contains the node.
149
+ if self . query . contains_node ( & dep_node) {
150
+ let dep_node_str = self . dep_node_str ( & dep_node) ;
151
+ self . tcx . sess . span_err (
152
+ item. span ,
153
+ & format ! ( "`{:?}` found in dep graph, but should be dirty" , dep_node_str) ) ;
154
+ }
155
+ }
120
156
}
121
157
}
122
158
123
159
fn assert_clean ( & self , item : & hir:: Item , dep_node : DepNode < DefId > ) {
124
160
debug ! ( "assert_clean({:?})" , dep_node) ;
125
161
126
- if !self . query . contains_node ( & dep_node) {
127
- let dep_node_str = self . dep_node_str ( dep_node) ;
128
- self . tcx . sess . span_err (
129
- item. span ,
130
- & format ! ( "`{:?}` not found in dep graph, but should be clean" , dep_node_str) ) ;
162
+ match dep_node {
163
+ DepNode :: Hir ( _) => {
164
+ // For HIR nodes, check the inputs.
165
+ if self . dirty_inputs . contains ( & dep_node) {
166
+ let dep_node_str = self . dep_node_str ( & dep_node) ;
167
+ self . tcx . sess . span_err (
168
+ item. span ,
169
+ & format ! ( "`{:?}` found in dirty-node set, but should be clean" , dep_node_str) ) ;
170
+ }
171
+ }
172
+ _ => {
173
+ // Otherwise, check if the dep-node exists.
174
+ if !self . query . contains_node ( & dep_node) {
175
+ let dep_node_str = self . dep_node_str ( & dep_node) ;
176
+ self . tcx . sess . span_err (
177
+ item. span ,
178
+ & format ! ( "`{:?}` not found in dep graph, but should be clean" , dep_node_str) ) ;
179
+ }
180
+ }
131
181
}
132
182
}
133
183
}
0 commit comments