@@ -15,7 +15,7 @@ use rustc::dep_graph::DepNode;
15
15
use rustc:: hir:: map as ast_map;
16
16
use rustc:: session:: { CompileResult , Session } ;
17
17
use rustc:: hir:: def:: { Def , CtorKind , DefMap } ;
18
- use rustc:: util:: nodemap:: NodeMap ;
18
+ use rustc:: util:: nodemap:: { NodeMap , NodeSet } ;
19
19
20
20
use syntax:: ast;
21
21
use syntax:: feature_gate:: { GateIssue , emit_feature_err} ;
@@ -34,6 +34,7 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
34
34
// each one. If the variant uses the default values (starting from `0`),
35
35
// then `None` is stored.
36
36
discriminant_map : RefCell < NodeMap < Option < & ' ast hir:: Expr > > > ,
37
+ detected_recursive_ids : NodeSet ,
37
38
}
38
39
39
40
impl < ' a , ' ast : ' a > Visitor < ' ast > for CheckCrateVisitor < ' a , ' ast > {
@@ -98,38 +99,43 @@ pub fn check_crate<'ast>(sess: &Session,
98
99
def_map : def_map,
99
100
ast_map : ast_map,
100
101
discriminant_map : RefCell :: new ( NodeMap ( ) ) ,
102
+ detected_recursive_ids : NodeSet ( ) ,
101
103
} ;
102
104
sess. track_errors ( || {
103
105
ast_map. krate ( ) . visit_all_items ( & mut visitor) ;
104
106
} )
105
107
}
106
108
107
- struct CheckItemRecursionVisitor < ' a , ' ast : ' a > {
108
- root_span : & ' a Span ,
109
- sess : & ' a Session ,
110
- ast_map : & ' a ast_map:: Map < ' ast > ,
111
- def_map : & ' a DefMap ,
109
+ struct CheckItemRecursionVisitor < ' a , ' b : ' a , ' ast : ' b > {
110
+ root_span : & ' b Span ,
111
+ sess : & ' b Session ,
112
+ ast_map : & ' b ast_map:: Map < ' ast > ,
113
+ def_map : & ' b DefMap ,
112
114
discriminant_map : & ' a RefCell < NodeMap < Option < & ' ast hir:: Expr > > > ,
113
115
idstack : Vec < ast:: NodeId > ,
116
+ detected_recursive_ids : & ' a mut NodeSet ,
114
117
}
115
118
116
- impl < ' a , ' ast : ' a > CheckItemRecursionVisitor < ' a , ' ast > {
117
- fn new ( v : & ' a CheckCrateVisitor < ' a , ' ast > ,
118
- span : & ' a Span )
119
- -> CheckItemRecursionVisitor < ' a , ' ast > {
119
+ impl < ' a , ' b : ' a , ' ast : ' b > CheckItemRecursionVisitor < ' a , ' b , ' ast > {
120
+ fn new ( v : & ' a mut CheckCrateVisitor < ' b , ' ast > , span : & ' b Span ) -> Self {
120
121
CheckItemRecursionVisitor {
121
122
root_span : span,
122
123
sess : v. sess ,
123
124
ast_map : v. ast_map ,
124
125
def_map : v. def_map ,
125
126
discriminant_map : & v. discriminant_map ,
126
127
idstack : Vec :: new ( ) ,
128
+ detected_recursive_ids : & mut v. detected_recursive_ids ,
127
129
}
128
130
}
129
131
fn with_item_id_pushed < F > ( & mut self , id : ast:: NodeId , f : F , span : Span )
130
132
where F : Fn ( & mut Self )
131
133
{
132
134
if self . idstack . iter ( ) . any ( |& x| x == id) {
135
+ if self . detected_recursive_ids . contains ( & id) {
136
+ return ;
137
+ }
138
+ self . detected_recursive_ids . insert ( id) ;
133
139
let any_static = self . idstack . iter ( ) . any ( |& x| {
134
140
if let ast_map:: NodeItem ( item) = self . ast_map . get ( x) {
135
141
if let hir:: ItemStatic ( ..) = item. node {
@@ -156,6 +162,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
156
162
}
157
163
return ;
158
164
}
165
+
159
166
self . idstack . push ( id) ;
160
167
f ( self ) ;
161
168
self . idstack . pop ( ) ;
@@ -201,9 +208,51 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
201
208
discriminant_map. insert ( * id, None ) ;
202
209
}
203
210
}
211
+
212
+ fn process_def ( & mut self , id : ast:: NodeId , span : Span ) {
213
+ match self . def_map . get ( & id) . map ( |d| d. base_def ) {
214
+ Some ( Def :: Static ( def_id, _) ) |
215
+ Some ( Def :: AssociatedConst ( def_id) ) |
216
+ Some ( Def :: Const ( def_id) ) => {
217
+ if let Some ( node_id) = self . ast_map . as_local_node_id ( def_id) {
218
+ match self . ast_map . get ( node_id) {
219
+ ast_map:: NodeItem ( item) => self . visit_item ( item) ,
220
+ ast_map:: NodeTraitItem ( item) => self . visit_trait_item ( item) ,
221
+ ast_map:: NodeImplItem ( item) => self . visit_impl_item ( item) ,
222
+ ast_map:: NodeForeignItem ( _) => { }
223
+ _ => {
224
+ span_bug ! ( span,
225
+ "expected item, found {}" ,
226
+ self . ast_map. node_to_string( node_id) ) ;
227
+ }
228
+ }
229
+ }
230
+ }
231
+ // For variants, we only want to check expressions that
232
+ // affect the specific variant used, but we need to check
233
+ // the whole enum definition to see what expression that
234
+ // might be (if any).
235
+ Some ( Def :: VariantCtor ( variant_id, CtorKind :: Const ) ) => {
236
+ if let Some ( variant_id) = self . ast_map . as_local_node_id ( variant_id) {
237
+ let variant = self . ast_map . expect_variant ( variant_id) ;
238
+ let enum_id = self . ast_map . get_parent ( variant_id) ;
239
+ let enum_item = self . ast_map . expect_item ( enum_id) ;
240
+ if let hir:: ItemEnum ( ref enum_def, ref generics) = enum_item. node {
241
+ self . populate_enum_discriminants ( enum_def) ;
242
+ self . visit_variant ( variant, generics, enum_id) ;
243
+ } else {
244
+ span_bug ! ( span,
245
+ "`check_static_recursion` found \
246
+ non-enum in Def::VariantCtor") ;
247
+ }
248
+ }
249
+ }
250
+ _ => ( ) ,
251
+ }
252
+ }
204
253
}
205
254
206
- impl < ' a , ' ast : ' a > Visitor < ' ast > for CheckItemRecursionVisitor < ' a , ' ast > {
255
+ impl < ' a , ' b : ' a , ' ast : ' b > Visitor < ' ast > for CheckItemRecursionVisitor < ' a , ' b , ' ast > {
207
256
fn visit_item ( & mut self , it : & ' ast hir:: Item ) {
208
257
self . with_item_id_pushed ( it. id , |v| intravisit:: walk_item ( v, it) , it. span ) ;
209
258
}
@@ -249,49 +298,14 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
249
298
250
299
fn visit_expr ( & mut self , e : & ' ast hir:: Expr ) {
251
300
match e. node {
252
- hir:: ExprPath ( ..) => {
253
- match self . def_map . get ( & e. id ) . map ( |d| d. base_def ) {
254
- Some ( Def :: Static ( def_id, _) ) |
255
- Some ( Def :: AssociatedConst ( def_id) ) |
256
- Some ( Def :: Const ( def_id) ) => {
257
- if let Some ( node_id) = self . ast_map . as_local_node_id ( def_id) {
258
- match self . ast_map . get ( node_id) {
259
- ast_map:: NodeItem ( item) => self . visit_item ( item) ,
260
- ast_map:: NodeTraitItem ( item) => self . visit_trait_item ( item) ,
261
- ast_map:: NodeImplItem ( item) => self . visit_impl_item ( item) ,
262
- ast_map:: NodeForeignItem ( _) => { }
263
- _ => {
264
- span_bug ! ( e. span,
265
- "expected item, found {}" ,
266
- self . ast_map. node_to_string( node_id) ) ;
267
- }
268
- }
269
- }
270
- }
271
- // For variants, we only want to check expressions that
272
- // affect the specific variant used, but we need to check
273
- // the whole enum definition to see what expression that
274
- // might be (if any).
275
- Some ( Def :: VariantCtor ( variant_id, CtorKind :: Const ) ) => {
276
- if let Some ( variant_id) = self . ast_map . as_local_node_id ( variant_id) {
277
- let variant = self . ast_map . expect_variant ( variant_id) ;
278
- let enum_id = self . ast_map . get_parent ( variant_id) ;
279
- let enum_item = self . ast_map . expect_item ( enum_id) ;
280
- if let hir:: ItemEnum ( ref enum_def, ref generics) = enum_item. node {
281
- self . populate_enum_discriminants ( enum_def) ;
282
- self . visit_variant ( variant, generics, enum_id) ;
283
- } else {
284
- span_bug ! ( e. span,
285
- "`check_static_recursion` found \
286
- non-enum in Def::VariantCtor") ;
287
- }
288
- }
289
- }
290
- _ => ( ) ,
291
- }
292
- }
301
+ hir:: ExprPath ( ..) => self . process_def ( e. id , e. span ) ,
293
302
_ => ( ) ,
294
303
}
295
304
intravisit:: walk_expr ( self , e) ;
296
305
}
306
+
307
+ fn visit_path ( & mut self , path : & ' ast hir:: Path , id : ast:: NodeId ) {
308
+ self . process_def ( id, path. span ) ;
309
+ intravisit:: walk_path ( self , path) ;
310
+ }
297
311
}
0 commit comments