mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-15 08:23:26 +00:00
Auto merge of #61988 - Centril:there-is-only-loop, r=matthewjasper
[let_chains, 3/6] And then there was only Loop Here we remove `hir::ExprKind::While`. Instead, we desugar: `'label: while $cond $body` into: ```rust 'label: loop { match DropTemps($cond) { true => $body, _ => break, } } ``` Per https://github.com/rust-lang/rust/issues/53667#issuecomment-471583239. This is a follow up to https://github.com/rust-lang/rust/pull/59288 which did the same for `if` expressions. r? @matthewjasper
This commit is contained in:
commit
254f201495
@ -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]
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
// }
|
||||
// }
|
||||
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.
|
||||
|
||||
// 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))),
|
||||
)
|
||||
});
|
||||
// `_ => 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)
|
||||
};
|
||||
|
||||
// `<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)
|
||||
};
|
||||
// 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,
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
|
||||
// `_ => break`
|
||||
let break_arm = {
|
||||
let pat_under = self.pat_wild(e.span);
|
||||
self.arm(hir_vec![pat_under], break_expr)
|
||||
};
|
||||
// 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());
|
||||
|
||||
// `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(),
|
||||
);
|
||||
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));
|
||||
|
||||
// `[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),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
// `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),
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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, ln);
|
||||
|
||||
self.cont_ln.insert(expr.hir_id, cond_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(..) |
|
||||
|
@ -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(..) |
|
||||
|
@ -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 }`.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,6 @@ pub enum ExprKind<'tcx> {
|
||||
source: ExprRef<'tcx>,
|
||||
},
|
||||
Loop {
|
||||
condition: Option<ExprRef<'tcx>>,
|
||||
body: ExprRef<'tcx>,
|
||||
},
|
||||
Match {
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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(..) => {
|
||||
|
@ -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!(
|
||||
|
@ -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 => "?",
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
fn main() {
|
||||
while true {
|
||||
while true { //~ WARN denote infinite loops with
|
||||
true //~ ERROR mismatched types
|
||||
//~| expected type `()`
|
||||
//~| found type `bool`
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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() {}
|
9
src/test/ui/consts/const-labeled-break.stderr
Normal file
9
src/test/ui/consts/const-labeled-break.stderr
Normal file
@ -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`.
|
@ -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 }
|
||||
| ^^^^
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
| ^^^^
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
|
@ -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 };
|
||||
|
@ -10,18 +10,6 @@ note: lint level defined here
|
||||
LL | #[deny(while_true)]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/lint-impl-fn.rs:27:5
|
||||
|
|
||||
LL | while true {}
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-impl-fn.rs:25:8
|
||||
|
|
||||
LL | #[deny(while_true)]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/lint-impl-fn.rs:18:25
|
||||
|
|
||||
@ -34,5 +22,17 @@ note: lint level defined here
|
||||
LL | #[deny(while_true)]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/lint-impl-fn.rs:27:5
|
||||
|
|
||||
LL | while true {}
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-impl-fn.rs:25:8
|
||||
|
|
||||
LL | #[deny(while_true)]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -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
|
||||
_ => {}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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() { }
|
||||
|
@ -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)
|
||||
LL | while {return} {
|
||||
| ____________________^
|
||||
LL | |
|
||||
LL | | println!("I am dead.");
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
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)
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user