diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 389cf4e313216..4e7476e4e6c61 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1758,9 +1758,9 @@ impl<'hir> LoweringContext<'_, 'hir> { /// ControlFlow::Break(residual) => /// #[allow(unreachable_code)] /// // If there is an enclosing `try {...}`: - /// break 'catch_target Try::from_residual(residual), + /// absurd(break 'catch_target Try::from_residual(residual)), /// // Otherwise: - /// return Try::from_residual(residual), + /// absurd(return Try::from_residual(residual)), /// } /// ``` fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> { @@ -1769,6 +1769,13 @@ impl<'hir> LoweringContext<'_, 'hir> { span, Some(self.allow_try_trait.clone()), ); + + let absurd_allowed_span = self.mark_span_with_reason( + DesugaringKind::QuestionMark, + span, + Some(self.allow_convert_absurd.clone()), + ); + let try_span = self.tcx.sess.source_map().end_point(span); let try_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, @@ -1810,7 +1817,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `ControlFlow::Break(residual) => // #[allow(unreachable_code)] - // return Try::from_residual(residual),` + // absurd(return Try::from_residual(residual)),` let break_arm = { let residual_ident = Ident::with_dummy_span(sym::residual); let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident); @@ -1823,20 +1830,27 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let ret_expr = if let Some(catch_node) = self.catch_scope { let target_id = Ok(self.lower_node_id(catch_node)); - self.arena.alloc(self.expr( + self.expr( try_span, hir::ExprKind::Break( hir::Destination { label: None, target_id }, Some(from_residual_expr), ), - )) + ) } else { - self.arena.alloc(self.expr(try_span, hir::ExprKind::Ret(Some(from_residual_expr)))) + self.expr(try_span, hir::ExprKind::Ret(Some(from_residual_expr))) }; - self.lower_attrs(ret_expr.hir_id, &attrs); + + let absurd_expr = self.expr_call_lang_item_fn( + absurd_allowed_span, + hir::LangItem::Absurd, + arena_vec![self; ret_expr], + ); + + self.lower_attrs(absurd_expr.hir_id, &attrs); let break_pat = self.pat_cf_break(try_span, residual_local); - self.arm(break_pat, ret_expr) + self.arm(break_pat, absurd_expr) }; hir::ExprKind::Match( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 833b0e9b5679e..90be5ffff4c2a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -130,6 +130,7 @@ struct LoweringContext<'a, 'hir> { node_id_to_local_id: NodeMap, allow_try_trait: Lrc<[Symbol]>, + allow_convert_absurd: Lrc<[Symbol]>, allow_gen_future: Lrc<[Symbol]>, allow_async_iterator: Lrc<[Symbol]>, allow_for_await: Lrc<[Symbol]>, @@ -173,6 +174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { impl_trait_defs: Vec::new(), impl_trait_bounds: Vec::new(), allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(), + allow_convert_absurd: [sym::convert_absurd].into(), allow_gen_future: if tcx.features().async_fn_track_caller { [sym::gen_future, sym::closure_track_caller].into() } else { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 727a292b0e782..4b2b02493a798 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -602,6 +602,7 @@ symbols! { const_try, constant, constructor, + convert_absurd, convert_identity, copy, copy_closures, diff --git a/tests/ui/async-await/issue-67765-async-diagnostic.rs b/tests/ui/async-await/issue-67765-async-diagnostic.rs index 7fe1baef952e1..20bf543d24667 100644 --- a/tests/ui/async-await/issue-67765-async-diagnostic.rs +++ b/tests/ui/async-await/issue-67765-async-diagnostic.rs @@ -10,7 +10,7 @@ async fn func<'a>() -> Result<(), &'a str> { let b = &s[..]; - Err(b)?; //~ ERROR cannot return value referencing local variable `s` + Err::<(), _>(b)?; //~ ERROR cannot return value referencing local variable `s` Ok(()) } diff --git a/tests/ui/async-await/issue-67765-async-diagnostic.stderr b/tests/ui/async-await/issue-67765-async-diagnostic.stderr index 833df51a7aac8..31f3fc57b19b3 100644 --- a/tests/ui/async-await/issue-67765-async-diagnostic.stderr +++ b/tests/ui/async-await/issue-67765-async-diagnostic.stderr @@ -4,8 +4,8 @@ error[E0515]: cannot return value referencing local variable `s` LL | let b = &s[..]; | - `s` is borrowed here LL | -LL | Err(b)?; - | ^^^^^^^ returns a value referencing data owned by the current function +LL | Err::<(), _>(b)?; + | ^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function error: aborting due to 1 previous error diff --git a/tests/ui/consts/try-operator.rs b/tests/ui/consts/try-operator.rs index 352dbeefa8a60..87b5531af8612 100644 --- a/tests/ui/consts/try-operator.rs +++ b/tests/ui/consts/try-operator.rs @@ -7,7 +7,7 @@ fn main() { const fn result() -> Result { - Err(())?; + Err::<(), _>(())?; Ok(true) } @@ -15,7 +15,7 @@ fn main() { assert_eq!(Err(()), FOO); const fn option() -> Option<()> { - None?; + None::<()>?; Some(()) } const BAR: Option<()> = option(); diff --git a/tests/ui/consts/try-operator.stderr b/tests/ui/consts/try-operator.stderr index 2c8b4c7fcd9cb..6176cefe81ad9 100644 --- a/tests/ui/consts/try-operator.stderr +++ b/tests/ui/consts/try-operator.stderr @@ -7,8 +7,8 @@ LL | #![feature(const_convert)] error[E0015]: `?` cannot determine the branch of `Result<(), ()>` in constant functions --> $DIR/try-operator.rs:10:9 | -LL | Err(())?; - | ^^^^^^^^ +LL | Err::<(), _>(())?; + | ^^^^^^^^^^^^^^^^^ | note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/result.rs:LL:COL @@ -21,8 +21,8 @@ LL + #![feature(effects)] error[E0015]: `?` cannot convert from residual of `Result` in constant functions --> $DIR/try-operator.rs:10:9 | -LL | Err(())?; - | ^^^^^^^^ +LL | Err::<(), _>(())?; + | ^^^^^^^^^^^^^^^^^ | note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/result.rs:LL:COL @@ -35,8 +35,8 @@ LL + #![feature(effects)] error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions --> $DIR/try-operator.rs:18:9 | -LL | None?; - | ^^^^^ +LL | None::<()>?; + | ^^^^^^^^^^^ | note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/option.rs:LL:COL @@ -49,8 +49,8 @@ LL + #![feature(effects)] error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions --> $DIR/try-operator.rs:18:9 | -LL | None?; - | ^^^^^ +LL | None::<()>?; + | ^^^^^^^^^^^ | note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/did_you_mean/compatible-variants.stderr b/tests/ui/did_you_mean/compatible-variants.stderr index f2bbd8ced8f24..7b88d93ead112 100644 --- a/tests/ui/did_you_mean/compatible-variants.stderr +++ b/tests/ui/did_you_mean/compatible-variants.stderr @@ -61,8 +61,6 @@ LL + Some(()) error[E0308]: `?` operator has incompatible types --> $DIR/compatible-variants.rs:35:5 | -LL | fn d() -> Option<()> { - | ---------- expected `Option<()>` because of return type LL | c()? | ^^^^ expected `Option<()>`, found `()` | diff --git a/tests/ui/impl-trait/cross-return-site-inference.rs b/tests/ui/impl-trait/cross-return-site-inference.rs index bed08a6c4186e..a0491ab0eebea 100644 --- a/tests/ui/impl-trait/cross-return-site-inference.rs +++ b/tests/ui/impl-trait/cross-return-site-inference.rs @@ -2,34 +2,34 @@ fn foo(b: bool) -> impl std::fmt::Debug { if b { - return vec![42] + return vec![42]; } [].into_iter().collect() } fn bar(b: bool) -> impl std::fmt::Debug { if b { - return [].into_iter().collect() + return [].into_iter().collect(); } vec![42] } fn bak(b: bool) -> impl std::fmt::Debug { if b { - return std::iter::empty().collect() + return std::iter::empty().collect(); } vec![42] } fn baa(b: bool) -> impl std::fmt::Debug { if b { - return [42].into_iter().collect() + return [42].into_iter().collect(); } vec![] } fn muh() -> Result<(), impl std::fmt::Debug> { - Err("whoops")?; + Err::<(), _>("whoops")?; Ok(()) //~^ ERROR type annotations needed } diff --git a/tests/ui/inference/cannot-infer-closure.rs b/tests/ui/inference/cannot-infer-closure.rs index bd5d10b417342..183ef9abd89f0 100644 --- a/tests/ui/inference/cannot-infer-closure.rs +++ b/tests/ui/inference/cannot-infer-closure.rs @@ -1,6 +1,6 @@ fn main() { let x = |a: (), b: ()| { - Err(a)?; + Err::<(), _>(a)?; Ok(b) //~^ ERROR type annotations needed }; diff --git a/tests/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/tests/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index 99fce1eeea6f6..72f05088dbaf0 100644 --- a/tests/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/tests/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -1,8 +1,6 @@ error[E0308]: `?` operator has incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | -LL | fn forbidden_narratives() -> Result { - | ----------------- expected `Result` because of return type LL | missing_discourses()? | ^^^^^^^^^^^^^^^^^^^^^ expected `Result`, found `isize` | diff --git a/tests/ui/label/label_break_value_desugared_break.rs b/tests/ui/label/label_break_value_desugared_break.rs index b7e7fd47c27f3..aac459102ef7d 100644 --- a/tests/ui/label/label_break_value_desugared_break.rs +++ b/tests/ui/label/label_break_value_desugared_break.rs @@ -5,14 +5,14 @@ fn main() { let _: Result<(), ()> = try { 'foo: { - Err(())?; + Err::<(), _>(())?; break 'foo; } }; 'foo: { let _: Result<(), ()> = try { - Err(())?; + Err::<(), _>(())?; break 'foo; }; } diff --git a/tests/ui/parser/try-with-nonterminal-block.rs b/tests/ui/parser/try-with-nonterminal-block.rs index bc52dcd0e01d3..0648b047518ec 100644 --- a/tests/ui/parser/try-with-nonterminal-block.rs +++ b/tests/ui/parser/try-with-nonterminal-block.rs @@ -11,7 +11,7 @@ macro_rules! create_try { fn main() { let x: Option<&str> = create_try! {{ - None?; + None::<()>?; "Hello world" }}; diff --git a/tests/ui/suggestions/remove-question-symbol-with-paren.stderr b/tests/ui/suggestions/remove-question-symbol-with-paren.stderr index bdea727a09816..f142f8875e5ab 100644 --- a/tests/ui/suggestions/remove-question-symbol-with-paren.stderr +++ b/tests/ui/suggestions/remove-question-symbol-with-paren.stderr @@ -1,9 +1,6 @@ error[E0308]: `?` operator has incompatible types --> $DIR/remove-question-symbol-with-paren.rs:5:6 | -LL | fn foo() -> Option<()> { - | ---------- expected `Option<()>` because of return type -LL | let x = Some(()); LL | (x?) | ^^ expected `Option<()>`, found `()` | diff --git a/tests/ui/suggestions/suggest-box.fixed b/tests/ui/suggestions/suggest-box.fixed index 7cd62c4318347..112b2a00578dc 100644 --- a/tests/ui/suggestions/suggest-box.fixed +++ b/tests/ui/suggestions/suggest-box.fixed @@ -2,7 +2,7 @@ fn main() { let _x: Box Result<(), ()>> = Box::new(|| { //~ ERROR mismatched types - Err(())?; + Err::<(), _>(())?; Ok(()) }); } diff --git a/tests/ui/suggestions/suggest-box.rs b/tests/ui/suggestions/suggest-box.rs index c31320c548594..39b7b7407ce6c 100644 --- a/tests/ui/suggestions/suggest-box.rs +++ b/tests/ui/suggestions/suggest-box.rs @@ -2,7 +2,7 @@ fn main() { let _x: Box Result<(), ()>> = || { //~ ERROR mismatched types - Err(())?; + Err::<(), _>(())?; Ok(()) }; } diff --git a/tests/ui/suggestions/suggest-box.stderr b/tests/ui/suggestions/suggest-box.stderr index 58f8774fe9ddd..f5ecc663a2906 100644 --- a/tests/ui/suggestions/suggest-box.stderr +++ b/tests/ui/suggestions/suggest-box.stderr @@ -5,7 +5,7 @@ LL | let _x: Box Result<(), ()>> = || { | _____________-------------------------------___^ | | | | | expected due to this -LL | | Err(())?; +LL | | Err::<(), _>(())?; LL | | Ok(()) LL | | }; | |_____^ expected `Box Result<(), ()>>`, found closure @@ -16,7 +16,7 @@ LL | | }; help: store this in the heap by calling `Box::new` | LL ~ let _x: Box Result<(), ()>> = Box::new(|| { -LL | Err(())?; +LL | Err::<(), _>(())?; LL | Ok(()) LL ~ }); | diff --git a/tests/ui/try-block/try-block-bad-lifetime.rs b/tests/ui/try-block/try-block-bad-lifetime.rs index bfff757a2df63..560eee44862df 100644 --- a/tests/ui/try-block/try-block-bad-lifetime.rs +++ b/tests/ui/try-block/try-block-bad-lifetime.rs @@ -12,10 +12,10 @@ pub fn main() { // result variable let result: Result<(), &str> = try { let my_string = String::from(""); - let my_str: & str = & my_string; + let my_str: &str = &my_string; //~^ ERROR `my_string` does not live long enough - Err(my_str) ?; - Err("") ?; + Err::<(), _>(my_str)?; + Err::<(), _>("")?; }; do_something_with(result); } @@ -25,13 +25,13 @@ pub fn main() { let mut i = 5; let k = &mut i; let mut j: Result<(), &mut i32> = try { - Err(k) ?; + 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 ! ("") }; + 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 index 28941cb0a9e40..eb0787b33979a 100644 --- a/tests/ui/try-block/try-block-bad-lifetime.stderr +++ b/tests/ui/try-block/try-block-bad-lifetime.stderr @@ -1,12 +1,12 @@ error[E0597]: `my_string` does not live long enough - --> $DIR/try-block-bad-lifetime.rs:15:33 + --> $DIR/try-block-bad-lifetime.rs:15:32 | LL | let result: Result<(), &str> = try { | ------ borrow later stored here LL | let my_string = String::from(""); | --------- binding `my_string` declared here -LL | let my_str: & str = & my_string; - | ^^^^^^^^^^^ borrowed value does not live long enough +LL | let my_str: &str = &my_string; + | ^^^^^^^^^^ borrowed value does not live long enough ... LL | }; | - `my_string` dropped here while still borrowed @@ -29,8 +29,8 @@ error[E0382]: use of moved value: `k` 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 | Err::<(), _>(k)?; + | - value moved here ... LL | ::std::mem::drop(k); | ^ value used here after move @@ -44,7 +44,7 @@ LL | let k = &mut i; LL | i = 40; | ^^^^^^ `i` is assigned to here but it was already borrowed LL | -LL | let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") }; +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 diff --git a/tests/ui/try-block/try-block-maybe-bad-lifetime.rs b/tests/ui/try-block/try-block-maybe-bad-lifetime.rs index 52ec0c44a059c..e339f724b5926 100644 --- a/tests/ui/try-block/try-block-maybe-bad-lifetime.rs +++ b/tests/ui/try-block/try-block-maybe-bad-lifetime.rs @@ -11,7 +11,7 @@ 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(())?; + Err::<(), _>(())?; &i }; i = 0; //~ ERROR cannot assign to `i` because it is borrowed @@ -22,7 +22,7 @@ pub fn main() { { let x = String::new(); let _y: Result<(), ()> = try { - Err(())?; + Err::<(), _>(())?; ::std::mem::drop(x); }; println!("{}", x); //~ ERROR borrow of moved value: `x` @@ -34,7 +34,7 @@ pub fn main() { let mut i = 222; let mut j = &-1; let _x: Result<(), ()> = try { - Err(())?; + Err::<(), _>(())?; j = &i; }; i = 0; //~ ERROR cannot assign to `i` because it is borrowed diff --git a/tests/ui/try-block/try-block-opt-init.rs b/tests/ui/try-block/try-block-opt-init.rs index fbe7f90d03039..7dc635de468af 100644 --- a/tests/ui/try-block/try-block-opt-init.rs +++ b/tests/ui/try-block/try-block-opt-init.rs @@ -7,7 +7,7 @@ fn use_val(_x: T) {} pub fn main() { let cfg_res; let _: Result<(), ()> = try { - Err(())?; + Err::<(), _>(())?; cfg_res = 5; Ok::<(), ()>(())?; use_val(cfg_res); diff --git a/tests/ui/try-block/try-block.rs b/tests/ui/try-block/try-block.rs index 7520cbaad378e..b7a68638d26ec 100644 --- a/tests/ui/try-block/try-block.rs +++ b/tests/ui/try-block/try-block.rs @@ -3,7 +3,6 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] //@ compile-flags: --edition 2018 - #![feature(try_blocks)] struct catch {} @@ -16,7 +15,9 @@ pub fn main() { assert_eq!(catch_result, Some(5)); let mut catch = true; - while catch { catch = false; } + while catch { + catch = false; + } assert_eq!(catch, false); catch = if catch { false } else { true }; @@ -27,13 +28,15 @@ pub fn main() { }; let catch_err: Result<_, i32> = try { - Err(22)?; + Err::<(), _>(22)?; 1 }; assert_eq!(catch_err, Err(22)); let catch_okay: Result = try { - if false { Err(25)?; } + if false { + Err::<(), _>(25)?; + } Ok::<(), i32>(())?; 28 }; @@ -41,7 +44,11 @@ pub fn main() { let catch_from_loop: Result = try { for i in 0..10 { - if i < 5 { Ok::(i)?; } else { Err(i)?; } + if i < 5 { + Ok::(i)?; + } else { + Err::<(), _>(i)?; + } } 22 }; @@ -56,7 +63,7 @@ pub fn main() { let cfg_init_2; let _res: Result<(), ()> = try { cfg_init_2 = 6; - Err(())?; + Err::<(), _>(())?; }; assert_eq!(cfg_init_2, 6); @@ -70,6 +77,6 @@ pub fn main() { let my_opt: Option<_> = try { () }; assert_eq!(my_opt, Some(())); - let my_opt: Option<_> = try { }; + let my_opt: Option<_> = try {}; assert_eq!(my_opt, Some(())); }