@@ -5,6 +5,7 @@ use rustc::hir::def_id::DefId;
5
5
use rustc:: ty:: subst:: SubstsRef ;
6
6
use rustc:: ty:: { self , Ty } ;
7
7
use rustc_codegen_ssa:: traits:: * ;
8
+ use rustc_data_structures:: fx:: FxHashSet ;
8
9
9
10
use rustc:: hir;
10
11
@@ -17,7 +18,8 @@ pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
17
18
qualified : bool )
18
19
-> String {
19
20
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) ;
21
23
result
22
24
}
23
25
@@ -26,7 +28,9 @@ pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
26
28
pub fn push_debuginfo_type_name < ' a , ' tcx > ( cx : & CodegenCx < ' a , ' tcx > ,
27
29
t : Ty < ' tcx > ,
28
30
qualified : bool ,
29
- output : & mut String ) {
31
+ output : & mut String ,
32
+ visited : & mut FxHashSet < Ty < ' tcx > > ) {
33
+
30
34
// When targeting MSVC, emit C++ style type names for compatibility with
31
35
// .natvis visualizers (and perhaps other existing native debuggers?)
32
36
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>,
42
46
ty:: Foreign ( def_id) => push_item_name ( cx, def_id, qualified, output) ,
43
47
ty:: Adt ( def, substs) => {
44
48
push_item_name ( cx, def. did , qualified, output) ;
45
- push_type_params ( cx, substs, output) ;
49
+ push_type_params ( cx, substs, output, visited ) ;
46
50
} ,
47
51
ty:: Tuple ( component_types) => {
48
52
output. push ( '(' ) ;
49
53
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 ) ;
51
55
output. push_str ( ", " ) ;
52
56
}
53
57
if !component_types. is_empty ( ) {
@@ -65,7 +69,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
65
69
hir:: MutMutable => output. push_str ( "mut " ) ,
66
70
}
67
71
68
- push_debuginfo_type_name ( cx, inner_type, true , output) ;
72
+ push_debuginfo_type_name ( cx, inner_type, true , output, visited ) ;
69
73
70
74
if cpp_like_names {
71
75
output. push ( '*' ) ;
@@ -79,15 +83,15 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
79
83
output. push_str ( "mut " ) ;
80
84
}
81
85
82
- push_debuginfo_type_name ( cx, inner_type, true , output) ;
86
+ push_debuginfo_type_name ( cx, inner_type, true , output, visited ) ;
83
87
84
88
if cpp_like_names {
85
89
output. push ( '*' ) ;
86
90
}
87
91
} ,
88
92
ty:: Array ( inner_type, len) => {
89
93
output. push ( '[' ) ;
90
- push_debuginfo_type_name ( cx, inner_type, true , output) ;
94
+ push_debuginfo_type_name ( cx, inner_type, true , output, visited ) ;
91
95
output. push_str ( & format ! ( "; {}" , len. unwrap_usize( cx. tcx) ) ) ;
92
96
output. push ( ']' ) ;
93
97
} ,
@@ -98,7 +102,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
98
102
output. push ( '[' ) ;
99
103
}
100
104
101
- push_debuginfo_type_name ( cx, inner_type, true , output) ;
105
+ push_debuginfo_type_name ( cx, inner_type, true , output, visited ) ;
102
106
103
107
if cpp_like_names {
104
108
output. push ( '>' ) ;
@@ -113,12 +117,31 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
113
117
& principal,
114
118
) ;
115
119
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 ) ;
117
121
} else {
118
122
output. push_str ( "dyn '_" ) ;
119
123
}
120
124
} ,
121
125
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
+
122
145
let sig = t. fn_sig ( cx. tcx ) ;
123
146
if sig. unsafety ( ) == hir:: Unsafety :: Unsafe {
124
147
output. push_str ( "unsafe " ) ;
@@ -136,7 +159,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
136
159
let sig = cx. tcx . normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , & sig) ;
137
160
if !sig. inputs ( ) . is_empty ( ) {
138
161
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 ) ;
140
163
output. push_str ( ", " ) ;
141
164
}
142
165
output. pop ( ) ;
@@ -155,8 +178,20 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
155
178
156
179
if !sig. output ( ) . is_unit ( ) {
157
180
output. push_str ( " -> " ) ;
158
- push_debuginfo_type_name ( cx, sig. output ( ) , true , output) ;
181
+ push_debuginfo_type_name ( cx, sig. output ( ) , true , output, visited ) ;
159
182
}
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) ;
160
195
} ,
161
196
ty:: Closure ( ..) => {
162
197
output. push_str ( "closure" ) ;
@@ -200,15 +235,16 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
200
235
// common denominator - otherwise we would run into conflicts.
201
236
fn push_type_params < ' a , ' tcx > ( cx : & CodegenCx < ' a , ' tcx > ,
202
237
substs : SubstsRef < ' tcx > ,
203
- output : & mut String ) {
238
+ output : & mut String ,
239
+ visited : & mut FxHashSet < Ty < ' tcx > > ) {
204
240
if substs. types ( ) . next ( ) . is_none ( ) {
205
241
return ;
206
242
}
207
243
208
244
output. push ( '<' ) ;
209
245
210
246
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 ) ;
212
248
output. push_str ( ", " ) ;
213
249
}
214
250
0 commit comments