diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index a132575b0c673..f81d18694136e 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 9c05f18762df1..2d82314f86ac2 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 ef05b57fb8f7d..3c967fa6d8317 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -63,7 +63,7 @@ use syntax::errors; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::print::pprust; use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned}; -use syntax::source_map::CompilerDesugaringKind::IfTemporary; +use syntax::source_map::CompilerDesugaringKind::CondTemporary; use syntax::std_inject; use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; @@ -4394,21 +4394,18 @@ impl<'a> LoweringContext<'a> { let then_blk = self.lower_block(then, false); let then_expr = self.expr_block(then_blk, ThinVec::new()); let (then_pats, scrutinee, desugar) = match cond.node { - // ` => ` + // ` => `: ExprKind::Let(ref pats, ref scrutinee) => { let scrutinee = self.lower_expr(scrutinee); let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause }; (pats, scrutinee, desugar) } - // `true => then`: + // `true => `: _ => { // Lower condition: let cond = self.lower_expr(cond); - // Wrap in a construct equivalent to `{ let _t = $cond; _t }` - // to preserve drop semantics since `if cond { ... }` - // don't let temporaries live outside of `cond`. - let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None); + let span_block = self.mark_span_with_reason(CondTemporary, cond.span, None); // 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`. @@ -4424,69 +4421,78 @@ impl<'a> LoweringContext<'a> { hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar) } // FIXME(#53667): handle lowering of && and parens. - ExprKind::While(ref cond, ref body, opt_label) => { - // Desugar `ExprWhileLet` - // from: `[opt_ident]: while let = ` - if let ExprKind::Let(ref pats, ref sub_expr) = cond.node { - // to: - // - // [opt_ident]: loop { - // match { - // => , - // _ => break - // } - // } - - // Note that the block AND the condition are evaluated in the loop scope. - // This is done to allow `break` from inside the condition of the loop. - let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| { - ( - this.lower_block(body, false), - this.expr_break(e.span, ThinVec::new()), - this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), - ) - }); + ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| { + // Note that the block AND the condition are evaluated in the loop scope. + // This is done to allow `break` from inside the condition of the loop. - // ` => ` - let pat_arm = { - let body_expr = P(self.expr_block(body, ThinVec::new())); - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); - self.arm(pats, body_expr) - }; + // `_ => break`: + let else_arm = { + let else_pat = this.pat_wild(e.span); + let else_expr = this.expr_break(e.span, ThinVec::new()); + this.arm(hir_vec![else_pat], else_expr) + }; - // `_ => break` - let break_arm = { - let pat_under = self.pat_wild(e.span); - self.arm(hir_vec![pat_under], break_expr) - }; + // Handle then + scrutinee: + let then_blk = this.lower_block(body, false); + let then_expr = this.expr_block(then_blk, ThinVec::new()); + let (then_pats, scrutinee, desugar, source) = match cond.node { + ExprKind::Let(ref pats, ref scrutinee) => { + // to: + // + // [opt_ident]: loop { + // match { + // => , + // _ => break + // } + // } + let scrutinee = this.with_loop_condition_scope(|t| t.lower_expr(scrutinee)); + let pats = pats.iter().map(|pat| this.lower_pat(pat)).collect(); + let desugar = hir::MatchSource::WhileLetDesugar; + (pats, scrutinee, desugar, hir::LoopSource::WhileLet) + } + _ => { + // We desugar: `'label: while $cond $body` into: + // + // ``` + // 'label: loop { + // match DropTemps($cond) { + // true => $body, + // _ => break, + // } + // } + // ``` - // `match { ... }` - let arms = hir_vec![pat_arm, break_arm]; - let match_expr = self.expr( - sub_expr.span, - hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar), - ThinVec::new(), - ); + // Lower condition: + let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond)); + let span_block = this.mark_span_with_reason(CondTemporary, cond.span, None); + // Wrap in a construct equivalent to `{ let _t = $cond; _t }` + // to preserve drop semantics since `while cond { ... }` does not + // let temporaries live outside of `cond`. + let cond = this.expr_drop_temps(span_block, P(cond), ThinVec::new()); - // `[opt_ident]: loop { ... }` - let loop_block = P(self.block_expr(P(match_expr))); - let loop_expr = hir::ExprKind::Loop( - loop_block, - self.lower_label(opt_label), - hir::LoopSource::WhileLet, - ); - // Add attributes to the outer returned expr node. - 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), - this.lower_label(opt_label), - ) - }) - } - } + let desugar = hir::MatchSource::WhileDesugar; + // `true => `: + let pats = hir_vec![this.pat_bool(e.span, true)]; + (pats, cond, desugar, hir::LoopSource::While) + } + }; + let then_arm = this.arm(then_pats, P(then_expr)); + + // `match { ... }` + let match_expr = this.expr_match( + scrutinee.span, + P(scrutinee), + hir_vec![then_arm, else_arm], + desugar, + ); + + // `[opt_ident]: loop { ... }` + hir::ExprKind::Loop( + P(this.block_expr(P(match_expr))), + this.lower_label(opt_label), + source + ) + }), ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { hir::ExprKind::Loop( this.lower_block(body, false), diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 037d04a5d8ed3..196b4f64af1a4 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -735,7 +735,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 bfbd8398f99f3..7b760a872387e 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