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:
parent
e4c141a331
commit
87e097a853
16 changed files with 153 additions and 151 deletions
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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(_) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ mod middle {
|
|||
mod resolve;
|
||||
mod typeck;
|
||||
mod fn_usage;
|
||||
mod check_loop;
|
||||
mod check_alt;
|
||||
mod check_const;
|
||||
mod lint;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern:break outside a loop
|
||||
// error-pattern:`break` outside of loop
|
||||
fn main() {
|
||||
let pth = break;
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
Loading…
Reference in a new issue