@@ -14,8 +14,9 @@ use middle::infer;
14
14
use middle:: region;
15
15
use middle:: subst;
16
16
use middle:: ty:: { self , Ty } ;
17
- use util:: ppaux:: { Repr } ;
17
+ use util:: ppaux:: { Repr , UserString } ;
18
18
19
+ use syntax:: ast;
19
20
use syntax:: codemap:: Span ;
20
21
21
22
pub fn check_safety_of_destructor_if_necessary < ' a , ' tcx > ( rcx : & mut Rcx < ' a , ' tcx > ,
@@ -28,29 +29,98 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
28
29
// types that have been traversed so far by `traverse_type_if_unseen`
29
30
let mut breadcrumbs: Vec < Ty < ' tcx > > = Vec :: new ( ) ;
30
31
31
- iterate_over_potentially_unsafe_regions_in_type (
32
+ let result = iterate_over_potentially_unsafe_regions_in_type (
32
33
rcx,
33
34
& mut breadcrumbs,
35
+ TypeContext :: Root ,
34
36
typ,
35
37
span,
36
38
scope,
39
+ 0 ,
37
40
0 ) ;
41
+ match result {
42
+ Ok ( ( ) ) => { }
43
+ Err ( Error :: Overflow ( ref ctxt, ref detected_on_typ) ) => {
44
+ let tcx = rcx. tcx ( ) ;
45
+ span_err ! ( tcx. sess, span, E0320 ,
46
+ "overflow while adding drop-check rules for {}" ,
47
+ typ. user_string( rcx. tcx( ) ) ) ;
48
+ match * ctxt {
49
+ TypeContext :: Root => {
50
+ // no need for an additional note if the overflow
51
+ // was somehow on the root.
52
+ }
53
+ TypeContext :: EnumVariant { def_id, variant, arg_index } => {
54
+ // FIXME (pnkfelix): eventually lookup arg_name
55
+ // for the given index on struct variants.
56
+ span_note ! (
57
+ rcx. tcx( ) . sess,
58
+ span,
59
+ "overflowed on enum {} variant {} argument {} type: {}" ,
60
+ ty:: item_path_str( tcx, def_id) ,
61
+ variant,
62
+ arg_index,
63
+ detected_on_typ. user_string( rcx. tcx( ) ) ) ;
64
+ }
65
+ TypeContext :: Struct { def_id, field } => {
66
+ span_note ! (
67
+ rcx. tcx( ) . sess,
68
+ span,
69
+ "overflowed on struct {} field {} type: {}" ,
70
+ ty:: item_path_str( tcx, def_id) ,
71
+ field,
72
+ detected_on_typ. user_string( rcx. tcx( ) ) ) ;
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ enum Error < ' tcx > {
80
+ Overflow ( TypeContext , ty:: Ty < ' tcx > ) ,
81
+ }
82
+
83
+ enum TypeContext {
84
+ Root ,
85
+ EnumVariant {
86
+ def_id : ast:: DefId ,
87
+ variant : ast:: Name ,
88
+ arg_index : usize ,
89
+ } ,
90
+ Struct {
91
+ def_id : ast:: DefId ,
92
+ field : ast:: Name ,
93
+ }
38
94
}
39
95
96
+ // The `depth` counts the number of calls to this function;
97
+ // the `xref_depth` counts the subset of such calls that go
98
+ // across a `Box<T>` or `PhantomData<T>`.
40
99
fn iterate_over_potentially_unsafe_regions_in_type < ' a , ' tcx > (
41
100
rcx : & mut Rcx < ' a , ' tcx > ,
42
101
breadcrumbs : & mut Vec < Ty < ' tcx > > ,
102
+ context : TypeContext ,
43
103
ty_root : ty:: Ty < ' tcx > ,
44
104
span : Span ,
45
105
scope : region:: CodeExtent ,
46
- depth : uint )
106
+ depth : uint ,
107
+ xref_depth : uint ) -> Result < ( ) , Error < ' tcx > >
47
108
{
109
+ // Issue #22443: Watch out for overflow. While we are careful to
110
+ // handle regular types properly, non-regular ones cause problems.
111
+ let recursion_limit = rcx. tcx ( ) . sess . recursion_limit . get ( ) ;
112
+ if xref_depth >= recursion_limit {
113
+ return Err ( Error :: Overflow ( context, ty_root) )
114
+ }
115
+
48
116
let origin = || infer:: SubregionOrigin :: SafeDestructor ( span) ;
49
117
let mut walker = ty_root. walk ( ) ;
50
118
let opt_phantom_data_def_id = rcx. tcx ( ) . lang_items . phantom_data ( ) ;
51
119
52
120
let destructor_for_type = rcx. tcx ( ) . destructor_for_type . borrow ( ) ;
53
121
122
+ let xref_depth_orig = xref_depth;
123
+
54
124
while let Some ( typ) = walker. next ( ) {
55
125
// Avoid recursing forever.
56
126
if breadcrumbs. contains ( & typ) {
@@ -61,20 +131,33 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
61
131
// If we encounter `PhantomData<T>`, then we should replace it
62
132
// with `T`, the type it represents as owned by the
63
133
// surrounding context, before doing further analysis.
64
- let typ = if let ty:: ty_struct( struct_did, substs) = typ. sty {
65
- if opt_phantom_data_def_id == Some ( struct_did) {
66
- let item_type = ty:: lookup_item_type ( rcx. tcx ( ) , struct_did) ;
67
- let tp_def = item_type. generics . types
68
- . opt_get ( subst:: TypeSpace , 0 ) . unwrap ( ) ;
69
- let new_typ = substs. type_for_def ( tp_def) ;
70
- debug ! ( "replacing phantom {} with {}" ,
134
+ let ( typ, xref_depth) = match typ. sty {
135
+ ty:: ty_struct( struct_did, substs) => {
136
+ if opt_phantom_data_def_id == Some ( struct_did) {
137
+ let item_type = ty:: lookup_item_type ( rcx. tcx ( ) , struct_did) ;
138
+ let tp_def = item_type. generics . types
139
+ . opt_get ( subst:: TypeSpace , 0 ) . unwrap ( ) ;
140
+ let new_typ = substs. type_for_def ( tp_def) ;
141
+ debug ! ( "replacing phantom {} with {}" ,
142
+ typ. repr( rcx. tcx( ) ) , new_typ. repr( rcx. tcx( ) ) ) ;
143
+ ( new_typ, xref_depth_orig + 1 )
144
+ } else {
145
+ ( typ, xref_depth_orig)
146
+ }
147
+ }
148
+
149
+ // Note: When ty_uniq is removed from compiler, the
150
+ // definition of `Box<T>` must carry a PhantomData that
151
+ // puts us into the previous case.
152
+ ty:: ty_uniq( new_typ) => {
153
+ debug ! ( "replacing ty_uniq {} with {}" ,
71
154
typ. repr( rcx. tcx( ) ) , new_typ. repr( rcx. tcx( ) ) ) ;
72
- new_typ
73
- } else {
74
- typ
155
+ ( new_typ, xref_depth_orig + 1 )
156
+ }
157
+
158
+ _ => {
159
+ ( typ, xref_depth_orig)
75
160
}
76
- } else {
77
- typ
78
161
} ;
79
162
80
163
let opt_type_did = match typ. sty {
@@ -87,9 +170,9 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
87
170
opt_type_did. and_then ( |did| destructor_for_type. get ( & did) ) ;
88
171
89
172
debug ! ( "iterate_over_potentially_unsafe_regions_in_type \
90
- {}typ: {} scope: {:?} opt_dtor: {:?}",
173
+ {}typ: {} scope: {:?} opt_dtor: {:?} xref: {} ",
91
174
( 0 ..depth) . map( |_| ' ' ) . collect:: <String >( ) ,
92
- typ. repr( rcx. tcx( ) ) , scope, opt_dtor) ;
175
+ typ. repr( rcx. tcx( ) ) , scope, opt_dtor, xref_depth ) ;
93
176
94
177
// If `typ` has a destructor, then we must ensure that all
95
178
// borrowed data reachable via `typ` must outlive the parent
@@ -228,6 +311,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
228
311
229
312
match typ. sty {
230
313
ty:: ty_struct( struct_did, substs) => {
314
+ debug ! ( "typ: {} is struct; traverse structure and not type-expression" ,
315
+ typ. repr( rcx. tcx( ) ) ) ;
231
316
// Don't recurse; we extract type's substructure,
232
317
// so do not process subparts of type expression.
233
318
walker. skip_current_subtree ( ) ;
@@ -240,17 +325,24 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
240
325
struct_did,
241
326
field. id ,
242
327
substs) ;
243
- iterate_over_potentially_unsafe_regions_in_type (
328
+ try! ( iterate_over_potentially_unsafe_regions_in_type (
244
329
rcx,
245
330
breadcrumbs,
331
+ TypeContext :: Struct {
332
+ def_id : struct_did,
333
+ field : field. name ,
334
+ } ,
246
335
field_type,
247
336
span,
248
337
scope,
249
- depth+1 )
338
+ depth+1 ,
339
+ xref_depth) )
250
340
}
251
341
}
252
342
253
343
ty:: ty_enum( enum_did, substs) => {
344
+ debug ! ( "typ: {} is enum; traverse structure and not type-expression" ,
345
+ typ. repr( rcx. tcx( ) ) ) ;
254
346
// Don't recurse; we extract type's substructure,
255
347
// so do not process subparts of type expression.
256
348
walker. skip_current_subtree ( ) ;
@@ -260,14 +352,20 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
260
352
enum_did,
261
353
substs) ;
262
354
for variant_info in all_variant_info. iter ( ) {
263
- for argument_type in variant_info. args . iter ( ) {
264
- iterate_over_potentially_unsafe_regions_in_type (
355
+ for ( i , arg_type ) in variant_info. args . iter ( ) . enumerate ( ) {
356
+ try! ( iterate_over_potentially_unsafe_regions_in_type (
265
357
rcx,
266
358
breadcrumbs,
267
- * argument_type,
359
+ TypeContext :: EnumVariant {
360
+ def_id : enum_did,
361
+ variant : variant_info. name ,
362
+ arg_index : i,
363
+ } ,
364
+ * arg_type,
268
365
span,
269
366
scope,
270
- depth+1 )
367
+ depth+1 ,
368
+ xref_depth) ) ;
271
369
}
272
370
}
273
371
}
@@ -290,4 +388,6 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
290
388
// is done.
291
389
}
292
390
}
391
+
392
+ return Ok ( ( ) ) ;
293
393
}
0 commit comments