summaryrefslogtreecommitdiffstats
path: root/tests/ui/expr
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/expr
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/expr')
-rw-r--r--tests/ui/expr/compound-assignment/eval-order.rs76
-rw-r--r--tests/ui/expr/if-bot.rs6
-rw-r--r--tests/ui/expr/if/attrs/bad-cfg.rs5
-rw-r--r--tests/ui/expr/if/attrs/bad-cfg.stderr8
-rw-r--r--tests/ui/expr/if/attrs/builtin-if-attr.rs12
-rw-r--r--tests/ui/expr/if/attrs/cfg-false-if-attr.rs43
-rw-r--r--tests/ui/expr/if/attrs/else-attrs.rs25
-rw-r--r--tests/ui/expr/if/attrs/else-attrs.stderr26
-rw-r--r--tests/ui/expr/if/attrs/gate-whole-expr.rs15
-rw-r--r--tests/ui/expr/if/attrs/let-chains-attr.rs13
-rw-r--r--tests/ui/expr/if/attrs/stmt-expr-gated.rs6
-rw-r--r--tests/ui/expr/if/attrs/stmt-expr-gated.stderr12
-rw-r--r--tests/ui/expr/if/bad-if-let-suggestion.rs24
-rw-r--r--tests/ui/expr/if/bad-if-let-suggestion.stderr74
-rw-r--r--tests/ui/expr/if/expr-if-panic-fn.rs20
-rw-r--r--tests/ui/expr/if/expr-if-panic-pass.rs18
-rw-r--r--tests/ui/expr/if/expr-if-panic.rs13
-rw-r--r--tests/ui/expr/if/expr-if.rs52
-rw-r--r--tests/ui/expr/if/if-branch-types.rs5
-rw-r--r--tests/ui/expr/if/if-branch-types.stderr16
-rw-r--r--tests/ui/expr/if/if-check-panic.rs25
-rw-r--r--tests/ui/expr/if/if-check.rs17
-rw-r--r--tests/ui/expr/if/if-cond-bot.rs13
-rw-r--r--tests/ui/expr/if/if-else-type-mismatch.rs46
-rw-r--r--tests/ui/expr/if/if-else-type-mismatch.stderr116
-rw-r--r--tests/ui/expr/if/if-let-arm-types.rs11
-rw-r--r--tests/ui/expr/if/if-let-arm-types.stderr17
-rw-r--r--tests/ui/expr/if/if-let.rs49
-rw-r--r--tests/ui/expr/if/if-let.stderr69
-rw-r--r--tests/ui/expr/if/if-loop.rs8
-rw-r--r--tests/ui/expr/if/if-no-match-bindings.rs28
-rw-r--r--tests/ui/expr/if/if-no-match-bindings.stderr95
-rw-r--r--tests/ui/expr/if/if-ret.rs8
-rw-r--r--tests/ui/expr/if/if-ret.stderr12
-rw-r--r--tests/ui/expr/if/if-typeck.rs10
-rw-r--r--tests/ui/expr/if/if-typeck.stderr12
-rw-r--r--tests/ui/expr/if/if-without-block.rs7
-rw-r--r--tests/ui/expr/if/if-without-block.stderr14
-rw-r--r--tests/ui/expr/if/if-without-else-as-fn-expr.rs49
-rw-r--r--tests/ui/expr/if/if-without-else-as-fn-expr.stderr83
-rw-r--r--tests/ui/expr/if/if-without-else-result.rs6
-rw-r--r--tests/ui/expr/if/if-without-else-result.stderr15
-rw-r--r--tests/ui/expr/if/issue-4201.rs9
-rw-r--r--tests/ui/expr/if/issue-4201.stderr18
-rw-r--r--tests/ui/expr/malformed_closure/missing_braces_around_block.fixed19
-rw-r--r--tests/ui/expr/malformed_closure/missing_braces_around_block.rs19
-rw-r--r--tests/ui/expr/malformed_closure/missing_braces_around_block.stderr38
-rw-r--r--tests/ui/expr/malformed_closure/ruby_style_closure.rs15
-rw-r--r--tests/ui/expr/malformed_closure/ruby_style_closure.stderr9
49 files changed, 1306 insertions, 0 deletions
diff --git a/tests/ui/expr/compound-assignment/eval-order.rs b/tests/ui/expr/compound-assignment/eval-order.rs
new file mode 100644
index 000000000..658adae19
--- /dev/null
+++ b/tests/ui/expr/compound-assignment/eval-order.rs
@@ -0,0 +1,76 @@
+// Test evaluation order of operands of the compound assignment operators
+
+// run-pass
+
+use std::ops::AddAssign;
+
+enum Side {
+ Lhs,
+ Rhs,
+}
+
+// In the following tests, we place our value into a wrapper type so that we
+// can do an element access as the outer place expression. If we just had the
+// block expression, it'd be a value expression and not compile.
+struct Wrapper<T>(T);
+
+// Evaluation order for `a op= b` where typeof(a) and typeof(b) are primitives
+// is first `b` then `a`.
+fn primitive_compound() {
+ let mut side_order = vec![];
+ let mut int = Wrapper(0);
+
+ {
+ side_order.push(Side::Lhs);
+ int
+ }.0 += {
+ side_order.push(Side::Rhs);
+ 0
+ };
+
+ assert!(matches!(side_order[..], [Side::Rhs, Side::Lhs]));
+}
+
+// Evaluation order for `a op=b` otherwise is first `a` then `b`.
+fn generic_compound<T: AddAssign<T> + Default>() {
+ let mut side_order = vec![];
+ let mut add_assignable: Wrapper<T> = Wrapper(Default::default());
+
+ {
+ side_order.push(Side::Lhs);
+ add_assignable
+ }.0 += {
+ side_order.push(Side::Rhs);
+ Default::default()
+ };
+
+ assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs]));
+}
+
+fn custom_compound() {
+ struct Custom;
+
+ impl AddAssign<()> for Custom {
+ fn add_assign(&mut self, _: ()) {
+ // this block purposely left blank
+ }
+ }
+
+ let mut side_order = vec![];
+ let mut custom = Wrapper(Custom);
+
+ {
+ side_order.push(Side::Lhs);
+ custom
+ }.0 += {
+ side_order.push(Side::Rhs);
+ };
+
+ assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs]));
+}
+
+fn main() {
+ primitive_compound();
+ generic_compound::<i32>();
+ custom_compound();
+}
diff --git a/tests/ui/expr/if-bot.rs b/tests/ui/expr/if-bot.rs
new file mode 100644
index 000000000..0f09db530
--- /dev/null
+++ b/tests/ui/expr/if-bot.rs
@@ -0,0 +1,6 @@
+// run-pass
+
+pub fn main() {
+ let i: isize = if false { panic!() } else { 5 };
+ println!("{}", i);
+}
diff --git a/tests/ui/expr/if/attrs/bad-cfg.rs b/tests/ui/expr/if/attrs/bad-cfg.rs
new file mode 100644
index 000000000..3f84929a0
--- /dev/null
+++ b/tests/ui/expr/if/attrs/bad-cfg.rs
@@ -0,0 +1,5 @@
+#![feature(stmt_expr_attributes)]
+
+fn main() {
+ let _ = #[cfg(FALSE)] if true {}; //~ ERROR removing an expression
+}
diff --git a/tests/ui/expr/if/attrs/bad-cfg.stderr b/tests/ui/expr/if/attrs/bad-cfg.stderr
new file mode 100644
index 000000000..8a2890886
--- /dev/null
+++ b/tests/ui/expr/if/attrs/bad-cfg.stderr
@@ -0,0 +1,8 @@
+error: removing an expression is not supported in this position
+ --> $DIR/bad-cfg.rs:4:13
+ |
+LL | let _ = #[cfg(FALSE)] if true {};
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/expr/if/attrs/builtin-if-attr.rs b/tests/ui/expr/if/attrs/builtin-if-attr.rs
new file mode 100644
index 000000000..7e2906615
--- /dev/null
+++ b/tests/ui/expr/if/attrs/builtin-if-attr.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+fn main() {
+ #[allow(unused_variables)]
+ if true {
+ let a = 1;
+ } else if false {
+ let b = 1;
+ } else {
+ let c = 1;
+ }
+}
diff --git a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs
new file mode 100644
index 000000000..1f77a1bb3
--- /dev/null
+++ b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs
@@ -0,0 +1,43 @@
+// check-pass
+
+#[cfg(FALSE)]
+fn simple_attr() {
+ #[attr] if true {}
+ #[allow_warnings] if true {}
+}
+
+#[cfg(FALSE)]
+fn if_else_chain() {
+ #[first_attr] if true {
+ } else if false {
+ } else {
+ }
+}
+
+#[cfg(FALSE)]
+fn if_let() {
+ #[attr] if let Some(_) = Some(true) {}
+}
+
+fn bar() {
+ #[cfg(FALSE)]
+ if true {
+ let x: () = true; // Should not error due to the #[cfg(FALSE)]
+ }
+
+ #[cfg_attr(not(unset_attr), cfg(FALSE))]
+ if true {
+ let a: () = true; // Should not error due to the applied #[cfg(FALSE)]
+ }
+}
+
+macro_rules! custom_macro {
+ ($expr:expr) => {}
+}
+
+custom_macro! {
+ #[attr] if true {}
+}
+
+
+fn main() {}
diff --git a/tests/ui/expr/if/attrs/else-attrs.rs b/tests/ui/expr/if/attrs/else-attrs.rs
new file mode 100644
index 000000000..85da7cf6b
--- /dev/null
+++ b/tests/ui/expr/if/attrs/else-attrs.rs
@@ -0,0 +1,25 @@
+#[cfg(FALSE)]
+fn if_else_parse_error() {
+ if true {
+ } #[attr] else if false { //~ ERROR expected
+ }
+}
+
+#[cfg(FALSE)]
+fn else_attr_ifparse_error() {
+ if true {
+ } else #[attr] if false { //~ ERROR outer attributes are not allowed
+ } else {
+ }
+}
+
+#[cfg(FALSE)]
+fn else_parse_error() {
+ if true {
+ } else if false {
+ } #[attr] else { //~ ERROR expected
+ }
+}
+
+fn main() {
+}
diff --git a/tests/ui/expr/if/attrs/else-attrs.stderr b/tests/ui/expr/if/attrs/else-attrs.stderr
new file mode 100644
index 000000000..273337705
--- /dev/null
+++ b/tests/ui/expr/if/attrs/else-attrs.stderr
@@ -0,0 +1,26 @@
+error: expected expression, found keyword `else`
+ --> $DIR/else-attrs.rs:4:15
+ |
+LL | } #[attr] else if false {
+ | ^^^^ expected expression
+
+error: outer attributes are not allowed on `if` and `else` branches
+ --> $DIR/else-attrs.rs:11:12
+ |
+LL | } else #[attr] if false {
+ | _______----_^^^^^^^_-
+ | | | |
+ | | | help: remove the attributes
+ | | the branch belongs to this `else`
+LL | | } else {
+LL | | }
+ | |_____- the attributes are attached to this branch
+
+error: expected expression, found keyword `else`
+ --> $DIR/else-attrs.rs:20:15
+ |
+LL | } #[attr] else {
+ | ^^^^ expected expression
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/expr/if/attrs/gate-whole-expr.rs b/tests/ui/expr/if/attrs/gate-whole-expr.rs
new file mode 100644
index 000000000..63772d54b
--- /dev/null
+++ b/tests/ui/expr/if/attrs/gate-whole-expr.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+fn main() {
+ let x = 1;
+
+ #[cfg(FALSE)]
+ if false {
+ x = 2;
+ } else if true {
+ x = 3;
+ } else {
+ x = 4;
+ }
+ assert_eq!(x, 1);
+}
diff --git a/tests/ui/expr/if/attrs/let-chains-attr.rs b/tests/ui/expr/if/attrs/let-chains-attr.rs
new file mode 100644
index 000000000..2cd873114
--- /dev/null
+++ b/tests/ui/expr/if/attrs/let-chains-attr.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+#![feature(let_chains)]
+
+#[cfg(FALSE)]
+fn foo() {
+ #[attr]
+ if let Some(_) = Some(true) && let Ok(_) = Ok(1) {
+ } else if let Some(false) = Some(true) {
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/expr/if/attrs/stmt-expr-gated.rs b/tests/ui/expr/if/attrs/stmt-expr-gated.rs
new file mode 100644
index 000000000..38599c8e6
--- /dev/null
+++ b/tests/ui/expr/if/attrs/stmt-expr-gated.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let _ = #[deny(warnings)] if true { //~ ERROR attributes on expressions
+ } else if false {
+ } else {
+ };
+}
diff --git a/tests/ui/expr/if/attrs/stmt-expr-gated.stderr b/tests/ui/expr/if/attrs/stmt-expr-gated.stderr
new file mode 100644
index 000000000..47dac39a9
--- /dev/null
+++ b/tests/ui/expr/if/attrs/stmt-expr-gated.stderr
@@ -0,0 +1,12 @@
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/stmt-expr-gated.rs:2:13
+ |
+LL | let _ = #[deny(warnings)] if true {
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/expr/if/bad-if-let-suggestion.rs b/tests/ui/expr/if/bad-if-let-suggestion.rs
new file mode 100644
index 000000000..a8b2a2830
--- /dev/null
+++ b/tests/ui/expr/if/bad-if-let-suggestion.rs
@@ -0,0 +1,24 @@
+// FIXME(compiler-errors): This really should suggest `let` on the RHS of the
+// `&&` operator, but that's kinda hard to do because of precedence.
+// Instead, for now we just make sure not to suggest `if let let`.
+fn a() {
+ if let x = 1 && i = 2 {}
+ //~^ ERROR cannot find value `i` in this scope
+ //~| ERROR `let` expressions in this position are unstable
+ //~| ERROR mismatched types
+ //~| ERROR `let` expressions are not supported here
+}
+
+fn b() {
+ if (i + j) = i {}
+ //~^ ERROR cannot find value `i` in this scope
+ //~| ERROR cannot find value `i` in this scope
+ //~| ERROR cannot find value `j` in this scope
+}
+
+fn c() {
+ if x[0] = 1 {}
+ //~^ ERROR cannot find value `x` in this scope
+}
+
+fn main() {}
diff --git a/tests/ui/expr/if/bad-if-let-suggestion.stderr b/tests/ui/expr/if/bad-if-let-suggestion.stderr
new file mode 100644
index 000000000..3a53a20b4
--- /dev/null
+++ b/tests/ui/expr/if/bad-if-let-suggestion.stderr
@@ -0,0 +1,74 @@
+error: `let` expressions are not supported here
+ --> $DIR/bad-if-let-suggestion.rs:5:8
+ |
+LL | if let x = 1 && i = 2 {}
+ | ^^^^^^^^^
+ |
+ = note: only supported directly in conditions of `if` and `while` expressions
+
+error[E0425]: cannot find value `i` in this scope
+ --> $DIR/bad-if-let-suggestion.rs:5:21
+ |
+LL | if let x = 1 && i = 2 {}
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `i` in this scope
+ --> $DIR/bad-if-let-suggestion.rs:13:9
+ |
+LL | fn a() {
+ | ------ similarly named function `a` defined here
+...
+LL | if (i + j) = i {}
+ | ^ help: a function with a similar name exists: `a`
+
+error[E0425]: cannot find value `j` in this scope
+ --> $DIR/bad-if-let-suggestion.rs:13:13
+ |
+LL | fn a() {
+ | ------ similarly named function `a` defined here
+...
+LL | if (i + j) = i {}
+ | ^ help: a function with a similar name exists: `a`
+
+error[E0425]: cannot find value `i` in this scope
+ --> $DIR/bad-if-let-suggestion.rs:13:18
+ |
+LL | fn a() {
+ | ------ similarly named function `a` defined here
+...
+LL | if (i + j) = i {}
+ | ^ help: a function with a similar name exists: `a`
+
+error[E0425]: cannot find value `x` in this scope
+ --> $DIR/bad-if-let-suggestion.rs:20:8
+ |
+LL | fn a() {
+ | ------ similarly named function `a` defined here
+...
+LL | if x[0] = 1 {}
+ | ^ help: a function with a similar name exists: `a`
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/bad-if-let-suggestion.rs:5:8
+ |
+LL | if let x = 1 && i = 2 {}
+ | ^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+ --> $DIR/bad-if-let-suggestion.rs:5:8
+ |
+LL | if let x = 1 && i = 2 {}
+ | ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+ |
+help: you might have meant to compare for equality
+ |
+LL | if let x = 1 && i == 2 {}
+ | +
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0308, E0425, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/expr/if/expr-if-panic-fn.rs b/tests/ui/expr/if/expr-if-panic-fn.rs
new file mode 100644
index 000000000..36e49785a
--- /dev/null
+++ b/tests/ui/expr/if/expr-if-panic-fn.rs
@@ -0,0 +1,20 @@
+// run-fail
+// error-pattern:explicit panic
+// ignore-emscripten no processes
+
+fn f() -> ! {
+ panic!()
+}
+
+fn g() -> isize {
+ let x = if true {
+ f()
+ } else {
+ 10
+ };
+ return x;
+}
+
+fn main() {
+ g();
+}
diff --git a/tests/ui/expr/if/expr-if-panic-pass.rs b/tests/ui/expr/if/expr-if-panic-pass.rs
new file mode 100644
index 000000000..6069cd835
--- /dev/null
+++ b/tests/ui/expr/if/expr-if-panic-pass.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+fn test_if_panic() {
+ let x = if false { panic!() } else { 10 };
+ assert_eq!(x, 10);
+}
+
+fn test_else_panic() {
+ let x = if true { 10 } else { panic!() };
+ assert_eq!(x, 10);
+}
+
+fn test_elseif_panic() {
+ let x = if false { 0 } else if false { panic!() } else { 10 };
+ assert_eq!(x, 10);
+}
+
+pub fn main() { test_if_panic(); test_else_panic(); test_elseif_panic(); }
diff --git a/tests/ui/expr/if/expr-if-panic.rs b/tests/ui/expr/if/expr-if-panic.rs
new file mode 100644
index 000000000..520ee0870
--- /dev/null
+++ b/tests/ui/expr/if/expr-if-panic.rs
@@ -0,0 +1,13 @@
+// run-fail
+// error-pattern:explicit panic
+// ignore-emscripten no processes
+
+fn main() {
+ let _x = if false {
+ 0
+ } else if true {
+ panic!()
+ } else {
+ 10
+ };
+}
diff --git a/tests/ui/expr/if/expr-if.rs b/tests/ui/expr/if/expr-if.rs
new file mode 100644
index 000000000..2b8474ff4
--- /dev/null
+++ b/tests/ui/expr/if/expr-if.rs
@@ -0,0 +1,52 @@
+// run-pass
+// Tests for if as expressions
+
+fn test_if() { let rs: bool = if true { true } else { false }; assert!((rs)); }
+
+fn test_else() {
+ let rs: bool = if false { false } else { true };
+ assert!((rs));
+}
+
+fn test_elseif1() {
+ let rs: bool = if true { true } else if true { false } else { false };
+ assert!((rs));
+}
+
+fn test_elseif2() {
+ let rs: bool = if false { false } else if true { true } else { false };
+ assert!((rs));
+}
+
+fn test_elseif3() {
+ let rs: bool = if false { false } else if false { false } else { true };
+ assert!((rs));
+}
+
+fn test_inferrence() {
+ let rs = if true { true } else { false };
+ assert!((rs));
+}
+
+fn test_if_as_if_condition() {
+ let rs1 = if if false { false } else { true } { true } else { false };
+ assert!((rs1));
+ let rs2 = if if true { false } else { true } { false } else { true };
+ assert!((rs2));
+}
+
+fn test_if_as_block_result() {
+ let rs = if true { if false { false } else { true } } else { false };
+ assert!((rs));
+}
+
+pub fn main() {
+ test_if();
+ test_else();
+ test_elseif1();
+ test_elseif2();
+ test_elseif3();
+ test_inferrence();
+ test_if_as_if_condition();
+ test_if_as_block_result();
+}
diff --git a/tests/ui/expr/if/if-branch-types.rs b/tests/ui/expr/if/if-branch-types.rs
new file mode 100644
index 000000000..c125ba306
--- /dev/null
+++ b/tests/ui/expr/if/if-branch-types.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let x = if true { 10i32 } else { 10u32 };
+ //~^ ERROR `if` and `else` have incompatible types
+ //~| expected `i32`, found `u32`
+}
diff --git a/tests/ui/expr/if/if-branch-types.stderr b/tests/ui/expr/if/if-branch-types.stderr
new file mode 100644
index 000000000..d2bba8821
--- /dev/null
+++ b/tests/ui/expr/if/if-branch-types.stderr
@@ -0,0 +1,16 @@
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-branch-types.rs:2:38
+ |
+LL | let x = if true { 10i32 } else { 10u32 };
+ | ----- ^^^^^ expected `i32`, found `u32`
+ | |
+ | expected because of this
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | let x = if true { 10i32 } else { 10i32 };
+ | ~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/expr/if/if-check-panic.rs b/tests/ui/expr/if/if-check-panic.rs
new file mode 100644
index 000000000..037cd427c
--- /dev/null
+++ b/tests/ui/expr/if/if-check-panic.rs
@@ -0,0 +1,25 @@
+// run-fail
+// error-pattern:Number is odd
+// ignore-emscripten no processes
+
+fn even(x: usize) -> bool {
+ if x < 2 {
+ return false;
+ } else if x == 2 {
+ return true;
+ } else {
+ return even(x - 2);
+ }
+}
+
+fn foo(x: usize) {
+ if even(x) {
+ println!("{}", x);
+ } else {
+ panic!("Number is odd");
+ }
+}
+
+fn main() {
+ foo(3);
+}
diff --git a/tests/ui/expr/if/if-check.rs b/tests/ui/expr/if/if-check.rs
new file mode 100644
index 000000000..6593225e7
--- /dev/null
+++ b/tests/ui/expr/if/if-check.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+fn even(x: usize) -> bool {
+ if x < 2 {
+ return false;
+ } else if x == 2 { return true; } else { return even(x - 2); }
+}
+
+fn foo(x: usize) {
+ if even(x) {
+ println!("{}", x);
+ } else {
+ panic!();
+ }
+}
+
+pub fn main() { foo(2); }
diff --git a/tests/ui/expr/if/if-cond-bot.rs b/tests/ui/expr/if/if-cond-bot.rs
new file mode 100644
index 000000000..bcd114678
--- /dev/null
+++ b/tests/ui/expr/if/if-cond-bot.rs
@@ -0,0 +1,13 @@
+// run-fail
+// error-pattern:quux
+// ignore-emscripten no processes
+
+fn my_err(s: String) -> ! {
+ println!("{}", s);
+ panic!("quux");
+}
+
+fn main() {
+ if my_err("bye".to_string()) {
+ }
+}
diff --git a/tests/ui/expr/if/if-else-type-mismatch.rs b/tests/ui/expr/if/if-else-type-mismatch.rs
new file mode 100644
index 000000000..1a0a36df2
--- /dev/null
+++ b/tests/ui/expr/if/if-else-type-mismatch.rs
@@ -0,0 +1,46 @@
+fn main() {
+ let _ = if true {
+ 1i32
+ } else {
+ 2u32
+ };
+ //~^^ ERROR `if` and `else` have incompatible types
+ let _ = if true { 42i32 } else { 42u32 };
+ //~^ ERROR `if` and `else` have incompatible types
+ let _ = if true {
+ 3u32;
+ } else {
+ 4u32
+ };
+ //~^^ ERROR `if` and `else` have incompatible types
+ let _ = if true {
+ 5u32
+ } else {
+ 6u32;
+ };
+ //~^^ ERROR `if` and `else` have incompatible types
+ let _ = if true {
+ 7i32;
+ } else {
+ 8u32
+ };
+ //~^^ ERROR `if` and `else` have incompatible types
+ let _ = if true {
+ 9i32
+ } else {
+ 10u32;
+ };
+ //~^^ ERROR `if` and `else` have incompatible types
+ let _ = if true {
+
+ } else {
+ 11u32
+ };
+ //~^^ ERROR `if` and `else` have incompatible types
+ let _ = if true {
+ 12i32
+ } else {
+
+ };
+ //~^^^ ERROR `if` and `else` have incompatible types
+}
diff --git a/tests/ui/expr/if/if-else-type-mismatch.stderr b/tests/ui/expr/if/if-else-type-mismatch.stderr
new file mode 100644
index 000000000..f1fffdb1e
--- /dev/null
+++ b/tests/ui/expr/if/if-else-type-mismatch.stderr
@@ -0,0 +1,116 @@
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-else-type-mismatch.rs:5:9
+ |
+LL | let _ = if true {
+ | _____________-
+LL | | 1i32
+ | | ---- expected because of this
+LL | | } else {
+LL | | 2u32
+ | | ^^^^ expected `i32`, found `u32`
+LL | | };
+ | |_____- `if` and `else` have incompatible types
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 2i32
+ | ~~~
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-else-type-mismatch.rs:8:38
+ |
+LL | let _ = if true { 42i32 } else { 42u32 };
+ | ----- ^^^^^ expected `i32`, found `u32`
+ | |
+ | expected because of this
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | let _ = if true { 42i32 } else { 42i32 };
+ | ~~~
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-else-type-mismatch.rs:13:9
+ |
+LL | let _ = if true {
+ | _____________-
+LL | | 3u32;
+ | | -----
+ | | | |
+ | | | help: consider removing this semicolon
+ | | expected because of this
+LL | | } else {
+LL | | 4u32
+ | | ^^^^ expected `()`, found `u32`
+LL | | };
+ | |_____- `if` and `else` have incompatible types
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-else-type-mismatch.rs:19:9
+ |
+LL | let _ = if true {
+ | _____________-
+LL | | 5u32
+ | | ---- expected because of this
+LL | | } else {
+LL | | 6u32;
+ | | ^^^^-
+ | | | |
+ | | | help: consider removing this semicolon
+ | | expected `u32`, found `()`
+LL | | };
+ | |_____- `if` and `else` have incompatible types
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-else-type-mismatch.rs:25:9
+ |
+LL | let _ = if true {
+ | _____________-
+LL | | 7i32;
+ | | ----- expected because of this
+LL | | } else {
+LL | | 8u32
+ | | ^^^^ expected `()`, found `u32`
+LL | | };
+ | |_____- `if` and `else` have incompatible types
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-else-type-mismatch.rs:31:9
+ |
+LL | let _ = if true {
+ | _____________-
+LL | | 9i32
+ | | ---- expected because of this
+LL | | } else {
+LL | | 10u32;
+ | | ^^^^^^ expected `i32`, found `()`
+LL | | };
+ | |_____- `if` and `else` have incompatible types
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-else-type-mismatch.rs:37:9
+ |
+LL | let _ = if true {
+ | _____________________-
+LL | |
+LL | | } else {
+ | |_____- expected because of this
+LL | 11u32
+ | ^^^^^ expected `()`, found `u32`
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-else-type-mismatch.rs:42:12
+ |
+LL | let _ = if true {
+ | ------- `if` and `else` have incompatible types
+LL | 12i32
+ | ----- expected because of this
+LL | } else {
+ | ____________^
+LL | |
+LL | | };
+ | |_____^ expected `i32`, found `()`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/expr/if/if-let-arm-types.rs b/tests/ui/expr/if/if-let-arm-types.rs
new file mode 100644
index 000000000..1e8260a01
--- /dev/null
+++ b/tests/ui/expr/if/if-let-arm-types.rs
@@ -0,0 +1,11 @@
+fn main() {
+ if let Some(b) = None {
+ //~^ NOTE `if` and `else` have incompatible types
+ ()
+ //~^ NOTE expected because of this
+ } else {
+ 1
+ };
+ //~^^ ERROR: `if` and `else` have incompatible types
+ //~| NOTE expected `()`, found integer
+}
diff --git a/tests/ui/expr/if/if-let-arm-types.stderr b/tests/ui/expr/if/if-let-arm-types.stderr
new file mode 100644
index 000000000..b40a0f479
--- /dev/null
+++ b/tests/ui/expr/if/if-let-arm-types.stderr
@@ -0,0 +1,17 @@
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/if-let-arm-types.rs:7:9
+ |
+LL | / if let Some(b) = None {
+LL | |
+LL | | ()
+ | | -- expected because of this
+LL | |
+LL | | } else {
+LL | | 1
+ | | ^ expected `()`, found integer
+LL | | };
+ | |_____- `if` and `else` have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/expr/if/if-let.rs b/tests/ui/expr/if/if-let.rs
new file mode 100644
index 000000000..7fdd2be95
--- /dev/null
+++ b/tests/ui/expr/if/if-let.rs
@@ -0,0 +1,49 @@
+// check-pass
+
+fn macros() {
+ macro_rules! foo {
+ ($p:pat, $e:expr, $b:block) => {{
+ if let $p = $e $b
+ //~^ WARN irrefutable `if let`
+ //~| WARN irrefutable `if let`
+ }}
+ }
+ macro_rules! bar{
+ ($p:pat, $e:expr, $b:block) => {{
+ foo!($p, $e, $b)
+ }}
+ }
+
+ foo!(a, 1, {
+ println!("irrefutable pattern");
+ });
+ bar!(a, 1, {
+ println!("irrefutable pattern");
+ });
+}
+
+pub fn main() {
+ if let a = 1 { //~ WARN irrefutable `if let`
+ println!("irrefutable pattern");
+ }
+
+ if let a = 1 { //~ WARN irrefutable `if let`
+ println!("irrefutable pattern");
+ } else if true {
+ println!("else-if in irrefutable `if let`");
+ } else {
+ println!("else in irrefutable `if let`");
+ }
+
+ if let 1 = 2 {
+ println!("refutable pattern");
+ } else if let a = 1 { //~ WARN irrefutable `if let`
+ println!("irrefutable pattern");
+ }
+
+ if true {
+ println!("if");
+ } else if let a = 1 { //~ WARN irrefutable `if let`
+ println!("irrefutable pattern");
+ }
+}
diff --git a/tests/ui/expr/if/if-let.stderr b/tests/ui/expr/if/if-let.stderr
new file mode 100644
index 000000000..c4bba3cb1
--- /dev/null
+++ b/tests/ui/expr/if/if-let.stderr
@@ -0,0 +1,69 @@
+warning: irrefutable `if let` pattern
+ --> $DIR/if-let.rs:6:16
+ |
+LL | if let $p = $e $b
+ | ^^^
+...
+LL | / foo!(a, 1, {
+LL | | println!("irrefutable pattern");
+LL | | });
+ | |______- in this macro invocation
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
+ = note: `#[warn(irrefutable_let_patterns)]` on by default
+ = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: irrefutable `if let` pattern
+ --> $DIR/if-let.rs:6:16
+ |
+LL | if let $p = $e $b
+ | ^^^
+...
+LL | / bar!(a, 1, {
+LL | | println!("irrefutable pattern");
+LL | | });
+ | |______- in this macro invocation
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
+ = note: this warning originates in the macro `foo` which comes from the expansion of the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: irrefutable `if let` pattern
+ --> $DIR/if-let.rs:26:8
+ |
+LL | if let a = 1 {
+ | ^^^^^^^^^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
+
+warning: irrefutable `if let` pattern
+ --> $DIR/if-let.rs:30:8
+ |
+LL | if let a = 1 {
+ | ^^^^^^^^^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
+
+warning: irrefutable `if let` pattern
+ --> $DIR/if-let.rs:40:15
+ |
+LL | } else if let a = 1 {
+ | ^^^^^^^^^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
+
+warning: irrefutable `if let` pattern
+ --> $DIR/if-let.rs:46:15
+ |
+LL | } else if let a = 1 {
+ | ^^^^^^^^^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
+
+warning: 6 warnings emitted
+
diff --git a/tests/ui/expr/if/if-loop.rs b/tests/ui/expr/if/if-loop.rs
new file mode 100644
index 000000000..06d0bdf45
--- /dev/null
+++ b/tests/ui/expr/if/if-loop.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+// This used to ICE because the "if" being unreachable was not handled correctly
+fn err() {
+ if loop {} {}
+}
+
+fn main() {}
diff --git a/tests/ui/expr/if/if-no-match-bindings.rs b/tests/ui/expr/if/if-no-match-bindings.rs
new file mode 100644
index 000000000..ca3df0fdd
--- /dev/null
+++ b/tests/ui/expr/if/if-no-match-bindings.rs
@@ -0,0 +1,28 @@
+// Checks for `if` expressions with respect to default match bindings.
+// Specifically, we do not accept `if cond { ... }` where `cond: &mut? bool`.
+// Meanwhile, `match cond { true => ..., _ => ... }` does accept that.
+
+// FIXME(@rust-lang/lang-team): consider relaxing this?
+
+fn b_ref<'a>() -> &'a bool { &true }
+fn b_mut_ref<'a>() -> &'a mut bool { &mut true }
+
+fn main() {
+ // This is OK:
+ match b_ref() { true => {}, _ => {} }
+ match b_mut_ref() { true => {}, _ => {} }
+ match &true { true => {}, _ => {} }
+ match &mut true { true => {}, _ => {} }
+
+ // This is NOT:
+ if b_ref() {} //~ ERROR mismatched types [E0308]
+ if b_mut_ref() {} //~ ERROR mismatched types [E0308]
+ if &true {} //~ ERROR mismatched types [E0308]
+ if &mut true {} //~ ERROR mismatched types [E0308]
+
+ // This is also NOT:
+ while b_ref() {} //~ ERROR mismatched types [E0308]
+ while b_mut_ref() {} //~ ERROR mismatched types [E0308]
+ while &true {} //~ ERROR mismatched types [E0308]
+ while &mut true {} //~ ERROR mismatched types [E0308]
+}
diff --git a/tests/ui/expr/if/if-no-match-bindings.stderr b/tests/ui/expr/if/if-no-match-bindings.stderr
new file mode 100644
index 000000000..737a5d604
--- /dev/null
+++ b/tests/ui/expr/if/if-no-match-bindings.stderr
@@ -0,0 +1,95 @@
+error[E0308]: mismatched types
+ --> $DIR/if-no-match-bindings.rs:18:8
+ |
+LL | if b_ref() {}
+ | ^^^^^^^ expected `bool`, found `&bool`
+ |
+help: consider dereferencing the borrow
+ |
+LL | if *b_ref() {}
+ | +
+
+error[E0308]: mismatched types
+ --> $DIR/if-no-match-bindings.rs:19:8
+ |
+LL | if b_mut_ref() {}
+ | ^^^^^^^^^^^ expected `bool`, found `&mut bool`
+ |
+help: consider dereferencing the borrow
+ |
+LL | if *b_mut_ref() {}
+ | +
+
+error[E0308]: mismatched types
+ --> $DIR/if-no-match-bindings.rs:20:8
+ |
+LL | if &true {}
+ | ^^^^^ expected `bool`, found `&bool`
+ |
+help: consider removing the borrow
+ |
+LL - if &true {}
+LL + if true {}
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/if-no-match-bindings.rs:21:8
+ |
+LL | if &mut true {}
+ | ^^^^^^^^^ expected `bool`, found `&mut bool`
+ |
+help: consider removing the borrow
+ |
+LL - if &mut true {}
+LL + if true {}
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/if-no-match-bindings.rs:24:11
+ |
+LL | while b_ref() {}
+ | ^^^^^^^ expected `bool`, found `&bool`
+ |
+help: consider dereferencing the borrow
+ |
+LL | while *b_ref() {}
+ | +
+
+error[E0308]: mismatched types
+ --> $DIR/if-no-match-bindings.rs:25:11
+ |
+LL | while b_mut_ref() {}
+ | ^^^^^^^^^^^ expected `bool`, found `&mut bool`
+ |
+help: consider dereferencing the borrow
+ |
+LL | while *b_mut_ref() {}
+ | +
+
+error[E0308]: mismatched types
+ --> $DIR/if-no-match-bindings.rs:26:11
+ |
+LL | while &true {}
+ | ^^^^^ expected `bool`, found `&bool`
+ |
+help: consider removing the borrow
+ |
+LL - while &true {}
+LL + while true {}
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/if-no-match-bindings.rs:27:11
+ |
+LL | while &mut true {}
+ | ^^^^^^^^^ expected `bool`, found `&mut bool`
+ |
+help: consider removing the borrow
+ |
+LL - while &mut true {}
+LL + while true {}
+ |
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/expr/if/if-ret.rs b/tests/ui/expr/if/if-ret.rs
new file mode 100644
index 000000000..896072ce7
--- /dev/null
+++ b/tests/ui/expr/if/if-ret.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+#![allow(unused_parens)]
+// pretty-expanded FIXME #23616
+
+fn foo() { if (return) { } } //~ WARNING unreachable block in `if`
+
+pub fn main() { foo(); }
diff --git a/tests/ui/expr/if/if-ret.stderr b/tests/ui/expr/if/if-ret.stderr
new file mode 100644
index 000000000..8ced271aa
--- /dev/null
+++ b/tests/ui/expr/if/if-ret.stderr
@@ -0,0 +1,12 @@
+warning: unreachable block in `if` or `while` expression
+ --> $DIR/if-ret.rs:6:24
+ |
+LL | fn foo() { if (return) { } }
+ | -------- ^^^ unreachable block in `if` or `while` expression
+ | |
+ | any code following this expression is unreachable
+ |
+ = note: `#[warn(unreachable_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/expr/if/if-typeck.rs b/tests/ui/expr/if/if-typeck.rs
new file mode 100644
index 000000000..d8c262bd6
--- /dev/null
+++ b/tests/ui/expr/if/if-typeck.rs
@@ -0,0 +1,10 @@
+// error-pattern:mismatched types
+// issue #513
+
+fn f() { }
+
+fn main() {
+
+ // f is not a bool
+ if f { }
+}
diff --git a/tests/ui/expr/if/if-typeck.stderr b/tests/ui/expr/if/if-typeck.stderr
new file mode 100644
index 000000000..74ed0ed0a
--- /dev/null
+++ b/tests/ui/expr/if/if-typeck.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+ --> $DIR/if-typeck.rs:9:8
+ |
+LL | if f { }
+ | ^ expected `bool`, found fn item
+ |
+ = note: expected type `bool`
+ found fn item `fn() {f}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/expr/if/if-without-block.rs b/tests/ui/expr/if/if-without-block.rs
new file mode 100644
index 000000000..5add9dfda
--- /dev/null
+++ b/tests/ui/expr/if/if-without-block.rs
@@ -0,0 +1,7 @@
+fn main() {
+ let n = 1;
+ if 5 == {
+ //~^ ERROR this `if` expression is missing a block after the condition
+ println!("five");
+ }
+}
diff --git a/tests/ui/expr/if/if-without-block.stderr b/tests/ui/expr/if/if-without-block.stderr
new file mode 100644
index 000000000..2d1ee04ce
--- /dev/null
+++ b/tests/ui/expr/if/if-without-block.stderr
@@ -0,0 +1,14 @@
+error: this `if` expression is missing a block after the condition
+ --> $DIR/if-without-block.rs:3:5
+ |
+LL | if 5 == {
+ | ^^
+ |
+help: this binary operation is possibly unfinished
+ --> $DIR/if-without-block.rs:3:8
+ |
+LL | if 5 == {
+ | ^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/expr/if/if-without-else-as-fn-expr.rs b/tests/ui/expr/if/if-without-else-as-fn-expr.rs
new file mode 100644
index 000000000..19fbfb27b
--- /dev/null
+++ b/tests/ui/expr/if/if-without-else-as-fn-expr.rs
@@ -0,0 +1,49 @@
+fn foo(bar: usize) -> usize {
+ if bar % 5 == 0 {
+ return 3;
+ }
+ //~^^^ ERROR `if` may be missing an `else` clause
+}
+
+fn foo2(bar: usize) -> usize {
+ let x: usize = if bar % 5 == 0 {
+ return 3;
+ };
+ //~^^^ ERROR `if` may be missing an `else` clause
+ x
+}
+
+fn foo3(bar: usize) -> usize {
+ if bar % 5 == 0 {
+ 3
+ }
+ //~^^^ ERROR `if` may be missing an `else` clause
+}
+
+fn foo_let(bar: usize) -> usize {
+ if let 0 = 1 {
+ return 3;
+ }
+ //~^^^ ERROR `if` may be missing an `else` clause
+}
+
+fn foo2_let(bar: usize) -> usize {
+ let x: usize = if let 0 = 1 {
+ return 3;
+ };
+ //~^^^ ERROR `if` may be missing an `else` clause
+ x
+}
+
+fn foo3_let(bar: usize) -> usize {
+ if let 0 = 1 {
+ 3
+ }
+ //~^^^ ERROR `if` may be missing an `else` clause
+}
+
+// FIXME(60254): deduplicate first error in favor of second.
+
+fn main() {
+ let _ = foo(1);
+}
diff --git a/tests/ui/expr/if/if-without-else-as-fn-expr.stderr b/tests/ui/expr/if/if-without-else-as-fn-expr.stderr
new file mode 100644
index 000000000..4daf27493
--- /dev/null
+++ b/tests/ui/expr/if/if-without-else-as-fn-expr.stderr
@@ -0,0 +1,83 @@
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/if-without-else-as-fn-expr.rs:2:5
+ |
+LL | fn foo(bar: usize) -> usize {
+ | ----- expected `usize` because of this return type
+LL | / if bar % 5 == 0 {
+LL | | return 3;
+LL | | }
+ | |_____^ expected `usize`, found `()`
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/if-without-else-as-fn-expr.rs:9:20
+ |
+LL | let x: usize = if bar % 5 == 0 {
+ | _________-__________^
+ | | |
+ | | expected because of this assignment
+LL | | return 3;
+LL | | };
+ | |_____^ expected `usize`, found `()`
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/if-without-else-as-fn-expr.rs:17:5
+ |
+LL | fn foo3(bar: usize) -> usize {
+ | ----- expected `usize` because of this return type
+LL | / if bar % 5 == 0 {
+LL | | 3
+LL | | }
+ | |_____^ expected `usize`, found `()`
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/if-without-else-as-fn-expr.rs:24:5
+ |
+LL | fn foo_let(bar: usize) -> usize {
+ | ----- expected `usize` because of this return type
+LL | / if let 0 = 1 {
+LL | | return 3;
+LL | | }
+ | |_____^ expected `usize`, found `()`
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/if-without-else-as-fn-expr.rs:31:20
+ |
+LL | let x: usize = if let 0 = 1 {
+ | _________-__________^
+ | | |
+ | | expected because of this assignment
+LL | | return 3;
+LL | | };
+ | |_____^ expected `usize`, found `()`
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/if-without-else-as-fn-expr.rs:39:5
+ |
+LL | fn foo3_let(bar: usize) -> usize {
+ | ----- expected `usize` because of this return type
+LL | / if let 0 = 1 {
+LL | | 3
+LL | | }
+ | |_____^ expected `usize`, found `()`
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0317`.
diff --git a/tests/ui/expr/if/if-without-else-result.rs b/tests/ui/expr/if/if-without-else-result.rs
new file mode 100644
index 000000000..95604758a
--- /dev/null
+++ b/tests/ui/expr/if/if-without-else-result.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let a = if true { true };
+ //~^ ERROR `if` may be missing an `else` clause [E0317]
+ //~| expected `bool`, found `()`
+ println!("{}", a);
+}
diff --git a/tests/ui/expr/if/if-without-else-result.stderr b/tests/ui/expr/if/if-without-else-result.stderr
new file mode 100644
index 000000000..317faf7c6
--- /dev/null
+++ b/tests/ui/expr/if/if-without-else-result.stderr
@@ -0,0 +1,15 @@
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/if-without-else-result.rs:2:13
+ |
+LL | let a = if true { true };
+ | ^^^^^^^^^^----^^
+ | | |
+ | | found here
+ | expected `bool`, found `()`
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0317`.
diff --git a/tests/ui/expr/if/issue-4201.rs b/tests/ui/expr/if/issue-4201.rs
new file mode 100644
index 000000000..59c465b9e
--- /dev/null
+++ b/tests/ui/expr/if/issue-4201.rs
@@ -0,0 +1,9 @@
+fn main() {
+ let a = if true {
+ 0
+ } else if false {
+//~^ ERROR `if` may be missing an `else` clause
+//~| expected integer, found `()`
+ 1
+ };
+}
diff --git a/tests/ui/expr/if/issue-4201.stderr b/tests/ui/expr/if/issue-4201.stderr
new file mode 100644
index 000000000..612fe7764
--- /dev/null
+++ b/tests/ui/expr/if/issue-4201.stderr
@@ -0,0 +1,18 @@
+error[E0317]: `if` may be missing an `else` clause
+ --> $DIR/issue-4201.rs:4:12
+ |
+LL | } else if false {
+ | ____________^
+LL | |
+LL | |
+LL | | 1
+ | | - found here
+LL | | };
+ | |_____^ expected integer, found `()`
+ |
+ = note: `if` expressions without `else` evaluate to `()`
+ = help: consider adding an `else` block that evaluates to the expected type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0317`.
diff --git a/tests/ui/expr/malformed_closure/missing_braces_around_block.fixed b/tests/ui/expr/malformed_closure/missing_braces_around_block.fixed
new file mode 100644
index 000000000..c50b9a12b
--- /dev/null
+++ b/tests/ui/expr/malformed_closure/missing_braces_around_block.fixed
@@ -0,0 +1,19 @@
+// This snippet ensures that no attempt to recover on a semicolon instead of
+// comma is made next to a closure body.
+//
+// If this recovery happens, then plenty of errors are emitted. Here, we expect
+// only one error.
+//
+// This is part of issue #88065:
+// https://github.com/rust-lang/rust/issues/88065
+
+// run-rustfix
+
+fn main() {
+ let num = 5;
+ (1..num).reduce(|a, b| {
+ //~^ ERROR: closure bodies that contain statements must be surrounded by braces
+ println!("{}", a);
+ a * b
+ }).unwrap();
+}
diff --git a/tests/ui/expr/malformed_closure/missing_braces_around_block.rs b/tests/ui/expr/malformed_closure/missing_braces_around_block.rs
new file mode 100644
index 000000000..58c81f3a6
--- /dev/null
+++ b/tests/ui/expr/malformed_closure/missing_braces_around_block.rs
@@ -0,0 +1,19 @@
+// This snippet ensures that no attempt to recover on a semicolon instead of
+// comma is made next to a closure body.
+//
+// If this recovery happens, then plenty of errors are emitted. Here, we expect
+// only one error.
+//
+// This is part of issue #88065:
+// https://github.com/rust-lang/rust/issues/88065
+
+// run-rustfix
+
+fn main() {
+ let num = 5;
+ (1..num).reduce(|a, b|
+ //~^ ERROR: closure bodies that contain statements must be surrounded by braces
+ println!("{}", a);
+ a * b
+ ).unwrap();
+}
diff --git a/tests/ui/expr/malformed_closure/missing_braces_around_block.stderr b/tests/ui/expr/malformed_closure/missing_braces_around_block.stderr
new file mode 100644
index 000000000..dac9a8cfc
--- /dev/null
+++ b/tests/ui/expr/malformed_closure/missing_braces_around_block.stderr
@@ -0,0 +1,38 @@
+error: closure bodies that contain statements must be surrounded by braces
+ --> $DIR/missing_braces_around_block.rs:14:26
+ |
+LL | (1..num).reduce(|a, b|
+ | ^
+...
+LL | ).unwrap();
+ | ^
+ |
+note: statement found outside of a block
+ --> $DIR/missing_braces_around_block.rs:16:26
+ |
+LL | println!("{}", a);
+ | -----------------^ this `;` turns the preceding closure into a statement
+ | |
+ | this expression is a statement because of the trailing semicolon
+note: the closure body may be incorrectly delimited
+ --> $DIR/missing_braces_around_block.rs:14:21
+ |
+LL | (1..num).reduce(|a, b|
+ | _____________________^
+LL | |
+LL | | println!("{}", a);
+ | |_________________________^ this is the parsed closure...
+LL | a * b
+LL | ).unwrap();
+ | - ...but likely you meant the closure to end here
+help: try adding braces
+ |
+LL ~ (1..num).reduce(|a, b| {
+LL |
+LL | println!("{}", a);
+LL | a * b
+LL ~ }).unwrap();
+ |
+
+error: aborting due to previous error
+
diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure.rs b/tests/ui/expr/malformed_closure/ruby_style_closure.rs
new file mode 100644
index 000000000..fdec072b8
--- /dev/null
+++ b/tests/ui/expr/malformed_closure/ruby_style_closure.rs
@@ -0,0 +1,15 @@
+// Part of issue #27300.
+// The problem here is that ruby-style closures are parsed as blocks whose
+// first statement is a closure. See the issue for more details:
+// https://github.com/rust-lang/rust/issues/27300
+
+// Note: this test represents what the compiler currently emits. The error
+// message will be improved later.
+
+fn main() {
+ let p = Some(45).and_then({
+ |x| println!("doubling {}", x);
+ Some(x * 2)
+ //~^ ERROR: cannot find value `x` in this scope
+ });
+}
diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure.stderr b/tests/ui/expr/malformed_closure/ruby_style_closure.stderr
new file mode 100644
index 000000000..e8b34121b
--- /dev/null
+++ b/tests/ui/expr/malformed_closure/ruby_style_closure.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `x` in this scope
+ --> $DIR/ruby_style_closure.rs:12:14
+ |
+LL | Some(x * 2)
+ | ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.