Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions tests-build/tests/fail/macros_join.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use tests_build::tokio;

#[tokio::main]
async fn main() {
// do not leak `RotatorSelect`
let _ = tokio::join!(async {
fn foo(_: impl RotatorSelect) {}
});

// do not leak `std::task::Poll::Pending`
let _ = tokio::join!(async { Pending });

// do not leak `std::task::Poll::Ready`
let _ = tokio::join!(async { Ready(0) });

// do not leak `std::future::Future`
let _ = tokio::join!(async {
struct MyFuture;

impl Future for MyFuture {
type Output = ();

fn poll(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
todo!()
}
}
});

// do not leak `std::pin::Pin`
let _ = tokio::join!(async {
let mut x = 5;
let _ = Pin::new(&mut x);
});

// do not leak `std::future::poll_fn`
let _ = tokio::join!(async {
let _ = poll_fn(|_cx| todo!());
});
}
60 changes: 60 additions & 0 deletions tests-build/tests/fail/macros_join.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
error[E0405]: cannot find trait `RotatorSelect` in this scope
--> tests/fail/macros_join.rs:7:24
|
7 | fn foo(_: impl RotatorSelect) {}
| ^^^^^^^^^^^^^ not found in this scope

error[E0425]: cannot find value `Pending` in this scope
--> tests/fail/macros_join.rs:11:34
|
11 | let _ = tokio::join!(async { Pending });
| ^^^^^^^ not found in this scope
|
help: consider importing this unit variant
|
1 + use std::task::Poll::Pending;
|

error[E0425]: cannot find function, tuple struct or tuple variant `Ready` in this scope
--> tests/fail/macros_join.rs:14:34
|
14 | let _ = tokio::join!(async { Ready(0) });
| ^^^^^ not found in this scope
|
help: consider importing this tuple variant
|
1 + use std::task::Poll::Ready;
|

error[E0405]: cannot find trait `Future` in this scope
--> tests/fail/macros_join.rs:20:14
|
20 | impl Future for MyFuture {
| ^^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use std::future::Future;
|

error[E0433]: failed to resolve: use of undeclared type `Pin`
--> tests/fail/macros_join.rs:35:17
|
35 | let _ = Pin::new(&mut x);
| ^^^ use of undeclared type `Pin`
|
help: consider importing this struct
|
1 + use std::pin::Pin;
|

error[E0425]: cannot find function `poll_fn` in this scope
--> tests/fail/macros_join.rs:40:17
|
40 | let _ = poll_fn(|_cx| todo!());
| ^^^^^^^ not found in this scope
|
help: consider importing this function
|
1 + use std::future::poll_fn;
|
42 changes: 42 additions & 0 deletions tests-build/tests/fail/macros_try_join.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use tests_build::tokio;

#[tokio::main]
async fn main() {
// do not leak `RotatorSelect`
let _ = tokio::try_join!(async {
fn foo(_: impl RotatorSelect) {}
});

// do not leak `std::task::Poll::Pending`
let _ = tokio::try_join!(async { Pending });

// do not leak `std::task::Poll::Ready`
let _ = tokio::try_join!(async { Ready(0) });

// do not leak `std::future::Future`
let _ = tokio::try_join!(async {
struct MyFuture;

impl Future for MyFuture {
type Output = ();

fn poll(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
todo!()
}
}
});

// do not leak `std::pin::Pin`
let _ = tokio::try_join!(async {
let mut x = 5;
let _ = Pin::new(&mut x);
});

// do not leak `std::future::poll_fn`
let _ = tokio::try_join!(async {
let _ = poll_fn(|_cx| todo!());
});
}
60 changes: 60 additions & 0 deletions tests-build/tests/fail/macros_try_join.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
error[E0405]: cannot find trait `RotatorSelect` in this scope
--> tests/fail/macros_try_join.rs:7:24
|
7 | fn foo(_: impl RotatorSelect) {}
| ^^^^^^^^^^^^^ not found in this scope

error[E0425]: cannot find value `Pending` in this scope
--> tests/fail/macros_try_join.rs:11:38
|
11 | let _ = tokio::try_join!(async { Pending });
| ^^^^^^^ not found in this scope
|
help: consider importing this unit variant
|
1 + use std::task::Poll::Pending;
|

error[E0425]: cannot find function, tuple struct or tuple variant `Ready` in this scope
--> tests/fail/macros_try_join.rs:14:38
|
14 | let _ = tokio::try_join!(async { Ready(0) });
| ^^^^^ not found in this scope
|
help: consider importing this tuple variant
|
1 + use std::task::Poll::Ready;
|

error[E0405]: cannot find trait `Future` in this scope
--> tests/fail/macros_try_join.rs:20:14
|
20 | impl Future for MyFuture {
| ^^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use std::future::Future;
|

error[E0433]: failed to resolve: use of undeclared type `Pin`
--> tests/fail/macros_try_join.rs:35:17
|
35 | let _ = Pin::new(&mut x);
| ^^^ use of undeclared type `Pin`
|
help: consider importing this struct
|
1 + use std::pin::Pin;
|

error[E0425]: cannot find function `poll_fn` in this scope
--> tests/fail/macros_try_join.rs:40:17
|
40 | let _ = poll_fn(|_cx| todo!());
| ^^^^^^^ not found in this scope
|
help: consider importing this function
|
1 + use std::future::poll_fn;
|
6 changes: 6 additions & 0 deletions tests-build/tests/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ fn compile_fail_full() {
#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_dead_code.rs");

#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_join.rs");

#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_try_join.rs");

#[cfg(feature = "full")]
t.compile_fail("tests/fail/macros_type_mismatch.rs");

Expand Down
19 changes: 8 additions & 11 deletions tokio/src/macros/join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,13 @@ doc! {macro_rules! join {
$( ( $($skip:tt)* ) $e:expr, )*

}) => {{
use $crate::macros::support::{maybe_done, poll_fn, Future, Pin, RotatorSelect};
use $crate::macros::support::Poll::{Ready, Pending};

// Safety: nothing must be moved out of `futures`. This is to satisfy
// the requirement of `Pin::new_unchecked` called below.
//
// We can't use the `pin!` macro for this because `futures` is a tuple
// and the standard library provides no way to pin-project to the fields
// of a tuple.
let mut futures = ( $( maybe_done($e), )* );
let mut futures = ( $( $crate::macros::support::maybe_done($e), )* );

// This assignment makes sure that the `poll_fn` closure only has a
// reference to the futures, instead of taking ownership of them. This
Expand All @@ -149,9 +146,9 @@ doc! {macro_rules! join {
// Each time the future created by poll_fn is polled, if not using biased mode,
// a different future is polled first to ensure every future passed to join!
// can make progress even if one of the futures consumes the whole budget.
let mut rotator = <$rotator_select as RotatorSelect>::Rotator::<{$($total)*}>::default();
let mut rotator = <$rotator_select as $crate::macros::support::RotatorSelect>::Rotator::<{$($total)*}>::default();

poll_fn(move |cx| {
$crate::macros::support::poll_fn(move |cx| {
const COUNT: u32 = $($total)*;

let mut is_pending = false;
Expand All @@ -176,10 +173,10 @@ doc! {macro_rules! join {

// Safety: future is stored on the stack above
// and never moved.
let mut fut = unsafe { Pin::new_unchecked(fut) };
let mut fut = unsafe { $crate::macros::support::Pin::new_unchecked(fut) };

// Try polling
if fut.poll(cx).is_pending() {
if $crate::macros::support::Future::poll(fut.as_mut(), cx).is_pending() {
is_pending = true;
}
} else {
Expand All @@ -190,15 +187,15 @@ doc! {macro_rules! join {
}

if is_pending {
Pending
$crate::macros::support::Poll::Pending
} else {
Ready(($({
$crate::macros::support::Poll::Ready(($({
// Extract the future for this branch from the tuple.
let ( $($skip,)* fut, .. ) = &mut futures;

// Safety: future is stored on the stack above
// and never moved.
let mut fut = unsafe { Pin::new_unchecked(fut) };
let mut fut = unsafe { $crate::macros::support::Pin::new_unchecked(fut) };

fut.take_output().expect("expected completed future")
},)*))
Expand Down
21 changes: 9 additions & 12 deletions tokio/src/macros/try_join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,16 +179,13 @@ doc! {macro_rules! try_join {
$( ( $($skip:tt)* ) $e:expr, )*

}) => {{
use $crate::macros::support::{maybe_done, poll_fn, Future, Pin, RotatorSelect};
use $crate::macros::support::Poll::{Ready, Pending};

// Safety: nothing must be moved out of `futures`. This is to satisfy
// the requirement of `Pin::new_unchecked` called below.
//
// We can't use the `pin!` macro for this because `futures` is a tuple
// and the standard library provides no way to pin-project to the fields
// of a tuple.
let mut futures = ( $( maybe_done($e), )* );
let mut futures = ( $( $crate::macros::support::maybe_done($e), )* );

// This assignment makes sure that the `poll_fn` closure only has a
// reference to the futures, instead of taking ownership of them. This
Expand All @@ -199,9 +196,9 @@ doc! {macro_rules! try_join {
// Each time the future created by poll_fn is polled, if not using biased mode,
// a different future is polled first to ensure every future passed to try_join!
// can make progress even if one of the futures consumes the whole budget.
let mut rotator = <$rotator_select as RotatorSelect>::Rotator::<{$($total)*}>::default();
let mut rotator = <$rotator_select as $crate::macros::support::RotatorSelect>::Rotator::<{$($total)*}>::default();

poll_fn(move |cx| {
$crate::macros::support::poll_fn(move |cx| {
const COUNT: u32 = $($total)*;

let mut is_pending = false;
Expand All @@ -226,13 +223,13 @@ doc! {macro_rules! try_join {

// Safety: future is stored on the stack above
// and never moved.
let mut fut = unsafe { Pin::new_unchecked(fut) };
let mut fut = unsafe { $crate::macros::support::Pin::new_unchecked(fut) };

// Try polling
if fut.as_mut().poll(cx).is_pending() {
if $crate::macros::support::Future::poll(fut.as_mut(), cx).is_pending() {
is_pending = true;
} else if fut.as_mut().output_mut().expect("expected completed future").is_err() {
return Ready(Err(fut.take_output().expect("expected completed future").err().unwrap()))
return $crate::macros::support::Poll::Ready(Err(fut.take_output().expect("expected completed future").err().unwrap()))
}
} else {
// Future skipped, one less future to skip in the next iteration
Expand All @@ -242,15 +239,15 @@ doc! {macro_rules! try_join {
}

if is_pending {
Pending
$crate::macros::support::Poll::Pending
} else {
Ready(Ok(($({
$crate::macros::support::Poll::Ready(Ok(($({
// Extract the future for this branch from the tuple.
let ( $($skip,)* fut, .. ) = &mut futures;

// Safety: future is stored on the stack above
// and never moved.
let mut fut = unsafe { Pin::new_unchecked(fut) };
let mut fut = unsafe { $crate::macros::support::Pin::new_unchecked(fut) };

fut
.take_output()
Expand Down