about summary refs log tree commit diff
path: root/tests/ui/try-block
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/try-block')
-rw-r--r--tests/ui/try-block/issue-45124.rs18
-rw-r--r--tests/ui/try-block/try-block-bad-lifetime.rs37
-rw-r--r--tests/ui/try-block/try-block-bad-lifetime.stderr52
-rw-r--r--tests/ui/try-block/try-block-bad-type.rs21
-rw-r--r--tests/ui/try-block/try-block-bad-type.stderr42
-rw-r--r--tests/ui/try-block/try-block-catch.rs10
-rw-r--r--tests/ui/try-block/try-block-catch.stderr10
-rw-r--r--tests/ui/try-block/try-block-in-edition2015.rs10
-rw-r--r--tests/ui/try-block/try-block-in-edition2015.stderr24
-rw-r--r--tests/ui/try-block/try-block-in-match.rs11
-rw-r--r--tests/ui/try-block/try-block-in-return.rs12
-rw-r--r--tests/ui/try-block/try-block-in-while.rs8
-rw-r--r--tests/ui/try-block/try-block-in-while.stderr11
-rw-r--r--tests/ui/try-block/try-block-maybe-bad-lifetime.rs44
-rw-r--r--tests/ui/try-block/try-block-maybe-bad-lifetime.stderr46
-rw-r--r--tests/ui/try-block/try-block-opt-init.rs16
-rw-r--r--tests/ui/try-block/try-block-opt-init.stderr17
-rw-r--r--tests/ui/try-block/try-block-type-error.rs18
-rw-r--r--tests/ui/try-block/try-block-type-error.stderr18
-rw-r--r--tests/ui/try-block/try-block-unreachable-code-lint.rs76
-rw-r--r--tests/ui/try-block/try-block-unreachable-code-lint.stderr40
-rw-r--r--tests/ui/try-block/try-block-unused-delims.fixed29
-rw-r--r--tests/ui/try-block/try-block-unused-delims.rs29
-rw-r--r--tests/ui/try-block/try-block-unused-delims.stderr72
-rw-r--r--tests/ui/try-block/try-block.rs75
-rw-r--r--tests/ui/try-block/try-is-identifier-edition2015.rs11
26 files changed, 757 insertions, 0 deletions
diff --git a/tests/ui/try-block/issue-45124.rs b/tests/ui/try-block/issue-45124.rs
new file mode 100644
index 00000000000..942014c9184
--- /dev/null
+++ b/tests/ui/try-block/issue-45124.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![allow(unreachable_code)]
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn main() {
+    let mut a = 0;
+    let () = {
+        let _: Result<(), ()> = try {
+            let _ = Err(())?;
+            return
+        };
+        a += 1;
+    };
+    a += 2;
+    assert_eq!(a, 3);
+}
diff --git a/tests/ui/try-block/try-block-bad-lifetime.rs b/tests/ui/try-block/try-block-bad-lifetime.rs
new file mode 100644
index 00000000000..d9524e99f9a
--- /dev/null
+++ b/tests/ui/try-block/try-block-bad-lifetime.rs
@@ -0,0 +1,37 @@
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+#[inline(never)]
+fn do_something_with<T>(_x: T) {}
+
+// This test checks that borrows made and returned inside try blocks are properly constrained
+pub fn main() {
+    {
+        // Test that borrows returned from a try block must be valid for the lifetime of the
+        // result variable
+        let result: Result<(), &str> = try {
+            let my_string = String::from("");
+            let my_str: & str = & my_string;
+            //~^ ERROR `my_string` does not live long enough
+            Err(my_str) ?;
+            Err("") ?;
+        };
+        do_something_with(result);
+    }
+
+    {
+        // Test that borrows returned from try blocks freeze their referent
+        let mut i = 5;
+        let k = &mut i;
+        let mut j: Result<(), &mut i32> = try {
+            Err(k) ?;
+            i = 10; //~ ERROR cannot assign to `i` because it is borrowed
+        };
+        ::std::mem::drop(k); //~ ERROR use of moved value: `k`
+        i = 40; //~ ERROR cannot assign to `i` because it is borrowed
+
+        let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") };
+        *i_ptr = 50;
+    }
+}
diff --git a/tests/ui/try-block/try-block-bad-lifetime.stderr b/tests/ui/try-block/try-block-bad-lifetime.stderr
new file mode 100644
index 00000000000..ea079e30d9c
--- /dev/null
+++ b/tests/ui/try-block/try-block-bad-lifetime.stderr
@@ -0,0 +1,52 @@
+error[E0597]: `my_string` does not live long enough
+  --> $DIR/try-block-bad-lifetime.rs:15:33
+   |
+LL |         let result: Result<(), &str> = try {
+   |             ------ borrow later stored here
+LL |             let my_string = String::from("");
+LL |             let my_str: & str = & my_string;
+   |                                 ^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL |         };
+   |         - `my_string` dropped here while still borrowed
+
+error[E0506]: cannot assign to `i` because it is borrowed
+  --> $DIR/try-block-bad-lifetime.rs:29:13
+   |
+LL |         let k = &mut i;
+   |                 ------ borrow of `i` occurs here
+...
+LL |             i = 10;
+   |             ^^^^^^ assignment to borrowed `i` occurs here
+LL |         };
+LL |         ::std::mem::drop(k);
+   |                          - borrow later used here
+
+error[E0382]: use of moved value: `k`
+  --> $DIR/try-block-bad-lifetime.rs:31:26
+   |
+LL |         let k = &mut i;
+   |             - move occurs because `k` has type `&mut i32`, which does not implement the `Copy` trait
+LL |         let mut j: Result<(), &mut i32> = try {
+LL |             Err(k) ?;
+   |                 - value moved here
+...
+LL |         ::std::mem::drop(k);
+   |                          ^ value used here after move
+
+error[E0506]: cannot assign to `i` because it is borrowed
+  --> $DIR/try-block-bad-lifetime.rs:32:9
+   |
+LL |         let k = &mut i;
+   |                 ------ borrow of `i` occurs here
+...
+LL |         i = 40;
+   |         ^^^^^^ assignment to borrowed `i` occurs here
+LL |
+LL |         let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") };
+   |                                         - borrow later used here
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0382, E0506, E0597.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/try-block/try-block-bad-type.rs b/tests/ui/try-block/try-block-bad-type.rs
new file mode 100644
index 00000000000..30ae96763c0
--- /dev/null
+++ b/tests/ui/try-block/try-block-bad-type.rs
@@ -0,0 +1,21 @@
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+pub fn main() {
+    let res: Result<u32, std::array::TryFromSliceError> = try {
+        Err("")?; //~ ERROR `?` couldn't convert the error
+        5
+    };
+
+    let res: Result<i32, i32> = try {
+        "" //~ ERROR type mismatch
+    };
+
+    let res: Result<i32, i32> = try { }; //~ ERROR type mismatch
+
+    let res: () = try { };
+    //~^ ERROR a `try` block must return `Result` or `Option`
+
+    let res: i32 = try { 5 }; //~ ERROR a `try` block must return `Result` or `Option`
+}
diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr
new file mode 100644
index 00000000000..e11c3f81003
--- /dev/null
+++ b/tests/ui/try-block/try-block-bad-type.stderr
@@ -0,0 +1,42 @@
+error[E0277]: `?` couldn't convert the error to `TryFromSliceError`
+  --> $DIR/try-block-bad-type.rs:7:16
+   |
+LL |         Err("")?;
+   |                ^ the trait `From<&str>` is not implemented for `TryFromSliceError`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = help: the trait `From<Infallible>` is implemented for `TryFromSliceError`
+   = note: required for `Result<u32, TryFromSliceError>` to implement `FromResidual<Result<Infallible, &str>>`
+
+error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str`
+  --> $DIR/try-block-bad-type.rs:12:9
+   |
+LL |         ""
+   |         ^^ expected `i32`, found `&str`
+
+error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == ()`
+  --> $DIR/try-block-bad-type.rs:15:39
+   |
+LL |     let res: Result<i32, i32> = try { };
+   |                                       ^ expected `i32`, found `()`
+
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
+  --> $DIR/try-block-bad-type.rs:17:25
+   |
+LL |     let res: () = try { };
+   |                         ^ could not wrap the final value of the block as `()` doesn't implement `Try`
+   |
+   = help: the trait `Try` is not implemented for `()`
+
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
+  --> $DIR/try-block-bad-type.rs:20:26
+   |
+LL |     let res: i32 = try { 5 };
+   |                          ^ could not wrap the final value of the block as `i32` doesn't implement `Try`
+   |
+   = help: the trait `Try` is not implemented for `i32`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/try-block/try-block-catch.rs b/tests/ui/try-block/try-block-catch.rs
new file mode 100644
index 00000000000..d165015611d
--- /dev/null
+++ b/tests/ui/try-block/try-block-catch.rs
@@ -0,0 +1,10 @@
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn main() {
+    let res: Option<bool> = try {
+        true
+    } catch { };
+    //~^ ERROR keyword `catch` cannot follow a `try` block
+}
diff --git a/tests/ui/try-block/try-block-catch.stderr b/tests/ui/try-block/try-block-catch.stderr
new file mode 100644
index 00000000000..39cf943f4d8
--- /dev/null
+++ b/tests/ui/try-block/try-block-catch.stderr
@@ -0,0 +1,10 @@
+error: keyword `catch` cannot follow a `try` block
+  --> $DIR/try-block-catch.rs:8:7
+   |
+LL |     } catch { };
+   |       ^^^^^
+   |
+   = help: try using `match` on the result of the `try` block instead
+
+error: aborting due to previous error
+
diff --git a/tests/ui/try-block/try-block-in-edition2015.rs b/tests/ui/try-block/try-block-in-edition2015.rs
new file mode 100644
index 00000000000..00964297308
--- /dev/null
+++ b/tests/ui/try-block/try-block-in-edition2015.rs
@@ -0,0 +1,10 @@
+// compile-flags: --edition 2015
+
+pub fn main() {
+    let try_result: Option<_> = try {
+    //~^ ERROR expected struct, variant or union type, found macro `try`
+        let x = 5; //~ ERROR expected identifier, found keyword
+        x
+    };
+    assert_eq!(try_result, Some(5));
+}
diff --git a/tests/ui/try-block/try-block-in-edition2015.stderr b/tests/ui/try-block/try-block-in-edition2015.stderr
new file mode 100644
index 00000000000..a00064c44d2
--- /dev/null
+++ b/tests/ui/try-block/try-block-in-edition2015.stderr
@@ -0,0 +1,24 @@
+error: expected identifier, found keyword `let`
+  --> $DIR/try-block-in-edition2015.rs:6:9
+   |
+LL |     let try_result: Option<_> = try {
+   |                                 --- while parsing this struct
+LL |
+LL |         let x = 5;
+   |         ^^^ expected identifier, found keyword
+
+error[E0574]: expected struct, variant or union type, found macro `try`
+  --> $DIR/try-block-in-edition2015.rs:4:33
+   |
+LL |     let try_result: Option<_> = try {
+   |                                 ^^^ not a struct, variant or union type
+   |
+   = note: if you want the `try` keyword, you need Rust 2018 or later
+help: use `!` to invoke the macro
+   |
+LL |     let try_result: Option<_> = try! {
+   |                                    +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0574`.
diff --git a/tests/ui/try-block/try-block-in-match.rs b/tests/ui/try-block/try-block-in-match.rs
new file mode 100644
index 00000000000..cd0b967e79d
--- /dev/null
+++ b/tests/ui/try-block/try-block-in-match.rs
@@ -0,0 +1,11 @@
+// run-pass
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn main() {
+    match try { } {
+        Err(()) => (),
+        Ok(()) => (),
+    }
+}
diff --git a/tests/ui/try-block/try-block-in-return.rs b/tests/ui/try-block/try-block-in-return.rs
new file mode 100644
index 00000000000..a15bfeef1c1
--- /dev/null
+++ b/tests/ui/try-block/try-block-in-return.rs
@@ -0,0 +1,12 @@
+// run-pass
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn issue_76271() -> Option<i32> {
+    return try { 4 }
+}
+
+fn main() {
+    assert_eq!(issue_76271(), Some(4));
+}
diff --git a/tests/ui/try-block/try-block-in-while.rs b/tests/ui/try-block/try-block-in-while.rs
new file mode 100644
index 00000000000..69793df525e
--- /dev/null
+++ b/tests/ui/try-block/try-block-in-while.rs
@@ -0,0 +1,8 @@
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn main() {
+    while try { false } {}
+    //~^ ERROR a `try` block must
+}
diff --git a/tests/ui/try-block/try-block-in-while.stderr b/tests/ui/try-block/try-block-in-while.stderr
new file mode 100644
index 00000000000..62cc26dd401
--- /dev/null
+++ b/tests/ui/try-block/try-block-in-while.stderr
@@ -0,0 +1,11 @@
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
+  --> $DIR/try-block-in-while.rs:6:17
+   |
+LL |     while try { false } {}
+   |                 ^^^^^ could not wrap the final value of the block as `bool` doesn't implement `Try`
+   |
+   = help: the trait `Try` is not implemented for `bool`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/try-block/try-block-maybe-bad-lifetime.rs b/tests/ui/try-block/try-block-maybe-bad-lifetime.rs
new file mode 100644
index 00000000000..cd2ddf63a2f
--- /dev/null
+++ b/tests/ui/try-block/try-block-maybe-bad-lifetime.rs
@@ -0,0 +1,44 @@
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+#[inline(never)]
+fn do_something_with<T>(_x: T) {}
+
+// This test checks that borrows made and returned inside try blocks are properly constrained
+pub fn main() {
+    {
+        // Test that a borrow which *might* be returned still freezes its referent
+        let mut i = 222;
+        let x: Result<&i32, ()> = try {
+            Err(())?;
+            &i
+        };
+        i = 0; //~ ERROR cannot assign to `i` because it is borrowed
+        let _ = i;
+        do_something_with(x);
+    }
+
+    {
+        let x = String::new();
+        let _y: Result<(), ()> = try {
+            Err(())?;
+            ::std::mem::drop(x);
+        };
+        println!("{}", x); //~ ERROR borrow of moved value: `x`
+    }
+
+    {
+        // Test that a borrow which *might* be assigned to an outer variable still freezes
+        // its referent
+        let mut i = 222;
+        let mut j = &-1;
+        let _x: Result<(), ()> = try {
+            Err(())?;
+            j = &i;
+        };
+        i = 0; //~ ERROR cannot assign to `i` because it is borrowed
+        let _ = i;
+        do_something_with(j);
+    }
+}
diff --git a/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr b/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr
new file mode 100644
index 00000000000..f738b03eed6
--- /dev/null
+++ b/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr
@@ -0,0 +1,46 @@
+error[E0506]: cannot assign to `i` because it is borrowed
+  --> $DIR/try-block-maybe-bad-lifetime.rs:17:9
+   |
+LL |             &i
+   |             -- borrow of `i` occurs here
+LL |         };
+LL |         i = 0;
+   |         ^^^^^ assignment to borrowed `i` occurs here
+LL |         let _ = i;
+LL |         do_something_with(x);
+   |                           - borrow later used here
+
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/try-block-maybe-bad-lifetime.rs:28:24
+   |
+LL |         let x = String::new();
+   |             - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+...
+LL |             ::std::mem::drop(x);
+   |                              - value moved here
+LL |         };
+LL |         println!("{}", x);
+   |                        ^ value borrowed here after move
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |             ::std::mem::drop(x.clone());
+   |                               ++++++++
+
+error[E0506]: cannot assign to `i` because it is borrowed
+  --> $DIR/try-block-maybe-bad-lifetime.rs:40:9
+   |
+LL |             j = &i;
+   |                 -- borrow of `i` occurs here
+LL |         };
+LL |         i = 0;
+   |         ^^^^^ assignment to borrowed `i` occurs here
+LL |         let _ = i;
+LL |         do_something_with(j);
+   |                           - borrow later used here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0506.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/try-block/try-block-opt-init.rs b/tests/ui/try-block/try-block-opt-init.rs
new file mode 100644
index 00000000000..f4f45abcc75
--- /dev/null
+++ b/tests/ui/try-block/try-block-opt-init.rs
@@ -0,0 +1,16 @@
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn use_val<T: Sized>(_x: T) {}
+
+pub fn main() {
+    let cfg_res;
+    let _: Result<(), ()> = try {
+        Err(())?;
+        cfg_res = 5;
+        Ok::<(), ()>(())?;
+        use_val(cfg_res);
+    };
+    assert_eq!(cfg_res, 5); //~ ERROR E0381
+}
diff --git a/tests/ui/try-block/try-block-opt-init.stderr b/tests/ui/try-block/try-block-opt-init.stderr
new file mode 100644
index 00000000000..c397385017f
--- /dev/null
+++ b/tests/ui/try-block/try-block-opt-init.stderr
@@ -0,0 +1,17 @@
+error[E0381]: used binding `cfg_res` is possibly-uninitialized
+  --> $DIR/try-block-opt-init.rs:15:5
+   |
+LL |     let cfg_res;
+   |         ------- binding declared here but left uninitialized
+...
+LL |         cfg_res = 5;
+   |         ----------- binding initialized here in some conditions
+...
+LL |     assert_eq!(cfg_res, 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^ `cfg_res` used here but it is possibly-uninitialized
+   |
+   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/try-block/try-block-type-error.rs b/tests/ui/try-block/try-block-type-error.rs
new file mode 100644
index 00000000000..fe1993a37f6
--- /dev/null
+++ b/tests/ui/try-block/try-block-type-error.rs
@@ -0,0 +1,18 @@
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn foo() -> Option<()> { Some(()) }
+
+fn main() {
+    let _: Option<f32> = try {
+        foo()?;
+        42
+        //~^ ERROR type mismatch
+    };
+
+    let _: Option<i32> = try {
+        foo()?;
+    };
+    //~^ ERROR type mismatch
+}
diff --git a/tests/ui/try-block/try-block-type-error.stderr b/tests/ui/try-block/try-block-type-error.stderr
new file mode 100644
index 00000000000..3e9a584a551
--- /dev/null
+++ b/tests/ui/try-block/try-block-type-error.stderr
@@ -0,0 +1,18 @@
+error[E0271]: type mismatch resolving `<Option<f32> as Try>::Output == {integer}`
+  --> $DIR/try-block-type-error.rs:10:9
+   |
+LL |         42
+   |         ^^
+   |         |
+   |         expected `f32`, found integer
+   |         help: use a float literal: `42.0`
+
+error[E0271]: type mismatch resolving `<Option<i32> as Try>::Output == ()`
+  --> $DIR/try-block-type-error.rs:16:5
+   |
+LL |     };
+   |     ^ expected `i32`, found `()`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/try-block/try-block-unreachable-code-lint.rs b/tests/ui/try-block/try-block-unreachable-code-lint.rs
new file mode 100644
index 00000000000..e1d82ea360d
--- /dev/null
+++ b/tests/ui/try-block/try-block-unreachable-code-lint.rs
@@ -0,0 +1,76 @@
+// Test unreachable_code lint for `try {}` block ok-wrapping. See issues #54165, #63324.
+
+// compile-flags: --edition 2018
+// check-pass
+#![feature(try_blocks)]
+#![warn(unreachable_code)]
+
+fn err() -> Result<u32, ()> {
+    Err(())
+}
+
+// In the following cases unreachable code is autogenerated and should not be reported.
+
+fn test_ok_wrapped_divergent_expr_1() {
+    let res: Result<u32, ()> = try {
+        loop {
+            err()?;
+        }
+    };
+    println!("res: {:?}", res);
+}
+
+fn test_ok_wrapped_divergent_expr_2() {
+    let _: Result<u32, ()> = try {
+        return
+    };
+}
+
+fn test_autogenerated_unit_after_divergent_expr() {
+    let _: Result<(), ()> = try {
+        return;
+    };
+}
+
+// In the following cases unreachable code should be reported.
+
+fn test_try_block_after_divergent_stmt() {
+    let _: Result<u32, ()> = {
+        return;
+
+        try {
+            loop {
+                err()?;
+            }
+        }
+        //~^^^^^ WARNING unreachable expression
+    };
+}
+
+fn test_wrapped_divergent_expr() {
+    let _: Result<u32, ()> = {
+        Err(return)
+        //~^ WARNING unreachable call
+    };
+}
+
+fn test_expr_after_divergent_stmt_in_try_block() {
+    let res: Result<u32, ()> = try {
+        loop {
+            err()?;
+        }
+
+        42
+        //~^ WARNING unreachable expression
+    };
+    println!("res: {:?}", res);
+}
+
+fn main() {
+    test_ok_wrapped_divergent_expr_1();
+    test_ok_wrapped_divergent_expr_2();
+    test_autogenerated_unit_after_divergent_expr();
+    test_try_block_after_divergent_stmt();
+    test_wrapped_divergent_expr();
+    test_expr_after_divergent_stmt_in_try_block();
+}
diff --git a/tests/ui/try-block/try-block-unreachable-code-lint.stderr b/tests/ui/try-block/try-block-unreachable-code-lint.stderr
new file mode 100644
index 00000000000..9fc0b661f1e
--- /dev/null
+++ b/tests/ui/try-block/try-block-unreachable-code-lint.stderr
@@ -0,0 +1,40 @@
+warning: unreachable expression
+  --> $DIR/try-block-unreachable-code-lint.rs:41:9
+   |
+LL |           return;
+   |           ------ any code following this expression is unreachable
+LL |
+LL | /         try {
+LL | |             loop {
+LL | |                 err()?;
+LL | |             }
+LL | |         }
+   | |_________^ unreachable expression
+   |
+note: the lint level is defined here
+  --> $DIR/try-block-unreachable-code-lint.rs:6:9
+   |
+LL | #![warn(unreachable_code)]
+   |         ^^^^^^^^^^^^^^^^
+
+warning: unreachable call
+  --> $DIR/try-block-unreachable-code-lint.rs:52:9
+   |
+LL |         Err(return)
+   |         ^^^ ------ any code following this expression is unreachable
+   |         |
+   |         unreachable call
+
+warning: unreachable expression
+  --> $DIR/try-block-unreachable-code-lint.rs:63:9
+   |
+LL | /         loop {
+LL | |             err()?;
+LL | |         }
+   | |_________- any code following this expression is unreachable
+LL |
+LL |           42
+   |           ^^ unreachable expression
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/try-block/try-block-unused-delims.fixed b/tests/ui/try-block/try-block-unused-delims.fixed
new file mode 100644
index 00000000000..756081738c3
--- /dev/null
+++ b/tests/ui/try-block/try-block-unused-delims.fixed
@@ -0,0 +1,29 @@
+// check-pass
+// compile-flags: --edition 2018
+// run-rustfix
+
+#![feature(try_blocks)]
+#![warn(unused_parens, unused_braces)]
+
+fn consume<T>(_: Result<T, T>) -> T { todo!() }
+
+fn main() {
+    consume(try {});
+    //~^ WARN unnecessary parentheses
+
+    consume(try {});
+    //~^ WARN unnecessary braces
+
+    match try {} {
+        //~^ WARN unnecessary parentheses
+        Ok(()) | Err(()) => (),
+    }
+
+    if let Err(()) = try {} {}
+    //~^ WARN unnecessary parentheses
+
+    match try {} {
+        //~^ WARN unnecessary parentheses
+        Ok(()) | Err(()) => (),
+    }
+}
diff --git a/tests/ui/try-block/try-block-unused-delims.rs b/tests/ui/try-block/try-block-unused-delims.rs
new file mode 100644
index 00000000000..ce087fb351d
--- /dev/null
+++ b/tests/ui/try-block/try-block-unused-delims.rs
@@ -0,0 +1,29 @@
+// check-pass
+// compile-flags: --edition 2018
+// run-rustfix
+
+#![feature(try_blocks)]
+#![warn(unused_parens, unused_braces)]
+
+fn consume<T>(_: Result<T, T>) -> T { todo!() }
+
+fn main() {
+    consume((try {}));
+    //~^ WARN unnecessary parentheses
+
+    consume({ try {} });
+    //~^ WARN unnecessary braces
+
+    match (try {}) {
+        //~^ WARN unnecessary parentheses
+        Ok(()) | Err(()) => (),
+    }
+
+    if let Err(()) = (try {}) {}
+    //~^ WARN unnecessary parentheses
+
+    match (try {}) {
+        //~^ WARN unnecessary parentheses
+        Ok(()) | Err(()) => (),
+    }
+}
diff --git a/tests/ui/try-block/try-block-unused-delims.stderr b/tests/ui/try-block/try-block-unused-delims.stderr
new file mode 100644
index 00000000000..765cd9c0fc4
--- /dev/null
+++ b/tests/ui/try-block/try-block-unused-delims.stderr
@@ -0,0 +1,72 @@
+warning: unnecessary parentheses around function argument
+  --> $DIR/try-block-unused-delims.rs:11:13
+   |
+LL |     consume((try {}));
+   |             ^      ^
+   |
+note: the lint level is defined here
+  --> $DIR/try-block-unused-delims.rs:6:9
+   |
+LL | #![warn(unused_parens, unused_braces)]
+   |         ^^^^^^^^^^^^^
+help: remove these parentheses
+   |
+LL -     consume((try {}));
+LL +     consume(try {});
+   |
+
+warning: unnecessary braces around function argument
+  --> $DIR/try-block-unused-delims.rs:14:13
+   |
+LL |     consume({ try {} });
+   |             ^^      ^^
+   |
+note: the lint level is defined here
+  --> $DIR/try-block-unused-delims.rs:6:24
+   |
+LL | #![warn(unused_parens, unused_braces)]
+   |                        ^^^^^^^^^^^^^
+help: remove these braces
+   |
+LL -     consume({ try {} });
+LL +     consume(try {});
+   |
+
+warning: unnecessary parentheses around `match` scrutinee expression
+  --> $DIR/try-block-unused-delims.rs:17:11
+   |
+LL |     match (try {}) {
+   |           ^      ^
+   |
+help: remove these parentheses
+   |
+LL -     match (try {}) {
+LL +     match try {} {
+   |
+
+warning: unnecessary parentheses around `let` scrutinee expression
+  --> $DIR/try-block-unused-delims.rs:22:22
+   |
+LL |     if let Err(()) = (try {}) {}
+   |                      ^      ^
+   |
+help: remove these parentheses
+   |
+LL -     if let Err(()) = (try {}) {}
+LL +     if let Err(()) = try {} {}
+   |
+
+warning: unnecessary parentheses around `match` scrutinee expression
+  --> $DIR/try-block-unused-delims.rs:25:11
+   |
+LL |     match (try {}) {
+   |           ^      ^
+   |
+help: remove these parentheses
+   |
+LL -     match (try {}) {
+LL +     match try {} {
+   |
+
+warning: 5 warnings emitted
+
diff --git a/tests/ui/try-block/try-block.rs b/tests/ui/try-block/try-block.rs
new file mode 100644
index 00000000000..c29ccc70427
--- /dev/null
+++ b/tests/ui/try-block/try-block.rs
@@ -0,0 +1,75 @@
+// run-pass
+
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+struct catch {}
+
+pub fn main() {
+    let catch_result: Option<_> = try {
+        let x = 5;
+        x
+    };
+    assert_eq!(catch_result, Some(5));
+
+    let mut catch = true;
+    while catch { catch = false; }
+    assert_eq!(catch, false);
+
+    catch = if catch { false } else { true };
+    assert_eq!(catch, true);
+
+    match catch {
+        _ => {}
+    };
+
+    let catch_err: Result<_, i32> = try {
+        Err(22)?;
+        1
+    };
+    assert_eq!(catch_err, Err(22));
+
+    let catch_okay: Result<i32, i32> = try {
+        if false { Err(25)?; }
+        Ok::<(), i32>(())?;
+        28
+    };
+    assert_eq!(catch_okay, Ok(28));
+
+    let catch_from_loop: Result<i32, i32> = try {
+        for i in 0..10 {
+            if i < 5 { Ok::<i32, i32>(i)?; } else { Err(i)?; }
+        }
+        22
+    };
+    assert_eq!(catch_from_loop, Err(5));
+
+    let cfg_init;
+    let _res: Result<(), ()> = try {
+        cfg_init = 5;
+    };
+    assert_eq!(cfg_init, 5);
+
+    let cfg_init_2;
+    let _res: Result<(), ()> = try {
+        cfg_init_2 = 6;
+        Err(())?;
+    };
+    assert_eq!(cfg_init_2, 6);
+
+    let my_string = "test".to_string();
+    let res: Result<&str, ()> = try {
+        // Unfortunately, deref doesn't fire here (#49356)
+        &my_string[..]
+    };
+    assert_eq!(res, Ok("test"));
+
+    let my_opt: Option<_> = try { () };
+    assert_eq!(my_opt, Some(()));
+
+    let my_opt: Option<_> = try { };
+    assert_eq!(my_opt, Some(()));
+}
diff --git a/tests/ui/try-block/try-is-identifier-edition2015.rs b/tests/ui/try-block/try-is-identifier-edition2015.rs
new file mode 100644
index 00000000000..90f56d5fa71
--- /dev/null
+++ b/tests/ui/try-block/try-is-identifier-edition2015.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+#![allow(non_camel_case_types)]
+// compile-flags: --edition 2015
+
+fn main() {
+    let try = 2;
+    struct try { try: u32 }
+    let try: try = try { try };
+    assert_eq!(try.try, 2);
+}