Skip to content

Commit 43c26e6

Browse files
committed
auto merge of #16190 : Pythoner6/rust/labeled-while-loop, r=alexcrichton
Fixes #12643 > Say! > I like labelled breaks/continues! I will use them with a `for` loop. And I will use with a `loop` loop. Say! I will use them ANYWHERE! … _even_ in a `while` loop. Because they're now supported there.
2 parents c8e86e9 + e76db8e commit 43c26e6

21 files changed

+106
-33
lines changed

src/librustc/lint/builtin.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl LintPass for WhileTrue {
5858

5959
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
6060
match e.node {
61-
ast::ExprWhile(cond, _) => {
61+
ast::ExprWhile(cond, _, _) => {
6262
match cond.node {
6363
ast::ExprLit(lit) => {
6464
match lit.node {
@@ -1073,7 +1073,7 @@ impl LintPass for UnnecessaryParens {
10731073
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
10741074
let (value, msg, struct_lit_needs_parens) = match e.node {
10751075
ast::ExprIf(cond, _, _) => (cond, "`if` condition", true),
1076-
ast::ExprWhile(cond, _) => (cond, "`while` condition", true),
1076+
ast::ExprWhile(cond, _, _) => (cond, "`while` condition", true),
10771077
ast::ExprMatch(head, _) => (head, "`match` head expression", true),
10781078
ast::ExprRet(Some(value)) => (value, "`return` value", false),
10791079
ast::ExprAssign(_, value) => (value, "assigned value", false),

src/librustc/middle/cfg/construct.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -227,7 +227,7 @@ impl<'a> CFGBuilder<'a> {
227227
self.add_node(expr.id, [then_exit, else_exit]) // 4, 5
228228
}
229229

230-
ast::ExprWhile(ref cond, ref body) => {
230+
ast::ExprWhile(ref cond, ref body, _) => {
231231
//
232232
// [pred]
233233
// |

src/librustc/middle/check_loop.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -35,7 +35,7 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
3535

3636
fn visit_expr(&mut self, e: &ast::Expr, cx:Context) {
3737
match e.node {
38-
ast::ExprWhile(ref e, ref b) => {
38+
ast::ExprWhile(ref e, ref b, _) => {
3939
self.visit_expr(&**e, cx);
4040
self.visit_block(&**b, Loop);
4141
}

src/librustc/middle/expr_use_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
410410
self.walk_block(&**blk);
411411
}
412412

413-
ast::ExprWhile(ref cond_expr, ref blk) => {
413+
ast::ExprWhile(ref cond_expr, ref blk, _) => {
414414
self.consume_expr(&**cond_expr);
415415
self.walk_block(&**blk);
416416
}

src/librustc/middle/liveness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,7 @@ impl<'a> Liveness<'a> {
10171017
self.propagate_through_expr(&**cond, ln)
10181018
}
10191019

1020-
ExprWhile(ref cond, ref blk) => {
1020+
ExprWhile(ref cond, ref blk, _) => {
10211021
self.propagate_through_loop(expr,
10221022
WhileLoop(cond.clone()),
10231023
&**blk,

src/librustc/middle/region.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -496,7 +496,7 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor,
496496
visitor.region_maps.mark_as_terminating_scope(body.id);
497497
}
498498

499-
ast::ExprWhile(expr, body) => {
499+
ast::ExprWhile(expr, body, _) => {
500500
visitor.region_maps.mark_as_terminating_scope(expr.id);
501501
visitor.region_maps.mark_as_terminating_scope(body.id);
502502
}

src/librustc/middle/resolve.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
2323

2424
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate};
2525
use syntax::ast::{DeclItem, DefId, Expr, ExprAgain, ExprBreak, ExprField};
26-
use syntax::ast::{ExprFnBlock, ExprForLoop, ExprLoop, ExprMethodCall};
26+
use syntax::ast::{ExprFnBlock, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
2727
use syntax::ast::{ExprPath, ExprProc, ExprStruct, ExprUnboxedFn, FnDecl};
2828
use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic, Generics};
2929
use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod};
@@ -5622,7 +5622,7 @@ impl<'a> Resolver<'a> {
56225622
visit::walk_expr(self, expr, ());
56235623
}
56245624

5625-
ExprLoop(_, Some(label)) => {
5625+
ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
56265626
self.with_label_rib(|this| {
56275627
let def_like = DlDef(DefLabel(expr.id));
56285628

src/librustc/middle/trans/debuginfo.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3512,7 +3512,7 @@ fn populate_scope_map(cx: &CrateContext,
35123512
}
35133513
}
35143514

3515-
ast::ExprWhile(ref cond_exp, ref loop_body) => {
3515+
ast::ExprWhile(ref cond_exp, ref loop_body, _) => {
35163516
walk_expr(cx, &**cond_exp, scope_stack, scope_map);
35173517

35183518
with_new_scope(cx,

src/librustc/middle/trans/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
900900
ast::ExprRet(ex) => {
901901
controlflow::trans_ret(bcx, ex)
902902
}
903-
ast::ExprWhile(ref cond, ref body) => {
903+
ast::ExprWhile(ref cond, ref body, _) => {
904904
controlflow::trans_while(bcx, expr.id, &**cond, &**body)
905905
}
906906
ast::ExprForLoop(ref pat, ref head, ref body, _) => {

src/librustc/middle/typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3757,7 +3757,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
37573757
check_then_else(fcx, &**cond, &**then_blk, opt_else_expr.clone(),
37583758
id, expr.span, expected);
37593759
}
3760-
ast::ExprWhile(ref cond, ref body) => {
3760+
ast::ExprWhile(ref cond, ref body, _) => {
37613761
check_expr_has_type(fcx, &**cond, ty::mk_bool());
37623762
check_block_no_value(fcx, &**body);
37633763
let cond_ty = fcx.expr_ty(&**cond);

src/librustc/middle/typeck/check/regionck.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -749,7 +749,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
749749
rcx.set_repeating_scope(repeating_scope);
750750
}
751751

752-
ast::ExprWhile(ref cond, ref body) => {
752+
ast::ExprWhile(ref cond, ref body, _) => {
753753
let repeating_scope = rcx.set_repeating_scope(cond.id);
754754
rcx.visit_expr(&**cond, ());
755755

src/libsyntax/ast.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,8 @@ pub enum Expr_ {
524524
ExprLit(Gc<Lit>),
525525
ExprCast(Gc<Expr>, P<Ty>),
526526
ExprIf(Gc<Expr>, P<Block>, Option<Gc<Expr>>),
527-
ExprWhile(Gc<Expr>, P<Block>),
527+
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
528+
ExprWhile(Gc<Expr>, P<Block>, Option<Ident>),
528529
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
529530
ExprForLoop(Gc<Pat>, Gc<Expr>, P<Block>, Option<Ident>),
530531
// Conditionless loop (can be exited with break, cont, or ret)

src/libsyntax/ext/expand.rs

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
6666
}
6767
}
6868

69+
ast::ExprWhile(cond, body, opt_ident) => {
70+
let cond = fld.fold_expr(cond);
71+
let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
72+
fld.cx.expr(e.span, ast::ExprWhile(cond, body, opt_ident))
73+
}
74+
6975
ast::ExprLoop(loop_block, opt_ident) => {
7076
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
7177
fld.cx.expr(e.span, ast::ExprLoop(loop_block, opt_ident))

src/libsyntax/fold.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -1132,18 +1132,20 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
11321132
folder.fold_block(tr),
11331133
fl.map(|x| folder.fold_expr(x)))
11341134
}
1135-
ExprWhile(cond, body) => {
1136-
ExprWhile(folder.fold_expr(cond), folder.fold_block(body))
1135+
ExprWhile(cond, body, opt_ident) => {
1136+
ExprWhile(folder.fold_expr(cond),
1137+
folder.fold_block(body),
1138+
opt_ident.map(|i| folder.fold_ident(i)))
11371139
}
1138-
ExprForLoop(pat, iter, body, ref maybe_ident) => {
1140+
ExprForLoop(pat, iter, body, ref opt_ident) => {
11391141
ExprForLoop(folder.fold_pat(pat),
11401142
folder.fold_expr(iter),
11411143
folder.fold_block(body),
1142-
maybe_ident.map(|i| folder.fold_ident(i)))
1144+
opt_ident.map(|i| folder.fold_ident(i)))
11431145
}
11441146
ExprLoop(body, opt_ident) => {
11451147
ExprLoop(folder.fold_block(body),
1146-
opt_ident.map(|x| folder.fold_ident(x)))
1148+
opt_ident.map(|i| folder.fold_ident(i)))
11471149
}
11481150
ExprMatch(expr, ref arms) => {
11491151
ExprMatch(folder.fold_expr(expr),

src/libsyntax/parse/parser.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -2094,19 +2094,22 @@ impl<'a> Parser<'a> {
20942094
return self.parse_for_expr(None);
20952095
}
20962096
if self.eat_keyword(keywords::While) {
2097-
return self.parse_while_expr();
2097+
return self.parse_while_expr(None);
20982098
}
20992099
if Parser::token_is_lifetime(&self.token) {
21002100
let lifetime = self.get_lifetime();
21012101
self.bump();
21022102
self.expect(&token::COLON);
2103+
if self.eat_keyword(keywords::While) {
2104+
return self.parse_while_expr(Some(lifetime))
2105+
}
21032106
if self.eat_keyword(keywords::For) {
21042107
return self.parse_for_expr(Some(lifetime))
21052108
}
21062109
if self.eat_keyword(keywords::Loop) {
21072110
return self.parse_loop_expr(Some(lifetime))
21082111
}
2109-
self.fatal("expected `for` or `loop` after a label")
2112+
self.fatal("expected `while`, `for`, or `loop` after a label")
21102113
}
21112114
if self.eat_keyword(keywords::Loop) {
21122115
return self.parse_loop_expr(None);
@@ -2762,12 +2765,12 @@ impl<'a> Parser<'a> {
27622765
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
27632766
}
27642767

2765-
pub fn parse_while_expr(&mut self) -> Gc<Expr> {
2768+
pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> Gc<Expr> {
27662769
let lo = self.last_span.lo;
27672770
let cond = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
27682771
let body = self.parse_block();
27692772
let hi = body.span.hi;
2770-
return self.mk_expr(lo, hi, ExprWhile(cond, body));
2773+
return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident));
27712774
}
27722775

27732776
pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> Gc<Expr> {

src/libsyntax/print/pprust.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -1438,7 +1438,11 @@ impl<'a> State<'a> {
14381438
ast::ExprIf(ref test, ref blk, elseopt) => {
14391439
try!(self.print_if(&**test, &**blk, elseopt, false));
14401440
}
1441-
ast::ExprWhile(ref test, ref blk) => {
1441+
ast::ExprWhile(ref test, ref blk, opt_ident) => {
1442+
for ident in opt_ident.iter() {
1443+
try!(self.print_ident(*ident));
1444+
try!(self.word_space(":"));
1445+
}
14421446
try!(self.head("while"));
14431447
try!(self.print_expr(&**test));
14441448
try!(space(&mut self.s));

src/libsyntax/visit.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -775,7 +775,7 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
775775
visitor.visit_block(&**if_block, env.clone());
776776
walk_expr_opt(visitor, optional_else, env.clone())
777777
}
778-
ExprWhile(ref subexpression, ref block) => {
778+
ExprWhile(ref subexpression, ref block, _) => {
779779
visitor.visit_expr(&**subexpression, env.clone());
780780
visitor.visit_block(&**block, env.clone())
781781
}

src/test/run-pass/hygienic-labels-in-let.rs

+17
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ macro_rules! loop_x {
1919
}
2020
}
2121

22+
macro_rules! while_true {
23+
($e: expr) => {
24+
// $e shouldn't be able to interact with this 'x
25+
'x: while 1i + 1 == 2 { $e }
26+
}
27+
}
28+
2229
macro_rules! run_once {
2330
($e: expr) => {
2431
// ditto
@@ -49,6 +56,16 @@ pub fn main() {
4956
};
5057
assert_eq!(k, 1i);
5158

59+
let l: int = {
60+
'x: for _ in range(0i, 1) {
61+
// ditto
62+
while_true!(break 'x);
63+
i += 1;
64+
}
65+
i + 1
66+
};
67+
assert_eq!(l, 1i);
68+
5269
let n: int = {
5370
'x: for _ in range(0i, 1) {
5471
// ditto

src/test/run-pass/hygienic-labels.rs

+12
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ macro_rules! run_once {
2424
}
2525
}
2626

27+
macro_rules! while_x {
28+
($e: expr) => {
29+
// ditto
30+
'x: while 1i + 1 == 2 { $e }
31+
}
32+
}
33+
2734
pub fn main() {
2835
'x: for _ in range(0i, 1) {
2936
// this 'x should refer to the outer loop, lexically
@@ -37,6 +44,11 @@ pub fn main() {
3744
fail!("break doesn't act hygienically inside infinite loop");
3845
}
3946

47+
'x: while 1i + 1 == 2 {
48+
while_x!(break 'x);
49+
fail!("break doesn't act hygienically inside infinite while loop");
50+
}
51+
4052
'x: for _ in range(0i, 1) {
4153
// ditto
4254
run_once!(continue 'x);

src/test/run-pass/labeled-break.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -20,4 +20,10 @@ pub fn main() {
2020
break 'bar;
2121
}
2222
}
23+
24+
'foobar: while 1i + 1 == 2 {
25+
loop {
26+
break 'foobar;
27+
}
28+
}
2329
}

src/test/run-pass/while-label.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
pub fn main() {
13+
let mut i = 100i;
14+
'w: while 1i + 1 == 2 {
15+
i -= 1;
16+
if i == 95 {
17+
break 'w;
18+
fail!("Should have broken out of loop");
19+
}
20+
}
21+
assert_eq!(i, 95);
22+
}

0 commit comments

Comments
 (0)