about summary refs log tree commit diff
path: root/tests/ui/expr
diff options
context:
space:
mode:
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 00000000000..658adae193e
--- /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 00000000000..0f09db530d4
--- /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 00000000000..3f84929a00e
--- /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 00000000000..8a2890886a1
--- /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 00000000000..7e290661501
--- /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 00000000000..1f77a1bb342
--- /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 00000000000..85da7cf6bb8
--- /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 00000000000..2733377054d
--- /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 00000000000..63772d54b53
--- /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 00000000000..2cd8731141a
--- /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 00000000000..38599c8e67c
--- /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 00000000000..47dac39a9ae
--- /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 00000000000..a8b2a283039
--- /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 00000000000..3a53a20b453
--- /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 00000000000..36e49785a49
--- /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 00000000000..6069cd835e1
--- /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 00000000000..520ee0870ee
--- /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 00000000000..2b8474ff453
--- /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 00000000000..c125ba30606
--- /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 00000000000..d2bba88211e
--- /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 00000000000..037cd427ccf
--- /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 00000000000..6593225e7dd
--- /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 00000000000..bcd11467852
--- /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 00000000000..1a0a36df2ad
--- /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 00000000000..f1fffdb1e7e
--- /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 00000000000..1e8260a017d
--- /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 00000000000..b40a0f479d3
--- /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 00000000000..7fdd2be955b
--- /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 00000000000..c4bba3cb1a8
--- /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 00000000000..06d0bdf456c
--- /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 00000000000..ca3df0fdde4
--- /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 00000000000..737a5d60448
--- /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 00000000000..896072ce728
--- /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 00000000000..8ced271aabc
--- /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 00000000000..d8c262bd6b3
--- /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 00000000000..74ed0ed0ae6
--- /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 00000000000..5add9dfda4b
--- /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 00000000000..2d1ee04ce09
--- /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 00000000000..19fbfb27ba6
--- /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 00000000000..4daf27493c1
--- /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 00000000000..95604758a6b
--- /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 00000000000..317faf7c619
--- /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 00000000000..59c465b9e14
--- /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 00000000000..612fe77642c
--- /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 00000000000..c50b9a12b6d
--- /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 00000000000..58c81f3a6e2
--- /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 00000000000..dac9a8cfc69
--- /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 00000000000..fdec072b8a8
--- /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 00000000000..e8b34121b5f
--- /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`.