Disallow ret inside of block functions

Also adds proper checking for cont/break being inside a loop.

Closes #1854
Issue #1619
This commit is contained in:
Marijn Haverbeke 2012-03-26 12:39:20 +02:00
parent e4c141a331
commit 87e097a853
16 changed files with 153 additions and 151 deletions

View File

@ -399,7 +399,7 @@ Loop through a rope, char by char, until the end.
fn iter_chars(rope: rope, it: fn(char)) {
loop_chars(rope) {|x|
it(x);
ret true
true
};
}
@ -1043,9 +1043,9 @@ mod node {
fn loop_chars(node: @node, it: fn(char) -> bool) -> bool {
ret loop_leaves(node, {|leaf|
ret str::all_between(*leaf.content,
leaf.byte_offset,
leaf.byte_len, it)
str::all_between(*leaf.content,
leaf.byte_offset,
leaf.byte_len, it)
})
}

View File

@ -155,6 +155,8 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
time(time_passes, "block-use checking",
bind middle::block_use::check_crate(ty_cx, crate));
time(time_passes, "loop checking",
bind middle::check_loop::check_crate(sess, crate));
time(time_passes, "function usage",
bind fn_usage::check_crate_fn_usage(ty_cx, crate));
time(time_passes, "alt checking",

View File

@ -654,8 +654,8 @@ impl unify_methods for infer_ctxt {
self.constrs(a, b)
}
} else {
ret self.uerr(ty::terr_constr_len(a_constrs.len(),
b_constrs.len()));
self.uerr(ty::terr_constr_len(a_constrs.len(),
b_constrs.len()))
}
}
}

View File

@ -71,21 +71,22 @@ fn find_last_uses(c: @crate, def_map: resolve::def_map,
visit::visit_crate(*c, cx, v);
let mini_table = std::map::int_hash();
cx.last_uses.items {|key, val|
if !val { ret; }
alt key {
path(id) {
mini_table.insert(id, is_last_use);
let def_node = ast_util::def_id_of_def(def_map.get(id)).node;
cx.spill_map.insert(def_node, ());
}
close(fn_id, local_id) {
cx.spill_map.insert(local_id, ());
let known = alt check mini_table.find(fn_id) {
some(closes_over(ids)) { ids }
none { [] }
};
mini_table.insert(fn_id, closes_over(known + [local_id]));
}
if val {
alt key {
path(id) {
mini_table.insert(id, is_last_use);
let def_node = ast_util::def_id_of_def(def_map.get(id)).node;
cx.spill_map.insert(def_node, ());
}
close(fn_id, local_id) {
cx.spill_map.insert(local_id, ());
let known = alt check mini_table.find(fn_id) {
some(closes_over(ids)) { ids }
none { [] }
};
mini_table.insert(fn_id, closes_over(known + [local_id]));
}
}
}
}
ret (mini_table, cx.spill_map);
@ -211,15 +212,16 @@ fn visit_stmt(s: @stmt, cx: ctx, v: visit::vt<ctx>) {
alt s.node {
stmt_decl(@{node: decl_local(ls), _}, _) {
shadow_in_current(cx, {|id|
let mut rslt = false;
for local in ls {
let mut found = false;
pat_util::pat_bindings(cx.tcx.def_map, local.node.pat,
{|pid, _a, _b|
if pid == id { found = true; }
});
if found { ret true; }
if found { rslt = true; break; }
}
false
rslt
});
}
_ {}
@ -236,8 +238,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
proto_any | proto_block {
visit_block(func, cx, {||
shadow_in_current(cx, {|id|
for arg in decl.inputs { if arg.id == id { ret true; } }
false
vec::any(decl.inputs, {|arg| arg.id == id})
});
visit::visit_fn(fk, decl, body, sp, id, cx, v);
});

View File

@ -2162,13 +2162,14 @@ fn find_impls_in_view_item(e: env, vi: @ast::view_item,
if vec::len(*pt) == 1u {
option::may(sc) {|sc|
list::iter(sc) {|level|
if vec::len(found) > 0u { ret; }
for imp in *level {
if imp.ident == pt[0] {
found += [@{ident: name with *imp}];
if vec::len(found) == 0u {
for imp in *level {
if imp.ident == pt[0] {
found += [@{ident: name with *imp}];
}
}
if vec::len(found) > 0u { impls += found; }
}
if vec::len(found) > 0u { impls += found; }
}
}
} else {

View File

@ -2772,11 +2772,12 @@ fn get_landing_pad(bcx: block) -> BasicBlockRef {
in_lpad_scope_cx(bcx) {|info|
// If there is a valid landing pad still around, use it
alt info.landing_pad {
some(target) { cached = some(target); ret; }
none {}
some(target) { cached = some(target); }
none {
pad_bcx = sub_block(bcx, "unwind");
info.landing_pad = some(pad_bcx.llbb);
}
}
pad_bcx = sub_block(bcx, "unwind");
info.landing_pad = some(pad_bcx.llbb);
}
alt cached { some(b) { ret b; } none {} } // Can't return from block above
// The landing pad return type (the type being propagated). Not sure what
@ -3374,13 +3375,7 @@ fn trans_break_cont(bcx: block, to_end: bool)
}
_ {}
}
unwind = alt check unwind.parent {
parent_some(cx) { cx }
parent_none {
bcx.sess().bug
(if to_end { "break" } else { "cont" } + " outside a loop");
}
};
unwind = alt check unwind.parent { parent_some(cx) { cx } };
}
cleanup_and_Br(bcx, unwind, target.llbb);
Unreachable(bcx);

View File

@ -265,7 +265,7 @@ fn revoke_clean(cx: block, val: ValueRef) {
vec::slice(info.cleanups, 0u, i) +
vec::slice(info.cleanups, i + 1u, info.cleanups.len());
scope_clean_changed(info);
ret;
break;
}
_ {}
}

View File

@ -180,7 +180,7 @@ fn trans_append(bcx: block, vec_ty: ty::t, lhsptr: ValueRef,
load_if_immediate(bcx, addr, unit_ty), unit_ty);
Store(bcx, InBoundsGEP(bcx, write_ptr, [C_int(ccx, 1)]),
write_ptr_ptr);
ret bcx;
bcx
})
}

View File

@ -96,25 +96,27 @@ fn type_needs(cx: ctx, use: uint, ty: ty::t) {
fn type_needs_inner(cx: ctx, use: uint, ty: ty::t) {
ty::maybe_walk_ty(ty) {|ty|
if !ty::type_has_params(ty) { ret false; }
alt ty::get(ty).struct {
ty::ty_fn(_) | ty::ty_ptr(_) | ty::ty_rptr(_, _) |
ty::ty_box(_) | ty::ty_iface(_, _) { ret false; }
ty::ty_enum(did, tps) {
for v in *ty::enum_variants(cx.ccx.tcx, did) {
for aty in v.args {
let t = ty::substitute_type_params(cx.ccx.tcx, tps, aty);
type_needs_inner(cx, use, t);
if ty::type_has_params(ty) {
alt ty::get(ty).struct {
ty::ty_fn(_) | ty::ty_ptr(_) | ty::ty_rptr(_, _) |
ty::ty_box(_) | ty::ty_iface(_, _) { false }
ty::ty_enum(did, tps) {
for v in *ty::enum_variants(cx.ccx.tcx, did) {
for aty in v.args {
let t = ty::substitute_type_params(cx.ccx.tcx, tps,
aty);
type_needs_inner(cx, use, t);
}
}
false
}
ty::ty_param(n, _) {
cx.uses[n] |= use;
false
}
_ { true }
}
ret false;
}
ty::ty_param(n, _) {
cx.uses[n] |= use;
}
_ {}
}
ret true;
} else { false }
}
}

View File

@ -1036,12 +1036,7 @@ fn type_allows_implicit_copy(cx: ctxt, ty: t) -> bool {
mt.mutbl != ast::m_imm
}
ty_rec(fields) {
for field in fields {
if field.mt.mutbl != ast::m_imm {
ret true;
}
}
false
vec::any(fields, {|f| f.mt.mutbl != ast::m_imm})
}
_ { false }
}
@ -1050,12 +1045,12 @@ fn type_allows_implicit_copy(cx: ctxt, ty: t) -> bool {
fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool {
ret type_structurally_contains(cx, ty, {|sty|
ret alt sty {
ty_uniq(_) { ret true; }
alt sty {
ty_uniq(_) { true }
ty_vec(_) { true }
ty_str { true }
_ { ret false; }
};
_ { false }
}
});
}

View File

@ -2169,43 +2169,45 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
let mut result = none, complained = false;
std::list::iter(fcx.ccx.impl_map.get(expr.id)) {|impls|
if option::is_some(result) { ret; }
for @{did, methods, _} in *impls {
alt vec::find(methods, {|m| m.ident == name}) {
some(m) {
let mut {n_tps, ty: self_ty} = impl_self_ty(tcx, did);
let mut {vars, ty: self_ty} = if n_tps > 0u {
bind_params(fcx, self_ty, n_tps)
} else {
{vars: [], ty: self_ty}
};
self_ty = universally_quantify_regions(tcx, self_ty);
let ty = universally_quantify_regions(tcx, ty);
alt unify::unify(fcx, self_ty, ty) {
result::ok(_) {
if option::is_some(result) {
// FIXME[impl] score specificity to resolve ambiguity?
if !complained {
tcx.sess.span_err(expr.span, "multiple applicable \
methods in scope");
complained = true;
}
if option::is_none(result) {
for @{did, methods, _} in *impls {
alt vec::find(methods, {|m| m.ident == name}) {
some(m) {
let mut {n_tps, ty: self_ty} = impl_self_ty(tcx, did);
let mut {vars, ty: self_ty} = if n_tps > 0u {
bind_params(fcx, self_ty, n_tps)
} else {
result = some({
method_ty: ty_from_did(tcx, m.did),
n_tps: m.n_tps,
substs: vars,
origin: method_static(m.did),
self_sub: none
});
{vars: [], ty: self_ty}
};
self_ty = universally_quantify_regions(tcx, self_ty);
let ty = universally_quantify_regions(tcx, ty);
alt unify::unify(fcx, self_ty, ty) {
result::ok(_) {
if option::is_some(result) {
// FIXME[impl] score specificity?
if !complained {
tcx.sess.span_err(expr.span,
"multiple applicable \
methods in scope");
complained = true;
}
} else {
result = some({
method_ty: ty_from_did(tcx, m.did),
n_tps: m.n_tps,
substs: vars,
origin: method_static(m.did),
self_sub: none
});
}
}
result::err(_) {}
}
}
result::err(_) {}
_ {}
}
}
_ {}
}
}
}
@ -3786,40 +3788,43 @@ mod vtable {
_ {
let mut found = none;
std::list::iter(isc) {|impls|
if option::is_some(found) { ret; }
for im in *impls {
let match = alt ty::impl_iface(tcx, im.did) {
some(ity) {
alt check ty::get(ity).struct {
ty::ty_iface(id, _) { id == iface_id }
}
}
_ { false }
};
if match {
let {n_tps, ty: self_ty} = impl_self_ty(tcx, im.did);
let {vars, ty: self_ty} = if n_tps > 0u {
bind_params(fcx, self_ty, n_tps)
} else { {vars: [], ty: self_ty} };
let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
alt unify::unify(fcx, ty, self_ty) {
result::ok(_) {
if option::is_some(found) {
tcx.sess.span_err(
sp, "multiple applicable implementations \
in scope");
} else {
connect_iface_tps(fcx, sp, vars, iface_tps,
im.did);
let params = vec::map(vars, {|t|
fixup_ty(fcx, sp, t)});
let subres = lookup_vtables(
fcx, isc, sp, im_bs, params, false);
found = some(vtable_static(im.did, params,
subres));
if option::is_none(found) {
for im in *impls {
let match = alt ty::impl_iface(tcx, im.did) {
some(ity) {
alt check ty::get(ity).struct {
ty::ty_iface(id, _) { id == iface_id }
}
}
result::err(_) {}
_ { false }
};
if match {
let {n_tps, ty: self_ty} =
impl_self_ty(tcx, im.did);
let {vars, ty: self_ty} = if n_tps > 0u {
bind_params(fcx, self_ty, n_tps)
} else { {vars: [], ty: self_ty} };
let im_bs =
ty::lookup_item_type(tcx, im.did).bounds;
alt unify::unify(fcx, ty, self_ty) {
result::ok(_) {
if option::is_some(found) {
tcx.sess.span_err(
sp, "multiple applicable implemen\
tations in scope");
} else {
connect_iface_tps(fcx, sp, vars,
iface_tps, im.did);
let params = vec::map(vars, {|t|
fixup_ty(fcx, sp, t)});
let subres = lookup_vtables(
fcx, isc, sp, im_bs, params, false);
found = some(vtable_static(im.did, params,
subres));
}
}
result::err(_) {}
}
}
}
}

View File

@ -36,6 +36,7 @@ mod middle {
mod resolve;
mod typeck;
mod fn_usage;
mod check_loop;
mod check_alt;
mod check_const;
mod lint;

View File

@ -134,21 +134,20 @@ fn get_cargo_root_nearest() -> result<path, str> {
let mut dirpath = path::split(dirname);
let cwd_cargo = path::connect(cwd, ".cargo");
let mut par_cargo = path::connect(dirname, ".cargo");
let mut rslt = result::ok(cwd_cargo);
if os::path_is_dir(cwd_cargo) || cwd_cargo == p {
ret result::ok(cwd_cargo);
}
while vec::is_not_empty(dirpath) && par_cargo != p {
if os::path_is_dir(par_cargo) {
ret result::ok(par_cargo);
if !os::path_is_dir(cwd_cargo) && cwd_cargo != p {
while vec::is_not_empty(dirpath) && par_cargo != p {
if os::path_is_dir(par_cargo) {
rslt = result::ok(par_cargo);
break;
}
vec::pop(dirpath);
dirname = path::dirname(dirname);
par_cargo = path::connect(dirname, ".cargo");
}
vec::pop(dirpath);
dirname = path::dirname(dirname);
par_cargo = path::connect(dirname, ".cargo");
}
result::ok(cwd_cargo)
rslt
}
}

View File

@ -285,9 +285,10 @@ fn future_writer() -> (writer, future::future<str>) {
loop {
alt comm::recv(port) {
write(s) { res += s }
done { ret res; }
done { break; }
}
};
}
res
};
(writer, future)
}

View File

@ -1,4 +1,4 @@
// error-pattern:break outside a loop
// error-pattern:`break` outside of loop
fn main() {
let pth = break;

View File

@ -11,7 +11,7 @@ fn call_id_2() { id(true) && id(ret); }
fn call_id_3() { id(ret) && id(ret); }
fn call_id_4() { while id(break) { } }
fn call_id_4() { while id(ret) { } }
fn bind_id_1() { bind id(fail); }