From bdb206f2855cc6f7d3d79379633f7429b7327fec Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 14 Aug 2012 19:20:56 -0700 Subject: [PATCH] rustc: Parse labeled loop, break, and again --- src/fuzzer/fuzzer.rs | 4 +- src/libsyntax/ast.rs | 9 ++-- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/fold.rs | 10 ++-- src/libsyntax/parse/classify.rs | 2 +- src/libsyntax/parse/parser.rs | 22 ++++++-- src/libsyntax/print/pprust.rs | 15 ++++-- src/libsyntax/visit.rs | 6 +-- src/rustc/middle/astencode.rs | 1 + src/rustc/middle/borrowck/gather_loans.rs | 2 +- src/rustc/middle/check_loop.rs | 6 +-- src/rustc/middle/liveness.rs | 18 +++++-- src/rustc/middle/mem_categorization.rs | 7 +-- src/rustc/middle/resolve3.rs | 61 +++++++++++++++++++---- src/rustc/middle/trans/base.rs | 12 +++-- src/rustc/middle/trans/type_use.rs | 4 +- src/rustc/middle/typeck/check.rs | 9 ++-- src/rustc/util/common.rs | 4 +- src/test/run-pass/labeled-break.rs | 11 ++++ 19 files changed, 152 insertions(+), 53 deletions(-) create mode 100644 src/test/run-pass/labeled-break.rs diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs index c6dde67dd75..6ceb788ac4c 100644 --- a/src/fuzzer/fuzzer.rs +++ b/src/fuzzer/fuzzer.rs @@ -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"))))))), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 39e116990dd..a09bd073c44 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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), 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), + expr_again(option), expr_ret(option<@expr>), expr_log(int, @expr, @expr), diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 6ea6ecb1ba3..4a6f8b1e77a 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 5cce86fd458..5bd35490f0e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -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)), diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index d8ae8044370..1fd9dc2c23c 100644 --- a/src/libsyntax/parse/classify.rs +++ b/src/libsyntax/parse/classify.rs @@ -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 } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 642cdaa8fab..977e75362f8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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 diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 39bc18529c9..49ded036e04 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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 { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 1903a688aea..93d253d2163 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -422,7 +422,7 @@ fn visit_expr(ex: @expr, e: E, v: vt) { 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(ex: @expr, e: E, v: vt) { 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); diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index d1ccc72ac00..0f9f4db36e7 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -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)) } } } diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs index 3541ddad626..83dc54e5f86 100644 --- a/src/rustc/middle/borrowck/gather_loans.rs +++ b/src/rustc/middle/borrowck/gather_loans.rs @@ -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); } diff --git a/src/rustc/middle/check_loop.rs b/src/rustc/middle/check_loop.rs index a105ce68529..1fef670c0ba 100644 --- a/src/rustc/middle/check_loop.rs +++ b/src/rustc/middle/check_loop.rs @@ -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"); } diff --git a/src/rustc/middle/liveness.rs b/src/rustc/middle/liveness.rs index f8983f2bebb..c89095423c6 100644 --- a/src/rustc/middle/liveness.rs +++ b/src/rustc/middle/liveness.rs @@ -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); diff --git a/src/rustc/middle/mem_categorization.rs b/src/rustc/middle/mem_categorization.rs index b509880ab5f..5ffc36f4160 100644 --- a/src/rustc/middle/mem_categorization.rs +++ b/src/rustc/middle/mem_categorization.rs @@ -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} diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs index a06e6ea1dba..0262efca156 100644 --- a/src/rustc/middle/resolve3.rs +++ b/src/rustc/middle/resolve3.rs @@ -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() -> hashmap { hashmap::(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; 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); } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 2734fa85ae6..487435f2ef2 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -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); } diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs index 880c6c546f2..a53d9b3a3ba 100644 --- a/src/rustc/middle/trans/type_use.rs +++ b/src/rustc/middle/trans/type_use.rs @@ -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(_) => () } } diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 3bc4e578c74..64ebcd5fbbb 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -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"); + } } } diff --git a/src/rustc/util/common.rs b/src/rustc/util/common.rs index 906f3b7bdb3..b4195d0c04c 100644 --- a/src/rustc/util/common.rs +++ b/src/rustc/util/common.rs @@ -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 } } diff --git a/src/test/run-pass/labeled-break.rs b/src/test/run-pass/labeled-break.rs new file mode 100644 index 00000000000..1934540179a --- /dev/null +++ b/src/test/run-pass/labeled-break.rs @@ -0,0 +1,11 @@ +// xfail-fast +// xfail-test + +fn main() { + loop foo: { + loop { + break foo; + } + } +} +