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 {
-                    // `<pat> => <then>`
+                    // `<pat> => <then>`:
                     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 => <then>`:
                     _ => {
                         // 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 <pat> = <sub_expr> <body>`
-                if let ExprKind::Let(ref pats, ref sub_expr) = cond.node {
-                    // to:
-                    //
-                    //   [opt_ident]: loop {
-                    //     match <sub_expr> {
-                    //       <pat> => <body>,
-                    //       _ => 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.
 
-                    // `<pat> => <body>`
-                    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 <sub_expr> {
+                        //       <pat> => <body>,
+                        //       _ => 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 <sub_expr> { ... }`
-                    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 => <then>`:
+                        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 <scrutinee> { ... }`
+                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 79b343ecfe29a..63f60d0ab9528 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 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<Expr>),
-    /// A while loop, with an optional label
-    ///
-    /// I.e., `'label: while expr { <block> }`.
-    While(P<Expr>, P<Block>, Option<Label>),
     /// A conditionless loop (can be exited with `break`, `continue`, or `return`).
     ///
     /// I.e., `'label: loop { <block> }`.
@@ -1653,6 +1647,8 @@ pub enum MatchSource {
     IfLetDesugar {
         contains_else_clause: bool,
     },
+    /// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`).
+    WhileDesugar,
     /// A `while let _ = _ { .. }` (which was desugared to a
     /// `loop { match _ { .. } }`).
     WhileLetDesugar,
@@ -1669,12 +1665,25 @@ pub enum MatchSource {
 pub enum LoopSource {
     /// A `loop { .. }` loop.
     Loop,
+    /// A `while _ { .. }` loop.
+    While,
     /// A `while let _ = _ { .. }` loop.
     WhileLet,
     /// A `for _ in _ { .. }` loop.
     ForLoop,
 }
 
+impl LoopSource {
+    pub fn name(self) -> &'static str {
+        match self {
+            LoopSource::Loop => "loop",
+            LoopSource::While => "while",
+            LoopSource::WhileLet => "while let",
+            LoopSource::ForLoop => "for",
+        }
+    }
+}
+
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum LoopIdError {
     OutsideLoopScope,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 573b9add133ea..367e4dba042cd 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1299,16 +1299,6 @@ impl<'a> State<'a> {
                 // Print `}`:
                 self.bclose_maybe_open(expr.span, indent_unit, true);
             }
-            hir::ExprKind::While(ref test, ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("while");
-                self.print_expr_as_cond(&test);
-                self.s.space();
-                self.print_block(&blk);
-            }
             hir::ExprKind::Loop(ref blk, opt_label, _) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident);
@@ -2289,7 +2279,6 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool {
     match e.node {
         hir::ExprKind::Match(..) |
         hir::ExprKind::Block(..) |
-        hir::ExprKind::While(..) |
         hir::ExprKind::Loop(..) => false,
         _ => true,
     }
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 9430661f75ab7..1db18d3028258 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -415,7 +415,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
 });
 
 impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
-    IfTemporary,
+    CondTemporary,
     Async,
     Await,
     QuestionMark,
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 77094604edacf..2448db032b965 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -487,11 +487,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 self.walk_block(&blk);
             }
 
-            hir::ExprKind::While(ref cond_expr, ref blk, _) => {
-                self.consume_expr(&cond_expr);
-                self.walk_block(&blk);
-            }
-
             hir::ExprKind::Unary(_, ref lhs) => {
                 self.consume_expr(&lhs);
             }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index c4d60b676b279..daf0d8103a2c0 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -93,7 +93,6 @@
 //!   It is the responsibility of typeck to ensure that there are no
 //!   `return` expressions in a function declared as diverging.
 
-use self::LoopKind::*;
 use self::LiveNodeKind::*;
 use self::VarKind::*;
 
@@ -120,14 +119,6 @@ use crate::hir::{Expr, HirId};
 use crate::hir::def_id::DefId;
 use crate::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 
-/// For use with `propagate_through_loop`.
-enum LoopKind<'a> {
-    /// An endless `loop` loop.
-    LoopLoop,
-    /// A `while` loop, with the given expression as condition.
-    WhileLoop(&'a Expr),
-}
-
 #[derive(Copy, Clone, PartialEq)]
 struct Variable(u32);
 
@@ -517,7 +508,6 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr) {
 
       // live nodes required for interesting control flow:
       hir::ExprKind::Match(..) |
-      hir::ExprKind::While(..) |
       hir::ExprKind::Loop(..) => {
         ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
@@ -1055,14 +1045,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 })
             }
 
-            hir::ExprKind::While(ref cond, ref blk, _) => {
-                self.propagate_through_loop(expr, WhileLoop(&cond), &blk, succ)
-            }
-
             // Note that labels have been resolved, so we don't need to look
             // at the label ident
             hir::ExprKind::Loop(ref blk, _, _) => {
-                self.propagate_through_loop(expr, LoopLoop, &blk, succ)
+                self.propagate_through_loop(expr, &blk, succ)
             }
 
             hir::ExprKind::Match(ref e, ref arms, _) => {
@@ -1353,74 +1339,44 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         }
     }
 
-    fn propagate_through_loop(&mut self,
-                              expr: &Expr,
-                              kind: LoopKind<'_>,
-                              body: &hir::Block,
-                              succ: LiveNode)
-                              -> LiveNode {
+    fn propagate_through_loop(
+        &mut self,
+        expr: &Expr,
+        body: &hir::Block,
+        succ: LiveNode
+    ) -> LiveNode {
         /*
-
         We model control flow like this:
 
-              (cond) <--+
-                |       |
-                v       |
-          +-- (expr)    |
-          |     |       |
-          |     v       |
-          |   (body) ---+
-          |
-          |
-          v
-        (succ)
+              (expr) <-+
+                |      |
+                v      |
+              (body) --+
 
+        Note that a `continue` expression targeting the `loop` will have a successor of `expr`.
+        Meanwhile, a `break` expression will have a successor of `succ`.
         */
 
-
         // first iteration:
         let mut first_merge = true;
         let ln = self.live_node(expr.hir_id, expr.span);
         self.init_empty(ln, succ);
-        match kind {
-            LoopLoop => {}
-            _ => {
-                // If this is not a `loop` loop, then it's possible we bypass
-                // the body altogether. Otherwise, the only way is via a `break`
-                // in the loop body.
-                self.merge_from_succ(ln, succ, first_merge);
-                first_merge = false;
-            }
-        }
         debug!("propagate_through_loop: using id for loop body {} {}",
                expr.hir_id, self.ir.tcx.hir().hir_to_pretty_string(body.hir_id));
 
         self.break_ln.insert(expr.hir_id, succ);
 
-        let cond_ln = match kind {
-            LoopLoop => ln,
-            WhileLoop(ref cond) => self.propagate_through_expr(&cond, ln),
-        };
-
-        self.cont_ln.insert(expr.hir_id, cond_ln);
+        self.cont_ln.insert(expr.hir_id, ln);
 
-        let body_ln = self.propagate_through_block(body, cond_ln);
+        let body_ln = self.propagate_through_block(body, ln);
 
         // repeat until fixed point is reached:
         while self.merge_from_succ(ln, body_ln, first_merge) {
             first_merge = false;
-
-            let new_cond_ln = match kind {
-                LoopLoop => ln,
-                WhileLoop(ref cond) => {
-                    self.propagate_through_expr(&cond, ln)
-                }
-            };
-            assert_eq!(cond_ln, new_cond_ln);
-            assert_eq!(body_ln, self.propagate_through_block(body, cond_ln));
+            assert_eq!(body_ln, self.propagate_through_block(body, ln));
         }
 
-        cond_ln
+        ln
     }
 }
 
@@ -1520,7 +1476,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
 
         // no correctness conditions related to liveness
         hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) |
-        hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) |
+        hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) |
         hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
         hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
         hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) | hir::ExprKind::Unary(..) |
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 088c862dcb879..66d8a2cc1115d 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -696,7 +696,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) |
             hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) |
             hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) |
-            hir::ExprKind::Binary(..) | hir::ExprKind::While(..) |
+            hir::ExprKind::Binary(..) |
             hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) |
             hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) |
             hir::ExprKind::Continue(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 26ac1275bb992..88c19715811d7 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -915,11 +915,6 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
                 terminating(body.hir_id.local_id);
             }
 
-            hir::ExprKind::While(ref expr, ref body, _) => {
-                terminating(expr.hir_id.local_id);
-                terminating(body.hir_id.local_id);
-            }
-
             hir::ExprKind::DropTemps(ref expr) => {
                 // `DropTemps(expr)` does not denote a conditional scope.
                 // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 0839a2b435ae8..3221b41ee1d44 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -1201,11 +1201,10 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
     }
 
     fn expression_label(ex: &hir::Expr) -> Option<ast::Ident> {
-        match ex.node {
-            hir::ExprKind::While(.., Some(label)) | hir::ExprKind::Loop(_, Some(label), _) => {
-                Some(label.ident)
-            }
-            _ => None,
+        if let hir::ExprKind::Loop(_, Some(label), _) = ex.node {
+            Some(label.ident)
+        } else {
+            None
         }
     }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 267b09bae35e4..c9605445c2401 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -64,22 +64,30 @@ declare_lint! {
 
 declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue {
-    fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) {
-        if let hir::ExprKind::While(ref cond, ..) = e.node {
-            if let hir::ExprKind::Lit(ref lit) = cond.node {
+/// Traverse through any amount of parenthesis and return the first non-parens expression.
+fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
+    while let ast::ExprKind::Paren(sub) = &expr.node {
+        expr = sub;
+    }
+    expr
+}
+
+impl EarlyLintPass for WhileTrue {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
+        if let ast::ExprKind::While(cond, ..) = &e.node {
+            if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).node {
                 if let ast::LitKind::Bool(true) = lit.node {
                     if lit.span.ctxt() == SyntaxContext::empty() {
                         let msg = "denote infinite loops with `loop { ... }`";
-                        let condition_span = cx.tcx.sess.source_map().def_span(e.span);
-                        let mut err = cx.struct_span_lint(WHILE_TRUE, condition_span, msg);
-                        err.span_suggestion_short(
-                            condition_span,
-                            "use `loop`",
-                            "loop".to_owned(),
-                            Applicability::MachineApplicable
-                        );
-                        err.emit();
+                        let condition_span = cx.sess.source_map().def_span(e.span);
+                        cx.struct_span_lint(WHILE_TRUE, condition_span, msg)
+                            .span_suggestion_short(
+                                condition_span,
+                                "use `loop`",
+                                "loop".to_owned(),
+                                Applicability::MachineApplicable
+                            )
+                            .emit();
                     }
                 }
             }
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index fb02782e6d320..2519981fa21b2 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -96,6 +96,7 @@ macro_rules! early_lint_passes {
             EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
             NonCamelCaseTypes: NonCamelCaseTypes,
             DeprecatedAttr: DeprecatedAttr::new(),
+            WhileTrue: WhileTrue,
         ]);
     )
 }
@@ -140,7 +141,6 @@ macro_rules! late_lint_mod_passes {
     ($macro:path, $args:tt) => (
         $macro!($args, [
             HardwiredLints: HardwiredLints,
-            WhileTrue: WhileTrue,
             ImproperCTypes: ImproperCTypes,
             VariantSizeDifferences: VariantSizeDifferences,
             BoxPointers: BoxPointers,
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 0a2ea78bfd7ab..e433da904a678 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -138,19 +138,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 join_block.unit()
             }
-            ExprKind::Loop {
-                condition: opt_cond_expr,
-                body,
-            } => {
-                // [block] --> [loop_block] -/eval. cond./-> [loop_block_end] -1-> [exit_block]
-                //                  ^                               |
-                //                  |                               0
-                //                  |                               |
-                //                  |                               v
-                //           [body_block_end] <-/eval. body/-- [body_block]
-                //
-                // If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
-                //
+            ExprKind::Loop { body } => {
                 // [block]
                 //    |
                 //   [loop_block] -> [body_block] -/eval. body/-> [body_block_end]
@@ -177,33 +165,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     destination.clone(),
                     move |this| {
                         // conduct the test, if necessary
-                        let body_block;
-                        if let Some(cond_expr) = opt_cond_expr {
-                            let cond_expr = this.hir.mirror(cond_expr);
-                            let (true_block, false_block)
-                                = this.test_bool(loop_block, cond_expr, source_info);
-                            body_block = true_block;
-
-                            // if the test is false, there's no `break` to assign `destination`, so
-                            // we have to do it
-                            this.cfg.push_assign_unit(false_block, source_info, destination);
-                            this.cfg.terminate(
-                                false_block,
-                                source_info,
-                                TerminatorKind::Goto { target: exit_block },
-                            );
-                        } else {
-                            body_block = this.cfg.start_new_block();
-                            let diverge_cleanup = this.diverge_cleanup();
-                            this.cfg.terminate(
-                                loop_block,
-                                source_info,
-                                TerminatorKind::FalseUnwind {
-                                    real_target: body_block,
-                                    unwind: Some(diverge_cleanup),
-                                },
-                            )
-                        }
+                        let body_block = this.cfg.start_new_block();
+                        let diverge_cleanup = this.diverge_cleanup();
+                        this.cfg.terminate(
+                            loop_block,
+                            source_info,
+                            TerminatorKind::FalseUnwind {
+                                real_target: body_block,
+                                unwind: Some(diverge_cleanup),
+                            },
+                        );
 
                         // The “return” value of the loop body must always be an unit. We therefore
                         // introduce a unit temporary as the destination for the loop body.
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index e7663ddaa9879..242afcf5abb2e 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -599,15 +599,8 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                 arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
             }
         }
-        hir::ExprKind::While(ref cond, ref body, _) => {
-            ExprKind::Loop {
-                condition: Some(cond.to_ref()),
-                body: block::to_expr_ref(cx, body),
-            }
-        }
         hir::ExprKind::Loop(ref body, _, _) => {
             ExprKind::Loop {
-                condition: None,
                 body: block::to_expr_ref(cx, body),
             }
         }
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 5431a31c4bb2a..0638cb462f73b 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -173,7 +173,6 @@ pub enum ExprKind<'tcx> {
         source: ExprRef<'tcx>,
     },
     Loop {
-        condition: Option<ExprRef<'tcx>>,
         body: ExprRef<'tcx>,
     },
     Match {
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 915ce9f20d07d..d822a26ce591b 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -371,7 +371,8 @@ fn check_arms<'a, 'tcx>(
             match is_useful(cx, &seen, &v, LeaveOutWitness) {
                 NotUseful => {
                     match source {
-                        hir::MatchSource::IfDesugar { .. } => bug!(),
+                        hir::MatchSource::IfDesugar { .. } |
+                        hir::MatchSource::WhileDesugar => bug!(),
                         hir::MatchSource::IfLetDesugar { .. } => {
                             cx.tcx.lint_hir(
                                 lint::builtin::IRREFUTABLE_LET_PATTERNS,
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 616e6974110e6..afe4c78dcfc37 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -12,27 +12,10 @@ use syntax::struct_span_err;
 use syntax_pos::Span;
 use errors::Applicability;
 
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum LoopKind {
-    Loop(hir::LoopSource),
-    WhileLoop,
-}
-
-impl LoopKind {
-    fn name(self) -> &'static str {
-        match self {
-            LoopKind::Loop(hir::LoopSource::Loop) => "loop",
-            LoopKind::Loop(hir::LoopSource::WhileLet) => "while let",
-            LoopKind::Loop(hir::LoopSource::ForLoop) => "for",
-            LoopKind::WhileLoop => "while",
-        }
-    }
-}
-
 #[derive(Clone, Copy, Debug, PartialEq)]
 enum Context {
     Normal,
-    Loop(LoopKind),
+    Loop(hir::LoopSource),
     Closure,
     LabeledBlock,
     AnonConst,
@@ -71,14 +54,8 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
 
     fn visit_expr(&mut self, e: &'hir hir::Expr) {
         match e.node {
-            hir::ExprKind::While(ref e, ref b, _) => {
-                self.with_context(Loop(LoopKind::WhileLoop), |v| {
-                    v.visit_expr(&e);
-                    v.visit_block(&b);
-                });
-            }
             hir::ExprKind::Loop(ref b, _, source) => {
-                self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
+                self.with_context(Loop(source), |v| v.visit_block(&b));
             }
             hir::ExprKind::Closure(_, ref function_decl, b, _, _) => {
                 self.visit_fn_decl(&function_decl);
@@ -117,15 +94,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                         None
                     } else {
                         Some(match self.hir_map.expect_expr(loop_id).node {
-                            hir::ExprKind::While(..) => LoopKind::WhileLoop,
-                            hir::ExprKind::Loop(_, _, source) => LoopKind::Loop(source),
+                            hir::ExprKind::Loop(_, _, source) => source,
                             ref r => span_bug!(e.span,
                                                "break label resolved to a non-loop: {:?}", r),
                         })
                     };
                     match loop_kind {
                         None |
-                        Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
+                        Some(hir::LoopSource::Loop) => (),
                         Some(kind) => {
                             struct_span_err!(self.sess, e.span, E0571,
                                              "`break` with value from a `{}` loop",
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index daa64478bca83..8ba3a25e3947c 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -520,13 +520,6 @@ fn check_expr_kind<'a, 'tcx>(
             NotPromotable
         }
 
-        // Loops (not very meaningful in constants).
-        hir::ExprKind::While(ref expr, ref box_block, ref _option_label) => {
-            let _ = v.check_expr(expr);
-            let _ = v.check_block(box_block);
-            NotPromotable
-        }
-
         hir::ExprKind::Loop(ref box_block, ref _option_label, ref _loop_source) => {
             let _ = v.check_block(box_block);
             NotPromotable
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index eeed5be867807..d24f92a6fafef 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -180,7 +180,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // then that's equivalent to there existing a LUB.
                 if let Some(mut err) = self.demand_suptype_diag(pat.span, expected, pat_ty) {
                     err.emit_unless(discrim_span
-                        .filter(|&s| s.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary))
+                        .filter(|&s| {
+                            // In the case of `if`- and `while`-expressions we've already checked
+                            // that `scrutinee: bool`. We know that the pattern is `true`,
+                            // so an error here would be a duplicate and from the wrong POV.
+                            s.is_compiler_desugaring(CompilerDesugaringKind::CondTemporary)
+                        })
                         .is_some());
                 }
 
@@ -624,14 +629,15 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         let tcx = self.tcx;
 
         use hir::MatchSource::*;
-        let (source_if, if_no_else, if_desugar) = match match_src {
+        let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
             IfDesugar { contains_else_clause } => (true, !contains_else_clause, true),
             IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false),
+            WhileDesugar => (false, false, true),
             _ => (false, false, false),
         };
 
         // Type check the descriminant and get its type.
-        let discrim_ty = if if_desugar {
+        let discrim_ty = if force_scrutinee_bool {
             // Here we want to ensure:
             //
             // 1. That default match bindings are *not* accepted in the condition of an
@@ -651,7 +657,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             return tcx.types.never;
         }
 
-        self.warn_arms_when_scrutinee_diverges(arms, source_if);
+        self.warn_arms_when_scrutinee_diverges(arms, match_src);
 
         // Otherwise, we have to union together the types that the
         // arms produce and so forth.
@@ -726,7 +732,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             if source_if {
                 let then_expr = &arms[0].body;
                 match (i, if_no_else) {
-                    (0, _) => coercion.coerce(self, &self.misc(span), then_expr, arm_ty),
+                    (0, _) => coercion.coerce(self, &self.misc(span), &arm.body, arm_ty),
                     (_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion),
                     (_, _) => {
                         let then_ty = prior_arm_ty.unwrap();
@@ -771,9 +777,14 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
 
     /// When the previously checked expression (the scrutinee) diverges,
     /// warn the user about the match arms being unreachable.
-    fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm], source_if: bool) {
+    fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm], source: hir::MatchSource) {
         if self.diverges.get().always() {
-            let msg = if source_if { "block in `if` expression" } else { "arm" };
+            use hir::MatchSource::*;
+            let msg = match source {
+                IfDesugar { .. } | IfLetDesugar { .. } => "block in `if` expression",
+                WhileDesugar { .. } | WhileLetDesugar { .. } => "block in `while` expression",
+                _ => "arm",
+            };
             for arm in arms {
                 self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg);
             }
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 603726dfe238c..b02a7c21027d4 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -159,11 +159,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Warn for non-block expressions with diverging children.
         match expr.node {
-            ExprKind::Block(..) |
-            ExprKind::Loop(..) | ExprKind::While(..) |
-            ExprKind::Match(..) => {}
-
-            _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression")
+            ExprKind::Block(..) | ExprKind::Loop(..) | ExprKind::Match(..) => {},
+            _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"),
         }
 
         // Any expression that produces a value of type `!` must have diverged
@@ -245,9 +242,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Assign(ref lhs, ref rhs) => {
                 self.check_expr_assign(expr, expected, lhs, rhs)
             }
-            ExprKind::While(ref cond, ref body, _) => {
-                self.check_expr_while(cond, body, expr)
-            }
             ExprKind::Loop(ref body, _, source) => {
                 self.check_expr_loop(body, source, expected, expr)
             }
@@ -702,36 +696,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_expr_while(
-        &self,
-        cond: &'tcx hir::Expr,
-        body: &'tcx hir::Block,
-        expr: &'tcx hir::Expr
-    ) -> Ty<'tcx> {
-        let ctxt = BreakableCtxt {
-            // Cannot use break with a value from a while loop.
-            coerce: None,
-            may_break: false, // Will get updated if/when we find a `break`.
-        };
-
-        let (ctxt, ()) = self.with_breakable_ctxt(expr.hir_id, ctxt, || {
-            self.check_expr_has_type_or_error(&cond, self.tcx.types.bool);
-            let cond_diverging = self.diverges.get();
-            self.check_block_no_value(&body);
-
-            // We may never reach the body so it diverging means nothing.
-            self.diverges.set(cond_diverging);
-        });
-
-        if ctxt.may_break {
-            // No way to know whether it's diverging because
-            // of a `break` or an outer `break` or `return`.
-            self.diverges.set(Diverges::Maybe);
-        }
-
-        self.tcx.mk_unit()
-    }
-
     fn check_expr_loop(
         &self,
         body: &'tcx hir::Block,
@@ -746,6 +710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Some(CoerceMany::new(coerce_to))
             }
 
+            hir::LoopSource::While |
             hir::LoopSource::WhileLet |
             hir::LoopSource::ForLoop => {
                 None
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index efe9079e19e4b..3bfb3477d4774 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2161,10 +2161,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// function is unreachable, and there hasn't been another warning.
     fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
         if self.diverges.get() == Diverges::Always &&
-            // If span arose from a desugaring of `if` then it is the condition itself,
-            // which diverges, that we are about to lint on. This gives suboptimal diagnostics
-            // and so we stop here and allow the block of the `if`-expression to be linted instead.
-            !span.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary) {
+            // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
+            // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
+            // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
+            !span.is_compiler_desugaring(CompilerDesugaringKind::CondTemporary) {
             self.diverges.set(Diverges::WarnedAlways);
 
             debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
@@ -3865,7 +3865,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             match expression.node {
                 ExprKind::Call(..) |
                 ExprKind::MethodCall(..) |
-                ExprKind::While(..) |
                 ExprKind::Loop(..) |
                 ExprKind::Match(..) |
                 ExprKind::Block(..) => {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index c66d746d6e029..f9ebe762e522f 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -685,16 +685,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
                 self.set_repeating_scope(repeating_scope);
             }
 
-            hir::ExprKind::While(ref cond, ref body, _) => {
-                let repeating_scope = self.set_repeating_scope(cond.hir_id);
-                self.visit_expr(&cond);
-
-                self.set_repeating_scope(body.hir_id);
-                self.visit_block(&body);
-
-                self.set_repeating_scope(repeating_scope);
-            }
-
             hir::ExprKind::Ret(Some(ref ret_expr)) => {
                 let call_site_scope = self.call_site_scope;
                 debug!(
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 4dbd4ccda910a..a6c8c76cf23f7 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -723,7 +723,8 @@ pub enum CompilerDesugaringKind {
     /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`.
     /// However, we do not want to blame `c` for unreachability but rather say that `i`
     /// is unreachable. This desugaring kind allows us to avoid blaming `c`.
-    IfTemporary,
+    /// This also applies to `while` loops.
+    CondTemporary,
     QuestionMark,
     TryBlock,
     /// Desugaring of an `impl Trait` in return type position
@@ -738,7 +739,7 @@ pub enum CompilerDesugaringKind {
 impl CompilerDesugaringKind {
     pub fn name(self) -> Symbol {
         Symbol::intern(match self {
-            CompilerDesugaringKind::IfTemporary => "if",
+            CompilerDesugaringKind::CondTemporary => "if and while condition",
             CompilerDesugaringKind::Async => "async",
             CompilerDesugaringKind::Await => "await",
             CompilerDesugaringKind::QuestionMark => "?",
diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs
index 0d6906086e9b1..a993d811d327f 100644
--- a/src/test/compile-fail/issue-52443.rs
+++ b/src/test/compile-fail/issue-52443.rs
@@ -2,6 +2,7 @@ fn main() {
     [(); & { loop { continue } } ]; //~ ERROR mismatched types
     [(); loop { break }]; //~ ERROR mismatched types
     [(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type
+    //~^ WARN denote infinite loops with
     [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
     //~^ ERROR constant contains unimplemented expression type
     //~| ERROR constant contains unimplemented expression type
diff --git a/src/test/incremental/hashes/while_let_loops.rs b/src/test/incremental/hashes/while_let_loops.rs
index af2066b90f1d8..39b28ec190639 100644
--- a/src/test/incremental/hashes/while_let_loops.rs
+++ b/src/test/incremental/hashes/while_let_loops.rs
@@ -141,7 +141,7 @@ pub fn change_break_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_break_label() {
     let mut _x = 0;
@@ -191,7 +191,7 @@ pub fn change_continue_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_label() {
     let mut _x = 0;
diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs
index d8ec76d76aa31..0607218546950 100644
--- a/src/test/incremental/hashes/while_loops.rs
+++ b/src/test/incremental/hashes/while_loops.rs
@@ -191,7 +191,7 @@ pub fn change_continue_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
+#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_label() {
     let mut _x = 0;
diff --git a/src/test/mir-opt/while-storage.rs b/src/test/mir-opt/while-storage.rs
index a486bd49a77d0..86c3f79d3a706 100644
--- a/src/test/mir-opt/while-storage.rs
+++ b/src/test/mir-opt/while-storage.rs
@@ -24,36 +24,33 @@ fn main() {
 //     StorageLive(_2);
 //     StorageLive(_3);
 //     _3 = _1;
-//     _2 = const get_bool(move _3) -> bb2;
+//     _2 = const get_bool(move _3) -> bb1;
 // }
 // bb1: {
-//     return;
+//     StorageDead(_3);
+//     switchInt(_2) -> [false: bb6, otherwise: bb2];
 // }
 // bb2: {
-//     StorageDead(_3);
-//     switchInt(move _2) -> [false: bb4, otherwise: bb3];
+//      StorageLive(_4);
+//      StorageLive(_5);
+//      _5 = _1;
+//      _4 = const get_bool(move _5) -> bb3;
 // }
 // bb3: {
-//     StorageDead(_2);
-//     StorageLive(_4);
-//     StorageLive(_5);
-//     _5 = _1;
-//     _4 = const get_bool(move _5) -> bb5;
+//      StorageDead(_5);
+//      switchInt(_4) -> [false: bb4, otherwise: bb5];
 // }
 // bb4: {
-//     StorageDead(_2);
-//     goto -> bb1;
-// }
-// bb5: {
-//     StorageDead(_5);
-//     switchInt(_4) -> [false: bb6, otherwise: bb7];
-// }
-// bb6: {
-//     StorageDead(_4);
-//     goto -> bb0;
-// }
-// bb7: {
-//     StorageDead(_4);
-//     goto -> bb1;
-// }
+//      StorageDead(_4);
+//      StorageDead(_2);
+//      goto -> bb0;
+// }
+//  bb5: {
+//      StorageDead(_4);
+//      goto -> bb6;
+//  }
+//  bb6: {
+//      StorageDead(_2);
+//      return;
+//  }
 // END rustc.while_loop.PreCodegen.after.mir
diff --git a/src/test/ui/block-result/block-must-not-have-result-while.rs b/src/test/ui/block-result/block-must-not-have-result-while.rs
index 96597631396df..108b9bc9e9b29 100644
--- a/src/test/ui/block-result/block-must-not-have-result-while.rs
+++ b/src/test/ui/block-result/block-must-not-have-result-while.rs
@@ -1,5 +1,5 @@
 fn main() {
-    while true {
+    while true { //~ WARN denote infinite loops with
         true //~  ERROR mismatched types
              //~| expected type `()`
              //~| found type `bool`
diff --git a/src/test/ui/block-result/block-must-not-have-result-while.stderr b/src/test/ui/block-result/block-must-not-have-result-while.stderr
index 302d2972f7de1..c41afcc9121c6 100644
--- a/src/test/ui/block-result/block-must-not-have-result-while.stderr
+++ b/src/test/ui/block-result/block-must-not-have-result-while.stderr
@@ -1,3 +1,11 @@
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/block-must-not-have-result-while.rs:2:5
+   |
+LL |     while true {
+   |     ^^^^^^^^^^ help: use `loop`
+   |
+   = note: #[warn(while_true)] on by default
+
 error[E0308]: mismatched types
   --> $DIR/block-must-not-have-result-while.rs:3:9
    |
diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.rs b/src/test/ui/borrowck/mut-borrow-in-loop.rs
index 09f3e4f9b76d8..22667906e12d6 100644
--- a/src/test/ui/borrowck/mut-borrow-in-loop.rs
+++ b/src/test/ui/borrowck/mut-borrow-in-loop.rs
@@ -12,7 +12,7 @@ impl<'a, T : 'a> FuncWrapper<'a, T> {
     }
 
     fn in_while(self, arg : &'a mut T) {
-        while true {
+        while true { //~ WARN denote infinite loops with
             (self.func)(arg) //~ ERROR cannot borrow
         }
     }
diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.stderr b/src/test/ui/borrowck/mut-borrow-in-loop.stderr
index eda2f518f9246..59cf4d533def8 100644
--- a/src/test/ui/borrowck/mut-borrow-in-loop.stderr
+++ b/src/test/ui/borrowck/mut-borrow-in-loop.stderr
@@ -1,3 +1,11 @@
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/mut-borrow-in-loop.rs:15:9
+   |
+LL |         while true {
+   |         ^^^^^^^^^^ help: use `loop`
+   |
+   = note: #[warn(while_true)] on by default
+
 error[E0499]: cannot borrow `*arg` as mutable more than once at a time
   --> $DIR/mut-borrow-in-loop.rs:10:25
    |
diff --git a/src/test/run-pass/consts/const-labeled-break.rs b/src/test/ui/consts/const-labeled-break.rs
similarity index 76%
rename from src/test/run-pass/consts/const-labeled-break.rs
rename to src/test/ui/consts/const-labeled-break.rs
index 9417159e6fb78..512ad9427ea54 100644
--- a/src/test/run-pass/consts/const-labeled-break.rs
+++ b/src/test/ui/consts/const-labeled-break.rs
@@ -4,7 +4,6 @@
 // See https://github.com/rust-lang/rust/issues/51350 for more information.
 
 const CRASH: () = 'a: while break 'a {};
+//~^ ERROR constant contains unimplemented expression type
 
-fn main() {
-    println!("{:?}", CRASH);
-}
+fn main() {}
diff --git a/src/test/ui/consts/const-labeled-break.stderr b/src/test/ui/consts/const-labeled-break.stderr
new file mode 100644
index 0000000000000..2009e92235566
--- /dev/null
+++ b/src/test/ui/consts/const-labeled-break.stderr
@@ -0,0 +1,9 @@
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/const-labeled-break.rs:6:19
+   |
+LL | const CRASH: () = 'a: while break 'a {};
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr
index abbdb4ab632dc..afe48ee9ae542 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr
@@ -169,7 +169,7 @@ LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
    = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0723]: loops and conditional expressions are not stable in const fn
+error[E0723]: loops are not allowed in const fn
   --> $DIR/min_const_fn.rs:102:29
    |
 LL | const fn foo30_5(b: bool) { while b { } }
@@ -179,7 +179,7 @@ LL | const fn foo30_5(b: bool) { while b { } }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:104:44
+  --> $DIR/min_const_fn.rs:105:44
    |
 LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
    |                                            ^^^^^^
@@ -188,7 +188,7 @@ LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:106:44
+  --> $DIR/min_const_fn.rs:107:44
    |
 LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
    |                                            ^^^^^^
@@ -197,7 +197,7 @@ LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: mutable references in const fn are unstable
-  --> $DIR/min_const_fn.rs:108:14
+  --> $DIR/min_const_fn.rs:109:14
    |
 LL | const fn inc(x: &mut i32) { *x += 1 }
    |              ^
@@ -206,7 +206,7 @@ LL | const fn inc(x: &mut i32) { *x += 1 }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:113:6
+  --> $DIR/min_const_fn.rs:114:6
    |
 LL | impl<T: std::fmt::Debug> Foo<T> {
    |      ^
@@ -215,7 +215,7 @@ LL | impl<T: std::fmt::Debug> Foo<T> {
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:118:6
+  --> $DIR/min_const_fn.rs:119:6
    |
 LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
    |      ^
@@ -224,7 +224,7 @@ LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:123:6
+  --> $DIR/min_const_fn.rs:124:6
    |
 LL | impl<T: Sync + Sized> Foo<T> {
    |      ^
@@ -233,7 +233,7 @@ LL | impl<T: Sync + Sized> Foo<T> {
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn.rs:129:24
+  --> $DIR/min_const_fn.rs:130:24
    |
 LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -242,7 +242,7 @@ LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:131:34
+  --> $DIR/min_const_fn.rs:132:34
    |
 LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -251,7 +251,7 @@ LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:133:22
+  --> $DIR/min_const_fn.rs:134:22
    |
 LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                      ^^^^^^^^^^^^^^^^^^^^
@@ -260,7 +260,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn.rs:134:23
+  --> $DIR/min_const_fn.rs:135:23
    |
 LL | const fn no_rpit() -> impl std::fmt::Debug {}
    |                       ^^^^^^^^^^^^^^^^^^^^
@@ -269,7 +269,7 @@ LL | const fn no_rpit() -> impl std::fmt::Debug {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:135:23
+  --> $DIR/min_const_fn.rs:136:23
    |
 LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    |                       ^^
@@ -278,7 +278,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:136:32
+  --> $DIR/min_const_fn.rs:137:32
    |
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -287,7 +287,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0515]: cannot return reference to temporary value
-  --> $DIR/min_const_fn.rs:136:63
+  --> $DIR/min_const_fn.rs:137:63
    |
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                                               ^--
@@ -296,7 +296,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                                               returns a reference to data owned by the current function
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:144:41
+  --> $DIR/min_const_fn.rs:145:41
    |
 LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -305,7 +305,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn.rs:147:21
+  --> $DIR/min_const_fn.rs:148:21
    |
 LL | const fn no_fn_ptrs(_x: fn()) {}
    |                     ^^
@@ -314,7 +314,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn.rs:149:27
+  --> $DIR/min_const_fn.rs:150:27
    |
 LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
    |                           ^^^^
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index 9523fcbfc603f..8b423da788292 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -99,7 +99,8 @@ const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
 //~^ ERROR casting pointers to ints is unstable
 const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
 //~^ ERROR loops and conditional expressions are not stable in const fn
-const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
+const fn foo30_5(b: bool) { while b { } }
+//~^ ERROR loops are not allowed in const fn
 const fn foo30_6() -> bool { let x = true; x }
 const fn foo36(a: bool, b: bool) -> bool { a && b }
 //~^ ERROR loops and conditional expressions are not stable in const fn
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index 28a5ffb201594..66cfe7fa0247c 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -169,7 +169,7 @@ LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
    = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0723]: loops and conditional expressions are not stable in const fn
+error[E0723]: loops are not allowed in const fn
   --> $DIR/min_const_fn.rs:102:29
    |
 LL | const fn foo30_5(b: bool) { while b { } }
@@ -179,7 +179,7 @@ LL | const fn foo30_5(b: bool) { while b { } }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:104:44
+  --> $DIR/min_const_fn.rs:105:44
    |
 LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
    |                                            ^^^^^^
@@ -188,7 +188,7 @@ LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:106:44
+  --> $DIR/min_const_fn.rs:107:44
    |
 LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
    |                                            ^^^^^^
@@ -197,7 +197,7 @@ LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: mutable references in const fn are unstable
-  --> $DIR/min_const_fn.rs:108:14
+  --> $DIR/min_const_fn.rs:109:14
    |
 LL | const fn inc(x: &mut i32) { *x += 1 }
    |              ^
@@ -206,7 +206,7 @@ LL | const fn inc(x: &mut i32) { *x += 1 }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:113:6
+  --> $DIR/min_const_fn.rs:114:6
    |
 LL | impl<T: std::fmt::Debug> Foo<T> {
    |      ^
@@ -215,7 +215,7 @@ LL | impl<T: std::fmt::Debug> Foo<T> {
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:118:6
+  --> $DIR/min_const_fn.rs:119:6
    |
 LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
    |      ^
@@ -224,7 +224,7 @@ LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:123:6
+  --> $DIR/min_const_fn.rs:124:6
    |
 LL | impl<T: Sync + Sized> Foo<T> {
    |      ^
@@ -233,7 +233,7 @@ LL | impl<T: Sync + Sized> Foo<T> {
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn.rs:129:24
+  --> $DIR/min_const_fn.rs:130:24
    |
 LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -242,7 +242,7 @@ LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:131:34
+  --> $DIR/min_const_fn.rs:132:34
    |
 LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -251,7 +251,7 @@ LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:133:22
+  --> $DIR/min_const_fn.rs:134:22
    |
 LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                      ^^^^^^^^^^^^^^^^^^^^
@@ -260,7 +260,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn.rs:134:23
+  --> $DIR/min_const_fn.rs:135:23
    |
 LL | const fn no_rpit() -> impl std::fmt::Debug {}
    |                       ^^^^^^^^^^^^^^^^^^^^
@@ -269,7 +269,7 @@ LL | const fn no_rpit() -> impl std::fmt::Debug {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:135:23
+  --> $DIR/min_const_fn.rs:136:23
    |
 LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    |                       ^^
@@ -278,7 +278,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:136:32
+  --> $DIR/min_const_fn.rs:137:32
    |
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -287,7 +287,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 warning[E0515]: cannot return reference to temporary value
-  --> $DIR/min_const_fn.rs:136:63
+  --> $DIR/min_const_fn.rs:137:63
    |
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                                               ^--
@@ -300,7 +300,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    = note: for more information, try `rustc --explain E0729`
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:144:41
+  --> $DIR/min_const_fn.rs:145:41
    |
 LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -309,7 +309,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn.rs:147:21
+  --> $DIR/min_const_fn.rs:148:21
    |
 LL | const fn no_fn_ptrs(_x: fn()) {}
    |                     ^^
@@ -318,7 +318,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {}
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn.rs:149:27
+  --> $DIR/min_const_fn.rs:150:27
    |
 LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
    |                           ^^^^
diff --git a/src/test/ui/if/if-no-match-bindings.rs b/src/test/ui/if/if-no-match-bindings.rs
index 581ce18c1d614..ca3df0fdde45d 100644
--- a/src/test/ui/if/if-no-match-bindings.rs
+++ b/src/test/ui/if/if-no-match-bindings.rs
@@ -19,4 +19,10 @@ fn main() {
     if b_mut_ref() {} //~ ERROR mismatched types [E0308]
     if &true {} //~ ERROR mismatched types [E0308]
     if &mut true {} //~ ERROR mismatched types [E0308]
+
+    // This is also NOT:
+    while b_ref() {} //~ ERROR mismatched types [E0308]
+    while b_mut_ref() {} //~ ERROR mismatched types [E0308]
+    while &true {} //~ ERROR mismatched types [E0308]
+    while &mut true {} //~ ERROR mismatched types [E0308]
 }
diff --git a/src/test/ui/if/if-no-match-bindings.stderr b/src/test/ui/if/if-no-match-bindings.stderr
index 7b0b472121fce..cbf52476ae37f 100644
--- a/src/test/ui/if/if-no-match-bindings.stderr
+++ b/src/test/ui/if/if-no-match-bindings.stderr
@@ -34,6 +34,42 @@ LL |     if &mut true {}
    = note: expected type `bool`
               found type `&mut bool`
 
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+  --> $DIR/if-no-match-bindings.rs:24:11
+   |
+LL |     while b_ref() {}
+   |           ^^^^^^^ expected bool, found &bool
+   |
+   = note: expected type `bool`
+              found type `&bool`
+
+error[E0308]: mismatched types
+  --> $DIR/if-no-match-bindings.rs:25:11
+   |
+LL |     while b_mut_ref() {}
+   |           ^^^^^^^^^^^ expected bool, found &mut bool
+   |
+   = note: expected type `bool`
+              found type `&mut bool`
+
+error[E0308]: mismatched types
+  --> $DIR/if-no-match-bindings.rs:26:11
+   |
+LL |     while &true {}
+   |           ^^^^^ expected bool, found &bool
+   |
+   = note: expected type `bool`
+              found type `&bool`
+
+error[E0308]: mismatched types
+  --> $DIR/if-no-match-bindings.rs:27:11
+   |
+LL |     while &mut true {}
+   |           ^^^^^^^^^ expected bool, found &mut bool
+   |
+   = note: expected type `bool`
+              found type `&mut bool`
+
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-27042.rs b/src/test/ui/issues/issue-27042.rs
index 8c7758597f03e..517c1f2e6c7cc 100644
--- a/src/test/ui/issues/issue-27042.rs
+++ b/src/test/ui/issues/issue-27042.rs
@@ -6,6 +6,7 @@ fn main() {
         loop { break }; //~ ERROR mismatched types
     let _: i32 =
         'b: //~ ERROR mismatched types
+        //~^ WARN denote infinite loops with
         while true { break }; // but here we cite the whole loop
     let _: i32 =
         'c: //~ ERROR mismatched types
diff --git a/src/test/ui/issues/issue-27042.stderr b/src/test/ui/issues/issue-27042.stderr
index cce7d24a5f602..c67b8ad738155 100644
--- a/src/test/ui/issues/issue-27042.stderr
+++ b/src/test/ui/issues/issue-27042.stderr
@@ -1,3 +1,13 @@
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/issue-27042.rs:8:9
+   |
+LL | /         'b:
+LL | |
+LL | |         while true { break }; // but here we cite the whole loop
+   | |____________________________^ help: use `loop`
+   |
+   = note: #[warn(while_true)] on by default
+
 error[E0308]: mismatched types
   --> $DIR/issue-27042.rs:6:16
    |
@@ -11,6 +21,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-27042.rs:8:9
    |
 LL | /         'b:
+LL | |
 LL | |         while true { break }; // but here we cite the whole loop
    | |____________________________^ expected i32, found ()
    |
@@ -18,7 +29,7 @@ LL | |         while true { break }; // but here we cite the whole loop
               found type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/issue-27042.rs:11:9
+  --> $DIR/issue-27042.rs:12:9
    |
 LL | /         'c:
 LL | |         for _ in None { break }; // but here we cite the whole loop
@@ -28,7 +39,7 @@ LL | |         for _ in None { break }; // but here we cite the whole loop
               found type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/issue-27042.rs:14:9
+  --> $DIR/issue-27042.rs:15:9
    |
 LL | /         'd:
 LL | |         while let Some(_) = None { break };
diff --git a/src/test/ui/lint/lint-impl-fn.stderr b/src/test/ui/lint/lint-impl-fn.stderr
index 56f85111d428f..2c9a264287c96 100644
--- a/src/test/ui/lint/lint-impl-fn.stderr
+++ b/src/test/ui/lint/lint-impl-fn.stderr
@@ -11,25 +11,25 @@ LL |     #[deny(while_true)]
    |            ^^^^^^^^^^
 
 error: denote infinite loops with `loop { ... }`
-  --> $DIR/lint-impl-fn.rs:27:5
+  --> $DIR/lint-impl-fn.rs:18:25
    |
-LL |     while true {}
-   |     ^^^^^^^^^^ help: use `loop`
+LL |         fn foo(&self) { while true {} }
+   |                         ^^^^^^^^^^ help: use `loop`
    |
 note: lint level defined here
-  --> $DIR/lint-impl-fn.rs:25:8
+  --> $DIR/lint-impl-fn.rs:13:8
    |
 LL | #[deny(while_true)]
    |        ^^^^^^^^^^
 
 error: denote infinite loops with `loop { ... }`
-  --> $DIR/lint-impl-fn.rs:18:25
+  --> $DIR/lint-impl-fn.rs:27:5
    |
-LL |         fn foo(&self) { while true {} }
-   |                         ^^^^^^^^^^ help: use `loop`
+LL |     while true {}
+   |     ^^^^^^^^^^ help: use `loop`
    |
 note: lint level defined here
-  --> $DIR/lint-impl-fn.rs:13:8
+  --> $DIR/lint-impl-fn.rs:25:8
    |
 LL | #[deny(while_true)]
    |        ^^^^^^^^^^
diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs
index c36101043a7f7..811bc87eb0e2e 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.rs
+++ b/src/test/ui/lint/lint-unnecessary-parens.rs
@@ -19,6 +19,7 @@ fn main() {
 
     if (true) {} //~ ERROR unnecessary parentheses around `if` condition
     while (true) {} //~ ERROR unnecessary parentheses around `while` condition
+    //~^ WARN denote infinite loops with
     match (true) { //~ ERROR unnecessary parentheses around `match` head expression
         _ => {}
     }
diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr
index dfbefd7b03ee5..05ecbfdf4fa39 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.stderr
+++ b/src/test/ui/lint/lint-unnecessary-parens.stderr
@@ -34,44 +34,52 @@ error: unnecessary parentheses around `while` condition
 LL |     while (true) {}
    |           ^^^^^^ help: remove these parentheses
 
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/lint-unnecessary-parens.rs:21:5
+   |
+LL |     while (true) {}
+   |     ^^^^^^^^^^^^ help: use `loop`
+   |
+   = note: #[warn(while_true)] on by default
+
 error: unnecessary parentheses around `match` head expression
-  --> $DIR/lint-unnecessary-parens.rs:22:11
+  --> $DIR/lint-unnecessary-parens.rs:23:11
    |
 LL |     match (true) {
    |           ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `let` head expression
-  --> $DIR/lint-unnecessary-parens.rs:25:16
+  --> $DIR/lint-unnecessary-parens.rs:26:16
    |
 LL |     if let 1 = (1) {}
    |                ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `let` head expression
-  --> $DIR/lint-unnecessary-parens.rs:26:19
+  --> $DIR/lint-unnecessary-parens.rs:27:19
    |
 LL |     while let 1 = (2) {}
    |                   ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around method argument
-  --> $DIR/lint-unnecessary-parens.rs:40:24
+  --> $DIR/lint-unnecessary-parens.rs:41:24
    |
 LL |     X { y: false }.foo((true));
    |                        ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:42:18
+  --> $DIR/lint-unnecessary-parens.rs:43:18
    |
 LL |     let mut _a = (0);
    |                  ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:43:10
+  --> $DIR/lint-unnecessary-parens.rs:44:10
    |
 LL |     _a = (0);
    |          ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:44:11
+  --> $DIR/lint-unnecessary-parens.rs:45:11
    |
 LL |     _a += (1);
    |           ^^^ help: remove these parentheses
diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr
index 5aaa9947f998a..de7c1fb898679 100644
--- a/src/test/ui/lint/suggestions.stderr
+++ b/src/test/ui/lint/suggestions.stderr
@@ -1,3 +1,11 @@
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/suggestions.rs:46:5
+   |
+LL |     while true {
+   |     ^^^^^^^^^^ help: use `loop`
+   |
+   = note: #[warn(while_true)] on by default
+
 warning: unnecessary parentheses around assigned value
   --> $DIR/suggestions.rs:49:31
    |
@@ -65,14 +73,6 @@ LL | pub fn defiant<T>(_t: T) {}
    |
    = note: #[warn(no_mangle_generic_items)] on by default
 
-warning: denote infinite loops with `loop { ... }`
-  --> $DIR/suggestions.rs:46:5
-   |
-LL |     while true {
-   |     ^^^^^^^^^^ help: use `loop`
-   |
-   = note: #[warn(while_true)] on by default
-
 warning: the `warp_factor:` in this pattern is redundant
   --> $DIR/suggestions.rs:61:23
    |
diff --git a/src/test/ui/liveness/liveness-move-in-while.rs b/src/test/ui/liveness/liveness-move-in-while.rs
index 420d1311f8b1f..9f3ebf1362b82 100644
--- a/src/test/ui/liveness/liveness-move-in-while.rs
+++ b/src/test/ui/liveness/liveness-move-in-while.rs
@@ -6,5 +6,8 @@ fn main() {
     loop {
         println!("{}", y); //~ ERROR borrow of moved value: `y`
         while true { while true { while true { x = y; x.clone(); } } }
+        //~^ WARN denote infinite loops with
+        //~| WARN denote infinite loops with
+        //~| WARN denote infinite loops with
     }
 }
diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr
index e1eed1b59f470..bbf5e50f1e09d 100644
--- a/src/test/ui/liveness/liveness-move-in-while.stderr
+++ b/src/test/ui/liveness/liveness-move-in-while.stderr
@@ -1,3 +1,23 @@
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/liveness-move-in-while.rs:8:9
+   |
+LL |         while true { while true { while true { x = y; x.clone(); } } }
+   |         ^^^^^^^^^^ help: use `loop`
+   |
+   = note: #[warn(while_true)] on by default
+
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/liveness-move-in-while.rs:8:22
+   |
+LL |         while true { while true { while true { x = y; x.clone(); } } }
+   |                      ^^^^^^^^^^ help: use `loop`
+
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/liveness-move-in-while.rs:8:35
+   |
+LL |         while true { while true { while true { x = y; x.clone(); } } }
+   |                                   ^^^^^^^^^^ help: use `loop`
+
 error[E0382]: borrow of moved value: `y`
   --> $DIR/liveness-move-in-while.rs:7:24
    |
diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs
index b80c847deb967..7c2f63ec51a79 100644
--- a/src/test/ui/loops/loop-break-value.rs
+++ b/src/test/ui/loops/loop-break-value.rs
@@ -23,7 +23,7 @@ fn main() {
         };
     };
 
-    'while_loop: while true {
+    'while_loop: while true { //~ WARN denote infinite loops with
         break;
         break (); //~ ERROR `break` with value from a `while` loop
         loop {
diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr
index 13fe50855408b..f458c88ea4892 100644
--- a/src/test/ui/loops/loop-break-value.stderr
+++ b/src/test/ui/loops/loop-break-value.stderr
@@ -1,3 +1,11 @@
+warning: denote infinite loops with `loop { ... }`
+  --> $DIR/loop-break-value.rs:26:5
+   |
+LL |     'while_loop: while true {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
+   |
+   = note: #[warn(while_true)] on by default
+
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:28:9
    |
diff --git a/src/test/ui/reachable/expr_while.rs b/src/test/ui/reachable/expr_while.rs
index 36a3e3dd961b2..10a4b69939f12 100644
--- a/src/test/ui/reachable/expr_while.rs
+++ b/src/test/ui/reachable/expr_while.rs
@@ -5,8 +5,8 @@
 
 fn foo() {
     while {return} {
+        //~^ ERROR unreachable block in `while` expression
         println!("Hello, world!");
-        //~^ ERROR unreachable
     }
 }
 
@@ -20,11 +20,10 @@ fn bar() {
 fn baz() {
     // Here, we cite the `while` loop as dead.
     while {return} {
+        //~^ ERROR unreachable block in `while` expression
         println!("I am dead.");
-        //~^ ERROR unreachable
     }
     println!("I am, too.");
-    //~^ ERROR unreachable
 }
 
 fn main() { }
diff --git a/src/test/ui/reachable/expr_while.stderr b/src/test/ui/reachable/expr_while.stderr
index d2f5588568aab..fc528926b4c97 100644
--- a/src/test/ui/reachable/expr_while.stderr
+++ b/src/test/ui/reachable/expr_while.stderr
@@ -1,31 +1,28 @@
-error: unreachable statement
-  --> $DIR/expr_while.rs:8:9
+error: unreachable block in `while` expression
+  --> $DIR/expr_while.rs:7:20
    |
-LL |         println!("Hello, world!");
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       while {return} {
+   |  ____________________^
+LL | |
+LL | |         println!("Hello, world!");
+LL | |     }
+   | |_____^
    |
 note: lint level defined here
   --> $DIR/expr_while.rs:4:9
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: unreachable statement
-  --> $DIR/expr_while.rs:23:9
+error: unreachable block in `while` expression
+  --> $DIR/expr_while.rs:22:20
    |
-LL |         println!("I am dead.");
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
-
-error: unreachable statement
-  --> $DIR/expr_while.rs:26:5
-   |
-LL |     println!("I am, too.");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+LL |       while {return} {
+   |  ____________________^
+LL | |
+LL | |         println!("I am dead.");
+LL | |     }
+   | |_____^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors