diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 0b8123c9703..4a616dc2464 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -203,6 +203,15 @@ borrowck_moved_due_to_method_call = *[false] call } +borrowck_moved_due_to_await = + {$place_name} {$is_partial -> + [true] partially moved + *[false] moved + } due to this {$is_loop_message -> + [true] await, in previous iteration of loop + *[false] await + } + borrowck_value_moved_here = value {$is_partial -> [true] partially moved diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 4243ec214b0..a780255725e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1085,12 +1085,21 @@ fn explain_captures( } } } else { - err.subdiagnostic(CaptureReasonLabel::MethodCall { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }); + if let Some((CallDesugaringKind::Await, _)) = desugaring { + err.subdiagnostic(CaptureReasonLabel::Await { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); + } else { + err.subdiagnostic(CaptureReasonLabel::MethodCall { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); + } // Erase and shadow everything that could be passed to the new infcx. let ty = moved_place.ty(self.body, tcx).ty; diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index bb95101845f..fceae5bb3ff 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -338,6 +338,14 @@ pub(crate) enum CaptureReasonLabel<'a> { is_partial: bool, is_loop_message: bool, }, + #[label(borrowck_moved_due_to_await)] + Await { + #[primary_span] + fn_call_span: Span, + place_name: &'a str, + is_partial: bool, + is_loop_message: bool, + }, #[label(borrowck_value_moved_here)] MovedHere { #[primary_span] diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 6c11edb742c..4cef2fcec1b 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -184,6 +184,9 @@ macro_rules! error { CallDesugaringKind::TryBlockFromOutput => { error!("`try` block cannot convert `{}` to the result in {}s") } + CallDesugaringKind::Await => { + error!("cannot convert `{}` into a future in {}s") + } }; diag_trait(&mut err, self_ty, kind.trait_def_id(tcx)); diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index 627c84c388c..98d55ea6d40 100644 --- a/compiler/rustc_middle/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -19,6 +19,8 @@ pub enum CallDesugaringKind { QuestionFromResidual, /// try { ..; x } calls type_of(x)::from_output(x) TryBlockFromOutput, + /// `.await` calls `IntoFuture::into_future` + Await, } impl CallDesugaringKind { @@ -29,6 +31,7 @@ pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId { tcx.require_lang_item(LangItem::Try, None) } Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), + Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(), } } } @@ -129,6 +132,8 @@ pub fn call_kind<'tcx>( && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) { Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0))) + } else if fn_call_span.is_desugaring(DesugaringKind::Await) { + Some((CallDesugaringKind::Await, method_substs.type_at(0))) } else { None }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index abf19c30e3d..c905eea202d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -208,6 +208,7 @@ Input, Into, IntoDiagnostic, + IntoFuture, IntoIterator, IoRead, IoWrite, diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs index 649b4338772..38c654e76b4 100644 --- a/library/core/src/future/into_future.rs +++ b/library/core/src/future/into_future.rs @@ -99,6 +99,7 @@ /// } /// ``` #[stable(feature = "into_future", since = "1.64.0")] +#[rustc_diagnostic_item = "IntoFuture"] pub trait IntoFuture { /// The output that the future will produce on completion. #[stable(feature = "into_future", since = "1.64.0")] diff --git a/tests/ui/async-await/clone-suggestion.stderr b/tests/ui/async-await/clone-suggestion.stderr index 8eea8bc3911..c02206f6f9b 100644 --- a/tests/ui/async-await/clone-suggestion.stderr +++ b/tests/ui/async-await/clone-suggestion.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value: `f` LL | let f = SharedFuture; | - move occurs because `f` has type `SharedFuture`, which does not implement the `Copy` trait LL | f.await; - | ----- `f` moved due to this method call + | ----- `f` moved due to this await LL | f.await; | ^ value used here after move |