summaryrefslogtreecommitdiffstats
path: root/src/test/ui/try-block
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/try-block
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/ui/try-block')
-rw-r--r--src/test/ui/try-block/issue-45124.rs18
-rw-r--r--src/test/ui/try-block/try-block-bad-lifetime.rs37
-rw-r--r--src/test/ui/try-block/try-block-bad-lifetime.stderr52
-rw-r--r--src/test/ui/try-block/try-block-bad-type.rs21
-rw-r--r--src/test/ui/try-block/try-block-bad-type.stderr42
-rw-r--r--src/test/ui/try-block/try-block-catch.rs10
-rw-r--r--src/test/ui/try-block/try-block-catch.stderr10
-rw-r--r--src/test/ui/try-block/try-block-in-edition2015.rs10
-rw-r--r--src/test/ui/try-block/try-block-in-edition2015.stderr24
-rw-r--r--src/test/ui/try-block/try-block-in-match.rs11
-rw-r--r--src/test/ui/try-block/try-block-in-return.rs12
-rw-r--r--src/test/ui/try-block/try-block-in-while.rs8
-rw-r--r--src/test/ui/try-block/try-block-in-while.stderr11
-rw-r--r--src/test/ui/try-block/try-block-maybe-bad-lifetime.rs44
-rw-r--r--src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr42
-rw-r--r--src/test/ui/try-block/try-block-opt-init.rs16
-rw-r--r--src/test/ui/try-block/try-block-opt-init.stderr17
-rw-r--r--src/test/ui/try-block/try-block-type-error.rs18
-rw-r--r--src/test/ui/try-block/try-block-type-error.stderr18
-rw-r--r--src/test/ui/try-block/try-block-unreachable-code-lint.rs76
-rw-r--r--src/test/ui/try-block/try-block-unreachable-code-lint.stderr40
-rw-r--r--src/test/ui/try-block/try-block-unused-delims.fixed29
-rw-r--r--src/test/ui/try-block/try-block-unused-delims.rs29
-rw-r--r--src/test/ui/try-block/try-block-unused-delims.stderr72
-rw-r--r--src/test/ui/try-block/try-block.rs75
-rw-r--r--src/test/ui/try-block/try-is-identifier-edition2015.rs11
26 files changed, 753 insertions, 0 deletions
diff --git a/src/test/ui/try-block/issue-45124.rs b/src/test/ui/try-block/issue-45124.rs
new file mode 100644
index 000000000..942014c91
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-bad-lifetime.rs b/src/test/ui/try-block/try-block-bad-lifetime.rs
new file mode 100644
index 000000000..d9524e99f
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-bad-lifetime.stderr b/src/test/ui/try-block/try-block-bad-lifetime.stderr
new file mode 100644
index 000000000..ea079e30d
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs
new file mode 100644
index 000000000..30ae96763
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr
new file mode 100644
index 000000000..f9906713f
--- /dev/null
+++ b/src/test/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 because of the requirements on the impl of `FromResidual<Result<Infallible, &str>>` for `Result<u32, TryFromSliceError>`
+
+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/src/test/ui/try-block/try-block-catch.rs b/src/test/ui/try-block/try-block-catch.rs
new file mode 100644
index 000000000..d16501561
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-catch.stderr b/src/test/ui/try-block/try-block-catch.stderr
new file mode 100644
index 000000000..39cf943f4
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-in-edition2015.rs b/src/test/ui/try-block/try-block-in-edition2015.rs
new file mode 100644
index 000000000..009642973
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr
new file mode 100644
index 000000000..a00064c44
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-in-match.rs b/src/test/ui/try-block/try-block-in-match.rs
new file mode 100644
index 000000000..cd0b967e7
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-in-return.rs b/src/test/ui/try-block/try-block-in-return.rs
new file mode 100644
index 000000000..a15bfeef1
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-in-while.rs b/src/test/ui/try-block/try-block-in-while.rs
new file mode 100644
index 000000000..69793df52
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr
new file mode 100644
index 000000000..62cc26dd4
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs b/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs
new file mode 100644
index 000000000..cd2ddf63a
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
new file mode 100644
index 000000000..c9f2a3ed9
--- /dev/null
+++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
@@ -0,0 +1,42 @@
+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)
+
+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/src/test/ui/try-block/try-block-opt-init.rs b/src/test/ui/try-block/try-block-opt-init.rs
new file mode 100644
index 000000000..f4f45abcc
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-opt-init.stderr b/src/test/ui/try-block/try-block-opt-init.stderr
new file mode 100644
index 000000000..c39738501
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-type-error.rs b/src/test/ui/try-block/try-block-type-error.rs
new file mode 100644
index 000000000..fe1993a37
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-type-error.stderr b/src/test/ui/try-block/try-block-type-error.stderr
new file mode 100644
index 000000000..3e9a584a5
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-unreachable-code-lint.rs b/src/test/ui/try-block/try-block-unreachable-code-lint.rs
new file mode 100644
index 000000000..e1d82ea36
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-unreachable-code-lint.stderr b/src/test/ui/try-block/try-block-unreachable-code-lint.stderr
new file mode 100644
index 000000000..9fc0b661f
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-unused-delims.fixed b/src/test/ui/try-block/try-block-unused-delims.fixed
new file mode 100644
index 000000000..756081738
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-unused-delims.rs b/src/test/ui/try-block/try-block-unused-delims.rs
new file mode 100644
index 000000000..ce087fb35
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block-unused-delims.stderr b/src/test/ui/try-block/try-block-unused-delims.stderr
new file mode 100644
index 000000000..765cd9c0f
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-block.rs b/src/test/ui/try-block/try-block.rs
new file mode 100644
index 000000000..c29ccc704
--- /dev/null
+++ b/src/test/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/src/test/ui/try-block/try-is-identifier-edition2015.rs b/src/test/ui/try-block/try-is-identifier-edition2015.rs
new file mode 100644
index 000000000..90f56d5fa
--- /dev/null
+++ b/src/test/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);
+}