diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index a49dc105498ed..c6228a913cfe2 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -298,14 +298,14 @@ pub struct ResolvedOpaqueTy<'tcx> { /// /// ```ignore (pseudo-Rust) /// async move { -/// let x: T = ...; +/// let x: T = expr; /// foo.await /// ... /// } /// ``` /// -/// Here, we would store the type `T`, the span of the value `x`, and the "scope-span" for -/// the scope that contains `x`. +/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for +/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`. #[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] pub struct GeneratorInteriorTypeCause<'tcx> { /// Type of the captured binding. @@ -314,6 +314,8 @@ pub struct GeneratorInteriorTypeCause<'tcx> { pub span: Span, /// Span of the scope of the captured binding. pub scope_span: Option, + /// Span of `.await` or `yield` expression. + pub yield_span: Span, /// Expr which the type evaluated from. pub expr: Option, } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 254db6cb869b1..51ac552c31239 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -125,6 +125,7 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, target_span: Span, scope_span: &Option, + await_span: Span, expr: Option, snippet: String, inner_generator_body: Option<&hir::Body<'_>>, @@ -1260,8 +1261,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty_matches(ty) }) .map(|expr| expr.span); - let ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. } = cause; - (span, source_map.span_to_snippet(*span), scope_span, expr, from_awaited_ty) + let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = + cause; + ( + span, + source_map.span_to_snippet(*span), + scope_span, + yield_span, + expr, + from_awaited_ty, + ) }); debug!( @@ -1269,11 +1278,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { generator_interior_types={:?} target_span={:?}", target_ty, tables.generator_interior_types, target_span ); - if let Some((target_span, Ok(snippet), scope_span, expr, from_awaited_ty)) = target_span { + if let Some((target_span, Ok(snippet), scope_span, yield_span, expr, from_awaited_ty)) = + target_span + { self.note_obligation_cause_for_async_await( err, *target_span, scope_span, + *yield_span, *expr, snippet, generator_body, @@ -1298,6 +1310,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, target_span: Span, scope_span: &Option, + yield_span: Span, expr: Option, snippet: String, inner_generator_body: Option<&hir::Body<'_>>, @@ -1392,10 +1405,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "note_obligation_cause_for_async_await generator_interior_types: {:#?}", tables.generator_interior_types ); - let await_span = tables.generator_interior_types.iter().map(|t| t.span).last().unwrap(); - let mut span = MultiSpan::from_span(await_span); + let mut span = MultiSpan::from_span(yield_span); span.push_span_label( - await_span, + yield_span, format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), ); diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index db9c8c35c2cee..716d23b4d173c 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -96,6 +96,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { span: source_span, ty: &ty, scope_span, + yield_span: yield_data.span, expr: expr.map(|e| e.hir_id), }) .or_insert(entries); diff --git a/src/test/ui/async-await/issue-71137.rs b/src/test/ui/async-await/issue-71137.rs new file mode 100644 index 0000000000000..ebb392a45308e --- /dev/null +++ b/src/test/ui/async-await/issue-71137.rs @@ -0,0 +1,21 @@ +// edition:2018 + +use std::future::Future; +use std::sync::Mutex; + +fn fake_spawn(f: F) { } + +async fn wrong_mutex() { + let m = Mutex::new(1); + { + let mut guard = m.lock().unwrap(); + (async { "right"; }).await; + *guard += 1; + } + + (async { "wrong"; }).await; +} + +fn main() { + fake_spawn(wrong_mutex()); //~ Error future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/issue-71137.stderr b/src/test/ui/async-await/issue-71137.stderr new file mode 100644 index 0000000000000..788a9bc2c7e47 --- /dev/null +++ b/src/test/ui/async-await/issue-71137.stderr @@ -0,0 +1,23 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-71137.rs:20:3 + | +LL | fn fake_spawn(f: F) { } + | ---- required by this bound in `fake_spawn` +... +LL | fake_spawn(wrong_mutex()); + | ^^^^^^^^^^ future returned by `wrong_mutex` is not `Send` + | + = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, i32>` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-71137.rs:12:5 + | +LL | let mut guard = m.lock().unwrap(); + | --------- has type `std::sync::MutexGuard<'_, i32>` which is not `Send` +LL | (async { "right"; }).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut guard` maybe used later +LL | *guard += 1; +LL | } + | - `mut guard` is later dropped here + +error: aborting due to previous error +