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