Skip to content
5 changes: 2 additions & 3 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1669,7 +1669,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let output = match coro {
Some(coro) => {
let fn_def_id = self.local_def_id(fn_node_id);
self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind, fn_span)
self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind)
}
None => match &decl.output {
FnRetTy::Ty(ty) => {
Expand Down Expand Up @@ -1754,9 +1754,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn_def_id: LocalDefId,
coro: CoroutineKind,
fn_kind: FnDeclKind,
fn_span: Span,
) -> hir::FnRetTy<'hir> {
let span = self.lower_span(fn_span);
let span = self.lower_span(output.span());

let (opaque_ty_node_id, allowed_features) = match coro {
CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1881,12 +1881,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let ty::Dynamic(_, _) = trait_pred.self_ty().skip_binder().kind() else {
return false;
};
if let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. })
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. })
| Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(fn_sig, _), .. }) =
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
&& let hir::FnRetTy::Return(ty) = fn_sig.decl.output
&& let hir::TyKind::Path(qpath) = ty.kind
&& let hir::QPath::Resolved(None, path) = qpath
&& let Res::Def(DefKind::TyAlias, def_id) = path.res
{
// Do not suggest
// type T = dyn Trait;
// fn foo() -> impl T { .. }
err.span_note(self.tcx.def_span(def_id), "this type alias is unsized");
err.multipart_suggestion(
format!(
"consider boxing the return type, and wrapping all of the returned values in \
`Box::new`",
),
vec![
(ty.span.shrink_to_lo(), "Box<".to_string()),
(ty.span.shrink_to_hi(), ">".to_string()),
],
Applicability::MaybeIncorrect,
);
return false;
}

err.code(E0746);
err.primary_message("return type cannot be a trait object without pointer indirection");
err.children.clear();

let span = obligation.cause.span;
let mut span = obligation.cause.span;
if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id)
&& let parent = self.tcx.parent(obligation.cause.body_id.into())
&& let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent)
&& self.tcx.asyncness(parent).is_async()
&& let Some(parent) = parent.as_local()
&& let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. })
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. })
| Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(fn_sig, _), ..
}) = self.tcx.hir_node_by_def_id(parent)
{
// Do not suggest (#147894)
// async fn foo() -> dyn Display impl { .. }
// and
// async fn foo() -> dyn Display Box<dyn { .. }>
span = fn_sig.decl.output.span();
err.span(span);
}
let body = self.tcx.hir_body_owned_by(obligation.cause.body_id);

let mut visitor = ReturnsVisitor::default();
Expand Down
37 changes: 17 additions & 20 deletions src/tools/clippy/tests/ui/future_not_send.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: future cannot be sent between threads safely
--> tests/ui/future_not_send.rs:8:1
--> tests/ui/future_not_send.rs:8:62
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send`
| ^^^^ future returned by `private_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> tests/ui/future_not_send.rs:11:20
Expand All @@ -23,10 +23,10 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
= help: to override `-D warnings` add `#[allow(clippy::future_not_send)]`

error: future cannot be sent between threads safely
--> tests/ui/future_not_send.rs:14:1
--> tests/ui/future_not_send.rs:14:41
|
LL | pub async fn public_future(rc: Rc<[u8]>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send`
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> tests/ui/future_not_send.rs:17:20
Expand All @@ -39,10 +39,10 @@ LL | async { true }.await;
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`

error: future cannot be sent between threads safely
--> tests/ui/future_not_send.rs:24:1
--> tests/ui/future_not_send.rs:24:63
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send`
| ^^^^ future returned by `private_future2` is not `Send`
|
note: captured value is not `Send`
--> tests/ui/future_not_send.rs:24:26
Expand All @@ -58,10 +58,10 @@ LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`

error: future cannot be sent between threads safely
--> tests/ui/future_not_send.rs:30:1
--> tests/ui/future_not_send.rs:30:42
|
LL | pub async fn public_future2(rc: Rc<[u8]>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send`
| ^ future returned by `public_future2` is not `Send`
|
note: captured value is not `Send`
--> tests/ui/future_not_send.rs:30:29
Expand All @@ -71,10 +71,10 @@ LL | pub async fn public_future2(rc: Rc<[u8]>) {}
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`

error: future cannot be sent between threads safely
--> tests/ui/future_not_send.rs:42:5
--> tests/ui/future_not_send.rs:42:39
|
LL | async fn private_future(&self) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send`
| ^^^^^ future returned by `private_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> tests/ui/future_not_send.rs:45:24
Expand All @@ -87,10 +87,10 @@ LL | async { true }.await;
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`

error: future cannot be sent between threads safely
--> tests/ui/future_not_send.rs:49:5
--> tests/ui/future_not_send.rs:49:38
|
LL | pub async fn public_future(&self) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send`
| ^ future returned by `public_future` is not `Send`
|
note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
--> tests/ui/future_not_send.rs:49:32
Expand All @@ -100,13 +100,10 @@ LL | pub async fn public_future(&self) {
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`

error: future cannot be sent between threads safely
--> tests/ui/future_not_send.rs:61:1
--> tests/ui/future_not_send.rs:61:37
|
LL | / async fn generic_future<T>(t: T) -> T
LL | |
LL | | where
LL | | T: Send,
| |____________^ future returned by `generic_future` is not `Send`
LL | async fn generic_future<T>(t: T) -> T
| ^ future returned by `generic_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> tests/ui/future_not_send.rs:67:20
Expand All @@ -118,10 +115,10 @@ LL | async { true }.await;
= note: `T` doesn't implement `std::marker::Sync`

error: future cannot be sent between threads safely
--> tests/ui/future_not_send.rs:83:1
--> tests/ui/future_not_send.rs:83:51
|
LL | async fn generic_future_always_unsend<T>(_: Rc<T>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `generic_future_always_unsend` is not `Send`
| ^ future returned by `generic_future_always_unsend` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> tests/ui/future_not_send.rs:86:20
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/async-await-let-else.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ error[E0277]: `Rc<()>` cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:47:13
|
LL | async fn foo2(x: Option<bool>) {
| ------------------------------ within this `impl Future<Output = ()>`
| - within this `impl Future<Output = ()>`
...
LL | is_send(foo2(Some(true)));
| ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely
Expand Down
30 changes: 30 additions & 0 deletions tests/ui/async-await/async-fn/dyn-in-return-type.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//@ edition:2024
//@ run-rustfix

async fn f() -> Box<impl core::fmt::Debug> {
//~^ ERROR return type cannot be a trait object without pointer indirection
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
Box::new("")
}
trait T {
async fn f(&self) -> Box<impl core::fmt::Debug> {
//~^ ERROR return type cannot be a trait object without pointer indirection
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
Box::new("")
}
}
impl T for () {
async fn f(&self) -> Box<impl core::fmt::Debug> {
//~^ ERROR return type cannot be a trait object without pointer indirection
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
Box::new("")
}
}

fn main() {
let _ = f();
let _ = ().f();
}
30 changes: 30 additions & 0 deletions tests/ui/async-await/async-fn/dyn-in-return-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//@ edition:2024
//@ run-rustfix

async fn f() -> dyn core::fmt::Debug {
//~^ ERROR return type cannot be a trait object without pointer indirection
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
Box::new("")
}
trait T {
async fn f(&self) -> dyn core::fmt::Debug {
//~^ ERROR return type cannot be a trait object without pointer indirection
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
Box::new("")
}
}
impl T for () {
async fn f(&self) -> dyn core::fmt::Debug {
//~^ ERROR return type cannot be a trait object without pointer indirection
//~| HELP consider returning an `impl Trait` instead of a `dyn Trait`
//~| HELP alternatively, box the return type, and wrap all of the returned values in `Box::new`
Box::new("")
}
}

fn main() {
let _ = f();
let _ = ().f();
}
51 changes: 51 additions & 0 deletions tests/ui/async-await/async-fn/dyn-in-return-type.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
error[E0746]: return type cannot be a trait object without pointer indirection
--> $DIR/dyn-in-return-type.rs:4:17
|
LL | async fn f() -> dyn core::fmt::Debug {
| ^^^^^^^^^^^^^^^^^^^^
|
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL - async fn f() -> dyn core::fmt::Debug {
LL + async fn f() -> impl core::fmt::Debug {
|
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | async fn f() -> Box<dyn core::fmt::Debug> {
| ++++ +

error[E0746]: return type cannot be a trait object without pointer indirection
--> $DIR/dyn-in-return-type.rs:11:26
|
LL | async fn f(&self) -> dyn core::fmt::Debug {
| ^^^^^^^^^^^^^^^^^^^^
|
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL - async fn f(&self) -> dyn core::fmt::Debug {
LL + async fn f(&self) -> impl core::fmt::Debug {
|
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | async fn f(&self) -> Box<dyn core::fmt::Debug> {
| ++++ +

error[E0746]: return type cannot be a trait object without pointer indirection
--> $DIR/dyn-in-return-type.rs:19:26
|
LL | async fn f(&self) -> dyn core::fmt::Debug {
| ^^^^^^^^^^^^^^^^^^^^
|
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL - async fn f(&self) -> dyn core::fmt::Debug {
LL + async fn f(&self) -> impl core::fmt::Debug {
|
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | async fn f(&self) -> Box<dyn core::fmt::Debug> {
| ++++ +

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0746`.
4 changes: 2 additions & 2 deletions tests/ui/async-await/async-fn/recurse-ice-129215.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ LL | a()
= help: the trait `Future` is not implemented for `()`

error[E0277]: `()` is not a future
--> $DIR/recurse-ice-129215.rs:3:1
--> $DIR/recurse-ice-129215.rs:3:13
|
LL | async fn a() {
| ^^^^^^^^^^^^ `()` is not a future
| ^ `()` is not a future
|
= help: the trait `Future` is not implemented for `()`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/async-example-desugared-boxed-in-trait.rs:11:5
--> $DIR/async-example-desugared-boxed-in-trait.rs:11:28
|
LL | async fn foo(&self) -> i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
| ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
|
note: type in trait
--> $DIR/async-example-desugared-boxed-in-trait.rs:7:22
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ warning: impl trait in impl method signature does not match trait method signatu
--> $DIR/async-example-desugared-boxed.rs:14:22
|
LL | async fn foo(&self) -> i32;
| --------------------------- return type from trait method defined here
| --- return type from trait method defined here
...
LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ warning: impl trait in impl method signature does not match trait method signatu
--> $DIR/async-example-desugared-manual.rs:22:22
|
LL | async fn foo(&self) -> i32;
| --------------------------- return type from trait method defined here
| --- return type from trait method defined here
...
LL | fn foo(&self) -> MyFuture {
| ^^^^^^^^
Expand Down
18 changes: 8 additions & 10 deletions tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
error[E0311]: the parameter type `T` may not live long enough
--> $DIR/async-generics-and-bounds.rs:8:5
--> $DIR/async-generics-and-bounds.rs:8:28
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
| ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | the parameter type `T` must be valid for the anonymous lifetime as defined here...
| ...so that the reference type `&(T, U)` does not outlive the data it points at
| - ^^^^^^^ ...so that the reference type `&(T, U)` does not outlive the data it points at
| |
| the parameter type `T` must be valid for the anonymous lifetime as defined here...
|
help: consider adding an explicit lifetime bound
|
LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, T: 'a;
| ++++ ++ ++ +++++++

error[E0311]: the parameter type `U` may not live long enough
--> $DIR/async-generics-and-bounds.rs:8:5
--> $DIR/async-generics-and-bounds.rs:8:28
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
| ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | the parameter type `U` must be valid for the anonymous lifetime as defined here...
| ...so that the reference type `&(T, U)` does not outlive the data it points at
| - ^^^^^^^ ...so that the reference type `&(T, U)` does not outlive the data it points at
| |
| the parameter type `U` must be valid for the anonymous lifetime as defined here...
|
help: consider adding an explicit lifetime bound
|
Expand Down
Loading
Loading