@@ -73,6 +73,9 @@ pub fn check_crate(tcx: ty::ctxt,
73
73
let visit = visit:: mk_vt ( @visit:: Visitor {
74
74
visit_expr : check_expr,
75
75
visit_fn : check_fn,
76
+ visit_foreign_item : check_foreign_item, // TODO(bblum) remove debug
77
+ visit_local : check_local,
78
+ visit_pat : check_pat,
76
79
visit_ty : check_ty,
77
80
visit_item : check_item,
78
81
visit_block : check_block,
@@ -234,7 +237,75 @@ fn check_fn(
234
237
}
235
238
}
236
239
237
- visit:: visit_fn ( fk, decl, body, sp, fn_id, cx, v) ;
240
+ // Check that return type and (possible) self type are statically sized.
241
+ // Arguments are checked separately in check_pat.
242
+ let return_type = match ty:: get ( ty:: node_id_to_type ( cx. tcx , fn_id) ) . sty {
243
+ ty:: ty_closure( ref f) => f. sig . output ,
244
+ ty:: ty_bare_fn( ref f) => f. sig . output ,
245
+ ref t => cx. tcx . sess . bug ( fmt ! ( "bad function type in kindchk: %?" , t) ) ,
246
+ } ;
247
+ check_sized ( cx, return_type, decl. output . span , "function return type" ) ;
248
+
249
+ match * fk {
250
+ visit:: fk_method( _, _, method) => match method. explicit_self . node {
251
+ sty_value => {
252
+ let self_type = ty:: node_id_to_type ( cx. tcx , method. self_id ) ;
253
+ check_sized ( cx, self_type, method. explicit_self . span ,
254
+ "by-value self type" ) ;
255
+ }
256
+ _ => { }
257
+ } ,
258
+ _ => { }
259
+ }
260
+
261
+ // XXX
262
+ // visit::visit_fn(fk, decl, body, sp, fn_id, cx, v);
263
+ for decl. inputs. each |a| {
264
+ ( v. visit_ty ) ( a. ty , cx, v) ;
265
+ }
266
+ ( v. visit_ty ) ( decl. output , cx, v) ;
267
+ ( v. visit_generics ) ( & visit:: generics_of_fn ( fk) , cx, v) ;
268
+ ( v. visit_block ) ( body, cx, v) ;
269
+ }
270
+
271
+ // XXX remove this whole function
272
+ fn check_foreign_item ( ni : @foreign_item , cx : Context , v : visit:: vt < Context > ) {
273
+ let e = cx;
274
+ match ni. node {
275
+ foreign_item_fn( ref fd, _, ref generics) => {
276
+ for fd. inputs. each |a| {
277
+ // (v.visit_pat)(a.pat, e, v);
278
+ ( v. visit_ty ) ( a. ty , e, v) ;
279
+ }
280
+ ( v. visit_ty ) ( fd. output , e, v) ;
281
+ ( v. visit_generics ) ( generics, e, v) ;
282
+ }
283
+ foreign_item_const( t) => {
284
+ ( v. visit_ty ) ( t, e, v) ;
285
+ }
286
+ }
287
+
288
+ }
289
+
290
+ fn check_pat ( p : @pat, cx : Context , v : visit:: vt < Context > ) {
291
+ // FIXME(#6308): Not sure if this is right. Does pat_bindings combined
292
+ // with check_pat cause nested patterns to be checked multiple times?
293
+ do pat_util:: pat_bindings ( cx. tcx . def_map , p) |mode, node, span, _| {
294
+ match mode {
295
+ bind_infer => {
296
+ check_sized ( cx, ty:: node_id_to_type ( cx. tcx , node) , span,
297
+ "local variable bound in pattern" ) ;
298
+ }
299
+ bind_by_ref( * ) => { } // OK to reference an unsized type.
300
+ }
301
+ }
302
+ visit:: visit_pat ( p, cx, v) ;
303
+ }
304
+
305
+ fn check_local ( loc : @local , cx : Context , v : visit:: vt < Context > ) {
306
+ check_sized ( cx, ty:: node_id_to_type ( cx. tcx , loc. node . id ) , loc. span ,
307
+ "statically-allocated variable" ) ;
308
+ visit:: visit_local ( loc, cx, v) ;
238
309
}
239
310
240
311
pub fn check_expr ( e : @expr, cx : Context , v : visit:: vt < Context > ) {
@@ -292,11 +363,40 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt<Context>) {
292
363
}
293
364
expr_repeat( element, count_expr, _) => {
294
365
let count = ty:: eval_repeat_count ( cx. tcx , count_expr) ;
366
+ let element_ty = ty:: expr_ty ( cx. tcx , element) ;
295
367
if count > 1 {
296
- let element_ty = ty:: expr_ty ( cx. tcx , element) ;
297
368
check_copy ( cx, element_ty, element. span ,
298
369
"repeated element will be copied" ) ;
299
370
}
371
+ check_sized ( cx, element_ty, element. span , "vector element" ) ;
372
+ }
373
+ // Ensure sized bounds when building containers & calling functions
374
+ expr_vec( ref elts, _) => {
375
+ for elts. each |elt| {
376
+ check_sized( cx, ty:: expr_ty( cx. tcx, * elt) , elt. span,
377
+ "vector element" ) ;
378
+ }
379
+ }
380
+ expr_call ( _, ref args, _) => {
381
+ // This case is partly a red herring, as fns with dynamically-
382
+ // sized types get forbidden elsewhere, but enum constructors are
383
+ // desugared to calls also, and enum definitions can't be checked.
384
+ for args. each |arg| {
385
+ check_sized ( cx, ty:: expr_ty ( cx. tcx , * arg) , arg. span ,
386
+ "function argument" ) ;
387
+ }
388
+ }
389
+ expr_tup( ref elts) => {
390
+ for elts. each |elt| {
391
+ check_sized ( cx, ty:: expr_ty ( cx. tcx , * elt) , elt. span ,
392
+ "tuple element" ) ;
393
+ }
394
+ }
395
+ expr_struct ( _, ref fields, _) => {
396
+ for fields. each |f| {
397
+ check_sized ( cx, ty:: expr_ty ( cx. tcx , f. node . expr ) ,
398
+ f. node . expr . span , "struct field" ) ;
399
+ }
300
400
}
301
401
_ => { }
302
402
}
@@ -419,6 +519,33 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
419
519
}
420
520
}
421
521
522
+ // We ensure types are statically-sized at the following boundaries, to ensure
523
+ // they are never stored somewhere that isn't immediately behind a pointer:
524
+ // 1. Expressions that build container data structures -- in check_expr
525
+ // - vectors
526
+ // - struct fields and tuple elements
527
+ // - enum elements (expressed as function calls)
528
+ // 2. Binding sites of stack-allocated variables
529
+ // - global and local decls (let...) -- in check_local
530
+ // - function arguments and pattern bindings -- in check_pat
531
+ // - function return types -- in check_fn
532
+ fn check_sized ( cx : Context , ty : ty:: t , sp : span , reason : & str ) {
533
+ if !ty:: type_is_sized ( cx. tcx , ty) {
534
+ match ty:: get ( ty) . sty {
535
+ ty:: ty_param( * ) => {
536
+ cx. tcx . sess . span_err ( sp,
537
+ fmt ! ( "can't use type %s of unknown size as a %s; add \
538
+ `Sized' bound", ty_to_str( cx. tcx, ty) , reason) ) ;
539
+ }
540
+ _ => {
541
+ cx. tcx . sess . span_err ( sp,
542
+ fmt ! ( "can't use dynamically-sized type %s as a %s" ,
543
+ ty_to_str( cx. tcx, ty) , reason) ) ;
544
+ }
545
+ }
546
+ }
547
+ }
548
+
422
549
/// This is rather subtle. When we are casting a value to a instantiated
423
550
/// trait like `a as trait<'r>`, regionck already ensures that any borrowed
424
551
/// pointers that appear in the type of `a` are bounded by `'r` (ed.: rem
0 commit comments