rustc: Parse labeled loop, break, and again
This commit is contained in:
parent
d54db12155
commit
bdb206f285
src
fuzzer
libsyntax
rustc
test/run-pass
@ -41,8 +41,8 @@ fn common_exprs() -> ~[ast::expr] {
|
||||
{ node: l, span: ast_util::dummy_sp() }
|
||||
}
|
||||
|
||||
~[dse(ast::expr_break),
|
||||
dse(ast::expr_again),
|
||||
~[dse(ast::expr_break(option::none)),
|
||||
dse(ast::expr_again(option::none)),
|
||||
dse(ast::expr_fail(option::none)),
|
||||
dse(ast::expr_fail(option::some(
|
||||
@dse(ast::expr_lit(@dsl(ast::lit_str(@~"boo"))))))),
|
||||
|
@ -89,7 +89,8 @@ enum def {
|
||||
node_id /* expr node that creates the closure */),
|
||||
def_class(def_id, bool /* has constructor */),
|
||||
def_typaram_binder(node_id), /* class, impl or trait that has ty params */
|
||||
def_region(node_id)
|
||||
def_region(node_id),
|
||||
def_label(node_id)
|
||||
}
|
||||
|
||||
// The set of meta_items that define the compilation environment of the crate,
|
||||
@ -316,7 +317,7 @@ enum expr_ {
|
||||
/* Conditionless loop (can be exited with break, cont, ret, or fail)
|
||||
Same semantics as while(true) { body }, but typestate knows that the
|
||||
(implicit) condition is always true. */
|
||||
expr_loop(blk),
|
||||
expr_loop(blk, option<ident>),
|
||||
expr_match(@expr, ~[arm], alt_mode),
|
||||
expr_fn(proto, fn_decl, blk, capture_clause),
|
||||
expr_fn_block(fn_decl, blk, capture_clause),
|
||||
@ -339,8 +340,8 @@ enum expr_ {
|
||||
expr_path(@path),
|
||||
expr_addr_of(mutability, @expr),
|
||||
expr_fail(option<@expr>),
|
||||
expr_break,
|
||||
expr_again,
|
||||
expr_break(option<ident>),
|
||||
expr_again(option<ident>),
|
||||
expr_ret(option<@expr>),
|
||||
expr_log(int, @expr, @expr),
|
||||
|
||||
|
@ -61,7 +61,7 @@ pure fn def_id_of_def(d: def) -> def_id {
|
||||
}
|
||||
def_arg(id, _) | def_local(id, _) | def_self(id) |
|
||||
def_upvar(id, _, _) | def_binding(id, _) | def_region(id)
|
||||
| def_typaram_binder(id) => {
|
||||
| def_typaram_binder(id) | def_label(id) => {
|
||||
local_def(id)
|
||||
}
|
||||
|
||||
|
@ -448,8 +448,9 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
|
||||
expr_while(cond, body) => {
|
||||
expr_while(fld.fold_expr(cond), fld.fold_block(body))
|
||||
}
|
||||
expr_loop(body) => {
|
||||
expr_loop(fld.fold_block(body))
|
||||
expr_loop(body, opt_ident) => {
|
||||
expr_loop(fld.fold_block(body),
|
||||
option::map(opt_ident, |x| fld.fold_ident(x)))
|
||||
}
|
||||
expr_match(expr, arms, mode) => {
|
||||
expr_match(fld.fold_expr(expr),
|
||||
@ -492,7 +493,10 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
|
||||
}
|
||||
expr_path(pth) => expr_path(fld.fold_path(pth)),
|
||||
expr_fail(e) => expr_fail(option::map(e, |x| fld.fold_expr(x))),
|
||||
expr_break | expr_again => copy e,
|
||||
expr_break(opt_ident) =>
|
||||
expr_break(option::map(opt_ident, |x| fld.fold_ident(x))),
|
||||
expr_again(opt_ident) =>
|
||||
expr_again(option::map(opt_ident, |x| fld.fold_ident(x))),
|
||||
expr_ret(e) => expr_ret(option::map(e, |x| fld.fold_expr(x))),
|
||||
expr_log(i, lv, e) => expr_log(i, fld.fold_expr(lv),
|
||||
fld.fold_expr(e)),
|
||||
|
@ -7,7 +7,7 @@ import ast_util::operator_prec;
|
||||
fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool {
|
||||
match e.node {
|
||||
ast::expr_if(_, _, _) | ast::expr_match(_, _, _) | ast::expr_block(_)
|
||||
| ast::expr_while(_, _) | ast::expr_loop(_)
|
||||
| ast::expr_while(_, _) | ast::expr_loop(_, _)
|
||||
| ast::expr_call(_, _, true) => false,
|
||||
_ => true
|
||||
}
|
||||
|
@ -939,10 +939,18 @@ class parser {
|
||||
ex = expr_ret(some(e));
|
||||
} else { ex = expr_ret(none); }
|
||||
} else if self.eat_keyword(~"break") {
|
||||
ex = expr_break;
|
||||
if is_ident(self.token) {
|
||||
ex = expr_break(some(self.parse_ident()));
|
||||
} else {
|
||||
ex = expr_break(none);
|
||||
}
|
||||
hi = self.span.hi;
|
||||
} else if self.eat_keyword(~"again") {
|
||||
ex = expr_again;
|
||||
if is_ident(self.token) {
|
||||
ex = expr_again(some(self.parse_ident()));
|
||||
} else {
|
||||
ex = expr_again(none);
|
||||
}
|
||||
hi = self.span.hi;
|
||||
} else if self.eat_keyword(~"copy") {
|
||||
let e = self.parse_expr();
|
||||
@ -1585,10 +1593,18 @@ class parser {
|
||||
}
|
||||
|
||||
fn parse_loop_expr() -> @expr {
|
||||
let opt_ident;
|
||||
if is_ident(self.token) {
|
||||
opt_ident = some(self.parse_ident());
|
||||
self.expect(token::COLON);
|
||||
} else {
|
||||
opt_ident = none;
|
||||
}
|
||||
|
||||
let lo = self.last_span.lo;
|
||||
let body = self.parse_block_no_value();
|
||||
let mut hi = body.span.hi;
|
||||
return self.mk_expr(lo, hi, expr_loop(body));
|
||||
return self.mk_expr(lo, hi, expr_loop(body, opt_ident));
|
||||
}
|
||||
|
||||
// For distingishing between record literals and blocks
|
||||
|
@ -1142,9 +1142,10 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
|
||||
space(s.s);
|
||||
print_block(s, blk);
|
||||
}
|
||||
ast::expr_loop(blk) => {
|
||||
ast::expr_loop(blk, opt_ident) => {
|
||||
head(s, ~"loop");
|
||||
space(s.s);
|
||||
option::iter(opt_ident, |ident| word_space(s, *ident));
|
||||
print_block(s, blk);
|
||||
}
|
||||
ast::expr_match(expr, arms, mode) => {
|
||||
@ -1310,8 +1311,16 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
ast::expr_break => word(s.s, ~"break"),
|
||||
ast::expr_again => word(s.s, ~"again"),
|
||||
ast::expr_break(opt_ident) => {
|
||||
word(s.s, ~"break");
|
||||
space(s.s);
|
||||
option::iter(opt_ident, |ident| word_space(s, *ident));
|
||||
}
|
||||
ast::expr_again(opt_ident) => {
|
||||
word(s.s, ~"again");
|
||||
space(s.s);
|
||||
option::iter(opt_ident, |ident| word_space(s, *ident));
|
||||
}
|
||||
ast::expr_ret(result) => {
|
||||
word(s.s, ~"return");
|
||||
match result {
|
||||
|
@ -422,7 +422,7 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
||||
visit_expr_opt(eo, e, v);
|
||||
}
|
||||
expr_while(x, b) => { v.visit_expr(x, e, v); v.visit_block(b, e, v); }
|
||||
expr_loop(b) => v.visit_block(b, e, v),
|
||||
expr_loop(b, _) => v.visit_block(b, e, v),
|
||||
expr_match(x, arms, _) => {
|
||||
v.visit_expr(x, e, v);
|
||||
for arms.each |a| { v.visit_arm(a, e, v); }
|
||||
@ -452,8 +452,8 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
||||
expr_index(a, b) => { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
|
||||
expr_path(p) => visit_path(p, e, v),
|
||||
expr_fail(eo) => visit_expr_opt(eo, e, v),
|
||||
expr_break => (),
|
||||
expr_again => (),
|
||||
expr_break(_) => (),
|
||||
expr_again(_) => (),
|
||||
expr_ret(eo) => visit_expr_opt(eo, e, v),
|
||||
expr_log(_, lv, x) => {
|
||||
v.visit_expr(lv, e, v);
|
||||
|
@ -374,6 +374,7 @@ impl ast::def: tr {
|
||||
ast::def_typaram_binder(nid) => {
|
||||
ast::def_typaram_binder(xcx.tr_id(nid))
|
||||
}
|
||||
ast::def_label(nid) => ast::def_label(xcx.tr_id(nid))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ fn req_loans_in_expr(ex: @ast::expr,
|
||||
}
|
||||
|
||||
// see explanation attached to the `root_ub` field:
|
||||
ast::expr_loop(body) => {
|
||||
ast::expr_loop(body, _) => {
|
||||
self.root_ub = body.node.id;
|
||||
visit::visit_expr(ex, self, vt);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
|
||||
v.visit_expr(e, cx, v);
|
||||
v.visit_block(b, {in_loop: true with cx}, v);
|
||||
}
|
||||
expr_loop(b) => {
|
||||
expr_loop(b, _) => {
|
||||
v.visit_block(b, {in_loop: true with cx}, v);
|
||||
}
|
||||
expr_fn(_, _, _, _) => {
|
||||
@ -29,12 +29,12 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
|
||||
e)));
|
||||
v.visit_block(b, {in_loop: true, can_ret: blk}, v);
|
||||
}
|
||||
expr_break => {
|
||||
expr_break(_) => {
|
||||
if !cx.in_loop {
|
||||
tcx.sess.span_err(e.span, ~"`break` outside of loop");
|
||||
}
|
||||
}
|
||||
expr_again => {
|
||||
expr_again(_) => {
|
||||
if !cx.in_loop {
|
||||
tcx.sess.span_err(e.span, ~"`again` outside of loop");
|
||||
}
|
||||
|
@ -469,7 +469,7 @@ fn visit_expr(expr: @expr, &&self: @ir_maps, vt: vt<@ir_maps>) {
|
||||
expr_assert(*) | expr_addr_of(*) | expr_copy(*) |
|
||||
expr_loop_body(*) | expr_do_body(*) | expr_cast(*) |
|
||||
expr_unary(*) | expr_fail(*) |
|
||||
expr_break | expr_again | expr_lit(_) | expr_ret(*) |
|
||||
expr_break(_) | expr_again(_) | expr_lit(_) | expr_ret(*) |
|
||||
expr_block(*) | expr_move(*) | expr_unary_move(*) | expr_assign(*) |
|
||||
expr_swap(*) | expr_assign_op(*) | expr_mac(*) | expr_struct(*) |
|
||||
expr_repeat(*) => {
|
||||
@ -962,7 +962,7 @@ class liveness {
|
||||
self.propagate_through_loop(expr, some(cond), blk, succ)
|
||||
}
|
||||
|
||||
expr_loop(blk) => {
|
||||
expr_loop(blk, _) => {
|
||||
self.propagate_through_loop(expr, none, blk, succ)
|
||||
}
|
||||
|
||||
@ -1000,21 +1000,29 @@ class liveness {
|
||||
self.propagate_through_opt_expr(o_e, self.s.exit_ln)
|
||||
}
|
||||
|
||||
expr_break => {
|
||||
expr_break(opt_label) => {
|
||||
if !self.break_ln.is_valid() {
|
||||
self.tcx.sess.span_bug(
|
||||
expr.span, ~"break with invalid break_ln");
|
||||
}
|
||||
|
||||
if opt_label.is_some() {
|
||||
self.tcx.sess.span_unimpl(expr.span, ~"labeled break");
|
||||
}
|
||||
|
||||
self.break_ln
|
||||
}
|
||||
|
||||
expr_again => {
|
||||
expr_again(opt_label) => {
|
||||
if !self.cont_ln.is_valid() {
|
||||
self.tcx.sess.span_bug(
|
||||
expr.span, ~"cont with invalid cont_ln");
|
||||
}
|
||||
|
||||
if opt_label.is_some() {
|
||||
self.tcx.sess.span_unimpl(expr.span, ~"labeled again");
|
||||
}
|
||||
|
||||
self.cont_ln
|
||||
}
|
||||
|
||||
@ -1457,7 +1465,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
|
||||
expr_assert(*) | expr_copy(*) |
|
||||
expr_loop_body(*) | expr_do_body(*) |
|
||||
expr_cast(*) | expr_unary(*) | expr_fail(*) |
|
||||
expr_ret(*) | expr_break | expr_again | expr_lit(_) |
|
||||
expr_ret(*) | expr_break(*) | expr_again(*) | expr_lit(_) |
|
||||
expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) |
|
||||
expr_struct(*) | expr_repeat(*) => {
|
||||
visit::visit_expr(expr, self, vt);
|
||||
|
@ -317,8 +317,8 @@ impl &mem_categorization_ctxt {
|
||||
ast::expr_if(*) | ast::expr_log(*) |
|
||||
ast::expr_binary(*) | ast::expr_while(*) |
|
||||
ast::expr_block(*) | ast::expr_loop(*) | ast::expr_match(*) |
|
||||
ast::expr_lit(*) | ast::expr_break | ast::expr_mac(*) |
|
||||
ast::expr_again | ast::expr_rec(*) | ast::expr_struct(*) |
|
||||
ast::expr_lit(*) | ast::expr_break(*) | ast::expr_mac(*) |
|
||||
ast::expr_again(*) | ast::expr_rec(*) | ast::expr_struct(*) |
|
||||
ast::expr_unary_move(*) | ast::expr_repeat(*) => {
|
||||
return self.cat_rvalue(expr, expr_ty);
|
||||
}
|
||||
@ -335,7 +335,8 @@ impl &mem_categorization_ctxt {
|
||||
ast::def_use(_) | ast::def_variant(*) |
|
||||
ast::def_ty(_) | ast::def_prim_ty(_) |
|
||||
ast::def_ty_param(*) | ast::def_class(*) |
|
||||
ast::def_typaram_binder(*) | ast::def_region(_) => {
|
||||
ast::def_typaram_binder(*) | ast::def_region(_) |
|
||||
ast::def_label(_) => {
|
||||
@{id:id, span:span,
|
||||
cat:cat_special(sk_static_item), lp:none,
|
||||
mutbl:m_imm, ty:expr_ty}
|
||||
|
@ -14,7 +14,7 @@ import syntax::ast::{bound_trait, binding_mode,
|
||||
capture_clause, class_ctor, class_dtor};
|
||||
import syntax::ast::{class_member, class_method, crate, crate_num, decl_item};
|
||||
import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn};
|
||||
import syntax::ast::{def_foreign_mod, def_id, def_local, def_mod};
|
||||
import syntax::ast::{def_foreign_mod, def_id, def_label, def_local, def_mod};
|
||||
import syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param};
|
||||
import syntax::ast::{def_typaram_binder, def_static_method};
|
||||
import syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op};
|
||||
@ -22,9 +22,10 @@ import syntax::ast::{expr_binary, expr_cast, expr_field, expr_fn};
|
||||
import syntax::ast::{expr_fn_block, expr_index, expr_path};
|
||||
import syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param};
|
||||
import syntax::ast::{def_upvar, def_use, def_variant, div, eq};
|
||||
import syntax::ast::{enum_variant_kind, expr, expr_assign_op, expr_binary};
|
||||
import syntax::ast::{expr_cast, expr_field, expr_fn, expr_fn_block};
|
||||
import syntax::ast::{expr_index, expr_path, expr_struct, expr_unary, fn_decl};
|
||||
import syntax::ast::{enum_variant_kind, expr, expr_again, expr_assign_op};
|
||||
import syntax::ast::{expr_binary, expr_break, expr_cast, expr_field, expr_fn};
|
||||
import syntax::ast::{expr_fn_block, expr_index, expr_loop};
|
||||
import syntax::ast::{expr_path, expr_struct, expr_unary, fn_decl};
|
||||
import syntax::ast::{foreign_item, foreign_item_fn, ge, gt, ident, trait_ref};
|
||||
import syntax::ast::{impure_fn, instance_var, item, item_class, item_const};
|
||||
import syntax::ast::{item_enum, item_fn, item_mac, item_foreign_mod};
|
||||
@ -310,10 +311,7 @@ fn atom_hashmap<V:copy>() -> hashmap<Atom,V> {
|
||||
hashmap::<Atom,V>(uint::hash, uint::eq)
|
||||
}
|
||||
|
||||
/**
|
||||
* One local scope. In Rust, local scopes can only contain value bindings.
|
||||
* Therefore, we don't have to worry about the other namespaces here.
|
||||
*/
|
||||
/// One local scope.
|
||||
class Rib {
|
||||
let bindings: hashmap<Atom,def_like>;
|
||||
let kind: RibKind;
|
||||
@ -676,12 +674,14 @@ class Resolver {
|
||||
|
||||
// The current set of local scopes, for values.
|
||||
// XXX: Reuse ribs to avoid allocation.
|
||||
|
||||
let value_ribs: @DVec<@Rib>;
|
||||
|
||||
// The current set of local scopes, for types.
|
||||
let type_ribs: @DVec<@Rib>;
|
||||
|
||||
// The current set of local scopes, for labels.
|
||||
let label_ribs: @DVec<@Rib>;
|
||||
|
||||
// Whether the current context is an X-ray context. An X-ray context is
|
||||
// allowed to access private names of any module.
|
||||
let mut xray_context: XrayFlag;
|
||||
@ -728,6 +728,7 @@ class Resolver {
|
||||
self.current_module = (*self.graph_root).get_module();
|
||||
self.value_ribs = @dvec();
|
||||
self.type_ribs = @dvec();
|
||||
self.label_ribs = @dvec();
|
||||
|
||||
self.xray_context = NoXray;
|
||||
self.current_trait_refs = none;
|
||||
@ -1486,7 +1487,7 @@ class Resolver {
|
||||
def_self(*) | def_arg(*) | def_local(*) |
|
||||
def_prim_ty(*) | def_ty_param(*) | def_binding(*) |
|
||||
def_use(*) | def_upvar(*) | def_region(*) |
|
||||
def_typaram_binder(*) => {
|
||||
def_typaram_binder(*) | def_label(*) => {
|
||||
fail fmt!("didn't expect `%?`", def);
|
||||
}
|
||||
}
|
||||
@ -3305,12 +3306,18 @@ class Resolver {
|
||||
(*self.type_ribs).pop();
|
||||
}
|
||||
|
||||
NoTypeParameters =>{
|
||||
NoTypeParameters => {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_label_rib(f: fn()) {
|
||||
(*self.label_ribs).push(@Rib(NormalRibKind));
|
||||
f();
|
||||
(*self.label_ribs).pop();
|
||||
}
|
||||
|
||||
fn resolve_function(rib_kind: RibKind,
|
||||
optional_declaration: option<@fn_decl>,
|
||||
type_parameters: TypeParameters,
|
||||
@ -3348,6 +3355,10 @@ class Resolver {
|
||||
let function_value_rib = @Rib(rib_kind);
|
||||
(*self.value_ribs).push(function_value_rib);
|
||||
|
||||
// Create a label rib for the function.
|
||||
let function_label_rib = @Rib(rib_kind);
|
||||
(*self.label_ribs).push(function_label_rib);
|
||||
|
||||
// If this function has type parameters, add them now.
|
||||
do self.with_type_parameter_rib(type_parameters) {
|
||||
// Resolve the type parameters.
|
||||
@ -3400,6 +3411,7 @@ class Resolver {
|
||||
debug!{"(resolving function) leaving function"};
|
||||
}
|
||||
|
||||
(*self.label_ribs).pop();
|
||||
(*self.value_ribs).pop();
|
||||
}
|
||||
|
||||
@ -4428,6 +4440,33 @@ class Resolver {
|
||||
visit_expr(expr, (), visitor);
|
||||
}
|
||||
|
||||
expr_loop(_, some(label)) => {
|
||||
do self.with_label_rib {
|
||||
let atom = self.atom_table.intern(label);
|
||||
let def_like = dl_def(def_label(expr.id));
|
||||
self.label_ribs.last().bindings.insert(atom, def_like);
|
||||
|
||||
visit_expr(expr, (), visitor);
|
||||
}
|
||||
}
|
||||
|
||||
expr_break(some(label)) | expr_again(some(label)) => {
|
||||
let atom = self.atom_table.intern(label);
|
||||
match self.search_ribs(self.label_ribs, atom, expr.span,
|
||||
DontAllowCapturingSelf) {
|
||||
none =>
|
||||
self.session.span_err(expr.span,
|
||||
fmt!("use of undeclared label \
|
||||
`%s`", *label)),
|
||||
some(dl_def(def @ def_label(id))) =>
|
||||
self.record_def(expr.id, def),
|
||||
some(_) =>
|
||||
self.session.span_bug(expr.span,
|
||||
~"label wasn't mapped to a \
|
||||
label def!")
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
visit_expr(expr, (), visitor);
|
||||
}
|
||||
|
@ -3852,12 +3852,18 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
|
||||
}
|
||||
|
||||
// These return nothing
|
||||
ast::expr_break => {
|
||||
ast::expr_break(label_opt) => {
|
||||
assert dest == ignore;
|
||||
if label_opt.is_some() {
|
||||
bcx.tcx().sess.span_unimpl(e.span, ~"labeled break");
|
||||
}
|
||||
return trans_break(bcx);
|
||||
}
|
||||
ast::expr_again => {
|
||||
ast::expr_again(label_opt) => {
|
||||
assert dest == ignore;
|
||||
if label_opt.is_some() {
|
||||
bcx.tcx().sess.span_unimpl(e.span, ~"labeled again");
|
||||
}
|
||||
return trans_cont(bcx);
|
||||
}
|
||||
ast::expr_ret(ex) => {
|
||||
@ -3880,7 +3886,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
|
||||
assert dest == ignore;
|
||||
return trans_while(bcx, cond, body);
|
||||
}
|
||||
ast::expr_loop(body) => {
|
||||
ast::expr_loop(body, _) => {
|
||||
assert dest == ignore;
|
||||
return trans_loop(bcx, body);
|
||||
}
|
||||
|
@ -253,10 +253,10 @@ fn mark_for_expr(cx: ctx, e: @expr) {
|
||||
})
|
||||
}
|
||||
expr_match(_, _, _) | expr_block(_) | expr_if(_, _, _) |
|
||||
expr_while(_, _) | expr_fail(_) | expr_break | expr_again |
|
||||
expr_while(_, _) | expr_fail(_) | expr_break(_) | expr_again(_) |
|
||||
expr_unary(_, _) | expr_lit(_) | expr_assert(_) |
|
||||
expr_mac(_) | expr_addr_of(_, _) |
|
||||
expr_ret(_) | expr_loop(_) |
|
||||
expr_ret(_) | expr_loop(_, _) |
|
||||
expr_loop_body(_) | expr_do_body(_) => ()
|
||||
}
|
||||
}
|
||||
|
@ -1466,8 +1466,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
}
|
||||
fcx.write_bot(id);
|
||||
}
|
||||
ast::expr_break => { fcx.write_bot(id); bot = true; }
|
||||
ast::expr_again => { fcx.write_bot(id); bot = true; }
|
||||
ast::expr_break(_) => { fcx.write_bot(id); bot = true; }
|
||||
ast::expr_again(_) => { fcx.write_bot(id); bot = true; }
|
||||
ast::expr_ret(expr_opt) => {
|
||||
bot = true;
|
||||
let ret_ty = match fcx.indirect_ret_ty {
|
||||
@ -1518,7 +1518,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
check_block_no_value(fcx, body);
|
||||
fcx.write_ty(id, ty::mk_nil(tcx));
|
||||
}
|
||||
ast::expr_loop(body) => {
|
||||
ast::expr_loop(body, _) => {
|
||||
check_block_no_value(fcx, body);
|
||||
fcx.write_ty(id, ty::mk_nil(tcx));
|
||||
bot = !may_break(body);
|
||||
@ -2296,6 +2296,9 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
||||
fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found type \
|
||||
parameter");
|
||||
}
|
||||
ast::def_label(*) => {
|
||||
fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found label");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ fn loop_query(b: ast::blk, p: fn@(ast::expr_) -> bool) -> bool {
|
||||
fn has_nonlocal_exits(b: ast::blk) -> bool {
|
||||
do loop_query(b) |e| {
|
||||
match e {
|
||||
ast::expr_break | ast::expr_again => true,
|
||||
ast::expr_break(_) | ast::expr_again(_) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
@ -68,7 +68,7 @@ fn has_nonlocal_exits(b: ast::blk) -> bool {
|
||||
fn may_break(b: ast::blk) -> bool {
|
||||
do loop_query(b) |e| {
|
||||
match e {
|
||||
ast::expr_break => true,
|
||||
ast::expr_break(_) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
11
src/test/run-pass/labeled-break.rs
Normal file
11
src/test/run-pass/labeled-break.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// xfail-fast
|
||||
// xfail-test
|
||||
|
||||
fn main() {
|
||||
loop foo: {
|
||||
loop {
|
||||
break foo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user