From 6ee3c47a3a41c495fcf52f342fe4253231a257c8 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 31 Mar 2022 18:33:05 -0300 Subject: [PATCH 01/15] [let_chains] Forbid let inside parentheses --- .../rustc_ast_passes/src/ast_validation.rs | 54 +- .../disallowed-positions.rs | 102 +++ .../disallowed-positions.stderr | 781 +++++++++++++----- ...e-does-not-interact-with-let-chains.stderr | 1 - .../ui/rfc-2497-if-let-chains/feature-gate.rs | 50 -- .../feature-gate.stderr | 236 +----- 6 files changed, 751 insertions(+), 473 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index a7c600fff785e..33727084ccf06 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -120,12 +120,21 @@ impl<'a> AstValidator<'a> { let err = "`let` expressions are not supported here"; let mut diag = sess.struct_span_err(expr.span, err); diag.note("only supported directly in conditions of `if` and `while` expressions"); - diag.note("as well as when nested within `&&` and parentheses in those conditions"); - if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason { - diag.span_note( - span, - "`||` operators are not currently supported in let chain expressions", - ); + match forbidden_let_reason { + ForbiddenLetReason::GenericForbidden => {} + ForbiddenLetReason::NotSupportedOr(span) => { + diag.span_note( + span, + "`||` operators are not supported in let chain expressions", + ); + } + ForbiddenLetReason::NotSupportedParentheses(span) => { + diag.span_note( + span, + "`let`s wrapped in parentheses are not supported in a context with let \ + chains", + ); + } } diag.emit(); } else { @@ -1009,9 +1018,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| { match &expr.kind { ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => { - let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span)); - this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs)); - this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs)); + let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span)); + this.with_let_management(local_reason, |this, _| this.visit_expr(lhs)); + this.with_let_management(local_reason, |this, _| this.visit_expr(rhs)); } ExprKind::If(cond, then, opt_else) => { this.visit_block(then); @@ -1036,7 +1045,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } } - ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => { + ExprKind::Paren(local_expr) => { + fn has_let_expr(expr: &Expr) -> bool { + match expr.kind { + ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs), + ExprKind::Let(..) => true, + _ => false, + } + } + let local_reason = if has_let_expr(local_expr) { + Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span)) + } + else { + forbidden_let_reason + }; + this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr)); + } + ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => { this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr)); return; } @@ -1810,8 +1835,13 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> /// Used to forbid `let` expressions in certain syntactic locations. #[derive(Clone, Copy)] enum ForbiddenLetReason { - /// A let chain with the `||` operator - ForbiddenWithOr(Span), /// `let` is not valid and the source environment is not important GenericForbidden, + /// A let chain with the `||` operator + NotSupportedOr(Span), + /// A let chain with invalid parentheses + /// + /// For exemple, `let 1 = 1 && (expr && expr)` is allowed + /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not + NotSupportedParentheses(Span), } diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs index 5b2693d07a790..1bd8b74240eac 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs @@ -25,6 +25,67 @@ use std::ops::Range; fn main() {} +fn _if() { + if (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + + if (((let 0 = 1))) {} + //~^ ERROR `let` expressions are not supported here + + if (let 0 = 1) && true {} + //~^ ERROR `let` expressions are not supported here + + if true && (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + + if (let 0 = 1) && (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here +} + +fn _while() { + while (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + + while (((let 0 = 1))) {} + //~^ ERROR `let` expressions are not supported here + + while (let 0 = 1) && true {} + //~^ ERROR `let` expressions are not supported here + + while true && (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + + while (let 0 = 1) && (let 0 = 1) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + + while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here +} + +fn _macros() { + macro_rules! use_expr { + ($e:expr) => { + if $e {} + while $e {} + } + } + use_expr!((let 0 = 1 && 0 == 0)); + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + use_expr!((let 0 = 1)); + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here +} + fn nested_within_if_expr() { if &let 0 = 0 {} //~ ERROR `let` expressions are not supported here //~^ ERROR mismatched types @@ -234,3 +295,44 @@ fn inside_const_generic_arguments() { //~| ERROR expressions must be enclosed in braces >::O == 5 {} } + +fn with_parenthesis() { + let opt = Some(Some(1i32)); + + if (let Some(a) = opt && true) { + //~^ ERROR `let` expressions are not supported here + } + + if (let Some(a) = opt) && true { + //~^ ERROR `let` expressions are not supported here + } + if (let Some(a) = opt) && (let Some(b) = a) { + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + } + if let Some(a) = opt && (true && true) { + } + + if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + } + if (let Some(a) = opt && (let Some(b) = a)) && true { + //~^ ERROR `let` expressions are not supported here + //~| ERROR `let` expressions are not supported here + } + if (let Some(a) = opt && (true)) && true { + //~^ ERROR `let` expressions are not supported here + } + + if (true && (true)) && let Some(a) = opt { + } + if (true) && let Some(a) = opt { + } + if true && let Some(a) = opt { + } + + let fun = || true; + if let true = (true && fun()) && (true) { + } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 34f059248b61d..00da9d2605765 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -1,5 +1,5 @@ error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:232:9 + --> $DIR/disallowed-positions.rs:293:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -12,555 +12,968 @@ LL | { true && let 1 = 1 } error: `let` expressions are not supported here --> $DIR/disallowed-positions.rs:29:9 | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:29:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:32:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:32:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:35:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:35:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:38:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:38:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:41:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:41:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:41:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:41:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:45:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:45:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:45:48 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:45:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:45:61 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:45:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:52:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:52:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:55:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:55:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:58:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:58:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:61:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:61:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:64:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:64:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:64:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:64:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:68:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:68:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:68:51 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:68:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:68:64 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:68:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:81:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:81:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:81:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:81:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:84:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:84:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:84:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:84:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:90:9 + | LL | if &let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:32:9 + --> $DIR/disallowed-positions.rs:93:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:33:9 + --> $DIR/disallowed-positions.rs:94:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:35:9 + --> $DIR/disallowed-positions.rs:96:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:43:9 + --> $DIR/disallowed-positions.rs:104:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:104:9 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:47:16 + --> $DIR/disallowed-positions.rs:108:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:47:13 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:108:13 | LL | if true || let 0 = 0 {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:48:17 + --> $DIR/disallowed-positions.rs:109:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:48:14 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:109:14 | LL | if (true || let 0 = 0) {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:49:25 + --> $DIR/disallowed-positions.rs:110:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:49:22 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:110:22 | LL | if true && (true || let 0 = 0) {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:50:25 + --> $DIR/disallowed-positions.rs:111:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:50:13 +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:111:17 | LL | if true || (true && let 0 = 0) {} - | ^^ + | ^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:53:12 + --> $DIR/disallowed-positions.rs:114:12 | LL | if x = let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:56:15 + --> $DIR/disallowed-positions.rs:117:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:117:15 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:58:11 + --> $DIR/disallowed-positions.rs:119:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:119:11 + | +LL | if ..(let 0 = 0) {} + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:60:9 + --> $DIR/disallowed-positions.rs:121:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:121:9 + | +LL | if (let 0 = 0).. {} + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:64:8 + --> $DIR/disallowed-positions.rs:125:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:68:8 + --> $DIR/disallowed-positions.rs:129:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:75:8 + --> $DIR/disallowed-positions.rs:136:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:83:8 + --> $DIR/disallowed-positions.rs:144:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:89:19 + --> $DIR/disallowed-positions.rs:150:19 | LL | if let true = let true = true {} | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:93:12 + --> $DIR/disallowed-positions.rs:154:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:96:12 + --> $DIR/disallowed-positions.rs:157:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:97:12 + --> $DIR/disallowed-positions.rs:158:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:99:12 + --> $DIR/disallowed-positions.rs:160:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:107:12 + --> $DIR/disallowed-positions.rs:168:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:168:12 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:111:19 + --> $DIR/disallowed-positions.rs:172:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:111:16 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:172:16 | LL | while true || let 0 = 0 {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:112:20 + --> $DIR/disallowed-positions.rs:173:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:112:17 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:173:17 | LL | while (true || let 0 = 0) {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:113:28 + --> $DIR/disallowed-positions.rs:174:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:113:25 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:174:25 | LL | while true && (true || let 0 = 0) {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:114:28 + --> $DIR/disallowed-positions.rs:175:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:114:16 +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:175:20 | LL | while true || (true && let 0 = 0) {} - | ^^ + | ^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:117:15 + --> $DIR/disallowed-positions.rs:178:15 | LL | while x = let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:120:18 + --> $DIR/disallowed-positions.rs:181:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:181:18 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:122:14 + --> $DIR/disallowed-positions.rs:183:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:183:14 + | +LL | while ..(let 0 = 0) {} + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:124:12 + --> $DIR/disallowed-positions.rs:185:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:185:12 + | +LL | while (let 0 = 0).. {} + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:128:11 + --> $DIR/disallowed-positions.rs:189:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:132:11 + --> $DIR/disallowed-positions.rs:193:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:139:11 + --> $DIR/disallowed-positions.rs:200:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:147:11 + --> $DIR/disallowed-positions.rs:208:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:153:22 + --> $DIR/disallowed-positions.rs:214:22 | LL | while let true = let true = true {} | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:167:6 + --> $DIR/disallowed-positions.rs:228:6 | LL | &let 0 = 0; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:169:6 + --> $DIR/disallowed-positions.rs:230:6 | LL | !let 0 = 0; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:170:6 + --> $DIR/disallowed-positions.rs:231:6 | LL | *let 0 = 0; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:172:6 + --> $DIR/disallowed-positions.rs:233:6 | LL | -let 0 = 0; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:180:6 + --> $DIR/disallowed-positions.rs:241:6 | LL | (let 0 = 0)?; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:241:6 + | +LL | (let 0 = 0)?; + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:184:13 + --> $DIR/disallowed-positions.rs:245:13 | LL | true || let 0 = 0; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:184:10 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:245:10 | LL | true || let 0 = 0; | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:185:14 + --> $DIR/disallowed-positions.rs:246:14 | LL | (true || let 0 = 0); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:185:11 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:246:11 | LL | (true || let 0 = 0); | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:186:22 + --> $DIR/disallowed-positions.rs:247:22 | LL | true && (true || let 0 = 0); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions -note: `||` operators are not currently supported in let chain expressions - --> $DIR/disallowed-positions.rs:186:19 +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:247:19 | LL | true && (true || let 0 = 0); | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:189:9 + --> $DIR/disallowed-positions.rs:250:9 | LL | x = let 0 = 0; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:191:12 + --> $DIR/disallowed-positions.rs:252:12 | LL | true..(let 0 = 0); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:252:12 + | +LL | true..(let 0 = 0); + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:192:8 + --> $DIR/disallowed-positions.rs:253:8 | LL | ..(let 0 = 0); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:253:8 + | +LL | ..(let 0 = 0); + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:193:6 + --> $DIR/disallowed-positions.rs:254:6 | LL | (let 0 = 0)..; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:254:6 + | +LL | (let 0 = 0)..; + | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:195:6 + --> $DIR/disallowed-positions.rs:256:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:199:6 + --> $DIR/disallowed-positions.rs:260:6 | LL | (let true = let true = true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:260:6 + | +LL | (let true = let true = true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:203:6 + --> $DIR/disallowed-positions.rs:264:6 | LL | &let 0 = 0 | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:214:17 + --> $DIR/disallowed-positions.rs:275:17 | LL | true && let 1 = 1 | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:218:17 + --> $DIR/disallowed-positions.rs:279:17 | LL | true && let 1 = 1 | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:222:17 + --> $DIR/disallowed-positions.rs:283:17 | LL | true && let 1 = 1 | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:232:17 + --> $DIR/disallowed-positions.rs:293:17 | LL | true && let 1 = 1 | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:302:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:302:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:306:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:306:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:309:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:309:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:309:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:309:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:316:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:316:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:316:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:316:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:320:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:320:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:320:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:320:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:324:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:324:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:29:8 + --> $DIR/disallowed-positions.rs:90:8 | LL | if &let 0 = 0 {} | ^^^^^^^^^^ expected `bool`, found `&bool` @@ -572,19 +985,19 @@ LL + if let 0 = 0 {} | error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:33:8 + --> $DIR/disallowed-positions.rs:94:8 | LL | if *let 0 = 0 {} | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:35:8 + --> $DIR/disallowed-positions.rs:96:8 | LL | if -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:43:8 + --> $DIR/disallowed-positions.rs:104:8 | LL | if (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -592,7 +1005,7 @@ LL | if (let 0 = 0)? {} = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:43:19 + --> $DIR/disallowed-positions.rs:104:19 | LL | / fn nested_within_if_expr() { LL | | if &let 0 = 0 {} @@ -609,7 +1022,7 @@ LL | | } = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:53:8 + --> $DIR/disallowed-positions.rs:114:8 | LL | if x = let 0 = 0 {} | ^^^^^^^^^^^^^ expected `bool`, found `()` @@ -620,7 +1033,7 @@ LL | if x == let 0 = 0 {} | ~~ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:56:8 + --> $DIR/disallowed-positions.rs:117:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -629,7 +1042,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:58:8 + --> $DIR/disallowed-positions.rs:119:8 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` @@ -638,7 +1051,7 @@ LL | if ..(let 0 = 0) {} found struct `RangeTo` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:60:8 + --> $DIR/disallowed-positions.rs:121:8 | LL | if (let 0 = 0).. {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` @@ -647,7 +1060,7 @@ LL | if (let 0 = 0).. {} found struct `RangeFrom` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:125:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -658,7 +1071,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:64:8 + --> $DIR/disallowed-positions.rs:125:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -667,7 +1080,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:68:12 + --> $DIR/disallowed-positions.rs:129:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -678,7 +1091,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:68:8 + --> $DIR/disallowed-positions.rs:129:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -687,7 +1100,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:75:12 + --> $DIR/disallowed-positions.rs:136:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -698,16 +1111,16 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:75:41 + --> $DIR/disallowed-positions.rs:136:41 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^ expected `bool`, found closure | = note: expected type `bool` - found closure `[closure@$DIR/disallowed-positions.rs:75:41: 75:48]` + found closure `[closure@$DIR/disallowed-positions.rs:136:41: 136:48]` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:75:8 + --> $DIR/disallowed-positions.rs:136:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -716,7 +1129,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:83:12 + --> $DIR/disallowed-positions.rs:144:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -727,7 +1140,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:83:44 + --> $DIR/disallowed-positions.rs:144:44 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^ expected `bool`, found `&&bool` @@ -739,7 +1152,7 @@ LL + if let Range { start: true, end } = t..false {} | error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:83:8 + --> $DIR/disallowed-positions.rs:144:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -748,7 +1161,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:39:20 + --> $DIR/disallowed-positions.rs:100:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -756,7 +1169,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:93:11 + --> $DIR/disallowed-positions.rs:154:11 | LL | while &let 0 = 0 {} | ^^^^^^^^^^ expected `bool`, found `&bool` @@ -768,19 +1181,19 @@ LL + while let 0 = 0 {} | error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:97:11 + --> $DIR/disallowed-positions.rs:158:11 | LL | while *let 0 = 0 {} | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:99:11 + --> $DIR/disallowed-positions.rs:160:11 | LL | while -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:107:11 + --> $DIR/disallowed-positions.rs:168:11 | LL | while (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -788,7 +1201,7 @@ LL | while (let 0 = 0)? {} = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:107:22 + --> $DIR/disallowed-positions.rs:168:22 | LL | / fn nested_within_while_expr() { LL | | while &let 0 = 0 {} @@ -805,7 +1218,7 @@ LL | | } = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:117:11 + --> $DIR/disallowed-positions.rs:178:11 | LL | while x = let 0 = 0 {} | ^^^^^^^^^^^^^ expected `bool`, found `()` @@ -816,7 +1229,7 @@ LL | while x == let 0 = 0 {} | ~~ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:120:11 + --> $DIR/disallowed-positions.rs:181:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -825,7 +1238,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:122:11 + --> $DIR/disallowed-positions.rs:183:11 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` @@ -834,7 +1247,7 @@ LL | while ..(let 0 = 0) {} found struct `RangeTo` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:124:11 + --> $DIR/disallowed-positions.rs:185:11 | LL | while (let 0 = 0).. {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` @@ -843,7 +1256,7 @@ LL | while (let 0 = 0).. {} found struct `RangeFrom` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:128:15 + --> $DIR/disallowed-positions.rs:189:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -854,7 +1267,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:128:11 + --> $DIR/disallowed-positions.rs:189:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -863,7 +1276,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:132:15 + --> $DIR/disallowed-positions.rs:193:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -874,7 +1287,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:132:11 + --> $DIR/disallowed-positions.rs:193:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -883,7 +1296,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:139:15 + --> $DIR/disallowed-positions.rs:200:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -894,16 +1307,16 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:139:44 + --> $DIR/disallowed-positions.rs:200:44 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^ expected `bool`, found closure | = note: expected type `bool` - found closure `[closure@$DIR/disallowed-positions.rs:139:44: 139:51]` + found closure `[closure@$DIR/disallowed-positions.rs:200:44: 200:51]` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:139:11 + --> $DIR/disallowed-positions.rs:200:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -912,7 +1325,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:147:15 + --> $DIR/disallowed-positions.rs:208:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -923,7 +1336,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:147:47 + --> $DIR/disallowed-positions.rs:208:47 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^ expected `bool`, found `&&bool` @@ -935,7 +1348,7 @@ LL + while let Range { start: true, end } = t..false {} | error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:147:11 + --> $DIR/disallowed-positions.rs:208:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -944,7 +1357,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:103:23 + --> $DIR/disallowed-positions.rs:164:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -952,19 +1365,19 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:170:5 + --> $DIR/disallowed-positions.rs:231:5 | LL | *let 0 = 0; | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:172:5 + --> $DIR/disallowed-positions.rs:233:5 | LL | -let 0 = 0; | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:180:5 + --> $DIR/disallowed-positions.rs:241:5 | LL | (let 0 = 0)?; | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -972,7 +1385,7 @@ LL | (let 0 = 0)?; = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:180:16 + --> $DIR/disallowed-positions.rs:241:16 | LL | / fn outside_if_and_while_expr() { LL | | &let 0 = 0; @@ -989,7 +1402,7 @@ LL | | } = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:195:10 + --> $DIR/disallowed-positions.rs:256:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1000,7 +1413,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:203:5 + --> $DIR/disallowed-positions.rs:264:5 | LL | fn outside_if_and_while_expr() { | - help: try adding a return type: `-> &bool` @@ -1009,14 +1422,14 @@ LL | &let 0 = 0 | ^^^^^^^^^^ expected `()`, found `&bool` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:176:17 + --> $DIR/disallowed-positions.rs:237:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 103 previous errors +error: aborting due to 134 previous errors Some errors have detailed explanations: E0277, E0308, E0600, E0614. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr index 992c34eb402d8..aebfc1a72b7aa 100644 --- a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr @@ -72,7 +72,6 @@ LL | let Some(n) = opt && let another = n else { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions - = note: as well as when nested within `&&` and parentheses in those conditions error[E0308]: mismatched types --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:19 diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs index 53fec8316e7e7..ac60bc7e57fd4 100644 --- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs +++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs @@ -11,35 +11,12 @@ use std::ops::Range; fn _if() { if let 0 = 1 {} // Stable! - if (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - if (((let 0 = 1))) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - if true && let 0 = 1 {} //~^ ERROR `let` expressions in this position are unstable [E0658] if let 0 = 1 && true {} //~^ ERROR `let` expressions in this position are unstable [E0658] - if (let 0 = 1) && true {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - if true && (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - if (let 0 = 1) && (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - - if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - if let Range { start: _, end: _ } = (true..true) && false {} //~^ ERROR `let` expressions in this position are unstable [E0658] } @@ -47,35 +24,12 @@ fn _if() { fn _while() { while let 0 = 1 {} // Stable! - while (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - while (((let 0 = 1))) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - while true && let 0 = 1 {} //~^ ERROR `let` expressions in this position are unstable [E0658] while let 0 = 1 && true {} //~^ ERROR `let` expressions in this position are unstable [E0658] - while (let 0 = 1) && true {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - while true && (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - while (let 0 = 1) && (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - - while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - //~| ERROR `let` expressions in this position are unstable [E0658] - while let Range { start: _, end: _ } = (true..true) && false {} //~^ ERROR `let` expressions in this position are unstable [E0658] } @@ -92,10 +46,6 @@ fn _macros() { while $e {} } } - use_expr!((let 0 = 1 && 0 == 0)); - //~^ ERROR `let` expressions in this position are unstable [E0658] - use_expr!((let 0 = 1)); - //~^ ERROR `let` expressions in this position are unstable [E0658] #[cfg(FALSE)] (let 0 = 1); //~^ ERROR `let` expressions in this position are unstable [E0658] use_expr!(let 0 = 1); diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr index 458826498fe2d..1eabee47c64ac 100644 --- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `let` - --> $DIR/feature-gate.rs:101:15 + --> $DIR/feature-gate.rs:51:15 | LL | macro_rules! use_expr { | --------------------- when calling this macro @@ -8,25 +8,7 @@ LL | use_expr!(let 0 = 1); | ^^^ no rules expected this token in macro call error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:14:9 - | -LL | if (let 0 = 1) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:17:11 - | -LL | if (((let 0 = 1))) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:20:16 + --> $DIR/feature-gate.rs:14:16 | LL | if true && let 0 = 1 {} | ^^^^^^^^^ @@ -35,7 +17,7 @@ LL | if true && let 0 = 1 {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:23:8 + --> $DIR/feature-gate.rs:17:8 | LL | if let 0 = 1 && true {} | ^^^^^^^^^ @@ -44,88 +26,7 @@ LL | if let 0 = 1 && true {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:26:9 - | -LL | if (let 0 = 1) && true {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:29:17 - | -LL | if true && (let 0 = 1) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:32:9 - | -LL | if (let 0 = 1) && (let 0 = 1) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:32:24 - | -LL | if (let 0 = 1) && (let 0 = 1) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:36:8 - | -LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:36:21 - | -LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:36:35 - | -LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:36:48 - | -LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:36:61 - | -LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:43:8 + --> $DIR/feature-gate.rs:20:8 | LL | if let Range { start: _, end: _ } = (true..true) && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -134,25 +35,7 @@ LL | if let Range { start: _, end: _ } = (true..true) && false {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:50:12 - | -LL | while (let 0 = 1) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:53:14 - | -LL | while (((let 0 = 1))) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:56:19 + --> $DIR/feature-gate.rs:27:19 | LL | while true && let 0 = 1 {} | ^^^^^^^^^ @@ -161,7 +44,7 @@ LL | while true && let 0 = 1 {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:59:11 + --> $DIR/feature-gate.rs:30:11 | LL | while let 0 = 1 && true {} | ^^^^^^^^^ @@ -170,88 +53,7 @@ LL | while let 0 = 1 && true {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:62:12 - | -LL | while (let 0 = 1) && true {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:65:20 - | -LL | while true && (let 0 = 1) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:68:12 - | -LL | while (let 0 = 1) && (let 0 = 1) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:68:27 - | -LL | while (let 0 = 1) && (let 0 = 1) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:72:11 - | -LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:72:24 - | -LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:72:38 - | -LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:72:51 - | -LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:72:64 - | -LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:79:11 + --> $DIR/feature-gate.rs:33:11 | LL | while let Range { start: _, end: _ } = (true..true) && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -260,7 +62,7 @@ LL | while let Range { start: _, end: _ } = (true..true) && false {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:99:20 + --> $DIR/feature-gate.rs:49:20 | LL | #[cfg(FALSE)] (let 0 = 1); | ^^^^^^^^^ @@ -269,7 +71,7 @@ LL | #[cfg(FALSE)] (let 0 = 1); = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:86:17 + --> $DIR/feature-gate.rs:40:17 | LL | noop_expr!((let 0 = 1)); | ^^^^^^^^^ @@ -277,24 +79,6 @@ LL | noop_expr!((let 0 = 1)); = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:95:16 - | -LL | use_expr!((let 0 = 1 && 0 == 0)); - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:97:16 - | -LL | use_expr!((let 0 = 1)); - | ^^^^^^^^^ - | - = note: see issue #53667 for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error: aborting due to 33 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0658`. From f1a40410ecce3c1b115e244c7e189e019e226c13 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 16:30:49 +0200 Subject: [PATCH 02/15] Return status from futex_wake(). --- library/std/src/sys/unix/futex.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs index c61d948fb601d..4231241a14224 100644 --- a/library/std/src/sys/unix/futex.rs +++ b/library/std/src/sys/unix/futex.rs @@ -69,14 +69,14 @@ pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option) { } #[cfg(any(target_os = "linux", target_os = "android"))] -pub fn futex_wake(futex: &AtomicI32) { +pub fn futex_wake(futex: &AtomicI32) -> bool { unsafe { libc::syscall( libc::SYS_futex, futex as *const AtomicI32, libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG, 1, - ); + ) > 0 } } @@ -93,12 +93,10 @@ pub fn futex_wake_all(futex: &AtomicI32) { } #[cfg(target_os = "emscripten")] -pub fn futex_wake(futex: &AtomicI32) { +pub fn futex_wake(futex: &AtomicI32) -> bool { extern "C" { fn emscripten_futex_wake(addr: *const AtomicI32, count: libc::c_int) -> libc::c_int; } - unsafe { - emscripten_futex_wake(futex as *const AtomicI32, 1); - } + unsafe { emscripten_futex_wake(futex as *const AtomicI32, 1) > 0 } } From 6cb463cb112a05298ce2467085b64dfb4a3d63b3 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 16:31:11 +0200 Subject: [PATCH 03/15] Add futex-based RwLock on Linux. --- .../std/src/sys/unix/locks/futex_rwlock.rs | 293 ++++++++++++++++++ library/std/src/sys/unix/locks/mod.rs | 4 +- 2 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 library/std/src/sys/unix/locks/futex_rwlock.rs diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs new file mode 100644 index 0000000000000..0665d7b3bfdc5 --- /dev/null +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -0,0 +1,293 @@ +use crate::sync::atomic::{ + AtomicI32, + Ordering::{Acquire, Relaxed, Release}, +}; +use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all}; + +pub type MovableRwLock = RwLock; + +pub struct RwLock { + // The state consists of a 30-bit reader counter, a 'readers waiting' flag, and a 'writers waiting' flag. + // Bits 0..30: + // 0: Unlocked + // 1..=0x3FFF_FFFE: Locked by N readers + // 0x3FFF_FFFF: Write locked + // Bit 30: Readers are waiting on this futex. + // Bit 31: Writers are waiting on the writer_notify futex. + state: AtomicI32, + // The 'condition variable' to notify writers through. + // Incremented on every signal. + writer_notify: AtomicI32, +} + +const READ_LOCKED: i32 = 1; +const MASK: i32 = (1 << 30) - 1; +const WRITE_LOCKED: i32 = MASK; +const MAX_READERS: i32 = MASK - 1; +const READERS_WAITING: i32 = 1 << 30; +const WRITERS_WAITING: i32 = 1 << 31; + +fn unlocked(state: i32) -> bool { + state & MASK == 0 +} + +fn write_locked(state: i32) -> bool { + state & MASK == WRITE_LOCKED +} + +fn readers_waiting(state: i32) -> bool { + state & READERS_WAITING != 0 +} + +fn writers_waiting(state: i32) -> bool { + state & WRITERS_WAITING != 0 +} + +fn read_lockable(state: i32) -> bool { + // This also returns false if the counter could overflow if we tried to read lock it. + state & MASK < MAX_READERS && !readers_waiting(state) && !writers_waiting(state) +} + +fn reached_max_readers(state: i32) -> bool { + state & MASK == MAX_READERS +} + +impl RwLock { + #[inline] + pub const fn new() -> Self { + Self { state: AtomicI32::new(0), writer_notify: AtomicI32::new(0) } + } + + #[inline] + pub unsafe fn destroy(&self) {} + + #[inline] + pub unsafe fn try_read(&self) -> bool { + self.state + .fetch_update(Acquire, Relaxed, |s| read_lockable(s).then(|| s + READ_LOCKED)) + .is_ok() + } + + #[inline] + pub unsafe fn read(&self) { + if !self.try_read() { + self.read_contended(); + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + let state = self.state.fetch_sub(READ_LOCKED, Release) - 1; + + // It's impossible for a reader to be waiting on a read-locked RwLock, + // except if there is also a writer waiting. + debug_assert!(!readers_waiting(state) || writers_waiting(state)); + + // Wake up a writer if we were the last reader and there's a writer waiting. + if unlocked(state) && writers_waiting(state) { + self.wake_writer_or_readers(state); + } + } + + #[cold] + fn read_contended(&self) { + let mut state = self.spin_read(); + + loop { + // If we can lock it, lock it. + if read_lockable(state) { + match self.state.compare_exchange(state, state + READ_LOCKED, Acquire, Relaxed) { + Ok(_) => return, // Locked! + Err(s) => { + state = s; + continue; + } + } + } + + // Check for overflow. + if reached_max_readers(state) { + panic!("too many active read locks on RwLock"); + } + + // Make sure the readers waiting bit is set before we go to sleep. + if !readers_waiting(state) { + if let Err(s) = + self.state.compare_exchange(state, state | READERS_WAITING, Relaxed, Relaxed) + { + state = s; + continue; + } + } + + // Wait for the state to change. + futex_wait(&self.state, state | READERS_WAITING, None); + + // Spin again after waking up. + state = self.spin_read(); + } + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + self.state.fetch_update(Acquire, Relaxed, |s| unlocked(s).then(|| s + WRITE_LOCKED)).is_ok() + } + + #[inline] + pub unsafe fn write(&self) { + if !self.try_write() { + self.write_contended(); + } + } + + #[inline] + pub unsafe fn write_unlock(&self) { + let state = self.state.fetch_sub(WRITE_LOCKED, Release) - WRITE_LOCKED; + + debug_assert!(unlocked(state)); + + if writers_waiting(state) || readers_waiting(state) { + self.wake_writer_or_readers(state); + } + } + + #[cold] + fn write_contended(&self) { + let mut state = self.spin_write(); + + let mut other_writers_waiting = 0; + + loop { + // If it's unlocked, we try to lock it. + if unlocked(state) { + match self.state.compare_exchange( + state, + state | WRITE_LOCKED | other_writers_waiting, + Acquire, + Relaxed, + ) { + Ok(_) => return, // Locked! + Err(s) => { + state = s; + continue; + } + } + } + + // Set the waiting bit indicating that we're waiting on it. + if !writers_waiting(state) { + if let Err(s) = + self.state.compare_exchange(state, state | WRITERS_WAITING, Relaxed, Relaxed) + { + state = s; + continue; + } + } + + // Other writers might be waiting now too, so we should make sure + // we keep that bit on once we manage lock it. + other_writers_waiting = WRITERS_WAITING; + + // Examine the notification counter before we check if `state` has changed, + // to make sure we don't miss any notifications. + let seq = self.writer_notify.load(Acquire); + + // Don't go to sleep if the lock has become available, + // or if the writers waiting bit is no longer set. + let s = self.state.load(Relaxed); + if unlocked(state) || !writers_waiting(s) { + state = s; + continue; + } + + // Wait for the state to change. + futex_wait(&self.writer_notify, seq, None); + + // Spin again after waking up. + state = self.spin_write(); + } + } + + /// Wake up waiting threads after unlocking. + /// + /// If both are waiting, this will wake up only one writer, but will fall + /// back to waking up readers if there was no writer to wake up. + #[cold] + fn wake_writer_or_readers(&self, mut state: i32) { + assert!(unlocked(state)); + + // The readers waiting bit might be turned on at any point now, + // since readers will block when there's anything waiting. + // Writers will just lock the lock though, regardless of the waiting bits, + // so we don't have to worry about the writer waiting bit. + // + // If the lock gets locked in the meantime, we don't have to do + // anything, because then the thread that locked the lock will take + // care of waking up waiters when it unlocks. + + // If only writers are waiting, wake one of them up. + if state == WRITERS_WAITING { + match self.state.compare_exchange(state, 0, Relaxed, Relaxed) { + Ok(_) => { + self.wake_writer(); + return; + } + Err(s) => { + // Maybe some readers are now waiting too. So, continue to the next `if`. + state = s; + } + } + } + + // If both writers and readers are waiting, leave the readers waiting + // and only wake up one writer. + if state == READERS_WAITING + WRITERS_WAITING { + if self.state.compare_exchange(state, READERS_WAITING, Relaxed, Relaxed).is_err() { + // The lock got locked. Not our problem anymore. + return; + } + if self.wake_writer() { + return; + } + // No writers were actually waiting. Continue to wake up readers instead. + state = READERS_WAITING; + } + + // If readers are waiting, wake them all up. + if state == READERS_WAITING { + if self.state.compare_exchange(state, 0, Relaxed, Relaxed).is_ok() { + futex_wake_all(&self.state); + } + } + } + + fn wake_writer(&self) -> bool { + self.writer_notify.fetch_add(1, Release); + futex_wake(&self.writer_notify) + } + + /// Spin for a while, but stop directly at the given condition. + fn spin_until(&self, f: impl Fn(i32) -> bool) -> i32 { + let mut spin = 100; // Chosen by fair dice roll. + loop { + let state = self.state.load(Relaxed); + if f(state) || spin == 0 { + return state; + } + crate::hint::spin_loop(); + spin -= 1; + } + } + + fn spin_write(&self) -> i32 { + // Stop spinning when it's unlocked or when there's waiting writers, to keep things somewhat fair. + self.spin_until(|state| unlocked(state) || writers_waiting(state)) + } + + fn spin_read(&self) -> i32 { + // Stop spinning when it's unlocked or read locked, or when there's waiting threads. + self.spin_until(|state| { + !write_locked(state) || readers_waiting(state) || writers_waiting(state) + }) + } +} diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs index 2b8dd168068b5..85afc939d2e89 100644 --- a/library/std/src/sys/unix/locks/mod.rs +++ b/library/std/src/sys/unix/locks/mod.rs @@ -4,13 +4,13 @@ cfg_if::cfg_if! { target_os = "android", ))] { mod futex; + mod futex_rwlock; #[allow(dead_code)] mod pthread_mutex; // Only used for PthreadMutexAttr, needed by pthread_remutex. mod pthread_remutex; // FIXME: Implement this using a futex - mod pthread_rwlock; // FIXME: Implement this using a futex pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; pub use pthread_remutex::ReentrantMutex; - pub use pthread_rwlock::{RwLock, MovableRwLock}; + pub use futex_rwlock::{RwLock, MovableRwLock}; } else { mod pthread_mutex; mod pthread_remutex; From 307aa588f42b65cbce27f0e366197e27ef531c77 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 8 Apr 2022 16:07:07 +0200 Subject: [PATCH 04/15] Fix typo in futex rwlock. Co-authored-by: Amanieu d'Antras --- library/std/src/sys/unix/locks/futex_rwlock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index 0665d7b3bfdc5..19ec6fa834908 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -77,7 +77,7 @@ impl RwLock { #[inline] pub unsafe fn read_unlock(&self) { - let state = self.state.fetch_sub(READ_LOCKED, Release) - 1; + let state = self.state.fetch_sub(READ_LOCKED, Release) - READ_LOCKED; // It's impossible for a reader to be waiting on a read-locked RwLock, // except if there is also a writer waiting. From bf3ef0da0c630ab239e4f26e86602eabe585e74f Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sat, 9 Apr 2022 15:25:46 -0400 Subject: [PATCH 05/15] Switch to the 'normal' basic block for writing asm outputs if needed. We may sometimes emit an `invoke` instead of a `call` for inline assembly during the MIR -> LLVM IR lowering. But we failed to update the IR builder's current basic block before writing the results to the outputs. This would result in invalid IR because the basic block would end in a `store` instruction, which isn't a valid terminator. --- compiler/rustc_codegen_llvm/src/asm.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 03c390b4bd427..91d132eb34350 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -290,6 +290,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs }); + // Switch to the 'normal' basic block if we did an `invoke` instead of a `call` + if let Some((dest, _, _)) = dest_catch_funclet { + self.switch_to_block(dest); + } + // Write results to outputs for (idx, op) in operands.iter().enumerate() { if let InlineAsmOperandRef::Out { reg, place: Some(place), .. } From 0b2f3604fd733db5ad9498eaf129655879c242b3 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sat, 9 Apr 2022 15:16:38 -0700 Subject: [PATCH 06/15] Update asm-may_unwind test to handle use of asm with outputs. --- src/test/codegen/asm-may_unwind.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/asm-may_unwind.rs b/src/test/codegen/asm-may_unwind.rs index 3b34d79c3a946..bf4202764a7ec 100644 --- a/src/test/codegen/asm-may_unwind.rs +++ b/src/test/codegen/asm-may_unwind.rs @@ -18,10 +18,23 @@ impl Drop for Foo { } } -// CHECK-LABEL: @may_unwind +// CHECK-LABEL: @asm_may_unwind #[no_mangle] -pub unsafe fn may_unwind() { +pub unsafe fn asm_may_unwind() { let _m = Foo; // CHECK: invoke void asm sideeffect alignstack inteldialect unwind "" asm!("", options(may_unwind)); } + +// CHECK-LABEL: @asm_with_result_may_unwind +#[no_mangle] +pub unsafe fn asm_with_result_may_unwind() -> u64 { + let _m = Foo; + let res: u64; + // CHECK: [[RES:%[0-9]+]] = invoke i64 asm sideeffect alignstack inteldialect unwind + // CHECK-NEXT: to label %[[NORMALBB:[a-b0-9]+]] + asm!("mov {}, 1", out(reg) res, options(may_unwind)); + // CHECK: [[NORMALBB]]: + // CHECK: ret i64 [[RES:%[0-9]+]] + res +} From bb3a071df8d75bad5e6fecb54ec61477ded777c3 Mon Sep 17 00:00:00 2001 From: nyanpasu64 Date: Sun, 10 Apr 2022 12:41:31 -0700 Subject: [PATCH 07/15] Fix formatting error in pin.rs docs --- library/core/src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index cef6a68b4d329..720317b05e080 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -175,7 +175,7 @@ //! relies on pinning requires unsafe code, but be aware that deciding to make //! use of pinning in your type (for example by implementing some operation on //! [Pin]<[&]Self> or [Pin]<[&mut] Self>) has consequences for your -//! [`Drop`][Drop]implementation as well: if an element of your type could have been pinned, +//! [`Drop`][Drop] implementation as well: if an element of your type could have been pinned, //! you must treat [`Drop`][Drop] as implicitly taking [Pin]<[&mut] Self>. //! //! For example, you could implement [`Drop`][Drop] as follows: From b92cd1a32c842e82575e59374545dda5f9b9f77a Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Sun, 10 Apr 2022 15:04:57 -0500 Subject: [PATCH 08/15] Clarify str::from_utf8_unchecked's invariants Specifically, make it clear that it is immediately UB to pass ill-formed UTF-8 into the function. The previous wording left space to interpret that the UB only occurred when calling another function, which "assumes that `&str`s are valid UTF-8." This does not change whether str being UTF-8 is a safety or a validity invariant. (As per previous discussion, it is a safety invariant, not a validity invariant.) It just makes it clear that valid UTF-8 is a precondition of str::from_utf8_unchecked, and that emitting an Abstract Machine fault (e.g. UB or a sanitizer error) on invalid UTF-8 is a valid thing to do. If user code wants to create an unsafe `&str` pointing to ill-formed UTF-8, it must be done via transmutes. Also, just, don't. --- library/core/src/str/converts.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index ef26cbfb640bf..81b1db4ac6fed 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -144,11 +144,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { /// /// # Safety /// -/// This function is unsafe because it does not check that the bytes passed to -/// it are valid UTF-8. If this constraint is violated, undefined behavior -/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. -/// -/// [`&str`]: str +/// The bytes passed in must be valid UTF-8. /// /// # Examples /// From 986c1687f868e7839f4e967bba32aeec6b2df5da Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 10 Apr 2022 16:37:24 -0500 Subject: [PATCH 09/15] Remove duplicate aliases for `codegen_{cranelift,gcc}` Bootstrap already allows selecting these in `PathSet::has`, which allows any string that matches the end of a full path. I found these by adding `assert!(path.exists())` in `StepDescription::paths`. I think ideally we wouldn't have any aliases that aren't paths, but I've held off on enforcing that here since it may be controversial, I'll open a separate PR. --- src/bootstrap/check.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 28e7f1fdca7a1..432a6c34ed584 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -243,12 +243,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.paths(&[ - "compiler/rustc_codegen_cranelift", - "rustc_codegen_cranelift", - "compiler/rustc_codegen_gcc", - "rustc_codegen_gcc", - ]) + run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"]) } fn make_run(run: RunConfig<'_>) { From 4c1438332be229ee1d1e1dbc02181a03678e04f9 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 10 Apr 2022 16:41:21 -0500 Subject: [PATCH 10/15] Add `build compiler/rustc_codegen_gcc` as an alias for `CodegenBackend` These paths (`_cranelift` and `_gcc`) are somewhat misleading, since they actually tell bootstrap to build *all* codegen backends. But this seems like a useful improvement in the meantime. --- src/bootstrap/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index afc333b5048ce..45991381dc0fe 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -795,7 +795,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("compiler/rustc_codegen_cranelift") + run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"]) } fn make_run(run: RunConfig<'_>) { From aeb3df76f66c4496b0fe4ed64ea86896c6bc8640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 11 Apr 2022 10:05:05 +0200 Subject: [PATCH 11/15] CI: do not compile libcore twice when performing LLVM PGO --- src/ci/pgo.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh index 689e6a11d6110..691d1282cf499 100755 --- a/src/ci/pgo.sh +++ b/src/ci/pgo.sh @@ -47,12 +47,6 @@ python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \ --stage 2 library/std \ --llvm-profile-generate -# Profile libcore compilation in opt-level=0 and opt-level=3 -RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \ - --edition=2021 --crate-type=lib ../library/core/src/lib.rs -RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \ - --edition=2021 --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs - # Compile rustc perf cp -r /tmp/rustc-perf ./ chown -R $(whoami): ./rustc-perf From 7c287915654d0b3f1cc4b060b41db32a83b000c5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 11 Apr 2022 14:26:52 +0200 Subject: [PATCH 12/15] Add doc comments to futex operations. --- library/std/src/sys/unix/futex.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs index 4231241a14224..b45d1c0149cb4 100644 --- a/library/std/src/sys/unix/futex.rs +++ b/library/std/src/sys/unix/futex.rs @@ -7,6 +7,11 @@ use crate::sync::atomic::AtomicI32; use crate::time::Duration; +/// Wait for a futex_wake operation to wake us. +/// +/// Returns directly if the futex doesn't hold the expected value. +/// +/// Returns false on timeout, and true in all other cases. #[cfg(any(target_os = "linux", target_os = "android"))] pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option) -> bool { use super::time::Timespec; @@ -68,6 +73,10 @@ pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option) { } } +/// Wake up one thread that's blocked on futex_wait on this futex. +/// +/// Returns true if this actually woke up such a thread, +/// or false if no thread was waiting on this futex. #[cfg(any(target_os = "linux", target_os = "android"))] pub fn futex_wake(futex: &AtomicI32) -> bool { unsafe { @@ -80,6 +89,7 @@ pub fn futex_wake(futex: &AtomicI32) -> bool { } } +/// Wake up all threads that are waiting on futex_wait on this futex. #[cfg(any(target_os = "linux", target_os = "android"))] pub fn futex_wake_all(futex: &AtomicI32) { unsafe { From 1f2c2bb24f88e9fd008ce130017cc1628626d296 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 11 Apr 2022 14:27:06 +0200 Subject: [PATCH 13/15] Add comments to futex rwlock implementation. --- library/std/src/sys/unix/locks/futex_rwlock.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index 19ec6fa834908..f602479bb52bb 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -45,6 +45,11 @@ fn writers_waiting(state: i32) -> bool { fn read_lockable(state: i32) -> bool { // This also returns false if the counter could overflow if we tried to read lock it. + // + // We don't allow read-locking if there's readers waiting, even if the lock is unlocked + // and there's no writers waiting. The only situation when this happens is after unlocking, + // at which point the unlocking thread might be waking up writers, which have priority over readers. + // The unlocking thread will clear the readers waiting bit and wake up readers, if necssary. state & MASK < MAX_READERS && !readers_waiting(state) && !writers_waiting(state) } @@ -249,7 +254,8 @@ impl RwLock { if self.wake_writer() { return; } - // No writers were actually waiting. Continue to wake up readers instead. + // No writers were actually blocked on futex_wait, so we continue + // to wake up readers instead, since we can't be sure if we notified a writer. state = READERS_WAITING; } @@ -261,6 +267,11 @@ impl RwLock { } } + /// This wakes one writer and returns true if we woke up a writer that was + /// blocked on futex_wait. + /// + /// If this returns false, it might still be the case that we notified a + /// writer that was about to go to sleep. fn wake_writer(&self) -> bool { self.writer_notify.fetch_add(1, Release); futex_wake(&self.writer_notify) From c4a4f48c527453ddce2a2f1496473319290c6d8e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 11 Apr 2022 14:29:32 +0200 Subject: [PATCH 14/15] Use compare_exchange_weak in futex rwlock implementation. --- library/std/src/sys/unix/locks/futex_rwlock.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index f602479bb52bb..2862cdea7dad7 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -75,7 +75,13 @@ impl RwLock { #[inline] pub unsafe fn read(&self) { - if !self.try_read() { + let state = self.state.load(Relaxed); + if !read_lockable(state) + || self + .state + .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) + .is_err() + { self.read_contended(); } } @@ -101,7 +107,8 @@ impl RwLock { loop { // If we can lock it, lock it. if read_lockable(state) { - match self.state.compare_exchange(state, state + READ_LOCKED, Acquire, Relaxed) { + match self.state.compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) + { Ok(_) => return, // Locked! Err(s) => { state = s; @@ -140,7 +147,7 @@ impl RwLock { #[inline] pub unsafe fn write(&self) { - if !self.try_write() { + if self.state.compare_exchange_weak(0, WRITE_LOCKED, Acquire, Relaxed).is_err() { self.write_contended(); } } @@ -165,7 +172,7 @@ impl RwLock { loop { // If it's unlocked, we try to lock it. if unlocked(state) { - match self.state.compare_exchange( + match self.state.compare_exchange_weak( state, state | WRITE_LOCKED | other_writers_waiting, Acquire, From 83393817419e197d696fb724560bc55b18346a01 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 11 Apr 2022 14:52:02 +0200 Subject: [PATCH 15/15] Use is_ or has_ prefix for pure `-> bool` functions. --- .../std/src/sys/unix/locks/futex_rwlock.rs | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index 2862cdea7dad7..aa16da97e4c19 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -27,33 +27,33 @@ const MAX_READERS: i32 = MASK - 1; const READERS_WAITING: i32 = 1 << 30; const WRITERS_WAITING: i32 = 1 << 31; -fn unlocked(state: i32) -> bool { +fn is_unlocked(state: i32) -> bool { state & MASK == 0 } -fn write_locked(state: i32) -> bool { +fn is_write_locked(state: i32) -> bool { state & MASK == WRITE_LOCKED } -fn readers_waiting(state: i32) -> bool { +fn has_readers_waiting(state: i32) -> bool { state & READERS_WAITING != 0 } -fn writers_waiting(state: i32) -> bool { +fn has_writers_waiting(state: i32) -> bool { state & WRITERS_WAITING != 0 } -fn read_lockable(state: i32) -> bool { +fn is_read_lockable(state: i32) -> bool { // This also returns false if the counter could overflow if we tried to read lock it. // // We don't allow read-locking if there's readers waiting, even if the lock is unlocked // and there's no writers waiting. The only situation when this happens is after unlocking, // at which point the unlocking thread might be waking up writers, which have priority over readers. // The unlocking thread will clear the readers waiting bit and wake up readers, if necssary. - state & MASK < MAX_READERS && !readers_waiting(state) && !writers_waiting(state) + state & MASK < MAX_READERS && !has_readers_waiting(state) && !has_writers_waiting(state) } -fn reached_max_readers(state: i32) -> bool { +fn has_reached_max_readers(state: i32) -> bool { state & MASK == MAX_READERS } @@ -69,14 +69,14 @@ impl RwLock { #[inline] pub unsafe fn try_read(&self) -> bool { self.state - .fetch_update(Acquire, Relaxed, |s| read_lockable(s).then(|| s + READ_LOCKED)) + .fetch_update(Acquire, Relaxed, |s| is_read_lockable(s).then(|| s + READ_LOCKED)) .is_ok() } #[inline] pub unsafe fn read(&self) { let state = self.state.load(Relaxed); - if !read_lockable(state) + if !is_read_lockable(state) || self .state .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) @@ -92,10 +92,10 @@ impl RwLock { // It's impossible for a reader to be waiting on a read-locked RwLock, // except if there is also a writer waiting. - debug_assert!(!readers_waiting(state) || writers_waiting(state)); + debug_assert!(!has_readers_waiting(state) || has_writers_waiting(state)); // Wake up a writer if we were the last reader and there's a writer waiting. - if unlocked(state) && writers_waiting(state) { + if is_unlocked(state) && has_writers_waiting(state) { self.wake_writer_or_readers(state); } } @@ -106,7 +106,7 @@ impl RwLock { loop { // If we can lock it, lock it. - if read_lockable(state) { + if is_read_lockable(state) { match self.state.compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) { Ok(_) => return, // Locked! @@ -118,12 +118,12 @@ impl RwLock { } // Check for overflow. - if reached_max_readers(state) { + if has_reached_max_readers(state) { panic!("too many active read locks on RwLock"); } // Make sure the readers waiting bit is set before we go to sleep. - if !readers_waiting(state) { + if !has_readers_waiting(state) { if let Err(s) = self.state.compare_exchange(state, state | READERS_WAITING, Relaxed, Relaxed) { @@ -142,7 +142,9 @@ impl RwLock { #[inline] pub unsafe fn try_write(&self) -> bool { - self.state.fetch_update(Acquire, Relaxed, |s| unlocked(s).then(|| s + WRITE_LOCKED)).is_ok() + self.state + .fetch_update(Acquire, Relaxed, |s| is_unlocked(s).then(|| s + WRITE_LOCKED)) + .is_ok() } #[inline] @@ -156,9 +158,9 @@ impl RwLock { pub unsafe fn write_unlock(&self) { let state = self.state.fetch_sub(WRITE_LOCKED, Release) - WRITE_LOCKED; - debug_assert!(unlocked(state)); + debug_assert!(is_unlocked(state)); - if writers_waiting(state) || readers_waiting(state) { + if has_writers_waiting(state) || has_readers_waiting(state) { self.wake_writer_or_readers(state); } } @@ -171,7 +173,7 @@ impl RwLock { loop { // If it's unlocked, we try to lock it. - if unlocked(state) { + if is_unlocked(state) { match self.state.compare_exchange_weak( state, state | WRITE_LOCKED | other_writers_waiting, @@ -187,7 +189,7 @@ impl RwLock { } // Set the waiting bit indicating that we're waiting on it. - if !writers_waiting(state) { + if !has_writers_waiting(state) { if let Err(s) = self.state.compare_exchange(state, state | WRITERS_WAITING, Relaxed, Relaxed) { @@ -207,7 +209,7 @@ impl RwLock { // Don't go to sleep if the lock has become available, // or if the writers waiting bit is no longer set. let s = self.state.load(Relaxed); - if unlocked(state) || !writers_waiting(s) { + if is_unlocked(state) || !has_writers_waiting(s) { state = s; continue; } @@ -226,7 +228,7 @@ impl RwLock { /// back to waking up readers if there was no writer to wake up. #[cold] fn wake_writer_or_readers(&self, mut state: i32) { - assert!(unlocked(state)); + assert!(is_unlocked(state)); // The readers waiting bit might be turned on at any point now, // since readers will block when there's anything waiting. @@ -299,13 +301,13 @@ impl RwLock { fn spin_write(&self) -> i32 { // Stop spinning when it's unlocked or when there's waiting writers, to keep things somewhat fair. - self.spin_until(|state| unlocked(state) || writers_waiting(state)) + self.spin_until(|state| is_unlocked(state) || has_writers_waiting(state)) } fn spin_read(&self) -> i32 { // Stop spinning when it's unlocked or read locked, or when there's waiting threads. self.spin_until(|state| { - !write_locked(state) || readers_waiting(state) || writers_waiting(state) + !is_write_locked(state) || has_readers_waiting(state) || has_writers_waiting(state) }) } }