@@ -15,24 +15,23 @@ 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 } ;
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} ;
22
22
use syntax_pos:: Span ;
23
23
use rustc:: hir:: intravisit:: { self , Visitor , NestedVisitorMap } ;
24
24
use rustc:: hir;
25
25
26
- use std:: cell:: RefCell ;
27
-
28
26
struct CheckCrateVisitor < ' a , ' ast : ' a > {
29
27
sess : & ' a Session ,
30
28
ast_map : & ' a ast_map:: Map < ' ast > ,
31
29
// `discriminant_map` is a cache that associates the `NodeId`s of local
32
30
// variant definitions with the discriminant expression that applies to
33
31
// each one. If the variant uses the default values (starting from `0`),
34
32
// then `None` is stored.
35
- discriminant_map : RefCell < NodeMap < Option < & ' ast hir:: Expr > > > ,
33
+ discriminant_map : NodeMap < Option < & ' ast hir:: Expr > > ,
34
+ detected_recursive_ids : NodeSet ,
36
35
}
37
36
38
37
impl < ' a , ' ast : ' a > Visitor < ' ast > for CheckCrateVisitor < ' a , ' ast > {
@@ -90,46 +89,49 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
90
89
}
91
90
}
92
91
93
- pub fn check_crate < ' ast > ( sess : & Session ,
94
- ast_map : & ast_map:: Map < ' ast > )
95
- -> CompileResult {
92
+ pub fn check_crate < ' ast > ( sess : & Session , ast_map : & ast_map:: Map < ' ast > ) -> CompileResult {
96
93
let _task = ast_map. dep_graph . in_task ( DepNode :: CheckStaticRecursion ) ;
97
94
98
95
let mut visitor = CheckCrateVisitor {
99
96
sess : sess,
100
97
ast_map : ast_map,
101
- discriminant_map : RefCell :: new ( NodeMap ( ) ) ,
98
+ discriminant_map : NodeMap ( ) ,
99
+ detected_recursive_ids : NodeSet ( ) ,
102
100
} ;
103
101
sess. track_errors ( || {
104
102
// FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
105
103
ast_map. krate ( ) . visit_all_item_likes ( & mut visitor. as_deep_visitor ( ) ) ;
106
104
} )
107
105
}
108
106
109
- struct CheckItemRecursionVisitor < ' a , ' ast : ' a > {
110
- root_span : & ' a Span ,
111
- sess : & ' a Session ,
112
- ast_map : & ' a ast_map:: Map < ' ast > ,
113
- discriminant_map : & ' a RefCell < NodeMap < Option < & ' ast hir:: Expr > > > ,
107
+ struct CheckItemRecursionVisitor < ' a , ' b : ' a , ' ast : ' b > {
108
+ root_span : & ' b Span ,
109
+ sess : & ' b Session ,
110
+ ast_map : & ' b ast_map:: Map < ' ast > ,
111
+ discriminant_map : & ' a mut NodeMap < Option < & ' ast hir:: Expr > > ,
114
112
idstack : Vec < ast:: NodeId > ,
113
+ detected_recursive_ids : & ' a mut NodeSet ,
115
114
}
116
115
117
- impl < ' a , ' ast : ' a > CheckItemRecursionVisitor < ' a , ' ast > {
118
- fn new ( v : & ' a CheckCrateVisitor < ' a , ' ast > ,
119
- span : & ' a Span )
120
- -> CheckItemRecursionVisitor < ' a , ' ast > {
116
+ impl < ' a , ' b : ' a , ' ast : ' b > CheckItemRecursionVisitor < ' a , ' b , ' ast > {
117
+ fn new ( v : & ' a mut CheckCrateVisitor < ' b , ' ast > , span : & ' b Span ) -> Self {
121
118
CheckItemRecursionVisitor {
122
119
root_span : span,
123
120
sess : v. sess ,
124
121
ast_map : v. ast_map ,
125
- discriminant_map : & v. discriminant_map ,
122
+ discriminant_map : & mut v. discriminant_map ,
126
123
idstack : Vec :: new ( ) ,
124
+ detected_recursive_ids : & mut v. detected_recursive_ids ,
127
125
}
128
126
}
129
127
fn with_item_id_pushed < F > ( & mut self , id : ast:: NodeId , f : F , span : Span )
130
128
where F : Fn ( & mut Self )
131
129
{
132
130
if self . idstack . iter ( ) . any ( |& x| x == id) {
131
+ if self . detected_recursive_ids . contains ( & id) {
132
+ return ;
133
+ }
134
+ self . detected_recursive_ids . insert ( id) ;
133
135
let any_static = self . idstack . iter ( ) . any ( |& x| {
134
136
if let ast_map:: NodeItem ( item) = self . ast_map . get ( x) {
135
137
if let hir:: ItemStatic ( ..) = item. node {
@@ -168,15 +170,14 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
168
170
// So for every variant, we need to track whether there is an expression
169
171
// somewhere in the enum definition that controls its discriminant. We do
170
172
// this by starting from the end and searching backward.
171
- fn populate_enum_discriminants ( & self , enum_definition : & ' ast hir:: EnumDef ) {
173
+ fn populate_enum_discriminants ( & mut self , enum_definition : & ' ast hir:: EnumDef ) {
172
174
// Get the map, and return if we already processed this enum or if it
173
175
// has no variants.
174
- let mut discriminant_map = self . discriminant_map . borrow_mut ( ) ;
175
176
match enum_definition. variants . first ( ) {
176
177
None => {
177
178
return ;
178
179
}
179
- Some ( variant) if discriminant_map. contains_key ( & variant. node . data . id ( ) ) => {
180
+ Some ( variant) if self . discriminant_map . contains_key ( & variant. node . data . id ( ) ) => {
180
181
return ;
181
182
}
182
183
_ => { }
@@ -190,24 +191,23 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
190
191
// is affected by that expression.
191
192
if let Some ( ref expr) = variant. node . disr_expr {
192
193
for id in & variant_stack {
193
- discriminant_map. insert ( * id, Some ( expr) ) ;
194
+ self . discriminant_map . insert ( * id, Some ( expr) ) ;
194
195
}
195
196
variant_stack. clear ( )
196
197
}
197
198
}
198
199
// If we are at the top, that always starts at 0, so any variant on the
199
200
// stack has a default value and does not need to be checked.
200
201
for id in & variant_stack {
201
- discriminant_map. insert ( * id, None ) ;
202
+ self . discriminant_map . insert ( * id, None ) ;
202
203
}
203
204
}
204
205
}
205
206
206
- impl < ' a , ' ast : ' a > Visitor < ' ast > for CheckItemRecursionVisitor < ' a , ' ast > {
207
+ impl < ' a , ' b : ' a , ' ast : ' b > Visitor < ' ast > for CheckItemRecursionVisitor < ' a , ' b , ' ast > {
207
208
fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' ast > {
208
209
NestedVisitorMap :: OnlyBodies ( & self . ast_map )
209
210
}
210
-
211
211
fn visit_item ( & mut self , it : & ' ast hir:: Item ) {
212
212
self . with_item_id_pushed ( it. id , |v| intravisit:: walk_item ( v, it) , it. span ) ;
213
213
}
@@ -227,7 +227,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
227
227
_: ast:: NodeId ) {
228
228
let variant_id = variant. node . data . id ( ) ;
229
229
let maybe_expr;
230
- if let Some ( get_expr) = self . discriminant_map . borrow ( ) . get ( & variant_id) {
230
+ if let Some ( get_expr) = self . discriminant_map . get ( & variant_id) {
231
231
// This is necessary because we need to let the `discriminant_map`
232
232
// borrow fall out of scope, so that we can reborrow farther down.
233
233
maybe_expr = ( * get_expr) . clone ( ) ;
@@ -251,51 +251,46 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
251
251
self . with_item_id_pushed ( ii. id , |v| intravisit:: walk_impl_item ( v, ii) , ii. span ) ;
252
252
}
253
253
254
- fn visit_expr ( & mut self , e : & ' ast hir:: Expr ) {
255
- match e. node {
256
- hir:: ExprPath ( hir:: QPath :: Resolved ( _, ref path) ) => {
257
- match path. def {
258
- Def :: Static ( def_id, _) |
259
- Def :: AssociatedConst ( def_id) |
260
- Def :: Const ( def_id) => {
261
- if let Some ( node_id) = self . ast_map . as_local_node_id ( def_id) {
262
- match self . ast_map . get ( node_id) {
263
- ast_map:: NodeItem ( item) => self . visit_item ( item) ,
264
- ast_map:: NodeTraitItem ( item) => self . visit_trait_item ( item) ,
265
- ast_map:: NodeImplItem ( item) => self . visit_impl_item ( item) ,
266
- ast_map:: NodeForeignItem ( _) => { }
267
- _ => {
268
- span_bug ! ( e. span,
269
- "expected item, found {}" ,
270
- self . ast_map. node_to_string( node_id) ) ;
271
- }
272
- }
254
+ fn visit_path ( & mut self , path : & ' ast hir:: Path , _: ast:: NodeId ) {
255
+ match path. def {
256
+ Def :: Static ( def_id, _) |
257
+ Def :: AssociatedConst ( def_id) |
258
+ Def :: Const ( def_id) => {
259
+ if let Some ( node_id) = self . ast_map . as_local_node_id ( def_id) {
260
+ match self . ast_map . get ( node_id) {
261
+ ast_map:: NodeItem ( item) => self . visit_item ( item) ,
262
+ ast_map:: NodeTraitItem ( item) => self . visit_trait_item ( item) ,
263
+ ast_map:: NodeImplItem ( item) => self . visit_impl_item ( item) ,
264
+ ast_map:: NodeForeignItem ( _) => { }
265
+ _ => {
266
+ span_bug ! ( path. span,
267
+ "expected item, found {}" ,
268
+ self . ast_map. node_to_string( node_id) ) ;
273
269
}
274
270
}
275
- // For variants, we only want to check expressions that
276
- // affect the specific variant used, but we need to check
277
- // the whole enum definition to see what expression that
278
- // might be (if any).
279
- Def :: VariantCtor ( variant_id , CtorKind :: Const ) => {
280
- if let Some ( variant_id ) = self . ast_map . as_local_node_id ( variant_id ) {
281
- let variant = self . ast_map . expect_variant ( variant_id ) ;
282
- let enum_id = self . ast_map . get_parent ( variant_id) ;
283
- let enum_item = self . ast_map . expect_item ( enum_id ) ;
284
- if let hir :: ItemEnum ( ref enum_def , ref generics ) = enum_item . node {
285
- self . populate_enum_discriminants ( enum_def ) ;
286
- self . visit_variant ( variant , generics , enum_id ) ;
287
- } else {
288
- span_bug ! ( e . span ,
289
- "`check_static_recursion` found \
290
- non-enum in Def::VariantCtor" ) ;
291
- }
292
- }
271
+ }
272
+ }
273
+ // For variants, we only want to check expressions that
274
+ // affect the specific variant used, but we need to check
275
+ // the whole enum definition to see what expression that
276
+ // might be ( if any).
277
+ Def :: VariantCtor ( variant_id , CtorKind :: Const ) => {
278
+ if let Some ( variant_id ) = self . ast_map . as_local_node_id ( variant_id) {
279
+ let variant = self . ast_map . expect_variant ( variant_id ) ;
280
+ let enum_id = self . ast_map . get_parent ( variant_id ) ;
281
+ let enum_item = self . ast_map . expect_item ( enum_id ) ;
282
+ if let hir :: ItemEnum ( ref enum_def , ref generics ) = enum_item . node {
283
+ self . populate_enum_discriminants ( enum_def ) ;
284
+ self . visit_variant ( variant , generics , enum_id ) ;
285
+ } else {
286
+ span_bug ! ( path . span ,
287
+ "`check_static_recursion` found \
288
+ non-enum in Def::VariantCtor" ) ;
293
289
}
294
- _ => ( ) ,
295
290
}
296
291
}
297
292
_ => ( ) ,
298
293
}
299
- intravisit:: walk_expr ( self , e ) ;
294
+ intravisit:: walk_path ( self , path ) ;
300
295
}
301
296
}
0 commit comments