diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index a132575b0c6..f81d1869413 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -165,48 +165,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(expr.hir_id.local_id, &[blk_exit]) } - hir::ExprKind::While(ref cond, ref body, _) => { - // - // [pred] - // | - // v 1 - // [loopback] <--+ 5 - // | | - // v 2 | - // +-----[cond] | - // | | | - // | v 4 | - // | [body] -----+ - // v 3 - // [expr] - // - // Note that `break` and `continue` statements - // may cause additional edges. - - let loopback = self.add_dummy_node(&[pred]); // 1 - - // Create expr_exit without pred (cond_exit) - let expr_exit = self.add_ast_node(expr.hir_id.local_id, &[]); // 3 - - // The LoopScope needs to be on the loop_scopes stack while evaluating the - // condition and the body of the loop (both can break out of the loop) - self.loop_scopes.push(LoopScope { - loop_id: expr.hir_id.local_id, - continue_index: loopback, - break_index: expr_exit - }); - - let cond_exit = self.expr(&cond, loopback); // 2 - - // Add pred (cond_exit) to expr_exit - self.add_contained_edge(cond_exit, expr_exit); - - let body_exit = self.block(&body, cond_exit); // 4 - self.add_contained_edge(body_exit, loopback); // 5 - self.loop_scopes.pop(); - expr_exit - } - hir::ExprKind::Loop(ref body, _, _) => { // // [pred] diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9c05f18762d..2d82314f86a 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1026,11 +1026,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprKind::DropTemps(ref subexpression) => { visitor.visit_expr(subexpression); } - ExprKind::While(ref subexpression, ref block, ref opt_label) => { - walk_list!(visitor, visit_label, opt_label); - visitor.visit_expr(subexpression); - visitor.visit_block(block); - } ExprKind::Loop(ref block, ref opt_label, _) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ef05b57fb8f..011808a7ff9 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4461,11 +4461,11 @@ impl<'a> LoweringContext<'a> { }; // `match { ... }` - let arms = hir_vec![pat_arm, break_arm]; - let match_expr = self.expr( + let match_expr = self.expr_match( sub_expr.span, - hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar), - ThinVec::new(), + sub_expr, + hir_vec![pat_arm, break_arm], + hir::MatchSource::WhileLetDesugar, ); // `[opt_ident]: loop { ... }` @@ -4479,10 +4479,46 @@ impl<'a> LoweringContext<'a> { loop_expr } else { self.with_loop_scope(e.id, |this| { - hir::ExprKind::While( - this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), - this.lower_block(body, false), + // We desugar: `'label: while $cond $body` into: + // + // ``` + // 'label: loop { + // match DropTemps($cond) { + // true => $block, + // _ => break, + // } + // } + // ``` + + // `true => then`: + let then_pat = this.pat_bool(e.span, true); + let then_blk = this.lower_block(body, false); + let then_expr = this.expr_block(then_blk, ThinVec::new()); + let then_arm = this.arm(hir_vec![then_pat], P(then_expr)); + + // `_ => break`: + let else_pat = this.pat_wild(e.span); + let else_expr = this.expr_break(e.span, ThinVec::new()); + let else_arm = this.arm(hir_vec![else_pat], else_expr); + + // Lower condition: + let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond)); + // Wrap in a construct equivalent to `{ let _t = $cond; _t }` + // to preserve drop semantics since `if cond { ... }` does not + // let temporaries live outside of `cond`. + let cond = this.expr_drop_temps(cond.span, P(cond), ThinVec::new()); + + let match_expr = this.expr_match( + cond.span, + P(cond), + vec![then_arm, else_arm].into(), + hir::MatchSource::WhileDesugar, + ); + + hir::ExprKind::Loop( + P(this.block_expr(P(match_expr))), this.lower_label(opt_label), + hir::LoopSource::While, ) }) } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 79b343ecfe2..63f60d0ab95 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -731,7 +731,7 @@ impl<'hir> Map<'hir> { match *node { Node::Expr(ref expr) => { match expr.node { - ExprKind::While(..) | ExprKind::Loop(..) | ExprKind::Ret(..) => true, + ExprKind::Loop(..) | ExprKind::Ret(..) => true, _ => false, } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index bfbd8398f99..7b760a87238 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1405,7 +1405,6 @@ impl Expr { ExprKind::Lit(_) => ExprPrecedence::Lit, ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, ExprKind::DropTemps(ref expr, ..) => expr.precedence(), - ExprKind::While(..) => ExprPrecedence::While, ExprKind::Loop(..) => ExprPrecedence::Loop, ExprKind::Match(..) => ExprPrecedence::Match, ExprKind::Closure(..) => ExprPrecedence::Closure, @@ -1464,7 +1463,6 @@ impl Expr { ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) | - ExprKind::While(..) | ExprKind::Loop(..) | ExprKind::Assign(..) | ExprKind::InlineAsm(..) | @@ -1532,10 +1530,6 @@ pub enum ExprKind { /// This construct only exists to tweak the drop order in HIR lowering. /// An example of that is the desugaring of `for` loops. DropTemps(P), - /// A while loop, with an optional label - /// - /// I.e., `'label: while expr { }`. - While(P, P, Option