Skip to content

Commit 46373b5

Browse files
committed
Check for Sized in kind.rs. XXX: This both breaks the build, and is hackishly-incomplete (cf rust-lang#6872)
1 parent c9876c6 commit 46373b5

File tree

1 file changed

+129
-2
lines changed

1 file changed

+129
-2
lines changed

src/librustc/middle/kind.rs

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ pub fn check_crate(tcx: ty::ctxt,
7373
let visit = visit::mk_vt(@visit::Visitor {
7474
visit_expr: check_expr,
7575
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,
7679
visit_ty: check_ty,
7780
visit_item: check_item,
7881
visit_block: check_block,
@@ -234,7 +237,75 @@ fn check_fn(
234237
}
235238
}
236239

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);
238309
}
239310

240311
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>) {
292363
}
293364
expr_repeat(element, count_expr, _) => {
294365
let count = ty::eval_repeat_count(cx.tcx, count_expr);
366+
let element_ty = ty::expr_ty(cx.tcx, element);
295367
if count > 1 {
296-
let element_ty = ty::expr_ty(cx.tcx, element);
297368
check_copy(cx, element_ty, element.span,
298369
"repeated element will be copied");
299370
}
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+
}
300400
}
301401
_ => {}
302402
}
@@ -419,6 +519,33 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
419519
}
420520
}
421521

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+
422549
/// This is rather subtle. When we are casting a value to a instantiated
423550
/// trait like `a as trait<'r>`, regionck already ensures that any borrowed
424551
/// pointers that appear in the type of `a` are bounded by `'r` (ed.: rem

0 commit comments

Comments
 (0)