diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index c0881befe24..56eb5e3686a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1570,36 +1570,121 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("does not implement `{}`", trait_ref.print_only_trait_path()) }; - let mut explain_yield = |interior_span: Span, - yield_span: Span, - scope_span: Option| { - let mut span = MultiSpan::from_span(yield_span); - if let Ok(snippet) = source_map.span_to_snippet(interior_span) { - span.push_span_label( - yield_span, - format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), - ); - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { - span.push_span_label( - source_map.end_point(scope_span), - format!("`{}` is later dropped here", snippet), - ); - } - } - span.push_span_label( - interior_span, - format!("has type `{}` which {}", target_ty, trait_explanation), - ); + let mut explain_yield = + |interior_span: Span, yield_span: Span, scope_span: Option| { + let mut span = MultiSpan::from_span(yield_span); + if let Ok(snippet) = source_map.span_to_snippet(interior_span) { + // #70935: If snippet contains newlines, display "the value" instead + // so that we do not emit complex diagnostics. + let snippet = &format!("`{}`", snippet); + let snippet = if snippet.contains('\n') { "the value" } else { snippet }; + // The multispan can be complex here, like: + // note: future is not `Send` as this value is used across an await + // --> $DIR/issue-70935-complex-spans.rs:13:9 + // | + // LL | baz(|| async{ + // | __________^___- + // | | _________| + // | || + // LL | || foo(tx.clone()); + // LL | || }).await; + // | || - ^- value is later dropped here + // | ||_________|______| + // | |__________| await occurs here, with value maybe used later + // | has type `closure` which is not `Send` + // = note: the return type of a function must have a statically known size + // So, detect it and separate into some notes, like: + // note: future is not `Send` as this value is used across an await + // --> $DIR/issue-70935-complex-spans.rs:13:9 + // | + // LL | / baz(|| async{ + // LL | | foo(tx.clone()); + // LL | | }).await; + // | |________________^ + // note: first, await occurs here, with the value maybe used later + // --> $DIR/issue-70935-complex-spans.rs:13:9 + // | + // LL | / baz(|| async{ + // LL | | foo(tx.clone()); + // LL | | }).await; + // | |________________^ + // note: ...but, the value is later dropped here + // --> $DIR/issue-70935-complex-spans.rs:15:17 + // | + // LL | }).await; + // | ^ + // = note: the return type of a function must have a statically known size - err.span_note( - span, - &format!( - "{} {} as this value is used across {}", - future_or_generator, trait_explanation, an_await_or_yield - ), - ); - }; + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + let scope_span = source_map.end_point(scope_span); + let is_overlapped = + yield_span.overlaps(scope_span) || yield_span.overlaps(interior_span); + if is_overlapped { + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + err.span_note( + yield_span, + &format!( + "first, {} occurs here, with {} maybe used later", + await_or_yield, snippet + ), + ); + err.span_note( + scope_span, + &format!("...but, {} is later dropped here", snippet), + ); + } else { + span.push_span_label( + yield_span, + format!( + "{} occurs here, with {} maybe used later", + await_or_yield, snippet + ), + ); + span.push_span_label( + scope_span, + format!("{} is later dropped here", snippet), + ); + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + } + } else { + span.push_span_label( + yield_span, + format!( + "{} occurs here, with {} maybe used later", + await_or_yield, snippet + ), + ); + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + } + } + }; match interior_or_upvar_span { GeneratorInteriorOrUpvar::Interior(interior_span) => { if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { diff --git a/src/test/ui/async-await/issue-70935-complex-spans.stderr b/src/test/ui/async-await/issue-70935-complex-spans.stderr index d9ce038f72b..c55f8abc42d 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.stderr @@ -1,31 +1,29 @@ error: future cannot be sent between threads safely --> $DIR/issue-70935-complex-spans.rs:10:45 | -LL | fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` -LL | -LL | / async move { -LL | | baz(|| async{ -LL | | foo(tx.clone()); -LL | | }).await; -LL | | } - | |_____- this returned value is of type `impl std::future::Future` +LL | fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender` + = help: the trait `Sync` is not implemented for `Sender` note: future is not `Send` as this value is used across an await --> $DIR/issue-70935-complex-spans.rs:13:9 | -LL | baz(|| async{ - | __________^___- - | | _________| - | || -LL | || foo(tx.clone()); -LL | || }).await; - | || - ^- value is later dropped here - | ||_________|______| - | |__________| await occurs here, with value maybe used later - | has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10 tx:&std::sync::mpsc::Sender]` which is not `Send` - = note: the return type of a function must have a statically known size +LL | / baz(|| async{ +LL | | foo(tx.clone()); +LL | | }).await; + | |________________^ +note: first, await occurs here, with the value maybe used later + --> $DIR/issue-70935-complex-spans.rs:13:9 + | +LL | / baz(|| async{ +LL | | foo(tx.clone()); +LL | | }).await; + | |________________^ +note: ...but, the value is later dropped here + --> $DIR/issue-70935-complex-spans.rs:15:17 + | +LL | }).await; + | ^ error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr index e4b2725686a..6ffbcd7ea65 100644 --- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -12,10 +12,17 @@ note: future is not `Send` as this value is used across an await --> $DIR/issue-65436-raw-ptr-not-send.rs:14:9 | LL | bar(Foo(std::ptr::null())).await; - | ^^^^^^^^----------------^^^^^^^^- `std::ptr::null()` is later dropped here - | | | - | | has type `*const u8` which is not `Send` - | await occurs here, with `std::ptr::null()` maybe used later + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: first, await occurs here, with `std::ptr::null()` maybe used later + --> $DIR/issue-65436-raw-ptr-not-send.rs:14:9 + | +LL | bar(Foo(std::ptr::null())).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...but, `std::ptr::null()` is later dropped here + --> $DIR/issue-65436-raw-ptr-not-send.rs:14:41 + | +LL | bar(Foo(std::ptr::null())).await; + | ^ help: consider moving this into a `let` binding to create a shorter lived borrow --> $DIR/issue-65436-raw-ptr-not-send.rs:14:13 |