@@ -5,6 +5,7 @@ use rustc::hir::def_id::DefId;
55use rustc:: ty:: subst:: SubstsRef ;
66use rustc:: ty:: { self , Ty } ;
77use rustc_codegen_ssa:: traits:: * ;
8+ use rustc_data_structures:: fx:: FxHashSet ;
89
910use rustc:: hir;
1011
@@ -17,7 +18,8 @@ pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
1718 qualified : bool )
1819 -> String {
1920 let mut result = String :: with_capacity ( 64 ) ;
20- push_debuginfo_type_name ( cx, t, qualified, & mut result) ;
21+ let mut visited = FxHashSet :: default ( ) ;
22+ push_debuginfo_type_name ( cx, t, qualified, & mut result, & mut visited) ;
2123 result
2224}
2325
@@ -26,7 +28,9 @@ pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
2628pub fn push_debuginfo_type_name < ' a , ' tcx > ( cx : & CodegenCx < ' a , ' tcx > ,
2729 t : Ty < ' tcx > ,
2830 qualified : bool ,
29- output : & mut String ) {
31+ output : & mut String ,
32+ visited : & mut FxHashSet < Ty < ' tcx > > ) {
33+
3034 // When targeting MSVC, emit C++ style type names for compatibility with
3135 // .natvis visualizers (and perhaps other existing native debuggers?)
3236 let cpp_like_names = cx. sess ( ) . target . target . options . is_like_msvc ;
@@ -42,12 +46,12 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
4246 ty:: Foreign ( def_id) => push_item_name ( cx, def_id, qualified, output) ,
4347 ty:: Adt ( def, substs) => {
4448 push_item_name ( cx, def. did , qualified, output) ;
45- push_type_params ( cx, substs, output) ;
49+ push_type_params ( cx, substs, output, visited ) ;
4650 } ,
4751 ty:: Tuple ( component_types) => {
4852 output. push ( '(' ) ;
4953 for & component_type in component_types {
50- push_debuginfo_type_name ( cx, component_type, true , output) ;
54+ push_debuginfo_type_name ( cx, component_type, true , output, visited ) ;
5155 output. push_str ( ", " ) ;
5256 }
5357 if !component_types. is_empty ( ) {
@@ -65,7 +69,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
6569 hir:: MutMutable => output. push_str ( "mut " ) ,
6670 }
6771
68- push_debuginfo_type_name ( cx, inner_type, true , output) ;
72+ push_debuginfo_type_name ( cx, inner_type, true , output, visited ) ;
6973
7074 if cpp_like_names {
7175 output. push ( '*' ) ;
@@ -79,15 +83,15 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
7983 output. push_str ( "mut " ) ;
8084 }
8185
82- push_debuginfo_type_name ( cx, inner_type, true , output) ;
86+ push_debuginfo_type_name ( cx, inner_type, true , output, visited ) ;
8387
8488 if cpp_like_names {
8589 output. push ( '*' ) ;
8690 }
8791 } ,
8892 ty:: Array ( inner_type, len) => {
8993 output. push ( '[' ) ;
90- push_debuginfo_type_name ( cx, inner_type, true , output) ;
94+ push_debuginfo_type_name ( cx, inner_type, true , output, visited ) ;
9195 output. push_str ( & format ! ( "; {}" , len. unwrap_usize( cx. tcx) ) ) ;
9296 output. push ( ']' ) ;
9397 } ,
@@ -98,7 +102,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
98102 output. push ( '[' ) ;
99103 }
100104
101- push_debuginfo_type_name ( cx, inner_type, true , output) ;
105+ push_debuginfo_type_name ( cx, inner_type, true , output, visited ) ;
102106
103107 if cpp_like_names {
104108 output. push ( '>' ) ;
@@ -113,12 +117,31 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
113117 & principal,
114118 ) ;
115119 push_item_name ( cx, principal. def_id , false , output) ;
116- push_type_params ( cx, principal. substs , output) ;
120+ push_type_params ( cx, principal. substs , output, visited ) ;
117121 } else {
118122 output. push_str ( "dyn '_" ) ;
119123 }
120124 } ,
121125 ty:: FnDef ( ..) | ty:: FnPtr ( _) => {
126+ // We've encountered a weird 'recursive type'
127+ // Currently, the only way to generate such a type
128+ // is by using 'impl trait':
129+ //
130+ // fn foo() -> impl Copy { foo }
131+ //
132+ // There's not really a sensible name we can generate,
133+ // since we don't include 'impl trait' types (e.g. ty::Opaque)
134+ // in the output
135+ //
136+ // Since we need to generate *something*, we just
137+ // use a dummy string that should make it clear
138+ // that something unusual is going on
139+ if !visited. insert ( t) {
140+ output. push_str ( "<recursive_type>" ) ;
141+ return ;
142+ }
143+
144+
122145 let sig = t. fn_sig ( cx. tcx ) ;
123146 if sig. unsafety ( ) == hir:: Unsafety :: Unsafe {
124147 output. push_str ( "unsafe " ) ;
@@ -136,7 +159,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
136159 let sig = cx. tcx . normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , & sig) ;
137160 if !sig. inputs ( ) . is_empty ( ) {
138161 for & parameter_type in sig. inputs ( ) {
139- push_debuginfo_type_name ( cx, parameter_type, true , output) ;
162+ push_debuginfo_type_name ( cx, parameter_type, true , output, visited ) ;
140163 output. push_str ( ", " ) ;
141164 }
142165 output. pop ( ) ;
@@ -155,8 +178,20 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
155178
156179 if !sig. output ( ) . is_unit ( ) {
157180 output. push_str ( " -> " ) ;
158- push_debuginfo_type_name ( cx, sig. output ( ) , true , output) ;
181+ push_debuginfo_type_name ( cx, sig. output ( ) , true , output, visited ) ;
159182 }
183+
184+
185+ // We only keep the type in 'visited'
186+ // for the duration of the body of this method.
187+ // It's fine for a particular function type
188+ // to show up multiple times in one overall type
189+ // (e.g. MyType<fn() -> u8, fn() -> u8>
190+ //
191+ // We only care about avoiding recursing
192+ // directly back to the type we're currently
193+ // processing
194+ visited. remove ( t) ;
160195 } ,
161196 ty:: Closure ( ..) => {
162197 output. push_str ( "closure" ) ;
@@ -200,15 +235,16 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
200235 // common denominator - otherwise we would run into conflicts.
201236 fn push_type_params < ' a , ' tcx > ( cx : & CodegenCx < ' a , ' tcx > ,
202237 substs : SubstsRef < ' tcx > ,
203- output : & mut String ) {
238+ output : & mut String ,
239+ visited : & mut FxHashSet < Ty < ' tcx > > ) {
204240 if substs. types ( ) . next ( ) . is_none ( ) {
205241 return ;
206242 }
207243
208244 output. push ( '<' ) ;
209245
210246 for type_parameter in substs. types ( ) {
211- push_debuginfo_type_name ( cx, type_parameter, true , output) ;
247+ push_debuginfo_type_name ( cx, type_parameter, true , output, visited ) ;
212248 output. push_str ( ", " ) ;
213249 }
214250
0 commit comments