@@ -15,24 +15,23 @@ use rustc::dep_graph::DepNode;
1515use rustc:: hir:: map as ast_map;
1616use rustc:: session:: { CompileResult , Session } ;
1717use rustc:: hir:: def:: { Def , CtorKind } ;
18- use rustc:: util:: nodemap:: NodeMap ;
18+ use rustc:: util:: nodemap:: { NodeMap , NodeSet } ;
1919
2020use syntax:: ast;
2121use syntax:: feature_gate:: { GateIssue , emit_feature_err} ;
2222use syntax_pos:: Span ;
2323use rustc:: hir:: intravisit:: { self , Visitor , NestedVisitorMap } ;
2424use rustc:: hir;
2525
26- use std:: cell:: RefCell ;
27-
2826struct CheckCrateVisitor < ' a , ' ast : ' a > {
2927 sess : & ' a Session ,
3028 ast_map : & ' a ast_map:: Map < ' ast > ,
3129 // `discriminant_map` is a cache that associates the `NodeId`s of local
3230 // variant definitions with the discriminant expression that applies to
3331 // each one. If the variant uses the default values (starting from `0`),
3432 // 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 ,
3635}
3736
3837impl < ' a , ' ast : ' a > Visitor < ' ast > for CheckCrateVisitor < ' a , ' ast > {
@@ -90,46 +89,49 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
9089 }
9190}
9291
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 {
9693 let _task = ast_map. dep_graph . in_task ( DepNode :: CheckStaticRecursion ) ;
9794
9895 let mut visitor = CheckCrateVisitor {
9996 sess : sess,
10097 ast_map : ast_map,
101- discriminant_map : RefCell :: new ( NodeMap ( ) ) ,
98+ discriminant_map : NodeMap ( ) ,
99+ detected_recursive_ids : NodeSet ( ) ,
102100 } ;
103101 sess. track_errors ( || {
104102 // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
105103 ast_map. krate ( ) . visit_all_item_likes ( & mut visitor. as_deep_visitor ( ) ) ;
106104 } )
107105}
108106
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 > > ,
114112 idstack : Vec < ast:: NodeId > ,
113+ detected_recursive_ids : & ' a mut NodeSet ,
115114}
116115
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 {
121118 CheckItemRecursionVisitor {
122119 root_span : span,
123120 sess : v. sess ,
124121 ast_map : v. ast_map ,
125- discriminant_map : & v. discriminant_map ,
122+ discriminant_map : & mut v. discriminant_map ,
126123 idstack : Vec :: new ( ) ,
124+ detected_recursive_ids : & mut v. detected_recursive_ids ,
127125 }
128126 }
129127 fn with_item_id_pushed < F > ( & mut self , id : ast:: NodeId , f : F , span : Span )
130128 where F : Fn ( & mut Self )
131129 {
132130 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) ;
133135 let any_static = self . idstack . iter ( ) . any ( |& x| {
134136 if let ast_map:: NodeItem ( item) = self . ast_map . get ( x) {
135137 if let hir:: ItemStatic ( ..) = item. node {
@@ -168,15 +170,14 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
168170 // So for every variant, we need to track whether there is an expression
169171 // somewhere in the enum definition that controls its discriminant. We do
170172 // 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 ) {
172174 // Get the map, and return if we already processed this enum or if it
173175 // has no variants.
174- let mut discriminant_map = self . discriminant_map . borrow_mut ( ) ;
175176 match enum_definition. variants . first ( ) {
176177 None => {
177178 return ;
178179 }
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 ( ) ) => {
180181 return ;
181182 }
182183 _ => { }
@@ -190,24 +191,23 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
190191 // is affected by that expression.
191192 if let Some ( ref expr) = variant. node . disr_expr {
192193 for id in & variant_stack {
193- discriminant_map. insert ( * id, Some ( expr) ) ;
194+ self . discriminant_map . insert ( * id, Some ( expr) ) ;
194195 }
195196 variant_stack. clear ( )
196197 }
197198 }
198199 // If we are at the top, that always starts at 0, so any variant on the
199200 // stack has a default value and does not need to be checked.
200201 for id in & variant_stack {
201- discriminant_map. insert ( * id, None ) ;
202+ self . discriminant_map . insert ( * id, None ) ;
202203 }
203204 }
204205}
205206
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 > {
207208 fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' ast > {
208209 NestedVisitorMap :: OnlyBodies ( & self . ast_map )
209210 }
210-
211211 fn visit_item ( & mut self , it : & ' ast hir:: Item ) {
212212 self . with_item_id_pushed ( it. id , |v| intravisit:: walk_item ( v, it) , it. span ) ;
213213 }
@@ -227,7 +227,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
227227 _: ast:: NodeId ) {
228228 let variant_id = variant. node . data . id ( ) ;
229229 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) {
231231 // This is necessary because we need to let the `discriminant_map`
232232 // borrow fall out of scope, so that we can reborrow farther down.
233233 maybe_expr = ( * get_expr) . clone ( ) ;
@@ -251,51 +251,46 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
251251 self . with_item_id_pushed ( ii. id , |v| intravisit:: walk_impl_item ( v, ii) , ii. span ) ;
252252 }
253253
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) ) ;
273269 }
274270 }
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" ) ;
293289 }
294- _ => ( ) ,
295290 }
296291 }
297292 _ => ( ) ,
298293 }
299- intravisit:: walk_expr ( self , e ) ;
294+ intravisit:: walk_path ( self , path ) ;
300295 }
301296}
0 commit comments