diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/async-await | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
305 files changed, 9809 insertions, 0 deletions
diff --git a/src/test/ui/async-await/argument-patterns.rs b/src/test/ui/async-await/argument-patterns.rs new file mode 100644 index 000000000..b9fc1a88c --- /dev/null +++ b/src/test/ui/async-await/argument-patterns.rs @@ -0,0 +1,28 @@ +// edition:2018 +// check-pass + +#![deny(unused_mut)] + +type A = Vec<u32>; + +async fn a(n: u32, mut vec: A) { + vec.push(n); +} + +async fn b(n: u32, ref mut vec: A) { + vec.push(n); +} + +async fn c(ref vec: A) { + vec.contains(&0); +} + +async fn d((a, mut b): (A, A)) { + b.push(1); +} + +async fn f((ref mut a, ref b): (A, A)) {} + +async fn g(((ref a, ref mut b), (ref mut c, ref d)): ((A, A), (A, A))) {} + +fn main() {} diff --git a/src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs b/src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs new file mode 100644 index 000000000..8e08b82b9 --- /dev/null +++ b/src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs @@ -0,0 +1,23 @@ +// check-pass +// Check that the anonymous lifetimes used here aren't considered to shadow one +// another. Note that `async fn` is different to `fn` here because the lifetimes +// are numbered by HIR lowering, rather than lifetime resolution. + +// edition:2018 + +struct A<'a, 'b>(&'a &'b i32); +struct B<'a>(&'a i32); + +impl A<'_, '_> { + async fn assoc(x: &u32, y: B<'_>) { + async fn nested(x: &u32, y: A<'_, '_>) {} + } + + async fn assoc2(x: &u32, y: A<'_, '_>) { + impl A<'_, '_> { + async fn nested_assoc(x: &u32, y: B<'_>) {} + } + } +} + +fn main() {} diff --git a/src/test/ui/async-await/async-await-let-else.rs b/src/test/ui/async-await/async-await-let-else.rs new file mode 100644 index 000000000..7ea07ae9a --- /dev/null +++ b/src/test/ui/async-await/async-await-let-else.rs @@ -0,0 +1,53 @@ +// edition:2021 +#![feature(let_else)] +use std::rc::Rc; + +async fn foo(x: Option<bool>) { + let Some(_) = x else { + let r = Rc::new(()); + bar().await + }; +} + +async fn bar() -> ! { + panic!() +} + +fn is_send<T: Send>(_: T) {} + +async fn foo2(x: Option<bool>) { + let Some(_) = x else { + bar2(Rc::new(())).await + }; +} + +async fn bar2<T>(_: T) -> ! { + panic!() +} + +async fn foo3(x: Option<bool>) { + let Some(_) = x else { + (Rc::new(()), bar().await); + return; + }; +} + +async fn foo4(x: Option<bool>) { + let Some(_) = x else { + let r = Rc::new(()); + bar().await; + println!("{:?}", r); + return; + }; +} + +fn main() { + is_send(foo(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo2(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo3(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo4(Some(true))); + //~^ ERROR future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/async-await-let-else.stderr b/src/test/ui/async-await/async-await-let-else.stderr new file mode 100644 index 000000000..4d23e27c4 --- /dev/null +++ b/src/test/ui/async-await/async-await-let-else.stderr @@ -0,0 +1,94 @@ +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:45:13 + | +LL | is_send(foo(Some(true))); + | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:8:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await + | ^^^^^^ await occurs here, with `r` maybe used later +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:47:13 + | +LL | is_send(foo2(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:20:26 + | +LL | bar2(Rc::new(())).await + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +LL | }; + | - `Rc::new(())` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:49:13 + | +LL | is_send(foo3(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:30:28 + | +LL | (Rc::new(()), bar().await); + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +note: `Rc::new(())` is later dropped here + --> $DIR/async-await-let-else.rs:30:35 + | +LL | (Rc::new(()), bar().await); + | ^ +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:51:13 + | +LL | is_send(foo4(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:38:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await; + | ^^^^^^ await occurs here, with `r` maybe used later +... +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs new file mode 100644 index 000000000..9cabf16f8 --- /dev/null +++ b/src/test/ui/async-await/async-await.rs @@ -0,0 +1,219 @@ +// run-pass + +// revisions: default nomiropt thirunsafeck +//[nomiropt]compile-flags: -Z mir-opt-level=0 +//[thirunsafeck]compile-flags: -Zthir-unsafeck + +#![allow(unused)] + +// edition: 2018 +// aux-build:arc_wake.rs + +extern crate arc_wake; + +use std::pin::Pin; +use std::future::Future; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{Context, Poll}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc<Self>) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct WakeOnceThenComplete(bool); + +fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } + +impl Future for WakeOnceThenComplete { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if self.0 { + Poll::Ready(()) + } else { + cx.waker().wake_by_ref(); + self.0 = true; + Poll::Pending + } + } +} + +fn async_block(x: u8) -> impl Future<Output = u8> { + async move { + wake_and_yield_once().await; + x + } +} + +fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a { + async move { + wake_and_yield_once().await; + *x + } +} + +fn async_nonmove_block(x: u8) -> impl Future<Output = u8> { + async move { + let future = async { + wake_and_yield_once().await; + x + }; + future.await + } +} + +// see async-closure.rs for async_closure + async_closure_in_unsafe_block + +async fn async_fn(x: u8) -> u8 { + wake_and_yield_once().await; + x +} + +async fn generic_async_fn<T>(x: T) -> T { + wake_and_yield_once().await; + x +} + +async fn async_fn_with_borrow(x: &u8) -> u8 { + wake_and_yield_once().await; + *x +} + +async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 { + wake_and_yield_once().await; + *x +} + +fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a { + async move { + wake_and_yield_once().await; + *x + } +} + +async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 { + wake_and_yield_once().await; + *x +} + +async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 { + wake_and_yield_once().await; + *x +} + +fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> { + async move { + async_fn_with_borrow_named_lifetime(&y).await + } +} + +async unsafe fn unsafe_async_fn(x: u8) -> u8 { + wake_and_yield_once().await; + x +} + +unsafe fn unsafe_fn(x: u8) -> u8 { + x +} + +fn async_block_in_unsafe_block(x: u8) -> impl Future<Output = u8> { + unsafe { + async move { + unsafe_fn(unsafe_async_fn(x).await) + } + } +} + +struct Foo; + +trait Bar { + fn foo() {} +} + +impl Foo { + async fn async_assoc_item(x: u8) -> u8 { + unsafe { + unsafe_async_fn(x).await + } + } + + async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 { + unsafe_async_fn(x).await + } +} + +fn test_future_yields_once_then_returns<F, Fut>(f: F) +where + F: FnOnce(u8) -> Fut, + Fut: Future<Output = u8>, +{ + let mut fut = Box::pin(f(9)); + let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); + let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); + assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx)); + assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx)); +} + +fn main() { + macro_rules! test { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns($fn_name); + )* } + } + + macro_rules! test_with_borrow { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns(|x| { + async move { + $fn_name(&x).await + } + }); + )* } + } + + test! { + async_block, + async_nonmove_block, + async_fn, + generic_async_fn, + async_fn_with_internal_borrow, + async_block_in_unsafe_block, + Foo::async_assoc_item, + |x| { + async move { + unsafe { unsafe_async_fn(x).await } + } + }, + |x| { + async move { + unsafe { Foo::async_unsafe_assoc_item(x).await } + } + }, + } + test_with_borrow! { + async_block_with_borrow_named_lifetime, + async_fn_with_borrow, + async_fn_with_borrow_named_lifetime, + async_fn_with_impl_future_named_lifetime, + |x| { + async move { + async_fn_multiple_args_named_lifetime(x, x).await + } + }, + } +} diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs new file mode 100644 index 000000000..b831d6102 --- /dev/null +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -0,0 +1,63 @@ +// Test that `async { .. }` blocks: +// 1. do not allow `break` expressions. +// 2. get targeted by `return` and not the parent function. +// 3. get targeted by `?` and not the parent function. +// +// edition:2018 + +fn main() {} + +use core::future::Future; + +fn return_targets_async_block_not_fn() -> u8 { + //~^ ERROR mismatched types + let block = async { + return 0u8; + }; + let _: &dyn Future<Output = ()> = █ + //~^ ERROR type mismatch +} + +async fn return_targets_async_block_not_async_fn() -> u8 { + //~^ ERROR mismatched types [E0308] + let block = async { + return 0u8; + }; + let _: &dyn Future<Output = ()> = █ + //~^ ERROR type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` +} + +fn no_break_in_async_block() { + async { + break 0u8; //~ ERROR `break` inside of an `async` block + }; +} + +fn no_break_in_async_block_even_with_outer_loop() { + loop { + async { + break 0u8; //~ ERROR `break` inside of an `async` block + }; + } +} + +struct MyErr; +fn err() -> Result<u8, MyErr> { Err(MyErr) } + +fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> { + //~^ ERROR mismatched types + let block = async { + err()?; + Ok(()) + }; + let _: &dyn Future<Output = Result<(), MyErr>> = █ +} + +fn rethrow_targets_async_block_not_async_fn() -> Result<u8, MyErr> { + //~^ ERROR mismatched types + let block = async { + err()?; + Ok(()) + }; + let _: &dyn Future<Output = Result<(), MyErr>> = █ +} diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr new file mode 100644 index 000000000..e58876896 --- /dev/null +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -0,0 +1,83 @@ +error[E0267]: `break` inside of an `async` block + --> $DIR/async-block-control-flow-static-semantics.rs:32:9 + | +LL | async { + | ___________- +LL | | break 0u8; + | | ^^^^^^^^^ cannot `break` inside of an `async` block +LL | | }; + | |_____- enclosing `async` block + +error[E0267]: `break` inside of an `async` block + --> $DIR/async-block-control-flow-static-semantics.rs:39:13 + | +LL | async { + | _______________- +LL | | break 0u8; + | | ^^^^^^^^^ cannot `break` inside of an `async` block +LL | | }; + | |_________- enclosing `async` block + +error[E0308]: mismatched types + --> $DIR/async-block-control-flow-static-semantics.rs:21:58 + | +LL | async fn return_targets_async_block_not_async_fn() -> u8 { + | __________________________________________________________^ +LL | | +LL | | let block = async { +LL | | return 0u8; +... | +LL | | +LL | | } + | |_^ expected `u8`, found `()` + +error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:26:39 + | +LL | let _: &dyn Future<Output = ()> = █ + | ^^^^^^ expected `()`, found `u8` + | + = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>` + +error[E0308]: mismatched types + --> $DIR/async-block-control-flow-static-semantics.rs:12:43 + | +LL | fn return_targets_async_block_not_fn() -> u8 { + | --------------------------------- ^^ expected `u8`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:17:39 + | +LL | let _: &dyn Future<Output = ()> = █ + | ^^^^^^ expected `()`, found `u8` + | + = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>` + +error[E0308]: mismatched types + --> $DIR/async-block-control-flow-static-semantics.rs:47:44 + | +LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> { + | ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected enum `Result<u8, MyErr>` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/async-block-control-flow-static-semantics.rs:56:50 + | +LL | fn rethrow_targets_async_block_not_async_fn() -> Result<u8, MyErr> { + | ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected enum `Result<u8, MyErr>` + found unit type `()` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0267, E0271, E0308. +For more information about an error, try `rustc --explain E0267`. diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.fixed b/src/test/ui/async-await/async-borrowck-escaping-block-error.fixed new file mode 100644 index 000000000..605cfdfe7 --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.fixed @@ -0,0 +1,18 @@ +// edition:2018 +// run-rustfix + +fn test_boxed() -> Box<impl std::future::Future<Output = u32>> { + let x = 0u32; + Box::new(async move { x } ) + //~^ ERROR E0373 +} + +fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ { + async move { *x } + //~^ ERROR E0373 +} + +fn main() { + let _ = test_boxed(); + let _ = test_ref(&0u32); +} diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.rs b/src/test/ui/async-await/async-borrowck-escaping-block-error.rs new file mode 100644 index 000000000..ec752c15f --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.rs @@ -0,0 +1,18 @@ +// edition:2018 +// run-rustfix + +fn test_boxed() -> Box<impl std::future::Future<Output = u32>> { + let x = 0u32; + Box::new(async { x } ) + //~^ ERROR E0373 +} + +fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ { + async { *x } + //~^ ERROR E0373 +} + +fn main() { + let _ = test_boxed(); + let _ = test_ref(&0u32); +} diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr new file mode 100644 index 000000000..f21c81151 --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr @@ -0,0 +1,41 @@ +error[E0373]: async block may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-borrowck-escaping-block-error.rs:6:20 + | +LL | Box::new(async { x } ) + | ^^-^^ + | | | + | | `x` is borrowed here + | may outlive borrowed value `x` + | +note: async block is returned here + --> $DIR/async-borrowck-escaping-block-error.rs:6:5 + | +LL | Box::new(async { x } ) + | ^^^^^^^^^^^^^^^^^^^^^^ +help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | Box::new(async move { x } ) + | ++++ + +error[E0373]: async block may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-borrowck-escaping-block-error.rs:11:11 + | +LL | async { *x } + | ^^--^^ + | | | + | | `x` is borrowed here + | may outlive borrowed value `x` + | +note: async block is returned here + --> $DIR/async-borrowck-escaping-block-error.rs:11:5 + | +LL | async { *x } + | ^^^^^^^^^^^^ +help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | async move { *x } + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/async-await/async-borrowck-escaping-closure-error.rs b/src/test/ui/async-await/async-borrowck-escaping-closure-error.rs new file mode 100644 index 000000000..e667b72ae --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-closure-error.rs @@ -0,0 +1,10 @@ +// edition:2018 +#![feature(async_closure)] +fn foo() -> Box<dyn std::future::Future<Output = u32>> { + let x = 0u32; + Box::new((async || x)()) + //~^ ERROR E0373 +} + +fn main() { +} diff --git a/src/test/ui/async-await/async-borrowck-escaping-closure-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-closure-error.stderr new file mode 100644 index 000000000..10691aad0 --- /dev/null +++ b/src/test/ui/async-await/async-borrowck-escaping-closure-error.stderr @@ -0,0 +1,21 @@ +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/async-borrowck-escaping-closure-error.rs:5:15 + | +LL | Box::new((async || x)()) + | ^^^^^^^^ - `x` is borrowed here + | | + | may outlive borrowed value `x` + | +note: closure is returned here + --> $DIR/async-borrowck-escaping-closure-error.rs:5:5 + | +LL | Box::new((async || x)()) + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | Box::new((async move || x)()) + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/async-await/async-closure-matches-expr.rs b/src/test/ui/async-await/async-closure-matches-expr.rs new file mode 100644 index 000000000..d82fbcdc5 --- /dev/null +++ b/src/test/ui/async-await/async-closure-matches-expr.rs @@ -0,0 +1,12 @@ +// build-pass +// edition:2018 + +#![feature(async_closure)] + +macro_rules! match_expr { + ($x:expr) => {} +} + +fn main() { + match_expr!(async || {}); +} diff --git a/src/test/ui/async-await/async-closure.rs b/src/test/ui/async-await/async-closure.rs new file mode 100644 index 000000000..12d66b19e --- /dev/null +++ b/src/test/ui/async-await/async-closure.rs @@ -0,0 +1,100 @@ +// run-pass + +// revisions: default nomiropt +//[nomiropt]compile-flags: -Z mir-opt-level=0 + +// edition:2018 +// aux-build:arc_wake.rs + +#![feature(async_closure)] + +extern crate arc_wake; + +use std::pin::Pin; +use std::future::Future; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{Context, Poll}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc<Self>) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct WakeOnceThenComplete(bool); + +fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } + +impl Future for WakeOnceThenComplete { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if self.0 { + Poll::Ready(()) + } else { + cx.waker().wake_by_ref(); + self.0 = true; + Poll::Pending + } + } +} + +fn async_closure(x: u8) -> impl Future<Output = u8> { + (async move |x: u8| -> u8 { + wake_and_yield_once().await; + x + })(x) +} + +fn async_closure_in_unsafe_block(x: u8) -> impl Future<Output = u8> { + (unsafe { + async move |x: u8| unsafe_fn(unsafe_async_fn(x).await) + })(x) +} + +async unsafe fn unsafe_async_fn(x: u8) -> u8 { + wake_and_yield_once().await; + x +} + +unsafe fn unsafe_fn(x: u8) -> u8 { + x +} + +fn test_future_yields_once_then_returns<F, Fut>(f: F) +where + F: FnOnce(u8) -> Fut, + Fut: Future<Output = u8>, +{ + let mut fut = Box::pin(f(9)); + let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); + let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); + assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx)); + assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx)); +} + +fn main() { + macro_rules! test { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns($fn_name); + )* } + } + + test! { + async_closure, + async_closure_in_unsafe_block, + } +} diff --git a/src/test/ui/async-await/async-error-span.rs b/src/test/ui/async-await/async-error-span.rs new file mode 100644 index 000000000..86d459bf0 --- /dev/null +++ b/src/test/ui/async-await/async-error-span.rs @@ -0,0 +1,17 @@ +// edition:2018 + +// Regression test for issue #62382. + +use std::future::Future; + +fn get_future() -> impl Future<Output = ()> { +//~^ ERROR `()` is not a future + panic!() +} + +async fn foo() { + let a; //~ ERROR type inside `async fn` body must be known in this context + get_future().await; +} + +fn main() {} diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr new file mode 100644 index 000000000..7d4447b6d --- /dev/null +++ b/src/test/ui/async-await/async-error-span.stderr @@ -0,0 +1,25 @@ +error[E0277]: `()` is not a future + --> $DIR/async-error-span.rs:7:20 + | +LL | fn get_future() -> impl Future<Output = ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/async-error-span.rs:13:9 + | +LL | let a; + | ^ cannot infer type + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/async-error-span.rs:14:17 + | +LL | get_future().await; + | ^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0698. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/async-fn-elided-impl-lifetime-parameter.rs b/src/test/ui/async-await/async-fn-elided-impl-lifetime-parameter.rs new file mode 100644 index 000000000..1c369fd74 --- /dev/null +++ b/src/test/ui/async-await/async-fn-elided-impl-lifetime-parameter.rs @@ -0,0 +1,15 @@ +// Check that `async fn` inside of an impl with `'_` +// in the header compiles correctly. +// +// Regression test for #63500. +// +// check-pass +// edition:2018 + +struct Foo<'a>(&'a u8); + +impl Foo<'_> { + async fn bar() {} +} + +fn main() { } diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs new file mode 100644 index 000000000..d7f8d7ac5 --- /dev/null +++ b/src/test/ui/async-await/async-fn-nonsend.rs @@ -0,0 +1,74 @@ +// edition:2018 +// compile-flags: --crate-type lib -Zdrop-tracking + +use std::{cell::RefCell, fmt::Debug, rc::Rc}; + +fn non_sync() -> impl Debug { + RefCell::new(()) +} + +fn non_send() -> impl Debug { + Rc::new(()) +} + +fn take_ref<T>(_: &T) {} + +async fn fut() {} + +async fn fut_arg<T>(_: T) {} + +async fn local_dropped_before_await() { + // this is okay now because of the drop + let x = non_send(); + drop(x); + fut().await; +} + +async fn non_send_temporary_in_match() { + // We could theoretically make this work as well (produce a `Send` future) + // for scrutinees / temporaries that can or will + // be dropped prior to the match body + // (e.g. `Copy` types). + match Some(non_send()) { + Some(_) => fut().await, + None => {} + } +} + +fn get_formatter() -> std::fmt::Formatter<'static> { + panic!() +} + +async fn non_sync_with_method_call() { + let f: &mut std::fmt::Formatter = &mut get_formatter(); + // It would by nice for this to work. + if non_sync().fmt(f).unwrap() == () { + fut().await; + } +} + +async fn non_sync_with_method_call_panic() { + let f: &mut std::fmt::Formatter = panic!(); + if non_sync().fmt(f).unwrap() == () { + fut().await; + } +} + +async fn non_sync_with_method_call_infinite_loop() { + let f: &mut std::fmt::Formatter = loop {}; + if non_sync().fmt(f).unwrap() == () { + fut().await; + } +} + +fn assert_send(_: impl Send) {} + +pub fn pass_assert() { + assert_send(local_dropped_before_await()); + assert_send(non_send_temporary_in_match()); + //~^ ERROR future cannot be sent between threads safely + assert_send(non_sync_with_method_call()); + //~^ ERROR future cannot be sent between threads safely + assert_send(non_sync_with_method_call_panic()); + assert_send(non_sync_with_method_call_infinite_loop()); +} diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr new file mode 100644 index 000000000..40ad46b48 --- /dev/null +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -0,0 +1,49 @@ +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:68:17 + | +LL | assert_send(non_send_temporary_in_match()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:33:25 + | +LL | match Some(non_send()) { + | ---------------- has type `Option<impl Debug>` which is not `Send` +LL | Some(_) => fut().await, + | ^^^^^^ await occurs here, with `Some(non_send())` maybe used later +... +LL | } + | - `Some(non_send())` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:64:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:70:17 + | +LL | assert_send(non_sync_with_method_call()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` + | + = help: the trait `Send` is not implemented for `dyn std::fmt::Write` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:46:14 + | +LL | let f: &mut std::fmt::Formatter = &mut get_formatter(); + | --------------- has type `Formatter<'_>` which is not `Send` +... +LL | fut().await; + | ^^^^^^ await occurs here, with `get_formatter()` maybe used later +LL | } +LL | } + | - `get_formatter()` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:64:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/async-await/async-fn-path-elision.rs b/src/test/ui/async-await/async-fn-path-elision.rs new file mode 100644 index 000000000..3f1f51c20 --- /dev/null +++ b/src/test/ui/async-await/async-fn-path-elision.rs @@ -0,0 +1,13 @@ +// edition:2018 + +struct HasLifetime<'a>(&'a bool); + +async fn error(lt: HasLifetime) { //~ ERROR implicit elided lifetime not allowed here + if *lt.0 {} +} + +fn no_error(lt: HasLifetime) { + if *lt.0 {} +} + +fn main() {} diff --git a/src/test/ui/async-await/async-fn-path-elision.stderr b/src/test/ui/async-await/async-fn-path-elision.stderr new file mode 100644 index 000000000..5e0c8c299 --- /dev/null +++ b/src/test/ui/async-await/async-fn-path-elision.stderr @@ -0,0 +1,15 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/async-fn-path-elision.rs:5:20 + | +LL | async fn error(lt: HasLifetime) { + | ^^^^^^^^^^^ expected lifetime parameter + | + = note: assuming a `'static` lifetime... +help: indicate the anonymous lifetime + | +LL | async fn error(lt: HasLifetime<'_>) { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0726`. diff --git a/src/test/ui/async-await/async-fn-send-uses-nonsend.rs b/src/test/ui/async-await/async-fn-send-uses-nonsend.rs new file mode 100644 index 000000000..35d9cb155 --- /dev/null +++ b/src/test/ui/async-await/async-fn-send-uses-nonsend.rs @@ -0,0 +1,57 @@ +// build-pass (FIXME(62277): could be check-pass?) +// edition:2018 +// compile-flags: --crate-type lib + +use std::{ + cell::RefCell, + fmt::Debug, + rc::Rc, +}; + +fn non_sync() -> impl Debug { RefCell::new(()) } + +fn non_send() -> impl Debug { Rc::new(()) } + +fn take_ref<T>(_: &T) {} + +async fn fut() {} + +async fn fut_arg<T>(_: T) {} + +async fn still_send() { + fut().await; + println!("{:?} {:?}", non_send(), non_sync()); + fut().await; + drop(non_send()); + drop(non_sync()); + fut().await; + fut_arg(non_sync()).await; + + // Note: all temporaries in `if let` and `match` scrutinee + // are dropped at the *end* of the blocks, so using `non_send()` + // in either of those positions with an await in the middle will + // cause a `!Send` future. It might be nice in the future to allow + // this for `Copy` types, since they can be "dropped" early without + // affecting the end user. + if let Some(_) = Some(non_sync()) { + fut().await; + } + match Some(non_sync()) { + Some(_) => fut().await, + None => fut().await, + } + + let _ = non_send(); + fut().await; + + { + let _x = non_send(); + } + fut().await; +} + +fn assert_send(_: impl Send) {} + +pub fn pass_assert() { + assert_send(still_send()); +} diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs new file mode 100644 index 000000000..155662566 --- /dev/null +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -0,0 +1,118 @@ +// Test that we don't duplicate storage for futures moved around in .await, and +// for futures moved into other futures. +// +// The exact sizes can change by a few bytes (we'd like to know when they do). +// What we don't want to see is the wrong multiple of 1024 (the size of BigFut) +// being reflected in the size. +// +// See issue #59123 for a full explanation. + +// ignore-emscripten (sizes don't match) +// run-pass + +// edition:2018 + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +const BIG_FUT_SIZE: usize = 1024; +struct BigFut(#[allow(unused_tuple_struct_fields)] [u8; BIG_FUT_SIZE]); + +impl BigFut { + fn new() -> Self { + BigFut([0; BIG_FUT_SIZE]) + } +} + +impl Drop for BigFut { + fn drop(&mut self) {} +} + +impl Future for BigFut { + type Output = (); + + fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Ready(()) + } +} + +#[allow(dead_code)] +struct Joiner { + a: Option<BigFut>, + b: Option<BigFut>, + c: Option<BigFut>, +} + +impl Future for Joiner { + type Output = (); + + fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Ready(()) + } +} + +fn noop() {} + +async fn single() { + let x = BigFut::new(); + x.await; +} + +async fn single_with_noop() { + let x = BigFut::new(); + noop(); + x.await; +} + +async fn joined() { + let a = BigFut::new(); + let b = BigFut::new(); + let c = BigFut::new(); + + let joiner = Joiner { + a: Some(a), + b: Some(b), + c: Some(c), + }; + joiner.await +} + +async fn joined_with_noop() { + let a = BigFut::new(); + let b = BigFut::new(); + let c = BigFut::new(); + + let joiner = Joiner { + a: Some(a), + b: Some(b), + c: Some(c), + }; + noop(); + joiner.await +} + +async fn mixed_sizes() { + let a = BigFut::new(); + let b = BigFut::new(); + let c = BigFut::new(); + let d = BigFut::new(); + let e = BigFut::new(); + let joiner = Joiner { + a: Some(a), + b: Some(b), + c: Some(c), + }; + + d.await; + e.await; + joiner.await; +} + +fn main() { + assert_eq!(1025, std::mem::size_of_val(&single())); + assert_eq!(1026, std::mem::size_of_val(&single_with_noop())); + assert_eq!(3076, std::mem::size_of_val(&joined())); + assert_eq!(3076, std::mem::size_of_val(&joined_with_noop())); + assert_eq!(6157, std::mem::size_of_val(&mixed_sizes())); +} diff --git a/src/test/ui/async-await/async-fn-size-uninit-locals.rs b/src/test/ui/async-await/async-fn-size-uninit-locals.rs new file mode 100644 index 000000000..31a086ba9 --- /dev/null +++ b/src/test/ui/async-await/async-fn-size-uninit-locals.rs @@ -0,0 +1,103 @@ +// Test that we don't store uninitialized locals in futures from `async fn`. +// +// The exact sizes can change by a few bytes (we'd like to know when they do). +// What we don't want to see is the wrong multiple of 1024 (the size of `Big`) +// being reflected in the size. + +// ignore-emscripten (sizes don't match) +// run-pass + +// edition:2018 + +#![allow(unused_variables, unused_assignments)] + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +const BIG_FUT_SIZE: usize = 1024; +struct Big(#[allow(unused_tuple_struct_fields)] [u8; BIG_FUT_SIZE]); + +impl Big { + fn new() -> Self { + Big([0; BIG_FUT_SIZE]) + } +} + +impl Drop for Big { + fn drop(&mut self) {} +} + +#[allow(dead_code)] +struct Joiner { + a: Option<Big>, + b: Option<Big>, + c: Option<Big>, +} + +impl Future for Joiner { + type Output = (); + + fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Ready(()) + } +} + +fn noop() {} +async fn fut() {} + +async fn single() { + let x; + fut().await; + x = Big::new(); +} + +async fn single_with_noop() { + let x; + fut().await; + noop(); + x = Big::new(); + noop(); +} + +async fn joined() { + let joiner; + let a = Big::new(); + let b = Big::new(); + let c = Big::new(); + + fut().await; + noop(); + joiner = Joiner { a: Some(a), b: Some(b), c: Some(c) }; + noop(); +} + +async fn joined_with_noop() { + let joiner; + let a = Big::new(); + let b = Big::new(); + let c = Big::new(); + + fut().await; + noop(); + joiner = Joiner { a: Some(a), b: Some(b), c: Some(c) }; + noop(); +} + +async fn join_retval() -> Joiner { + let a = Big::new(); + let b = Big::new(); + let c = Big::new(); + + fut().await; + noop(); + Joiner { a: Some(a), b: Some(b), c: Some(c) } +} + +fn main() { + assert_eq!(2, std::mem::size_of_val(&single())); + assert_eq!(3, std::mem::size_of_val(&single_with_noop())); + assert_eq!(3078, std::mem::size_of_val(&joined())); + assert_eq!(3078, std::mem::size_of_val(&joined_with_noop())); + assert_eq!(3074, std::mem::size_of_val(&join_retval())); +} diff --git a/src/test/ui/async-await/async-fn-size.rs b/src/test/ui/async-await/async-fn-size.rs new file mode 100644 index 000000000..0c1f36364 --- /dev/null +++ b/src/test/ui/async-await/async-fn-size.rs @@ -0,0 +1,105 @@ +// run-pass +// aux-build:arc_wake.rs +// edition:2018 + +extern crate arc_wake; + +use std::pin::Pin; +use std::future::Future; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{Context, Poll}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc<Self>) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct WakeOnceThenComplete(bool, u8); + +impl Future for WakeOnceThenComplete { + type Output = u8; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<u8> { + if self.0 { + Poll::Ready(self.1) + } else { + cx.waker().wake_by_ref(); + self.0 = true; + Poll::Pending + } + } +} + +fn wait(fut: impl Future<Output = u8>) -> u8 { + let mut fut = Box::pin(fut); + let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); + let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); + loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(out) => return out, + Poll::Pending => (), + } + } +} + +fn base() -> WakeOnceThenComplete { WakeOnceThenComplete(false, 1) } + +async fn await1_level1() -> u8 { + base().await +} + +async fn await2_level1() -> u8 { + base().await + base().await +} + +async fn await3_level1() -> u8 { + base().await + base().await + base().await +} + +async fn await3_level2() -> u8 { + await3_level1().await + await3_level1().await + await3_level1().await +} + +async fn await3_level3() -> u8 { + await3_level2().await + await3_level2().await + await3_level2().await +} + +async fn await3_level4() -> u8 { + await3_level3().await + await3_level3().await + await3_level3().await +} + +async fn await3_level5() -> u8 { + await3_level4().await + await3_level4().await + await3_level4().await +} + +fn main() { + assert_eq!(2, std::mem::size_of_val(&base())); + assert_eq!(3, std::mem::size_of_val(&await1_level1())); + assert_eq!(4, std::mem::size_of_val(&await2_level1())); + assert_eq!(5, std::mem::size_of_val(&await3_level1())); + assert_eq!(8, std::mem::size_of_val(&await3_level2())); + assert_eq!(11, std::mem::size_of_val(&await3_level3())); + assert_eq!(14, std::mem::size_of_val(&await3_level4())); + assert_eq!(17, std::mem::size_of_val(&await3_level5())); + + assert_eq!(1, wait(base())); + assert_eq!(1, wait(await1_level1())); + assert_eq!(2, wait(await2_level1())); + assert_eq!(3, wait(await3_level1())); + assert_eq!(9, wait(await3_level2())); + assert_eq!(27, wait(await3_level3())); + assert_eq!(81, wait(await3_level4())); + assert_eq!(243, wait(await3_level5())); +} diff --git a/src/test/ui/async-await/async-matches-expr.rs b/src/test/ui/async-await/async-matches-expr.rs new file mode 100644 index 000000000..299faa058 --- /dev/null +++ b/src/test/ui/async-await/async-matches-expr.rs @@ -0,0 +1,10 @@ +// build-pass (FIXME(62277): could be check-pass?) +// edition:2018 + +macro_rules! match_expr { + ($x:expr) => {} +} + +fn main() { + match_expr!(async {}); +} diff --git a/src/test/ui/async-await/async-trait-fn.rs b/src/test/ui/async-await/async-trait-fn.rs new file mode 100644 index 000000000..e2062e827 --- /dev/null +++ b/src/test/ui/async-await/async-trait-fn.rs @@ -0,0 +1,11 @@ +// edition:2018 +trait T { + async fn foo() {} //~ ERROR functions in traits cannot be declared `async` + async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async` + async fn baz() { //~ ERROR functions in traits cannot be declared `async` + // Nested item must not ICE. + fn a() {} + } +} + +fn main() {} diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr new file mode 100644 index 000000000..1eb8969a8 --- /dev/null +++ b/src/test/ui/async-await/async-trait-fn.stderr @@ -0,0 +1,41 @@ +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:3:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:4:5 + | +LL | async fn bar(&self) {} + | -----^^^^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:5:5 + | +LL | async fn baz() { + | ^---- + | | + | _____`async` because of this + | | +LL | | // Nested item must not ICE. +LL | | fn a() {} +LL | | } + | |_____^ + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0706`. diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr new file mode 100644 index 000000000..2114fb59b --- /dev/null +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr @@ -0,0 +1,35 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/async-unsafe-fn-call-in-safe.rs:14:5 + | +LL | S::f(); + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/async-unsafe-fn-call-in-safe.rs:17:5 + | +LL | f(); + | ^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/async-unsafe-fn-call-in-safe.rs:23:5 + | +LL | S::f(); + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/async-unsafe-fn-call-in-safe.rs:24:5 + | +LL | f(); + | ^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs new file mode 100644 index 000000000..c941dc27a --- /dev/null +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs @@ -0,0 +1,25 @@ +// edition:2018 +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + +struct S; + +impl S { + async unsafe fn f() {} +} + +async unsafe fn f() {} + +async fn g() { + S::f(); + //[mir]~^ ERROR call to unsafe function is unsafe + //[thir]~^^ ERROR call to unsafe function `S::f` is unsafe + f(); + //[mir]~^ ERROR call to unsafe function is unsafe + //[thir]~^^ ERROR call to unsafe function `f` is unsafe +} + +fn main() { + S::f(); //[mir]~ ERROR call to unsafe function is unsafe + f(); //[mir]~ ERROR call to unsafe function is unsafe +} diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr new file mode 100644 index 000000000..68d97d3fd --- /dev/null +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block + --> $DIR/async-unsafe-fn-call-in-safe.rs:14:5 + | +LL | S::f(); + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block + --> $DIR/async-unsafe-fn-call-in-safe.rs:17:5 + | +LL | f(); + | ^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/async-await/async-with-closure.rs b/src/test/ui/async-await/async-with-closure.rs new file mode 100644 index 000000000..0b2255266 --- /dev/null +++ b/src/test/ui/async-await/async-with-closure.rs @@ -0,0 +1,24 @@ +// build-pass (FIXME(62277): could be check-pass?) +// edition:2018 + +trait MyClosure { + type Args; +} + +impl<R> MyClosure for dyn FnMut() -> R +where R: 'static { + type Args = (); +} + +struct MyStream<C: ?Sized + MyClosure> { + x: C::Args, +} + +async fn get_future<C: ?Sized + MyClosure>(_stream: MyStream<C>) {} + +async fn f() { + let messages: MyStream<dyn FnMut()> = unimplemented!(); + get_future(messages).await; +} + +fn main() {} diff --git a/src/test/ui/async-await/auxiliary/arc_wake.rs b/src/test/ui/async-await/auxiliary/arc_wake.rs new file mode 100644 index 000000000..c21886f26 --- /dev/null +++ b/src/test/ui/async-await/auxiliary/arc_wake.rs @@ -0,0 +1,64 @@ +// edition:2018 + +use std::sync::Arc; +use std::task::{ + Waker, RawWaker, RawWakerVTable, +}; + +macro_rules! waker_vtable { + ($ty:ident) => { + &RawWakerVTable::new( + clone_arc_raw::<$ty>, + wake_arc_raw::<$ty>, + wake_by_ref_arc_raw::<$ty>, + drop_arc_raw::<$ty>, + ) + }; +} + +pub trait ArcWake { + fn wake(self: Arc<Self>); + + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.clone().wake() + } + + fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized + { + let ptr = Arc::into_raw(wake) as *const (); + + unsafe { + Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) + } + } +} + +unsafe fn increase_refcount<T: ArcWake>(data: *const ()) { + // Retain Arc by creating a copy + let arc: Arc<T> = Arc::from_raw(data as *const T); + let arc_clone = arc.clone(); + // Forget the Arcs again, so that the refcount isn't decrased + let _ = Arc::into_raw(arc); + let _ = Arc::into_raw(arc_clone); +} + +unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker { + increase_refcount::<T>(data); + RawWaker::new(data, waker_vtable!(T)) +} + +unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) { + // Drop Arc + let _: Arc<T> = Arc::from_raw(data as *const T); +} + +unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) { + let arc: Arc<T> = Arc::from_raw(data as *const T); + ArcWake::wake(arc); +} + +unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) { + let arc: Arc<T> = Arc::from_raw(data as *const T); + ArcWake::wake_by_ref(&arc); + let _ = Arc::into_raw(arc); +} diff --git a/src/test/ui/async-await/auxiliary/issue-72470-lib.rs b/src/test/ui/async-await/auxiliary/issue-72470-lib.rs new file mode 100644 index 000000000..8383eba89 --- /dev/null +++ b/src/test/ui/async-await/auxiliary/issue-72470-lib.rs @@ -0,0 +1,175 @@ +// compile-flags: -C opt-level=3 +// edition:2018 + +use std::future::Future; +use std::marker::PhantomData; +use std::pin::Pin; +use std::sync::atomic::AtomicUsize; +use std::sync::Arc; +use std::task::Poll::{Pending, Ready}; +use std::task::Waker; +use std::task::{Context, Poll}; +use std::{ + ptr, + task::{RawWaker, RawWakerVTable}, +}; + +/// Future for the [`poll_fn`] function. +pub struct PollFn<F> { + f: F, +} + +impl<F> Unpin for PollFn<F> {} + +/// Creates a new future wrapping around a function returning [`Poll`]. +pub fn poll_fn<T, F>(f: F) -> PollFn<F> +where + F: FnMut(&mut Context<'_>) -> Poll<T>, +{ + PollFn { f } +} + +impl<T, F> Future for PollFn<F> +where + F: FnMut(&mut Context<'_>) -> Poll<T>, +{ + type Output = T; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { + (&mut self.f)(cx) + } +} +pub fn run<F: Future>(future: F) -> F::Output { + BasicScheduler.block_on(future) +} + +pub(crate) struct BasicScheduler; + +impl BasicScheduler { + pub(crate) fn block_on<F>(&mut self, mut future: F) -> F::Output + where + F: Future, + { + let waker = unsafe { Waker::from_raw(raw_waker()) }; + let mut cx = std::task::Context::from_waker(&waker); + + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + loop { + if let Ready(v) = future.as_mut().poll(&mut cx) { + return v; + } + } + } +} + +// ===== impl Spawner ===== + +fn raw_waker() -> RawWaker { + RawWaker::new(ptr::null(), waker_vtable()) +} + +fn waker_vtable() -> &'static RawWakerVTable { + &RawWakerVTable::new( + clone_arc_raw, + wake_arc_raw, + wake_by_ref_arc_raw, + drop_arc_raw, + ) +} + +unsafe fn clone_arc_raw(_: *const ()) -> RawWaker { + raw_waker() +} + +unsafe fn wake_arc_raw(_: *const ()) {} + +unsafe fn wake_by_ref_arc_raw(_: *const ()) {} + +unsafe fn drop_arc_raw(_: *const ()) {} + +struct AtomicWaker {} + +impl AtomicWaker { + /// Create an `AtomicWaker` + fn new() -> AtomicWaker { + AtomicWaker {} + } + + fn register_by_ref(&self, _waker: &Waker) {} +} + +#[allow(dead_code)] +struct Tx<T> { + inner: Arc<Chan<T>>, +} + +struct Rx<T> { + inner: Arc<Chan<T>>, +} + +#[allow(dead_code)] +struct Chan<T> { + tx: PhantomData<T>, + semaphore: Sema, + rx_waker: AtomicWaker, + rx_closed: bool, +} + +fn channel<T>() -> (Tx<T>, Rx<T>) { + let chan = Arc::new(Chan { + tx: PhantomData, + semaphore: Sema(AtomicUsize::new(0)), + rx_waker: AtomicWaker::new(), + rx_closed: false, + }); + + ( + Tx { + inner: chan.clone(), + }, + Rx { inner: chan }, + ) +} + +// ===== impl Rx ===== + +impl<T> Rx<T> { + /// Receive the next value + fn recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> { + self.inner.rx_waker.register_by_ref(cx.waker()); + + if self.inner.rx_closed && self.inner.semaphore.is_idle() { + Ready(None) + } else { + Pending + } + } +} + +struct Sema(AtomicUsize); + +impl Sema { + fn is_idle(&self) -> bool { + false + } +} + +pub struct UnboundedReceiver<T> { + chan: Rx<T>, +} + +pub fn unbounded_channel<T>() -> UnboundedReceiver<T> { + let (tx, rx) = channel(); + + drop(tx); + let rx = UnboundedReceiver { chan: rx }; + + rx +} + +impl<T> UnboundedReceiver<T> { + pub async fn recv(&mut self) -> Option<T> { + poll_fn(|cx| self.chan.recv(cx)).await + } +} diff --git a/src/test/ui/async-await/await-into-future.rs b/src/test/ui/async-await/await-into-future.rs new file mode 100644 index 000000000..8bf1385b3 --- /dev/null +++ b/src/test/ui/async-await/await-into-future.rs @@ -0,0 +1,28 @@ +// run-pass +// aux-build: issue-72470-lib.rs +// edition:2021 +extern crate issue_72470_lib; +use std::{future::{Future, IntoFuture}, pin::Pin}; + +struct AwaitMe; + +impl IntoFuture for AwaitMe { + type Output = i32; + type IntoFuture = Pin<Box<dyn Future<Output = i32>>>; + + fn into_future(self) -> Self::IntoFuture { + Box::pin(me()) + } +} + +async fn me() -> i32 { + 41 +} + +async fn run() { + assert_eq!(AwaitMe.await, 41); +} + +fn main() { + issue_72470_lib::run(run()); +} diff --git a/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.rs b/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.rs new file mode 100644 index 000000000..50c163999 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.rs @@ -0,0 +1,38 @@ +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod await { //~ ERROR `await` is a keyword in the 2018 edition + //~^ WARN this is accepted in the current edition + pub struct await; //~ ERROR `await` is a keyword in the 2018 edition + //~^ WARN this is accepted in the current edition + } +} +use outer_mod::await::await; //~ ERROR `await` is a keyword in the 2018 edition +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this is accepted in the current edition +//~^^^ WARN this is accepted in the current edition + +struct Foo { await: () } +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this is accepted in the current edition + +impl Foo { fn await() {} } +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this is accepted in the current edition + +macro_rules! await { +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this is accepted in the current edition + () => {} +} + +fn main() { + await!(); //~ ERROR `await` is a keyword in the 2018 edition + //~^ WARN this is accepted in the current edition + + match await { await => {} } //~ ERROR `await` is a keyword in the 2018 edition + //~^ ERROR `await` is a keyword in the 2018 edition + //~^^ WARN this is accepted in the current edition + //~^^^ WARN this is accepted in the current edition +} diff --git a/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr b/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr new file mode 100644 index 000000000..50a82c08c --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr @@ -0,0 +1,97 @@ +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:5:13 + | +LL | pub mod await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | +note: the lint level is defined here + --> $DIR/2015-edition-error-various-positions.rs:2:9 + | +LL | #![deny(keyword_idents)] + | ^^^^^^^^^^^^^^ + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:7:20 + | +LL | pub struct await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:11:16 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:11:23 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:16:14 + | +LL | struct Foo { await: () } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:20:15 + | +LL | impl Foo { fn await() {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:24:14 + | +LL | macro_rules! await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:31:5 + | +LL | await!(); + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:34:11 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-various-positions.rs:34:19 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/async-await/await-keyword/2015-edition-warning.fixed b/src/test/ui/async-await/await-keyword/2015-edition-warning.fixed new file mode 100644 index 000000000..117495e13 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2015-edition-warning.fixed @@ -0,0 +1,27 @@ +// run-rustfix + +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod r#await { +//~^ ERROR `await` is a keyword +//~| WARN this is accepted in the current edition + pub struct r#await; +//~^ ERROR `await` is a keyword +//~| WARN this is accepted in the current edition + } +} +use outer_mod::r#await::r#await; +//~^ ERROR `await` is a keyword +//~| ERROR `await` is a keyword +//~| WARN this is accepted in the current edition +//~| WARN this is accepted in the current edition + +fn main() { + match r#await { r#await => {} } +//~^ ERROR `await` is a keyword +//~| ERROR `await` is a keyword +//~| WARN this is accepted in the current edition +//~| WARN this is accepted in the current edition +} diff --git a/src/test/ui/async-await/await-keyword/2015-edition-warning.rs b/src/test/ui/async-await/await-keyword/2015-edition-warning.rs new file mode 100644 index 000000000..b3c64895c --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2015-edition-warning.rs @@ -0,0 +1,27 @@ +// run-rustfix + +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod await { +//~^ ERROR `await` is a keyword +//~| WARN this is accepted in the current edition + pub struct await; +//~^ ERROR `await` is a keyword +//~| WARN this is accepted in the current edition + } +} +use outer_mod::await::await; +//~^ ERROR `await` is a keyword +//~| ERROR `await` is a keyword +//~| WARN this is accepted in the current edition +//~| WARN this is accepted in the current edition + +fn main() { + match await { await => {} } +//~^ ERROR `await` is a keyword +//~| ERROR `await` is a keyword +//~| WARN this is accepted in the current edition +//~| WARN this is accepted in the current edition +} diff --git a/src/test/ui/async-await/await-keyword/2015-edition-warning.stderr b/src/test/ui/async-await/await-keyword/2015-edition-warning.stderr new file mode 100644 index 000000000..1c4c19ea4 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2015-edition-warning.stderr @@ -0,0 +1,61 @@ +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:7:13 + | +LL | pub mod await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | +note: the lint level is defined here + --> $DIR/2015-edition-warning.rs:4:9 + | +LL | #![deny(keyword_idents)] + | ^^^^^^^^^^^^^^ + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:10:20 + | +LL | pub struct await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:15:16 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:15:23 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:22:11 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-warning.rs:22:19 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs new file mode 100644 index 000000000..9e78f7c51 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.rs @@ -0,0 +1,24 @@ +// edition:2018 + +#![allow(non_camel_case_types)] + +mod outer_mod { + pub mod await { //~ ERROR expected identifier, found keyword `await` + pub struct await; //~ ERROR expected identifier, found keyword `await` + } +} +use self::outer_mod::await::await; //~ ERROR expected identifier, found keyword `await` +//~^ ERROR expected identifier, found keyword `await` + +struct Foo { await: () } +//~^ ERROR expected identifier, found keyword `await` + +impl Foo { fn await() {} } +//~^ ERROR expected identifier, found keyword `await` + +macro_rules! await { +//~^ ERROR expected identifier, found keyword `await` + () => {} +} + +fn main() {} diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr new file mode 100644 index 000000000..ccbaa1f2a --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2018-edition-error-in-non-macro-position.stderr @@ -0,0 +1,79 @@ +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:6:13 + | +LL | pub mod await { + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | pub mod r#await { + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:7:20 + | +LL | pub struct await; + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | pub struct r#await; + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:10:22 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | use self::outer_mod::r#await::await; + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:10:29 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | use self::outer_mod::await::r#await; + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:13:14 + | +LL | struct Foo { await: () } + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | struct Foo { r#await: () } + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:16:15 + | +LL | impl Foo { fn await() {} } + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | impl Foo { fn r#await() {} } + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:19:14 + | +LL | macro_rules! await { + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | macro_rules! r#await { + | ++ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error.rs b/src/test/ui/async-await/await-keyword/2018-edition-error.rs new file mode 100644 index 000000000..7ce52259a --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2018-edition-error.rs @@ -0,0 +1,16 @@ +// edition:2018 +#![allow(non_camel_case_types)] + +mod outer_mod { + pub mod await { //~ ERROR expected identifier + pub struct await; //~ ERROR expected identifier + } +} +use self::outer_mod::await::await; //~ ERROR expected identifier + //~^ ERROR expected identifier, found keyword `await` + +macro_rules! await { () => {}; } //~ ERROR expected identifier, found keyword `await` + +fn main() { + await!(); //~ ERROR expected expression, found `)` +} diff --git a/src/test/ui/async-await/await-keyword/2018-edition-error.stderr b/src/test/ui/async-await/await-keyword/2018-edition-error.stderr new file mode 100644 index 000000000..34bfdfc71 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/2018-edition-error.stderr @@ -0,0 +1,63 @@ +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error.rs:5:13 + | +LL | pub mod await { + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | pub mod r#await { + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error.rs:6:20 + | +LL | pub struct await; + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | pub struct r#await; + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error.rs:9:22 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | use self::outer_mod::r#await::await; + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error.rs:9:29 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | use self::outer_mod::await::r#await; + | ++ + +error: expected identifier, found keyword `await` + --> $DIR/2018-edition-error.rs:12:14 + | +LL | macro_rules! await { () => {}; } + | ^^^^^ expected identifier, found keyword + | +help: escape `await` to use it as an identifier + | +LL | macro_rules! r#await { () => {}; } + | ++ + +error: expected expression, found `)` + --> $DIR/2018-edition-error.rs:15:12 + | +LL | await!(); + | ^ expected expression + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs new file mode 100644 index 000000000..554ac673d --- /dev/null +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs @@ -0,0 +1,132 @@ +// edition:2018 + +async fn bar() -> Result<(), ()> { + Ok(()) +} + +async fn foo1() -> Result<(), ()> { + let _ = await bar(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo2() -> Result<(), ()> { + let _ = await? bar(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo3() -> Result<(), ()> { + let _ = await bar()?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo21() -> Result<(), ()> { + let _ = await { bar() }; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo22() -> Result<(), ()> { + let _ = await(bar()); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo23() -> Result<(), ()> { + let _ = await { bar() }?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo4() -> Result<(), ()> { + let _ = (await bar())?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo5() -> Result<(), ()> { + let _ = bar().await(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo6() -> Result<(), ()> { + let _ = bar().await()?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo7() -> Result<(), ()> { + let _ = bar().await; // OK + Ok(()) +} +async fn foo8() -> Result<(), ()> { + let _ = bar().await?; // OK + Ok(()) +} +fn foo9() -> Result<(), ()> { + let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo10() -> Result<(), ()> { + let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo11() -> Result<(), ()> { + let _ = await bar()?; //~ ERROR incorrect use of `await` + Ok(()) +} +fn foo12() -> Result<(), ()> { + let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo13() -> Result<(), ()> { + let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo14() -> Result<(), ()> { + let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo15() -> Result<(), ()> { + let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) +} +fn foo16() -> Result<(), ()> { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) +} +fn foo24() -> Result<(), ()> { + fn foo() -> Result<(), ()> { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) + } + foo() +} +fn foo25() -> Result<(), ()> { + let foo = || { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) + }; + foo() +} + +async fn foo26() -> Result<(), ()> { + let _ = await!(bar()); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo27() -> Result<(), ()> { + let _ = await!(bar())?; //~ ERROR incorrect use of `await` + Ok(()) +} +fn foo28() -> Result<(), ()> { + fn foo() -> Result<(), ()> { + let _ = await!(bar())?; //~ ERROR incorrect use of `await` + //~^ ERROR `await` is only allowed inside `async` functions + Ok(()) + } + foo() +} +fn foo29() -> Result<(), ()> { + let foo = || { + let _ = await!(bar())?; //~ ERROR incorrect use of `await` + //~^ ERROR `await` is only allowed inside `async` functions + Ok(()) + }; + foo() +} + +fn main() { + match await { await => () } + //~^ ERROR expected expression, found `=>` + //~| ERROR incorrect use of `await` +} //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `}` diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr new file mode 100644 index 000000000..b30f28837 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -0,0 +1,230 @@ +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:8:13 + | +LL | let _ = await bar(); + | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:12:13 + | +LL | let _ = await? bar(); + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:16:13 + | +LL | let _ = await bar()?; + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:20:13 + | +LL | let _ = await { bar() }; + | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:24:13 + | +LL | let _ = await(bar()); + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:28:13 + | +LL | let _ = await { bar() }?; + | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:32:14 + | +LL | let _ = (await bar())?; + | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:36:24 + | +LL | let _ = bar().await(); + | ^^ help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:40:24 + | +LL | let _ = bar().await()?; + | ^^ help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:52:13 + | +LL | let _ = await bar(); + | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:57:13 + | +LL | let _ = await? bar(); + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:62:13 + | +LL | let _ = await bar()?; + | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:66:14 + | +LL | let _ = (await bar())?; + | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:71:24 + | +LL | let _ = bar().await(); + | ^^ help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:76:24 + | +LL | let _ = bar().await()?; + | ^^ help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:104:13 + | +LL | let _ = await!(bar()); + | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:108:13 + | +LL | let _ = await!(bar())?; + | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:113:17 + | +LL | let _ = await!(bar())?; + | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:121:17 + | +LL | let _ = await!(bar())?; + | ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await` + +error: expected expression, found `=>` + --> $DIR/incorrect-syntax-suggestions.rs:129:25 + | +LL | match await { await => () } + | ----- ^^ expected expression + | | + | while parsing this incorrect await expression + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:129:11 + | +LL | match await { await => () } + | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await` + +error: expected one of `.`, `?`, `{`, or an operator, found `}` + --> $DIR/incorrect-syntax-suggestions.rs:132:1 + | +LL | match await { await => () } + | ----- - expected one of `.`, `?`, `{`, or an operator + | | + | while parsing this `match` expression +... +LL | } + | ^ unexpected token + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:52:13 + | +LL | fn foo9() -> Result<(), ()> { + | ---- this is not `async` +LL | let _ = await bar(); + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:57:13 + | +LL | fn foo10() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = await? bar(); + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:66:14 + | +LL | fn foo12() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = (await bar())?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:71:18 + | +LL | fn foo13() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = bar().await(); + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:76:18 + | +LL | fn foo14() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = bar().await()?; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:81:18 + | +LL | fn foo15() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = bar().await; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:85:18 + | +LL | fn foo16() -> Result<(), ()> { + | ----- this is not `async` +LL | let _ = bar().await?; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:90:22 + | +LL | fn foo() -> Result<(), ()> { + | --- this is not `async` +LL | let _ = bar().await?; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:97:22 + | +LL | let foo = || { + | -- this is not `async` +LL | let _ = bar().await?; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:113:29 + | +LL | fn foo() -> Result<(), ()> { + | --- this is not `async` +LL | let _ = await!(bar())?; + | ^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:121:29 + | +LL | let foo = || { + | -- this is not `async` +LL | let _ = await!(bar())?; + | ^ only allowed inside `async` functions and blocks + +error: aborting due to 33 previous errors + +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/async-await/await-keyword/post_expansion_error.rs b/src/test/ui/async-await/await-keyword/post_expansion_error.rs new file mode 100644 index 000000000..b4c899b0d --- /dev/null +++ b/src/test/ui/async-await/await-keyword/post_expansion_error.rs @@ -0,0 +1,10 @@ +// edition:2018 + +macro_rules! r#await { + () => { println!("Hello, world!") } +} + +fn main() { + await!() + //~^ ERROR expected expression, found `)` +} diff --git a/src/test/ui/async-await/await-keyword/post_expansion_error.stderr b/src/test/ui/async-await/await-keyword/post_expansion_error.stderr new file mode 100644 index 000000000..0996c38b3 --- /dev/null +++ b/src/test/ui/async-await/await-keyword/post_expansion_error.stderr @@ -0,0 +1,8 @@ +error: expected expression, found `)` + --> $DIR/post_expansion_error.rs:8:12 + | +LL | await!() + | ^ expected expression + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/await-unsize.rs b/src/test/ui/async-await/await-unsize.rs new file mode 100644 index 000000000..aa09d4bdf --- /dev/null +++ b/src/test/ui/async-await/await-unsize.rs @@ -0,0 +1,14 @@ +// Regression test for #62312 + +// check-pass +// edition:2018 + +async fn make_boxed_object() -> Box<dyn Send> { + Box::new(()) as _ +} + +async fn await_object() { + let _ = make_boxed_object().await; +} + +fn main() {} diff --git a/src/test/ui/async-await/bound-normalization.rs b/src/test/ui/async-await/bound-normalization.rs new file mode 100644 index 000000000..5d260682f --- /dev/null +++ b/src/test/ui/async-await/bound-normalization.rs @@ -0,0 +1,14 @@ +// check-pass +// edition:2018 + +// See issue 60414 + +trait Trait { + type Assoc; +} + +async fn foo<T: Trait<Assoc=()>>() -> T::Assoc { + () +} + +fn main() {} diff --git a/src/test/ui/async-await/conditional-and-guaranteed-initialization.rs b/src/test/ui/async-await/conditional-and-guaranteed-initialization.rs new file mode 100644 index 000000000..56f4cbbd1 --- /dev/null +++ b/src/test/ui/async-await/conditional-and-guaranteed-initialization.rs @@ -0,0 +1,16 @@ +// check-pass +// edition:2018 +// compile-flags: --crate-type lib + +async fn conditional_and_guaranteed_initialization(x: usize) -> usize { + let y; + if x > 5 { + y = echo(10).await; + } else { + y = get_something().await; + } + y +} + +async fn echo(x: usize) -> usize { x } +async fn get_something() -> usize { 10 } diff --git a/src/test/ui/async-await/default-struct-update.rs b/src/test/ui/async-await/default-struct-update.rs new file mode 100644 index 000000000..64fb6280d --- /dev/null +++ b/src/test/ui/async-await/default-struct-update.rs @@ -0,0 +1,22 @@ +// build-pass +// edition:2018 +// compile-flags: -Zdrop-tracking=y + +fn main() { + let _ = foo(); +} + +async fn from_config(_: Config) {} + +async fn foo() { + from_config(Config { + nickname: None, + ..Default::default() + }) + .await; +} + +#[derive(Default)] +struct Config { + nickname: Option<Box<u8>>, +} diff --git a/src/test/ui/async-await/dont-print-desugared-async.rs b/src/test/ui/async-await/dont-print-desugared-async.rs new file mode 100644 index 000000000..68341a24c --- /dev/null +++ b/src/test/ui/async-await/dont-print-desugared-async.rs @@ -0,0 +1,8 @@ +// Test that we don't show variables with from async fn desugaring + +// edition:2018 + +async fn async_fn(&ref mut s: &[i32]) {} +//~^ ERROR cannot borrow data in a `&` reference as mutable [E0596] + +fn main() {} diff --git a/src/test/ui/async-await/dont-print-desugared-async.stderr b/src/test/ui/async-await/dont-print-desugared-async.stderr new file mode 100644 index 000000000..d80467c7f --- /dev/null +++ b/src/test/ui/async-await/dont-print-desugared-async.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/dont-print-desugared-async.rs:5:20 + | +LL | async fn async_fn(&ref mut s: &[i32]) {} + | ^^^^^^^^^ cannot borrow as mutable through `&` reference + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/async-await/dont-suggest-missing-await.rs b/src/test/ui/async-await/dont-suggest-missing-await.rs new file mode 100644 index 000000000..a8e5b38ec --- /dev/null +++ b/src/test/ui/async-await/dont-suggest-missing-await.rs @@ -0,0 +1,19 @@ +// edition:2018 + +// This test ensures we don't make the suggestion in bodies that aren't `async`. + +fn take_u32(x: u32) {} + +async fn make_u32() -> u32 { + 22 +} + +async fn dont_suggest_await_in_closure() { + || { + let x = make_u32(); + take_u32(x) + //~^ ERROR mismatched types [E0308] + }; +} + +fn main() {} diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr new file mode 100644 index 000000000..627bf05bb --- /dev/null +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -0,0 +1,28 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-missing-await.rs:14:18 + | +LL | take_u32(x) + | -------- ^ expected `u32`, found opaque type + | | + | arguments to this function are incorrect + | +note: while checking the return type of the `async fn` + --> $DIR/dont-suggest-missing-await.rs:7:24 + | +LL | async fn make_u32() -> u32 { + | ^^^ checked the `Output` of this `async fn`, found opaque type + = note: expected type `u32` + found opaque type `impl Future<Output = u32>` +note: function defined here + --> $DIR/dont-suggest-missing-await.rs:5:4 + | +LL | fn take_u32(x: u32) {} + | ^^^^^^^^ ------ +help: consider `await`ing on the `Future` + | +LL | take_u32(x.await) + | ++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/drop-and-assign.rs b/src/test/ui/async-await/drop-and-assign.rs new file mode 100644 index 000000000..fa3f33036 --- /dev/null +++ b/src/test/ui/async-await/drop-and-assign.rs @@ -0,0 +1,19 @@ +// edition:2021 +// compile-flags: -Zdrop-tracking +// build-pass + +struct A; +impl Drop for A { fn drop(&mut self) {} } + +pub async fn f() { + let mut a = A; + a = A; + drop(a); + async {}.await; +} + +fn assert_send<T: Send>(_: T) {} + +fn main() { + let _ = f(); +} diff --git a/src/test/ui/async-await/drop-order/auxiliary/arc_wake.rs b/src/test/ui/async-await/drop-order/auxiliary/arc_wake.rs new file mode 100644 index 000000000..c21886f26 --- /dev/null +++ b/src/test/ui/async-await/drop-order/auxiliary/arc_wake.rs @@ -0,0 +1,64 @@ +// edition:2018 + +use std::sync::Arc; +use std::task::{ + Waker, RawWaker, RawWakerVTable, +}; + +macro_rules! waker_vtable { + ($ty:ident) => { + &RawWakerVTable::new( + clone_arc_raw::<$ty>, + wake_arc_raw::<$ty>, + wake_by_ref_arc_raw::<$ty>, + drop_arc_raw::<$ty>, + ) + }; +} + +pub trait ArcWake { + fn wake(self: Arc<Self>); + + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.clone().wake() + } + + fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized + { + let ptr = Arc::into_raw(wake) as *const (); + + unsafe { + Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) + } + } +} + +unsafe fn increase_refcount<T: ArcWake>(data: *const ()) { + // Retain Arc by creating a copy + let arc: Arc<T> = Arc::from_raw(data as *const T); + let arc_clone = arc.clone(); + // Forget the Arcs again, so that the refcount isn't decrased + let _ = Arc::into_raw(arc); + let _ = Arc::into_raw(arc_clone); +} + +unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker { + increase_refcount::<T>(data); + RawWaker::new(data, waker_vtable!(T)) +} + +unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) { + // Drop Arc + let _: Arc<T> = Arc::from_raw(data as *const T); +} + +unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) { + let arc: Arc<T> = Arc::from_raw(data as *const T); + ArcWake::wake(arc); +} + +unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) { + let arc: Arc<T> = Arc::from_raw(data as *const T); + ArcWake::wake_by_ref(&arc); + let _ = Arc::into_raw(arc); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs new file mode 100644 index 000000000..9817d377a --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs @@ -0,0 +1,270 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +#![allow(unused_variables)] + +// Test that the drop order for parameters in a fn and async fn matches up. Also test that +// parameters (used or unused) are not dropped until the async fn completes execution. +// See also #54716. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::marker::PhantomData; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc<Self>) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check that unused bindings are dropped after the function is polled. +async fn foo_async(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foo_sync(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns are dropped after the function is polled. +async fn bar_async(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn bar_sync(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns within more complex patterns are dropped after the function +/// is polled. +async fn baz_async((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn baz_sync((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore and unused bindings within and outwith more complex patterns are dropped +/// after the function is polled. +async fn foobar_async(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foobar_sync(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +struct Foo; + +impl Foo { + /// Check that unused bindings are dropped after the method is polled. + async fn foo_async(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method is polled. + async fn bar_async(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// is polled. + async fn baz_async((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method is polled. + async fn foobar_async( + ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync( + ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +struct Bar<'a>(PhantomData<&'a ()>); + +impl<'a> Bar<'a> { + /// Check that unused bindings are dropped after the method with self is polled. + async fn foo_async(&'a self, ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(&'a self, ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method with self is polled. + async fn bar_async(&'a self, ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(&'a self, ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// with self is polled. + async fn baz_async(&'a self, (ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync(&'a self, (ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method with self is polled. + async fn foobar_async( + &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync( + &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +fn assert_drop_order_after_poll<Fut: Future<Output = ()>>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())), + |l| bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods w/out self (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())), + |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + Foo::foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + Foo::foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods (see doc comment on function for what it tests). + let b = Bar(Default::default()); + assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())), + |l| b.bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| b.baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + b.foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + b.foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs new file mode 100644 index 000000000..6c10ead36 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs @@ -0,0 +1,265 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +// revisions: default nomiropt +//[nomiropt]compile-flags: -Z mir-opt-level=0 + +#![allow(unused_variables)] + +// Test that the drop order for parameters in a fn and async fn matches up. Also test that +// parameters (used or unused) are not dropped until the async fn completes execution. +// See also #54716. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::marker::PhantomData; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc<Self>) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check that unused bindings are dropped after the function is polled. +async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns are dropped after the function is polled. +async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns within more complex patterns are dropped after the function +/// is polled. +async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore and unused bindings within and outwith more complex patterns are dropped +/// after the function is polled. +async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +struct Foo; + +impl Foo { + /// Check that unused bindings are dropped after the method is polled. + async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method is polled. + async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// is polled. + async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method is polled. + async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +struct Bar<'a>(PhantomData<&'a ()>); + +impl<'a> Bar<'a> { + /// Check that unused bindings are dropped after the method with self is polled. + async fn foo_async(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method with self is polled. + async fn bar_async(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// with self is polled. + async fn baz_async(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method with self is polled. + async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +fn assert_drop_order_after_poll<Fut: Future<Output = ()>>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())), + |l| bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods w/out self (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())), + |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + Foo::foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + Foo::foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods (see doc comment on function for what it tests). + let b = Bar(Default::default()); + assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())), + |l| b.bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| b.baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + b.foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + b.foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs b/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs new file mode 100644 index 000000000..15cc9fbc8 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs @@ -0,0 +1,176 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +#![deny(dead_code)] +#![allow(unused_variables)] +#![allow(unused_must_use)] +#![allow(path_statements)] + +// Test that the drop order for locals in a fn and async fn matches up. +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::pin::Pin; +use std::rc::Rc; +use std::sync::Arc; +use std::task::{Context, Poll}; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc<Self>) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +struct NeverReady; + +impl Future for NeverReady { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { + Poll::Pending + } +} + +async fn simple_variable_declaration_async(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + let x = D("x", l.clone()); + let y = D("y", l.clone()); + NeverReady.await; +} + +fn simple_variable_declaration_sync(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + let x = D("x", l.clone()); + let y = D("y", l.clone()); +} + +async fn varable_completely_contained_within_block_async(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + async { + let x = D("x", l.clone()); + } + .await; + let y = D("y", l.clone()); + NeverReady.await; +} + +fn varable_completely_contained_within_block_sync(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + { + let x = D("x", l.clone()); + } + let y = D("y", l.clone()); +} + +async fn variables_moved_into_separate_blocks_async(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + let x = D("x", l.clone()); + let y = D("y", l.clone()); + async move { x }.await; + async move { y }.await; + NeverReady.await; +} + +fn variables_moved_into_separate_blocks_sync(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + let x = D("x", l.clone()); + let y = D("y", l.clone()); + { + x + }; + { + y + }; +} + +async fn variables_moved_into_same_block_async(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + let x = D("x", l.clone()); + let y = D("y", l.clone()); + async move { + x; + y; + }; + NeverReady.await; +} + +fn variables_moved_into_same_block_sync(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + let x = D("x", l.clone()); + let y = D("y", l.clone()); + { + x; + y; + }; + return; +} + +async fn move_after_current_await_doesnt_affect_order(l: DropOrderListPtr) { + l.borrow_mut().push(DropOrder::Function); + let x = D("x", l.clone()); + let y = D("y", l.clone()); + NeverReady.await; + async move { + x; + y; + }; +} + +fn assert_drop_order_after_cancel<Fut: Future<Output = ()>>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + drop(fut); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + assert_drop_order_after_cancel( + simple_variable_declaration_async, + simple_variable_declaration_sync, + ); + assert_drop_order_after_cancel( + varable_completely_contained_within_block_async, + varable_completely_contained_within_block_sync, + ); + assert_drop_order_after_cancel( + variables_moved_into_separate_blocks_async, + variables_moved_into_separate_blocks_sync, + ); + assert_drop_order_after_cancel( + variables_moved_into_same_block_async, + variables_moved_into_same_block_sync, + ); + assert_drop_order_after_cancel( + move_after_current_await_doesnt_affect_order, + simple_variable_declaration_sync, + ); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs b/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs new file mode 100644 index 000000000..edfecb910 --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs @@ -0,0 +1,98 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +// revisions: default nomiropt +//[nomiropt]compile-flags: -Z mir-opt-level=0 + +#![allow(unused_variables)] + +// Test the drop order for parameters relative to local variables and +// temporaries created in the tail return expression of the function +// body. In particular, check that this drop order is the same between +// an `async fn` and an ordinary `fn`. See #64512. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc<Self>) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check drop order of temporary "temp" as compared to `x`, `y`, and `z`. +/// +/// Expected order: +/// - `z` +/// - temp +/// - `y` +/// - `x` +async fn foo_async(x: D, _y: D) { + let l = x.1.clone(); + let z = D("z", l.clone()); + l.borrow_mut().push(DropOrder::Function); + helper_async(&D("temp", l)).await +} + +async fn helper_async(v: &D) { } + +fn foo_sync(x: D, _y: D) { + let l = x.1.clone(); + let z = D("z", l.clone()); + l.borrow_mut().push(DropOrder::Function); + helper_sync(&D("temp", l)) +} + +fn helper_sync(v: &D) { } + +fn assert_drop_order_after_poll<Fut: Future<Output = ()>>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let r = fut.as_mut().poll(&mut cx); + + assert!(match r { + std::task::Poll::Ready(()) => true, + _ => false, + }); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); +} diff --git a/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs new file mode 100644 index 000000000..79dedb1ba --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.rs @@ -0,0 +1,13 @@ +// edition:2018 + +async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) { + assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425] + assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425] +} + +async fn baz_async(ref mut x: u32, ref y: u32) { + assert_eq!(__arg0, 1); //~ ERROR cannot find value `__arg0` in this scope [E0425] + assert_eq!(__arg1, 2); //~ ERROR cannot find value `__arg1` in this scope [E0425] +} + +fn main() {} diff --git a/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr new file mode 100644 index 000000000..aa04a613f --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr @@ -0,0 +1,27 @@ +error[E0425]: cannot find value `__arg1` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:4:16 + | +LL | assert_eq!(__arg1, (1, 2, 3)); + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `__arg2` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:5:16 + | +LL | assert_eq!(__arg2, 4); + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `__arg0` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:9:16 + | +LL | assert_eq!(__arg0, 1); + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `__arg1` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:10:16 + | +LL | assert_eq!(__arg1, 2); + | ^^^^^^ not found in this scope + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs b/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs new file mode 100644 index 000000000..cfd68bc0d --- /dev/null +++ b/src/test/ui/async-await/drop-order/drop-order-when-cancelled.rs @@ -0,0 +1,309 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +// revisions: default nomiropt +//[nomiropt]compile-flags: -Z mir-opt-level=0 + +// Test that the drop order for parameters in a fn and async fn matches up. Also test that +// parameters (used or unused) are not dropped until the async fn is cancelled. +// This file is mostly copy-pasted from drop-order-for-async-fn-parameters.rs + +#![allow(unused_variables)] + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::marker::PhantomData; +use std::pin::Pin; +use std::rc::Rc; +use std::sync::Arc; +use std::task::{Context, Poll}; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc<Self>) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +struct NeverReady; + +impl Future for NeverReady { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { + Poll::Pending + } +} + +/// Check that unused bindings are dropped after the function is polled. +async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; +} + +fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns are dropped after the function is polled. +async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; +} + +fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns within more complex patterns are dropped after the function +/// is polled. +async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; +} + +fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore and unused bindings within and outwith more complex patterns are dropped +/// after the function is polled. +async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; +} + +fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +struct Foo; + +impl Foo { + /// Check that unused bindings are dropped after the method is polled. + async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; + } + + fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method is polled. + async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; + } + + fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// is polled. + async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; + } + + fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method is polled. + async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; + } + + fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +struct Bar<'a>(PhantomData<&'a ()>); + +impl<'a> Bar<'a> { + /// Check that unused bindings are dropped after the method with self is polled. + async fn foo_async(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; + } + + fn foo_sync(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method with self is polled. + async fn bar_async(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; + } + + fn bar_sync(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// with self is polled. + async fn baz_async(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; + } + + fn baz_sync(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method with self is polled. + async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + NeverReady.await; + } + + fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +fn assert_drop_order_after_cancel<Fut: Future<Output = ()>>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + + // Parameters are never dropped until the future completes. + assert_eq!(*actual_order.borrow(), vec![DropOrder::Function]); + + drop(fut); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_cancel( + |l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone())), + ); + assert_drop_order_after_cancel( + |l| bar_async(D("x", l.clone()), D("_", l.clone())), + |l| bar_sync(D("x", l.clone()), D("_", l.clone())), + ); + assert_drop_order_after_cancel( + |l| baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| baz_sync((D("x", l.clone()), D("_", l.clone()))), + ); + assert_drop_order_after_cancel( + |l| { + foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods w/out self (see doc comment on function for what it tests). + assert_drop_order_after_cancel( + |l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())), + ); + assert_drop_order_after_cancel( + |l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())), + |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())), + ); + assert_drop_order_after_cancel( + |l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))), + ); + assert_drop_order_after_cancel( + |l| { + Foo::foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + Foo::foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods (see doc comment on function for what it tests). + let b = Bar(Default::default()); + assert_drop_order_after_cancel( + |l| b.foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())), + ); + assert_drop_order_after_cancel( + |l| b.bar_async(D("x", l.clone()), D("_", l.clone())), + |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())), + ); + assert_drop_order_after_cancel( + |l| b.baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))), + ); + assert_drop_order_after_cancel( + |l| { + b.foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + b.foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); +} diff --git a/src/test/ui/async-await/drop-track-field-assign-nonsend.rs b/src/test/ui/async-await/drop-track-field-assign-nonsend.rs new file mode 100644 index 000000000..b6c0fda15 --- /dev/null +++ b/src/test/ui/async-await/drop-track-field-assign-nonsend.rs @@ -0,0 +1,45 @@ +// Derived from an ICE found in tokio-xmpp during a crater run. +// edition:2021 +// compile-flags: -Zdrop-tracking + +#![allow(dead_code)] + +#[derive(Clone)] +struct InfoResult { + node: Option<std::rc::Rc<String>> +} + +struct Agent { + info_result: InfoResult +} + +impl Agent { + async fn handle(&mut self) { + let mut info = self.info_result.clone(); + info.node = None; + let element = parse_info(info); + let _ = send_element(element).await; + } +} + +struct Element { +} + +async fn send_element(_: Element) {} + +fn parse(_: &[u8]) -> Result<(), ()> { + Ok(()) +} + +fn parse_info(_: InfoResult) -> Element { + Element { } +} + +fn assert_send<T: Send>(_: T) {} + +fn main() { + let agent = Agent { info_result: InfoResult { node: None } }; + // FIXME: It would be nice for this to work. See #94067. + assert_send(agent.handle()); + //~^ cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/drop-track-field-assign-nonsend.stderr b/src/test/ui/async-await/drop-track-field-assign-nonsend.stderr new file mode 100644 index 000000000..d95483c81 --- /dev/null +++ b/src/test/ui/async-await/drop-track-field-assign-nonsend.stderr @@ -0,0 +1,25 @@ +error: future cannot be sent between threads safely + --> $DIR/drop-track-field-assign-nonsend.rs:43:17 + | +LL | assert_send(agent.handle()); + | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` +note: future is not `Send` as this value is used across an await + --> $DIR/drop-track-field-assign-nonsend.rs:21:38 + | +LL | let mut info = self.info_result.clone(); + | -------- has type `InfoResult` which is not `Send` +... +LL | let _ = send_element(element).await; + | ^^^^^^ await occurs here, with `mut info` maybe used later +LL | } + | - `mut info` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/drop-track-field-assign-nonsend.rs:38:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/drop-track-field-assign.rs b/src/test/ui/async-await/drop-track-field-assign.rs new file mode 100644 index 000000000..3a393cd16 --- /dev/null +++ b/src/test/ui/async-await/drop-track-field-assign.rs @@ -0,0 +1,44 @@ +// Derived from an ICE found in tokio-xmpp during a crater run. +// edition:2021 +// compile-flags: -Zdrop-tracking +// build-pass + +#![allow(dead_code)] + +#[derive(Clone)] +struct InfoResult { + node: Option<String> +} + +struct Agent { + info_result: InfoResult +} + +impl Agent { + async fn handle(&mut self) { + let mut info = self.info_result.clone(); + info.node = Some("bar".into()); + let element = parse_info(info); + let _ = send_element(element).await; + } +} + +struct Element { +} + +async fn send_element(_: Element) {} + +fn parse(_: &[u8]) -> Result<(), ()> { + Ok(()) +} + +fn parse_info(_: InfoResult) -> Element { + Element { } +} + +fn main() { + let mut agent = Agent { + info_result: InfoResult { node: None } + }; + let _ = agent.handle(); +} diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs new file mode 100644 index 000000000..e5dc9c8a5 --- /dev/null +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs @@ -0,0 +1,38 @@ +// edition:2015 + +async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 + +fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in Rust 2015 + +async fn async_baz() { //~ ERROR `async fn` is not permitted in Rust 2015 + async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015 +} + +struct Foo {} + +impl Foo { + async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 +} + +trait Bar { + async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 + //~^ ERROR functions in traits cannot be declared `async` +} + +fn main() { + macro_rules! accept_item { ($x:item) => {} } + + accept_item! { + async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 + } + + accept_item! { + impl Foo { + async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015 + } + } + + let inside_closure = || { + async fn bar() {} //~ ERROR `async fn` is not permitted in Rust 2015 + }; +} diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr new file mode 100644 index 000000000..35f9c581c --- /dev/null +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -0,0 +1,96 @@ +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:3:1 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:5:12 + | +LL | fn baz() { async fn foo() {} } + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:7:1 + | +LL | async fn async_baz() { + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:8:5 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:14:5 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:18:5 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:36:9 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:26:9 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:31:13 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/edition-deny-async-fns-2015.rs:18:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0670, E0706. +For more information about an error, try `rustc --explain E0670`. diff --git a/src/test/ui/async-await/expansion-in-attrs.rs b/src/test/ui/async-await/expansion-in-attrs.rs new file mode 100644 index 000000000..af77c3463 --- /dev/null +++ b/src/test/ui/async-await/expansion-in-attrs.rs @@ -0,0 +1,13 @@ +// check-pass +// edition:2018 + +macro_rules! with_doc { + ($doc: expr) => { + #[doc = $doc] + async fn f() {} + }; +} + +with_doc!(concat!("")); + +fn main() {} diff --git a/src/test/ui/async-await/feature-async-closure.rs b/src/test/ui/async-await/feature-async-closure.rs new file mode 100644 index 000000000..d07116b13 --- /dev/null +++ b/src/test/ui/async-await/feature-async-closure.rs @@ -0,0 +1,8 @@ +// edition:2018 +// gate-test-async_closure + +fn f() { + let _ = async || {}; //~ ERROR async closures are unstable +} + +fn main() {} diff --git a/src/test/ui/async-await/feature-async-closure.stderr b/src/test/ui/async-await/feature-async-closure.stderr new file mode 100644 index 000000000..485a838b6 --- /dev/null +++ b/src/test/ui/async-await/feature-async-closure.stderr @@ -0,0 +1,13 @@ +error[E0658]: async closures are unstable + --> $DIR/feature-async-closure.rs:5:13 + | +LL | let _ = async || {}; + | ^^^^^ + | + = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = help: to use an async block, remove the `||`: `async {` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/async-await/futures-api.rs b/src/test/ui/async-await/futures-api.rs new file mode 100644 index 000000000..a7da058de --- /dev/null +++ b/src/test/ui/async-await/futures-api.rs @@ -0,0 +1,61 @@ +// run-pass + +// aux-build:arc_wake.rs + +extern crate arc_wake; + +use std::future::Future; +use std::pin::Pin; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{ + Context, Poll, +}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc<Self>) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct MyFuture; + +impl Future for MyFuture { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + // Wake twice + let waker = cx.waker(); + waker.wake_by_ref(); + waker.wake_by_ref(); + Poll::Ready(()) + } +} + +fn test_waker() { + let counter = Arc::new(Counter { + wakes: AtomicUsize::new(0), + }); + let waker = ArcWake::into_waker(counter.clone()); + assert_eq!(2, Arc::strong_count(&counter)); + { + let mut context = Context::from_waker(&waker); + assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&mut context)); + assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); + } + drop(waker); + assert_eq!(1, Arc::strong_count(&counter)); +} + +fn main() { + test_waker(); +} diff --git a/src/test/ui/async-await/generator-desc.rs b/src/test/ui/async-await/generator-desc.rs new file mode 100644 index 000000000..500812016 --- /dev/null +++ b/src/test/ui/async-await/generator-desc.rs @@ -0,0 +1,16 @@ +// edition:2018 +#![feature(async_closure)] +use std::future::Future; + +async fn one() {} +async fn two() {} + +fn fun<F: Future<Output = ()>>(f1: F, f2: F) {} +fn main() { + fun(async {}, async {}); + //~^ ERROR mismatched types + fun(one(), two()); + //~^ ERROR mismatched types + fun((async || {})(), (async || {})()); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/async-await/generator-desc.stderr b/src/test/ui/async-await/generator-desc.stderr new file mode 100644 index 000000000..3be8c5520 --- /dev/null +++ b/src/test/ui/async-await/generator-desc.stderr @@ -0,0 +1,74 @@ +error[E0308]: mismatched types + --> $DIR/generator-desc.rs:10:25 + | +LL | fun(async {}, async {}); + | -- ^^ + | | | + | | expected `async` block, found a different `async` block + | | arguments to this function are incorrect + | the expected `async` block + | + = note: expected `async` block `[static generator@$DIR/generator-desc.rs:10:15: 10:17]` + found `async` block `[static generator@$DIR/generator-desc.rs:10:25: 10:27]` +note: function defined here + --> $SRC_DIR/core/src/future/mod.rs:LL:COL + | +LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return> + | ^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/generator-desc.rs:12:16 + | +LL | fun(one(), two()); + | --- ^^^^^ expected opaque type, found a different opaque type + | | + | arguments to this function are incorrect + | +note: while checking the return type of the `async fn` + --> $DIR/generator-desc.rs:5:16 + | +LL | async fn one() {} + | ^ checked the `Output` of this `async fn`, expected opaque type +note: while checking the return type of the `async fn` + --> $DIR/generator-desc.rs:6:16 + | +LL | async fn two() {} + | ^ checked the `Output` of this `async fn`, found opaque type + = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>) + found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>) + = help: consider `await`ing on both `Future`s + = note: distinct uses of `impl Trait` result in different opaque types +note: function defined here + --> $DIR/generator-desc.rs:8:4 + | +LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {} + | ^^^ ----- ----- + +error[E0308]: mismatched types + --> $DIR/generator-desc.rs:14:26 + | +LL | fun((async || {})(), (async || {})()); + | --- -- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body + | | | + | | the expected `async` closure body + | arguments to this function are incorrect + | + ::: $SRC_DIR/core/src/future/mod.rs:LL:COL + | +LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return> + | ------------------------------- + | | + | the expected opaque type + | the found opaque type + | + = note: expected opaque type `impl Future<Output = ()>` (`async` closure body) + found opaque type `impl Future<Output = ()>` (`async` closure body) +note: function defined here + --> $DIR/generator-desc.rs:8:4 + | +LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {} + | ^^^ ----- ----- + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/generics-and-bounds.rs b/src/test/ui/async-await/generics-and-bounds.rs new file mode 100644 index 000000000..963b19b34 --- /dev/null +++ b/src/test/ui/async-await/generics-and-bounds.rs @@ -0,0 +1,88 @@ +// build-pass (FIXME(62277): could be check-pass?) +// edition:2018 +// compile-flags: --crate-type lib + +use std::future::Future; + +pub async fn simple_generic<T>() {} + +pub trait Foo { + fn foo(&self) {} +} + +struct FooType; +impl Foo for FooType {} + +pub async fn call_generic_bound<F: Foo>(f: F) { + f.foo() +} + +pub async fn call_where_clause<F>(f: F) +where + F: Foo, +{ + f.foo() +} + +pub async fn call_impl_trait(f: impl Foo) { + f.foo() +} + +pub async fn call_with_ref(f: &impl Foo) { + f.foo() +} + +pub fn async_fn_with_same_generic_params_unifies() { + let mut a = call_generic_bound(FooType); + a = call_generic_bound(FooType); + + let mut b = call_where_clause(FooType); + b = call_where_clause(FooType); + + let mut c = call_impl_trait(FooType); + c = call_impl_trait(FooType); + + let f_one = FooType; + let f_two = FooType; + let mut d = call_with_ref(&f_one); + d = call_with_ref(&f_two); +} + +pub fn simple_generic_block<T>() -> impl Future<Output = ()> { + async move {} +} + +pub fn call_generic_bound_block<F: Foo>(f: F) -> impl Future<Output = ()> { + async move { f.foo() } +} + +pub fn call_where_clause_block<F>(f: F) -> impl Future<Output = ()> +where + F: Foo, +{ + async move { f.foo() } +} + +pub fn call_impl_trait_block(f: impl Foo) -> impl Future<Output = ()> { + async move { f.foo() } +} + +pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future<Output = ()> + 'a { + async move { f.foo() } +} + +pub fn async_block_with_same_generic_params_unifies() { + let mut a = call_generic_bound_block(FooType); + a = call_generic_bound_block(FooType); + + let mut b = call_where_clause_block(FooType); + b = call_where_clause_block(FooType); + + let mut c = call_impl_trait_block(FooType); + c = call_impl_trait_block(FooType); + + let f_one = FooType; + let f_two = FooType; + let mut d = call_with_ref_block(&f_one); + d = call_with_ref_block(&f_two); +} diff --git a/src/test/ui/async-await/incorrect-move-async-order-issue-79694.fixed b/src/test/ui/async-await/incorrect-move-async-order-issue-79694.fixed new file mode 100644 index 000000000..055800d23 --- /dev/null +++ b/src/test/ui/async-await/incorrect-move-async-order-issue-79694.fixed @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/async-await/incorrect-move-async-order-issue-79694.rs b/src/test/ui/async-await/incorrect-move-async-order-issue-79694.rs new file mode 100644 index 000000000..e8be16516 --- /dev/null +++ b/src/test/ui/async-await/incorrect-move-async-order-issue-79694.rs @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/async-await/incorrect-move-async-order-issue-79694.stderr b/src/test/ui/async-await/incorrect-move-async-order-issue-79694.stderr new file mode 100644 index 000000000..5367b986d --- /dev/null +++ b/src/test/ui/async-await/incorrect-move-async-order-issue-79694.stderr @@ -0,0 +1,13 @@ +error: the order of `move` and `async` is incorrect + --> $DIR/incorrect-move-async-order-issue-79694.rs:7:13 + | +LL | let _ = move async { }; + | ^^^^^^^^^^ + | +help: try switching the order + | +LL | let _ = async move { }; + | ~~~~~~~~~~ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/interior-with-const-generic-expr.rs b/src/test/ui/async-await/interior-with-const-generic-expr.rs new file mode 100644 index 000000000..86ba7582d --- /dev/null +++ b/src/test/ui/async-await/interior-with-const-generic-expr.rs @@ -0,0 +1,26 @@ +// edition:2018 +// run-pass + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] +#![allow(unused)] + +fn main() { + let x = test(); +} + +fn concat<const A: usize, const B: usize>(a: [f32; A], b: [f32; B]) -> [f32; A + B] { + todo!() +} + +async fn reverse<const A: usize>(x: [f32; A]) -> [f32; A] { + todo!() +} + +async fn test() { + let a = [0.0]; + let b = [1.0, 2.0]; + let ab = concat(a,b); + let ba = reverse(ab).await; + println!("{:?}", ba); +} diff --git a/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs b/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs new file mode 100644 index 000000000..16cf7ad52 --- /dev/null +++ b/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs @@ -0,0 +1,17 @@ +// Regression test for #54239, shouldn't trigger lint. +// check-pass +// edition:2018 + +#![deny(missing_debug_implementations)] + +struct DontLookAtMe(i32); + +async fn secret() -> DontLookAtMe { + DontLookAtMe(41) +} + +pub async fn looking() -> i32 { // Shouldn't trigger lint here. + secret().await.0 +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-60709.rs b/src/test/ui/async-await/issue-60709.rs new file mode 100644 index 000000000..61f6ed1b7 --- /dev/null +++ b/src/test/ui/async-await/issue-60709.rs @@ -0,0 +1,28 @@ +// This used to compile the future down to ud2, due to uninhabited types being +// handled incorrectly in generators. +// compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018 + +// run-pass +// ignore-asmjs wasm2js does not support source maps yet + +use std::future::Future; +use std::task::Poll; +use std::task::Context; +use std::pin::Pin; +use std::rc::Rc; + +struct Never(); +impl Future for Never { + type Output = (); + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Pending + } +} + +fn main() { + let fut = async { + let _rc = Rc::new(()); // Also crashes with Arc + Never().await; + }; + let _bla = fut; // Moving the future is required. +} diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs new file mode 100644 index 000000000..750fad839 --- /dev/null +++ b/src/test/ui/async-await/issue-61076.rs @@ -0,0 +1,97 @@ +// edition:2018 + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct T; + +struct Tuple(i32); + +struct Struct { + a: i32 +} + +impl Struct { + fn method(&self) {} +} + +impl Future for Struct { + type Output = Struct; + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { Poll::Pending } +} + +impl Future for Tuple { + type Output = Tuple; + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { Poll::Pending } +} + +impl Future for T { + type Output = Result<(), ()>; + + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Pending + } +} + +async fn foo() -> Result<(), ()> { + Ok(()) +} + +async fn bar() -> Result<(), ()> { + foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` + //~^ NOTE the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>` + //~| HELP the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>` + //~| HELP consider `await`ing on the `Future` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + Ok(()) +} + +async fn struct_() -> Struct { + Struct { a: 1 } +} + +async fn tuple() -> Tuple { + //~^ NOTE checked the `Output` of this `async fn`, expected opaque type + //~| NOTE while checking the return type of the `async fn` + //~| NOTE in this expansion of desugaring of `async` block or function + Tuple(1i32) +} + +async fn baz() -> Result<(), ()> { + let t = T; + t?; //~ ERROR the `?` operator can only be applied to values that implement `Try` + //~^ NOTE the `?` operator cannot be applied to type `T` + //~| HELP the trait `Try` is not implemented for `T` + //~| HELP consider `await`ing on the `Future` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + + + let _: i32 = tuple().0; //~ ERROR no field `0` + //~^ HELP consider `await`ing on the `Future` + //~| NOTE field not available in `impl Future` + + let _: i32 = struct_().a; //~ ERROR no field `a` + //~^ HELP consider `await`ing on the `Future` + //~| NOTE field not available in `impl Future` + + struct_().method(); //~ ERROR no method named + //~^ NOTE method not found in `impl Future<Output = Struct>` + //~| HELP consider `await`ing on the `Future` + Ok(()) +} + +async fn match_() { + match tuple() { //~ HELP consider `await`ing on the `Future` + //~^ NOTE this expression has type `impl Future<Output = Tuple>` + Tuple(_) => {} //~ ERROR mismatched types + //~^ NOTE expected opaque type, found struct `Tuple` + //~| NOTE expected opaque type `impl Future<Output = Tuple>` + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr new file mode 100644 index 000000000..33839ea59 --- /dev/null +++ b/src/test/ui/async-await/issue-61076.stderr @@ -0,0 +1,82 @@ +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/issue-61076.rs:42:5 + | +LL | foo()?; + | ^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>` + | + = help: the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>` +help: consider `await`ing on the `Future` + | +LL | foo().await?; + | ++++++ + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/issue-61076.rs:65:5 + | +LL | t?; + | ^^ the `?` operator cannot be applied to type `T` + | + = help: the trait `Try` is not implemented for `T` +help: consider `await`ing on the `Future` + | +LL | t.await?; + | ++++++ + +error[E0609]: no field `0` on type `impl Future<Output = Tuple>` + --> $DIR/issue-61076.rs:74:26 + | +LL | let _: i32 = tuple().0; + | ^ field not available in `impl Future`, but it is available in its `Output` + | +help: consider `await`ing on the `Future` and access the field of its `Output` + | +LL | let _: i32 = tuple().await.0; + | ++++++ + +error[E0609]: no field `a` on type `impl Future<Output = Struct>` + --> $DIR/issue-61076.rs:78:28 + | +LL | let _: i32 = struct_().a; + | ^ field not available in `impl Future`, but it is available in its `Output` + | +help: consider `await`ing on the `Future` and access the field of its `Output` + | +LL | let _: i32 = struct_().await.a; + | ++++++ + +error[E0599]: no method named `method` found for opaque type `impl Future<Output = Struct>` in the current scope + --> $DIR/issue-61076.rs:82:15 + | +LL | struct_().method(); + | ^^^^^^ method not found in `impl Future<Output = Struct>` + | +help: consider `await`ing on the `Future` and calling the method on its `Output` + | +LL | struct_().await.method(); + | ++++++ + +error[E0308]: mismatched types + --> $DIR/issue-61076.rs:91:9 + | +LL | match tuple() { + | ------- this expression has type `impl Future<Output = Tuple>` +LL | +LL | Tuple(_) => {} + | ^^^^^^^^ expected opaque type, found struct `Tuple` + | +note: while checking the return type of the `async fn` + --> $DIR/issue-61076.rs:56:21 + | +LL | async fn tuple() -> Tuple { + | ^^^^^ checked the `Output` of this `async fn`, expected opaque type + = note: expected opaque type `impl Future<Output = Tuple>` + found struct `Tuple` +help: consider `await`ing on the `Future` + | +LL | match tuple().await { + | ++++++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0277, E0308, E0599, E0609. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-61452.rs b/src/test/ui/async-await/issue-61452.rs new file mode 100644 index 000000000..9381251ad --- /dev/null +++ b/src/test/ui/async-await/issue-61452.rs @@ -0,0 +1,13 @@ +// edition:2018 + +pub async fn f(x: Option<usize>) { + x.take(); + //~^ ERROR cannot borrow `x` as mutable, as it is not declared as mutable [E0596] +} + +pub async fn g(x: usize) { + x += 1; + //~^ ERROR cannot assign twice to immutable variable `x` [E0384] +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-61452.stderr b/src/test/ui/async-await/issue-61452.stderr new file mode 100644 index 000000000..2d3bb48e0 --- /dev/null +++ b/src/test/ui/async-await/issue-61452.stderr @@ -0,0 +1,23 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/issue-61452.rs:4:5 + | +LL | pub async fn f(x: Option<usize>) { + | - help: consider changing this to be mutable: `mut x` +LL | x.take(); + | ^^^^^^^^ cannot borrow as mutable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/issue-61452.rs:9:5 + | +LL | pub async fn g(x: usize) { + | - + | | + | first assignment to `x` + | help: consider making this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0384, E0596. +For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/async-await/issue-61793.rs b/src/test/ui/async-await/issue-61793.rs new file mode 100644 index 000000000..9180e1d81 --- /dev/null +++ b/src/test/ui/async-await/issue-61793.rs @@ -0,0 +1,16 @@ +// This testcase used to ICE in codegen due to inconsistent field reordering +// in the generator state, claiming a ZST field was after a non-ZST field, +// while those two fields were at the same offset (which is impossible). +// That is, memory ordering of `(X, ())`, but offsets of `((), X)`. + +// build-pass +// edition:2018 + +async fn foo<F>(_: &(), _: F) {} + +fn main() { + foo(&(), || {}); + async { + foo(&(), || {}).await; + }; +} diff --git a/src/test/ui/async-await/issue-61949-self-return-type.rs b/src/test/ui/async-await/issue-61949-self-return-type.rs new file mode 100644 index 000000000..43429ba23 --- /dev/null +++ b/src/test/ui/async-await/issue-61949-self-return-type.rs @@ -0,0 +1,26 @@ +// edition:2018 + +// This test checks that `Self` is prohibited as a return type. See #61949 for context. + +pub struct Foo<'a> { + pub bar: &'a i32, +} + +impl<'a> Foo<'a> { + pub async fn new(_bar: &'a i32) -> Self { + //~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + Foo { + bar: &22 + } + } +} + +async fn foo() { + let x = { + let bar = 22; + Foo::new(&bar).await + }; + drop(x); +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr new file mode 100644 index 000000000..52b726e18 --- /dev/null +++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr @@ -0,0 +1,9 @@ +error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + --> $DIR/issue-61949-self-return-type.rs:10:40 + | +LL | pub async fn new(_bar: &'a i32) -> Self { + | ^^^^ help: consider spelling out the type instead: `Foo<'a>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0760`. diff --git a/src/test/ui/async-await/issue-62658.rs b/src/test/ui/async-await/issue-62658.rs new file mode 100644 index 000000000..d0af01e0c --- /dev/null +++ b/src/test/ui/async-await/issue-62658.rs @@ -0,0 +1,27 @@ +// This test created a generator whose size was not rounded to a multiple of its +// alignment. This caused an assertion error in codegen. + +// build-pass +// edition:2018 + +async fn noop() {} + +async fn foo() { + // This suspend should be the largest variant. + { + let x = [0u8; 17]; + noop().await; + println!("{:?}", x); + } + + // Add one variant that's aligned to 8 bytes. + { + let x = 0u64; + noop().await; + println!("{:?}", x); + } +} + +fn main() { + let _ = foo(); +} diff --git a/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs new file mode 100644 index 000000000..54059b29f --- /dev/null +++ b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs @@ -0,0 +1,19 @@ +// check-pass +// edition:2018 + +struct Test(String); + +impl Test { + async fn borrow_async(&self) {} + + fn with(&mut self, s: &str) -> &mut Self { + self.0 = s.into(); + self + } +} + +async fn test() { + Test("".to_string()).with("123").borrow_async().await; +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs new file mode 100644 index 000000000..c5ea2b821 --- /dev/null +++ b/src/test/ui/async-await/issue-63832-await-short-temporary-lifetime.rs @@ -0,0 +1,12 @@ +// check-pass +// edition:2018 + +async fn foo(x: &[Vec<u32>]) -> u32 { + 0 +} + +async fn bar() { + foo(&[vec![123]]).await; +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-64130-1-sync.rs b/src/test/ui/async-await/issue-64130-1-sync.rs new file mode 100644 index 000000000..af83f14bb --- /dev/null +++ b/src/test/ui/async-await/issue-64130-1-sync.rs @@ -0,0 +1,23 @@ +#![feature(negative_impls)] +// edition:2018 + +// This tests the the specialized async-await-specific error when futures don't implement an +// auto trait (which is specifically Sync) due to some type that was captured. + +struct Foo; + +impl !Sync for Foo {} + +fn is_sync<T: Sync>(t: T) { } + +async fn bar() { + let x = Foo; + baz().await; +} + +async fn baz() { } + +fn main() { + is_sync(bar()); + //~^ ERROR future cannot be shared between threads safely +} diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr new file mode 100644 index 000000000..e205de473 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-1-sync.stderr @@ -0,0 +1,24 @@ +error: future cannot be shared between threads safely + --> $DIR/issue-64130-1-sync.rs:21:13 + | +LL | is_sync(bar()); + | ^^^^^ future returned by `bar` is not `Sync` + | + = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo` +note: future is not `Sync` as this value is used across an await + --> $DIR/issue-64130-1-sync.rs:15:10 + | +LL | let x = Foo; + | - has type `Foo` which is not `Sync` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here +note: required by a bound in `is_sync` + --> $DIR/issue-64130-1-sync.rs:11:15 + | +LL | fn is_sync<T: Sync>(t: T) { } + | ^^^^ required by this bound in `is_sync` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-64130-2-send.rs b/src/test/ui/async-await/issue-64130-2-send.rs new file mode 100644 index 000000000..2362831d8 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-2-send.rs @@ -0,0 +1,23 @@ +#![feature(negative_impls)] +// edition:2018 + +// This tests the the specialized async-await-specific error when futures don't implement an +// auto trait (which is specifically Send) due to some type that was captured. + +struct Foo; + +impl !Send for Foo {} + +fn is_send<T: Send>(t: T) { } + +async fn bar() { + let x = Foo; + baz().await; +} + +async fn baz() { } + +fn main() { + is_send(bar()); + //~^ ERROR future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr new file mode 100644 index 000000000..2225000e2 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-2-send.stderr @@ -0,0 +1,24 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-64130-2-send.rs:21:13 + | +LL | is_send(bar()); + | ^^^^^ future returned by `bar` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-64130-2-send.rs:15:10 + | +LL | let x = Foo; + | - has type `Foo` which is not `Send` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here +note: required by a bound in `is_send` + --> $DIR/issue-64130-2-send.rs:11:15 + | +LL | fn is_send<T: Send>(t: T) { } + | ^^^^ required by this bound in `is_send` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-64130-3-other.rs b/src/test/ui/async-await/issue-64130-3-other.rs new file mode 100644 index 000000000..52801c35b --- /dev/null +++ b/src/test/ui/async-await/issue-64130-3-other.rs @@ -0,0 +1,26 @@ +#![feature(auto_traits)] +#![feature(negative_impls)] +// edition:2018 + +// This tests the the unspecialized async-await-specific error when futures don't implement an +// auto trait (which is not Send or Sync) due to some type that was captured. + +auto trait Qux {} + +struct Foo; + +impl !Qux for Foo {} + +fn is_qux<T: Qux>(t: T) {} + +async fn bar() { + let x = Foo; + baz().await; +} + +async fn baz() {} + +fn main() { + is_qux(bar()); + //~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>` +} diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr new file mode 100644 index 000000000..17867a6a3 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>` + --> $DIR/issue-64130-3-other.rs:24:12 + | +LL | async fn bar() { + | - within this `impl Future<Output = ()>` +... +LL | is_qux(bar()); + | ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo` + | +note: future does not implement `Qux` as this value is used across an await + --> $DIR/issue-64130-3-other.rs:18:10 + | +LL | let x = Foo; + | - has type `Foo` which does not implement `Qux` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here +note: required by a bound in `is_qux` + --> $DIR/issue-64130-3-other.rs:14:14 + | +LL | fn is_qux<T: Qux>(t: T) {} + | ^^^ required by this bound in `is_qux` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-64130-4-async-move.rs b/src/test/ui/async-await/issue-64130-4-async-move.rs new file mode 100644 index 000000000..2538f3435 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-4-async-move.rs @@ -0,0 +1,28 @@ +// edition:2018 +use std::any::Any; +use std::future::Future; + +struct Client(Box<dyn Any + Send>); + +impl Client { + fn status(&self) -> u16 { + 200 + } +} + +async fn get() { } + +pub fn foo() -> impl Future + Send { + //~^ ERROR future cannot be sent between threads safely + let client = Client(Box::new(true)); + async move { + match client.status() { + 200 => { + let _x = get().await; + }, + _ => (), + } + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr new file mode 100644 index 000000000..d631e6dc7 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -0,0 +1,26 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-64130-4-async-move.rs:15:17 + | +LL | pub fn foo() -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | + = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-64130-4-async-move.rs:21:31 + | +LL | match client.status() { + | ------ has type `&Client` which is not `Send` +LL | 200 => { +LL | let _x = get().await; + | ^^^^^^ await occurs here, with `client` maybe used later +... +LL | } + | - `client` is later dropped here +help: consider moving this into a `let` binding to create a shorter lived borrow + --> $DIR/issue-64130-4-async-move.rs:19:15 + | +LL | match client.status() { + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs new file mode 100644 index 000000000..b652d2391 --- /dev/null +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs @@ -0,0 +1,25 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![allow(must_not_suspend)] + +// This tests the basic example case for the async-await-specific error. + +use std::sync::Mutex; + +fn is_send<T: Send>(t: T) { } + +async fn foo() { + bar(&Mutex::new(22)).await; +} + +async fn bar(x: &Mutex<u32>) { + let g = x.lock().unwrap(); + baz().await; +} + +async fn baz() { } + +fn main() { + is_send(foo()); + //~^ ERROR future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr new file mode 100644 index 000000000..1da80d98b --- /dev/null +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -0,0 +1,24 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-64130-non-send-future-diags.rs:23:13 + | +LL | is_send(foo()); + | ^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-64130-non-send-future-diags.rs:17:10 + | +LL | let g = x.lock().unwrap(); + | - has type `MutexGuard<'_, u32>` which is not `Send` +LL | baz().await; + | ^^^^^^ await occurs here, with `g` maybe used later +LL | } + | - `g` is later dropped here +note: required by a bound in `is_send` + --> $DIR/issue-64130-non-send-future-diags.rs:9:15 + | +LL | fn is_send<T: Send>(t: T) { } + | ^^^^ required by this bound in `is_send` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-64391.rs b/src/test/ui/async-await/issue-64391.rs new file mode 100644 index 000000000..c6faad3aa --- /dev/null +++ b/src/test/ui/async-await/issue-64391.rs @@ -0,0 +1,14 @@ +// Regression test for Issue #64391. The goal here is that this +// function compiles. In the past, due to incorrect drop order for +// temporaries in the tail expression, we failed to compile this +// example. The drop order itself is directly tested in +// `drop-order/drop-order-for-temporary-in-tail-return-expr.rs`. +// +// check-pass +// edition:2018 + +async fn add(x: u32, y: u32) -> u32 { + async { x + y }.await +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-66312.rs b/src/test/ui/async-await/issue-66312.rs new file mode 100644 index 000000000..9224971ec --- /dev/null +++ b/src/test/ui/async-await/issue-66312.rs @@ -0,0 +1,14 @@ +// edition:2018 + +trait Test<T> { + fn is_some(self: T); //~ ERROR invalid `self` parameter type +} + +async fn f() { + let x = Some(2); + if x.is_some() { + println!("Some"); + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-66312.stderr b/src/test/ui/async-await/issue-66312.stderr new file mode 100644 index 000000000..80d294a10 --- /dev/null +++ b/src/test/ui/async-await/issue-66312.stderr @@ -0,0 +1,12 @@ +error[E0307]: invalid `self` parameter type: T + --> $DIR/issue-66312.rs:4:22 + | +LL | fn is_some(self: T); + | ^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0307`. diff --git a/src/test/ui/async-await/issue-66387-if-without-else.rs b/src/test/ui/async-await/issue-66387-if-without-else.rs new file mode 100644 index 000000000..3ab8220b4 --- /dev/null +++ b/src/test/ui/async-await/issue-66387-if-without-else.rs @@ -0,0 +1,10 @@ +// edition:2018 +async fn f() -> i32 { + if true { //~ ERROR `if` may be missing an `else` clause + return 0; + } + // An `if` block without `else` causes the type table not to have a type for this expr. + // Check that we do not unconditionally access the type table and we don't ICE. +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-66387-if-without-else.stderr b/src/test/ui/async-await/issue-66387-if-without-else.stderr new file mode 100644 index 000000000..e8e2a4898 --- /dev/null +++ b/src/test/ui/async-await/issue-66387-if-without-else.stderr @@ -0,0 +1,14 @@ +error[E0317]: `if` may be missing an `else` clause + --> $DIR/issue-66387-if-without-else.rs:3:5 + | +LL | / if true { +LL | | return 0; +LL | | } + | |_____^ expected `()`, found `i32` + | + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0317`. diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.rs b/src/test/ui/async-await/issue-67252-unnamed-future.rs new file mode 100644 index 000000000..1a7ff6133 --- /dev/null +++ b/src/test/ui/async-await/issue-67252-unnamed-future.rs @@ -0,0 +1,24 @@ +// edition:2018 +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +fn spawn<T: Send>(_: T) {} + +pub struct AFuture; +impl Future for AFuture{ + type Output = (); + + fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> { + unimplemented!() + } +} + +async fn foo() { + spawn(async { //~ ERROR future cannot be sent between threads safely + let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` + AFuture.await; + }); +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr new file mode 100644 index 000000000..01c0d3225 --- /dev/null +++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr @@ -0,0 +1,24 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-67252-unnamed-future.rs:18:5 + | +LL | spawn(async { + | ^^^^^ future created by async block is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*mut ()` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-67252-unnamed-future.rs:20:16 + | +LL | let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` + | -- has type `*mut ()` which is not `Send` +LL | AFuture.await; + | ^^^^^^ await occurs here, with `_a` maybe used later +LL | }); + | - `_a` is later dropped here +note: required by a bound in `spawn` + --> $DIR/issue-67252-unnamed-future.rs:6:13 + | +LL | fn spawn<T: Send>(_: T) {} + | ^^^^ required by this bound in `spawn` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-67651.rs b/src/test/ui/async-await/issue-67651.rs new file mode 100644 index 000000000..bd96a3b70 --- /dev/null +++ b/src/test/ui/async-await/issue-67651.rs @@ -0,0 +1,20 @@ +// edition:2018 + +trait From { + fn from(); +} + +impl From for () { + fn from() {} +} + +impl From for () { +//~^ ERROR conflicting implementations of trait + fn from() {} +} + +fn bar() -> impl core::future::Future<Output = ()> { + async move { From::from() } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-67651.stderr b/src/test/ui/async-await/issue-67651.stderr new file mode 100644 index 000000000..89017f6cc --- /dev/null +++ b/src/test/ui/async-await/issue-67651.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `From` for type `()` + --> $DIR/issue-67651.rs:11:1 + | +LL | impl From for () { + | ---------------- first implementation here +... +LL | impl From for () { + | ^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/async-await/issue-67765-async-diagnostic.rs b/src/test/ui/async-await/issue-67765-async-diagnostic.rs new file mode 100644 index 000000000..5093916e7 --- /dev/null +++ b/src/test/ui/async-await/issue-67765-async-diagnostic.rs @@ -0,0 +1,16 @@ +// edition:2018 +// +// Regression test for issue #67765 +// Tests that we point at the proper location when giving +// a lifetime error. +fn main() {} + +async fn func<'a>() -> Result<(), &'a str> { + let s = String::new(); + + let b = &s[..]; + + Err(b)?; //~ ERROR cannot return value referencing local variable `s` + + Ok(()) +} diff --git a/src/test/ui/async-await/issue-67765-async-diagnostic.stderr b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr new file mode 100644 index 000000000..492e06fbb --- /dev/null +++ b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing local variable `s` + --> $DIR/issue-67765-async-diagnostic.rs:13:5 + | +LL | let b = &s[..]; + | - `s` is borrowed here +LL | +LL | Err(b)?; + | ^^^^^^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/async-await/issue-68112.rs b/src/test/ui/async-await/issue-68112.rs new file mode 100644 index 000000000..bfabf81d1 --- /dev/null +++ b/src/test/ui/async-await/issue-68112.rs @@ -0,0 +1,64 @@ +// edition:2018 + +use std::{ + future::Future, + cell::RefCell, + sync::Arc, + pin::Pin, + task::{Context, Poll}, +}; + +fn require_send(_: impl Send) {} + +struct Ready<T>(Option<T>); +impl<T> Future for Ready<T> { + type Output = T; + fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> { + Poll::Ready(self.0.take().unwrap()) + } +} +fn ready<T>(t: T) -> Ready<T> { + Ready(Some(t)) +} + +fn make_non_send_future1() -> impl Future<Output = Arc<RefCell<i32>>> { + ready(Arc::new(RefCell::new(0))) +} + +fn test1() { + let send_fut = async { + let non_send_fut = make_non_send_future1(); + let _ = non_send_fut.await; + ready(0).await; + }; + require_send(send_fut); + //~^ ERROR future cannot be sent between threads +} + +fn test1_no_let() { + let send_fut = async { + let _ = make_non_send_future1().await; + ready(0).await; + }; + require_send(send_fut); + //~^ ERROR future cannot be sent between threads +} + +async fn ready2<T>(t: T) -> T { t } +fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> { + ready2(Arc::new(RefCell::new(0))) +} + +// Ideally this test would have diagnostics similar to the test above, but right +// now it doesn't. +fn test2() { + let send_fut = async { + let non_send_fut = make_non_send_future2(); + let _ = non_send_fut.await; + ready(0).await; + }; + require_send(send_fut); + //~^ ERROR `RefCell<i32>` cannot be shared between threads safely +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr new file mode 100644 index 000000000..4285fbbec --- /dev/null +++ b/src/test/ui/async-await/issue-68112.stderr @@ -0,0 +1,74 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-68112.rs:34:5 + | +LL | require_send(send_fut); + | ^^^^^^^^^^^^ future created by async block is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/issue-68112.rs:31:17 + | +LL | let _ = non_send_fut.await; + | ^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send` +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:11:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error: future cannot be sent between threads safely + --> $DIR/issue-68112.rs:43:5 + | +LL | require_send(send_fut); + | ^^^^^^^^^^^^ future created by async block is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/issue-68112.rs:40:17 + | +LL | let _ = make_non_send_future1().await; + | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send` +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:11:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error[E0277]: `RefCell<i32>` cannot be shared between threads safely + --> $DIR/issue-68112.rs:60:5 + | +LL | require_send(send_fut); + | ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>` +note: required because it's used within this `async fn` body + --> $DIR/issue-68112.rs:47:31 + | +LL | async fn ready2<T>(t: T) -> T { t } + | ^^^^^ +note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>` + --> $DIR/issue-68112.rs:48:31 + | +LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>` +note: required because it's used within this `async` block + --> $DIR/issue-68112.rs:55:26 + | +LL | let send_fut = async { + | __________________________^ +LL | | let non_send_fut = make_non_send_future2(); +LL | | let _ = non_send_fut.await; +LL | | ready(0).await; +LL | | }; + | |_____^ +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:11:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-68523-start.rs b/src/test/ui/async-await/issue-68523-start.rs new file mode 100644 index 000000000..2ced88a16 --- /dev/null +++ b/src/test/ui/async-await/issue-68523-start.rs @@ -0,0 +1,9 @@ +// edition:2018 + +#![feature(start)] + +#[start] +pub async fn start(_: isize, _: *const *const u8) -> isize { +//~^ ERROR `start` is not allowed to be `async` + 0 +} diff --git a/src/test/ui/async-await/issue-68523-start.stderr b/src/test/ui/async-await/issue-68523-start.stderr new file mode 100644 index 000000000..3a0a3b5de --- /dev/null +++ b/src/test/ui/async-await/issue-68523-start.stderr @@ -0,0 +1,9 @@ +error[E0752]: `start` is not allowed to be `async` + --> $DIR/issue-68523-start.rs:6:1 + | +LL | pub async fn start(_: isize, _: *const *const u8) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `start` is not allowed to be `async` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0752`. diff --git a/src/test/ui/async-await/issue-68523.rs b/src/test/ui/async-await/issue-68523.rs new file mode 100644 index 000000000..7a67661a0 --- /dev/null +++ b/src/test/ui/async-await/issue-68523.rs @@ -0,0 +1,6 @@ +// edition:2018 + +async fn main() -> Result<i32, ()> { +//~^ ERROR `main` function is not allowed to be `async` + Ok(1) +} diff --git a/src/test/ui/async-await/issue-68523.stderr b/src/test/ui/async-await/issue-68523.stderr new file mode 100644 index 000000000..dfdf078e3 --- /dev/null +++ b/src/test/ui/async-await/issue-68523.stderr @@ -0,0 +1,9 @@ +error[E0752]: `main` function is not allowed to be `async` + --> $DIR/issue-68523.rs:3:1 + | +LL | async fn main() -> Result<i32, ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` function is not allowed to be `async` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0752`. diff --git a/src/test/ui/async-await/issue-69446-fnmut-capture.rs b/src/test/ui/async-await/issue-69446-fnmut-capture.rs new file mode 100644 index 000000000..842115538 --- /dev/null +++ b/src/test/ui/async-await/issue-69446-fnmut-capture.rs @@ -0,0 +1,22 @@ +// Regression test for issue #69446 - we should display +// which variable is captured +// edition:2018 + +use core::future::Future; + +struct Foo; +impl Foo { + fn foo(&mut self) {} +} + +async fn bar<T>(_: impl FnMut() -> T) +where + T: Future<Output = ()>, +{} + +fn main() { + let mut x = Foo; + bar(move || async { //~ ERROR captured + x.foo(); + }); +} diff --git a/src/test/ui/async-await/issue-69446-fnmut-capture.stderr b/src/test/ui/async-await/issue-69446-fnmut-capture.stderr new file mode 100644 index 000000000..3d2b0402b --- /dev/null +++ b/src/test/ui/async-await/issue-69446-fnmut-capture.stderr @@ -0,0 +1,19 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-69446-fnmut-capture.rs:19:17 + | +LL | let mut x = Foo; + | ----- variable defined here +LL | bar(move || async { + | _______________-_^ + | | | + | | inferred to be a `FnMut` closure +LL | | x.foo(); + | | - variable captured here +LL | | }); + | |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-70594.rs b/src/test/ui/async-await/issue-70594.rs new file mode 100644 index 000000000..9e7c5847b --- /dev/null +++ b/src/test/ui/async-await/issue-70594.rs @@ -0,0 +1,11 @@ +// edition:2018 + +async fn fun() { + [1; ().await]; + //~^ error: `await` is only allowed inside `async` functions and blocks + //~| error: `.await` is not allowed in a `const` + //~| error: `.await` is not allowed in a `const` + //~| error: `()` is not a future +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr new file mode 100644 index 000000000..a88bce6cc --- /dev/null +++ b/src/test/ui/async-await/issue-70594.stderr @@ -0,0 +1,39 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-70594.rs:4:11 + | +LL | async fn fun() { + | --- this is not `async` +LL | [1; ().await]; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0744]: `.await` is not allowed in a `const` + --> $DIR/issue-70594.rs:4:9 + | +LL | [1; ().await]; + | ^^^^^^^^ + +error[E0744]: `.await` is not allowed in a `const` + --> $DIR/issue-70594.rs:4:11 + | +LL | [1; ().await]; + | ^^^^^^ + +error[E0277]: `()` is not a future + --> $DIR/issue-70594.rs:4:11 + | +LL | [1; ().await]; + | ^^^^^^ `()` is not a future + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + = note: required because of the requirements on the impl of `IntoFuture` for `()` +help: remove the `.await` + | +LL - [1; ().await]; +LL + [1; ()]; + | + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0728, E0744. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-70818.rs b/src/test/ui/async-await/issue-70818.rs new file mode 100644 index 000000000..019c56eb2 --- /dev/null +++ b/src/test/ui/async-await/issue-70818.rs @@ -0,0 +1,9 @@ +// edition:2018 + +use std::future::Future; +fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + //~^ Error future cannot be sent between threads safely + async { (ty, ty1) } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr new file mode 100644 index 000000000..20109d4d1 --- /dev/null +++ b/src/test/ui/async-await/issue-70818.stderr @@ -0,0 +1,18 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-70818.rs:4:38 + | +LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | +note: captured value is not `Send` + --> $DIR/issue-70818.rs:6:18 + | +LL | async { (ty, ty1) } + | ^^^ has type `U` which is not `Send` +help: consider restricting type parameter `U` + | +LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + | +++++++++++++++++++ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr new file mode 100644 index 000000000..2ce7309e1 --- /dev/null +++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr @@ -0,0 +1,35 @@ +error[E0277]: `Sender<i32>` cannot be shared between threads safely + --> $DIR/issue-70935-complex-spans.rs:12:45 + | +LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Sender<i32>` + = note: required because of the requirements on the impl of `Send` for `&Sender<i32>` +note: required because it's used within this closure + --> $DIR/issue-70935-complex-spans.rs:16:13 + | +LL | baz(|| async{ + | ^^ +note: required because it's used within this `async fn` body + --> $DIR/issue-70935-complex-spans.rs:9:67 + | +LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { + | ___________________________________________________________________^ +LL | | } + | |_^ + = note: required because it captures the following types: `ResumeTy`, `impl for<'r, 's, 't0> Future<Output = ()>`, `()` +note: required because it's used within this `async` block + --> $DIR/issue-70935-complex-spans.rs:15:16 + | +LL | async move { + | ________________^ +LL | | baz(|| async{ +LL | | foo(tx.clone()); +LL | | }).await; +LL | | } + | |_____^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr b/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr new file mode 100644 index 000000000..2b81b4000 --- /dev/null +++ b/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr @@ -0,0 +1,25 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-70935-complex-spans.rs:12:45 + | +LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | + = help: the trait `Sync` is not implemented for `Sender<i32>` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-70935-complex-spans.rs:18:11 + | +LL | baz(|| async{ + | _____________- +LL | | foo(tx.clone()); +LL | | }).await; + | | - ^^^^^^ await occurs here, with the value maybe used later + | |_________| + | has type `[closure@$DIR/issue-70935-complex-spans.rs:16:13: 16:15]` which is not `Send` +note: the value is later dropped here + --> $DIR/issue-70935-complex-spans.rs:18:17 + | +LL | }).await; + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-70935-complex-spans.rs b/src/test/ui/async-await/issue-70935-complex-spans.rs new file mode 100644 index 000000000..48847cdf9 --- /dev/null +++ b/src/test/ui/async-await/issue-70935-complex-spans.rs @@ -0,0 +1,28 @@ +// edition:2018 +// revisions: normal drop_tracking +// [drop_tracking]compile-flags:-Zdrop-tracking +// #70935: Check if we do not emit snippet +// with newlines which lead complex diagnostics. + +use std::future::Future; + +async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { +} + +fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { + //[normal]~^ ERROR future cannot be sent between threads safely + //[drop_tracking]~^^ ERROR `Sender<i32>` cannot be shared between threads + async move { + baz(|| async{ + foo(tx.clone()); + }).await; + } +} + +fn bar(_s: impl Future + Send) { +} + +fn main() { + let (tx, _rx) = std::sync::mpsc::channel(); + bar(foo(tx)); +} 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 000000000..7695e0325 --- /dev/null +++ b/src/test/ui/async-await/issue-71137.rs @@ -0,0 +1,23 @@ +// edition:2018 +#![feature(must_not_suspend)] +#![allow(must_not_suspend)] + +use std::future::Future; +use std::sync::Mutex; + +fn fake_spawn<F: Future + Send + 'static>(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 000000000..eade6aa2d --- /dev/null +++ b/src/test/ui/async-await/issue-71137.stderr @@ -0,0 +1,25 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-71137.rs:22:14 + | +LL | fake_spawn(wrong_mutex()); + | ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-71137.rs:14:25 + | +LL | let mut guard = m.lock().unwrap(); + | --------- has type `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 +note: required by a bound in `fake_spawn` + --> $DIR/issue-71137.rs:8:27 + | +LL | fn fake_spawn<F: Future + Send + 'static>(f: F) { } + | ^^^^ required by this bound in `fake_spawn` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-72442.rs b/src/test/ui/async-await/issue-72442.rs new file mode 100644 index 000000000..2280154c7 --- /dev/null +++ b/src/test/ui/async-await/issue-72442.rs @@ -0,0 +1,26 @@ +// edition:2018 +// incremental + +use std::fs::File; +use std::future::Future; +use std::io::prelude::*; + +fn main() -> Result<(), Box<dyn std::error::Error>> { + block_on(async { + { + let path = std::path::Path::new("."); + let mut f = File::open(path.to_str())?; + //~^ ERROR the trait bound + let mut src = String::new(); + f.read_to_string(&mut src)?; + Ok(()) + } + }) +} + +fn block_on<F>(f: F) -> F::Output +where + F: Future<Output = Result<(), Box<dyn std::error::Error>>>, +{ + Ok(()) +} diff --git a/src/test/ui/async-await/issue-72442.stderr b/src/test/ui/async-await/issue-72442.stderr new file mode 100644 index 000000000..919abf646 --- /dev/null +++ b/src/test/ui/async-await/issue-72442.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `Option<&str>: AsRef<Path>` is not satisfied + --> $DIR/issue-72442.rs:12:36 + | +LL | let mut f = File::open(path.to_str())?; + | ---------- ^^^^^^^^^^^^^ the trait `AsRef<Path>` is not implemented for `Option<&str>` + | | + | required by a bound introduced by this call + | +note: required by a bound in `File::open` + --> $SRC_DIR/std/src/fs.rs:LL:COL + | +LL | pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> { + | ^^^^^^^^^^^ required by this bound in `File::open` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-72470-llvm-dominate.rs b/src/test/ui/async-await/issue-72470-llvm-dominate.rs new file mode 100644 index 000000000..5bb69a073 --- /dev/null +++ b/src/test/ui/async-await/issue-72470-llvm-dominate.rs @@ -0,0 +1,66 @@ +// compile-flags: -C opt-level=3 +// aux-build: issue-72470-lib.rs +// edition:2018 +// build-pass + +// Regression test for issue #72470, using the minimization +// in https://github.com/jonas-schievink/llvm-error + +extern crate issue_72470_lib; + +use std::future::Future; +use std::pin::Pin; +use std::sync::Mutex; +use std::task::Poll::{Pending, Ready}; + +#[allow(dead_code)] +enum Msg { + A(Vec<()>), + B, +} + +#[allow(dead_code)] +enum Out { + _0(Option<Msg>), + Disabled, +} + +#[allow(unused_must_use)] +fn main() { + let mut rx = issue_72470_lib::unbounded_channel::<Msg>(); + let entity = Mutex::new(()); + issue_72470_lib::run(async move { + { + let output = { + let mut fut = rx.recv(); + issue_72470_lib::poll_fn(|cx| { + loop { + let fut = unsafe { Pin::new_unchecked(&mut fut) }; + let out = match fut.poll(cx) { + Ready(out) => out, + Pending => { + break; + } + }; + #[allow(unused_variables)] + match &out { + Some(_msg) => {} + _ => break, + } + return Ready(Out::_0(out)); + } + Ready(Out::_0(None)) + }) + .await + }; + match output { + Out::_0(Some(_msg)) => { + entity.lock(); + } + Out::_0(None) => unreachable!(), + _ => unreachable!(), + } + } + entity.lock(); + }); +} diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.rs b/src/test/ui/async-await/issue-72590-type-error-sized.rs new file mode 100644 index 000000000..00e098d43 --- /dev/null +++ b/src/test/ui/async-await/issue-72590-type-error-sized.rs @@ -0,0 +1,22 @@ +// Regression test for issue #72590 +// Tests that we don't emit a spurious "size cannot be statically determined" error +// edition:2018 + +struct Foo { + foo: Nonexistent, //~ ERROR cannot find + other: str +} + +struct Bar { + test: Missing //~ ERROR cannot find +} + +impl Foo { + async fn frob(self) {} //~ ERROR the size +} + +impl Bar { + async fn myfn(self) {} +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr new file mode 100644 index 000000000..778423578 --- /dev/null +++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr @@ -0,0 +1,34 @@ +error[E0412]: cannot find type `Nonexistent` in this scope + --> $DIR/issue-72590-type-error-sized.rs:6:10 + | +LL | foo: Nonexistent, + | ^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/issue-72590-type-error-sized.rs:11:11 + | +LL | test: Missing + | ^^^^^^^ not found in this scope + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-72590-type-error-sized.rs:15:19 + | +LL | async fn frob(self) {} + | ^^^^ doesn't have a size known at compile-time + | + = help: within `Foo`, the trait `Sized` is not implemented for `str` +note: required because it appears within the type `Foo` + --> $DIR/issue-72590-type-error-sized.rs:5:8 + | +LL | struct Foo { + | ^^^ + = help: unsized fn params are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | async fn frob(&self) {} + | + + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0412. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-73050.rs b/src/test/ui/async-await/issue-73050.rs new file mode 100644 index 000000000..790f24a23 --- /dev/null +++ b/src/test/ui/async-await/issue-73050.rs @@ -0,0 +1,12 @@ +// check-pass +// edition:2018 + +#[allow(unused)] +async fn foo<'a>() { + let _data = &mut [0u8; { 1 + 4 }]; + bar().await +} + +async fn bar() {} + +fn main() {} diff --git a/src/test/ui/async-await/issue-73137.rs b/src/test/ui/async-await/issue-73137.rs new file mode 100644 index 000000000..c43ce2cad --- /dev/null +++ b/src/test/ui/async-await/issue-73137.rs @@ -0,0 +1,41 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/73137> + +// run-pass +// edition:2018 + +#![allow(dead_code)] +use std::future::Future; +use std::task::{Waker, Wake, Context}; +use std::sync::Arc; + +struct DummyWaker; +impl Wake for DummyWaker { + fn wake(self: Arc<Self>) {} +} + +struct Foo { + a: usize, + b: &'static u32, +} + +#[inline(never)] +fn nop<T>(_: T) {} + +fn main() { + let mut fut = Box::pin(async { + let action = Foo { + b: &42, + a: async { 0 }.await, + }; + + // An error in the generator transform caused `b` to be overwritten with `a` when `b` was + // borrowed. + nop(&action.b); + assert_ne!(0usize, unsafe { std::mem::transmute(action.b) }); + + async {}.await; + }); + let waker = Waker::from(Arc::new(DummyWaker)); + let mut cx = Context::from_waker(&waker); + let _ = fut.as_mut().poll(&mut cx); +} diff --git a/src/test/ui/async-await/issue-73541-1.rs b/src/test/ui/async-await/issue-73541-1.rs new file mode 100644 index 000000000..7fb0d6c39 --- /dev/null +++ b/src/test/ui/async-await/issue-73541-1.rs @@ -0,0 +1,12 @@ +// edition:2018 + +fn main() { + 'a: loop { + async { + loop { + continue 'a + //~^ ERROR use of unreachable label `'a` + } + }; + } +} diff --git a/src/test/ui/async-await/issue-73541-1.stderr b/src/test/ui/async-await/issue-73541-1.stderr new file mode 100644 index 000000000..80c1fdf00 --- /dev/null +++ b/src/test/ui/async-await/issue-73541-1.stderr @@ -0,0 +1,14 @@ +error[E0767]: use of unreachable label `'a` + --> $DIR/issue-73541-1.rs:7:26 + | +LL | 'a: loop { + | -- unreachable label defined here +... +LL | continue 'a + | ^^ unreachable label `'a` + | + = note: labels are unreachable through functions, closures, async blocks and modules + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0767`. diff --git a/src/test/ui/async-await/issue-73541-2.rs b/src/test/ui/async-await/issue-73541-2.rs new file mode 100644 index 000000000..70b4ab253 --- /dev/null +++ b/src/test/ui/async-await/issue-73541-2.rs @@ -0,0 +1,20 @@ +// edition:2018 + +async fn c() { + 'a: loop { + macro_rules! b { + () => { + continue 'a + //~^ ERROR use of unreachable label `'a` + } + } + + async { + loop { + b!(); + } + }; + } +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-73541-2.stderr b/src/test/ui/async-await/issue-73541-2.stderr new file mode 100644 index 000000000..4c9741f6f --- /dev/null +++ b/src/test/ui/async-await/issue-73541-2.stderr @@ -0,0 +1,18 @@ +error[E0767]: use of unreachable label `'a` + --> $DIR/issue-73541-2.rs:7:26 + | +LL | 'a: loop { + | -- unreachable label defined here +... +LL | continue 'a + | ^^ unreachable label `'a` +... +LL | b!(); + | ---- in this macro invocation + | + = note: labels are unreachable through functions, closures, async blocks and modules + = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0767`. diff --git a/src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs new file mode 100644 index 000000000..c3423ad62 --- /dev/null +++ b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs @@ -0,0 +1,14 @@ +// edition:2018 +// compile-flags: -Zdrop-tracking +// Regression test for issue #73741 +// Ensures that we don't emit spurious errors when +// a type error ocurrs in an `async fn` + +async fn weird() { + 1 = 2; //~ ERROR invalid left-hand side + + let mut loop_count = 0; + async {}.await +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr new file mode 100644 index 000000000..d4e3b6c3b --- /dev/null +++ b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr @@ -0,0 +1,11 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/issue-73741-type-err-drop-tracking.rs:8:7 + | +LL | 1 = 2; + | - ^ + | | + | cannot assign to this expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0070`. diff --git a/src/test/ui/async-await/issue-73741-type-err.rs b/src/test/ui/async-await/issue-73741-type-err.rs new file mode 100644 index 000000000..c5b9e34ed --- /dev/null +++ b/src/test/ui/async-await/issue-73741-type-err.rs @@ -0,0 +1,14 @@ +// edition:2018 +// +// Regression test for issue #73741 +// Ensures that we don't emit spurious errors when +// a type error ocurrs in an `async fn` + +async fn weird() { + 1 = 2; //~ ERROR invalid left-hand side + + let mut loop_count = 0; + async {}.await +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-73741-type-err.stderr b/src/test/ui/async-await/issue-73741-type-err.stderr new file mode 100644 index 000000000..0b5343a98 --- /dev/null +++ b/src/test/ui/async-await/issue-73741-type-err.stderr @@ -0,0 +1,11 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/issue-73741-type-err.rs:8:7 + | +LL | 1 = 2; + | - ^ + | | + | cannot assign to this expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0070`. diff --git a/src/test/ui/async-await/issue-74047.rs b/src/test/ui/async-await/issue-74047.rs new file mode 100644 index 000000000..2e4f3e675 --- /dev/null +++ b/src/test/ui/async-await/issue-74047.rs @@ -0,0 +1,17 @@ +// edition:2018 + +use std::convert::{TryFrom, TryInto}; +use std::io; + +pub struct MyStream; +pub struct OtherStream; + +pub async fn connect() -> io::Result<MyStream> { + let stream: MyStream = OtherStream.try_into()?; + Ok(stream) +} + +impl TryFrom<OtherStream> for MyStream {} +//~^ ERROR: missing + +fn main() {} diff --git a/src/test/ui/async-await/issue-74047.stderr b/src/test/ui/async-await/issue-74047.stderr new file mode 100644 index 000000000..28174825d --- /dev/null +++ b/src/test/ui/async-await/issue-74047.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `Error`, `try_from` + --> $DIR/issue-74047.rs:14:1 + | +LL | impl TryFrom<OtherStream> for MyStream {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error`, `try_from` in implementation + | + = help: implement the missing item: `type Error = Type;` + = help: implement the missing item: `fn try_from(_: T) -> Result<Self, <Self as TryFrom<T>>::Error> { todo!() }` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.rs b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.rs new file mode 100644 index 000000000..95683241a --- /dev/null +++ b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.rs @@ -0,0 +1,37 @@ +// edition:2018 +#![feature(async_closure)] +use std::future::Future; + +// test the quality of annotations giving lifetimes names (`'1`) when async constructs are involved + +pub async fn async_fn(x: &mut i32) -> &i32 { + let y = &*x; + *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed + y +} + +pub fn async_closure(x: &mut i32) -> impl Future<Output=&i32> { + (async move || { + let y = &*x; + *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed + y + })() +} + +pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future<Output=&i32> { + (async move || -> &i32 { + let y = &*x; + *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed + y + })() +} + +pub fn async_block(x: &mut i32) -> impl Future<Output=&i32> { + async move { + let y = &*x; + *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed + y + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr new file mode 100644 index 000000000..b96cab9f0 --- /dev/null +++ b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr @@ -0,0 +1,51 @@ +error[E0506]: cannot assign to `*x` because it is borrowed + --> $DIR/issue-74072-lifetime-name-annotations.rs:9:5 + | +LL | pub async fn async_fn(x: &mut i32) -> &i32 { + | - let's call the lifetime of this reference `'1` +LL | let y = &*x; + | --- borrow of `*x` occurs here +LL | *x += 1; + | ^^^^^^^ assignment to borrowed `*x` occurs here +LL | y + | - returning this value requires that `*x` is borrowed for `'1` + +error[E0506]: cannot assign to `*x` because it is borrowed + --> $DIR/issue-74072-lifetime-name-annotations.rs:16:9 + | +LL | let y = &*x; + | --- borrow of `*x` occurs here +LL | *x += 1; + | ^^^^^^^ assignment to borrowed `*x` occurs here +LL | y + | - returning this value requires that `*x` is borrowed for `'1` +LL | })() + | - return type of async closure is &'1 i32 + +error[E0506]: cannot assign to `*x` because it is borrowed + --> $DIR/issue-74072-lifetime-name-annotations.rs:24:9 + | +LL | (async move || -> &i32 { + | - let's call the lifetime of this reference `'1` +LL | let y = &*x; + | --- borrow of `*x` occurs here +LL | *x += 1; + | ^^^^^^^ assignment to borrowed `*x` occurs here +LL | y + | - returning this value requires that `*x` is borrowed for `'1` + +error[E0506]: cannot assign to `*x` because it is borrowed + --> $DIR/issue-74072-lifetime-name-annotations.rs:32:9 + | +LL | let y = &*x; + | --- borrow of `*x` occurs here +LL | *x += 1; + | ^^^^^^^ assignment to borrowed `*x` occurs here +LL | y + | - returning this value requires that `*x` is borrowed for `'1` +LL | } + | - return type of async block is &'1 i32 + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/async-await/issue-74497-lifetime-in-opaque.rs b/src/test/ui/async-await/issue-74497-lifetime-in-opaque.rs new file mode 100644 index 000000000..2d765eb41 --- /dev/null +++ b/src/test/ui/async-await/issue-74497-lifetime-in-opaque.rs @@ -0,0 +1,19 @@ +// edition:2018 + +// test that names give to anonymous lifetimes in opaque types like `impl Future` are correctly +// introduced in error messages + +use std::future::Future; + +pub async fn foo<F, T>(_: F) +where + F: Fn(&u8) -> T, + T: Future<Output = ()>, +{ +} + +pub async fn bar(_: &u8) {} + +fn main() { + let _ = foo(|x| bar(x)); //~ ERROR lifetime may not live long enough +} diff --git a/src/test/ui/async-await/issue-74497-lifetime-in-opaque.stderr b/src/test/ui/async-await/issue-74497-lifetime-in-opaque.stderr new file mode 100644 index 000000000..4427014ae --- /dev/null +++ b/src/test/ui/async-await/issue-74497-lifetime-in-opaque.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-74497-lifetime-in-opaque.rs:18:21 + | +LL | let _ = foo(|x| bar(x)); + | -- ^^^^^^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure `impl Future<Output = ()>` contains a lifetime `'2` + | has type `&'1 u8` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-75785-confusing-named-region.rs b/src/test/ui/async-await/issue-75785-confusing-named-region.rs new file mode 100644 index 000000000..452614087 --- /dev/null +++ b/src/test/ui/async-await/issue-75785-confusing-named-region.rs @@ -0,0 +1,13 @@ +// edition:2018 +// +// Regression test for issue #75785 +// Tests that we don't point to a confusing named +// region when emitting a diagnostic + +pub async fn async_fn(x: &mut i32) -> (&i32, &i32) { + let y = &*x; + *x += 1; //~ ERROR cannot assign to + (&32, y) +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-75785-confusing-named-region.stderr b/src/test/ui/async-await/issue-75785-confusing-named-region.stderr new file mode 100644 index 000000000..3b731d9c6 --- /dev/null +++ b/src/test/ui/async-await/issue-75785-confusing-named-region.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `*x` because it is borrowed + --> $DIR/issue-75785-confusing-named-region.rs:9:5 + | +LL | pub async fn async_fn(x: &mut i32) -> (&i32, &i32) { + | - let's call the lifetime of this reference `'1` +LL | let y = &*x; + | --- borrow of `*x` occurs here +LL | *x += 1; + | ^^^^^^^ assignment to borrowed `*x` occurs here +LL | (&32, y) + | -------- returning this value requires that `*x` is borrowed for `'1` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/async-await/issue-76547.rs b/src/test/ui/async-await/issue-76547.rs new file mode 100644 index 000000000..587feb624 --- /dev/null +++ b/src/test/ui/async-await/issue-76547.rs @@ -0,0 +1,38 @@ +// Test for diagnostic improvement issue #76547 +// edition:2018 + +use std::{ + future::Future, + task::{Context, Poll} +}; +use std::pin::Pin; + +pub struct ListFut<'a>(&'a mut [&'a mut [u8]]); +impl<'a> Future for ListFut<'a> { + type Output = (); + + fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> { + unimplemented!() + } +} + +async fn fut(bufs: &mut [&mut [u8]]) { + ListFut(bufs).await + //~^ ERROR lifetime may not live long enough +} + +pub struct ListFut2<'a>(&'a mut [&'a mut [u8]]); +impl<'a> Future for ListFut2<'a> { + type Output = i32; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> { + unimplemented!() + } +} + +async fn fut2(bufs: &mut [&mut [u8]]) -> i32 { + ListFut2(bufs).await + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-76547.stderr b/src/test/ui/async-await/issue-76547.stderr new file mode 100644 index 000000000..4d96cce82 --- /dev/null +++ b/src/test/ui/async-await/issue-76547.stderr @@ -0,0 +1,32 @@ +error: lifetime may not live long enough + --> $DIR/issue-76547.rs:20:13 + | +LL | async fn fut(bufs: &mut [&mut [u8]]) { + | - - let's call the lifetime of this reference `'2` + | | + | let's call the lifetime of this reference `'1` +LL | ListFut(bufs).await + | ^^^^ this usage requires that `'1` must outlive `'2` + | +help: consider introducing a named lifetime parameter + | +LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/issue-76547.rs:34:14 + | +LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 { + | - - let's call the lifetime of this reference `'2` + | | + | let's call the lifetime of this reference `'1` +LL | ListFut2(bufs).await + | ^^^^ this usage requires that `'1` must outlive `'2` + | +help: consider introducing a named lifetime parameter + | +LL | async fn fut2<'a>(bufs: &'a mut [&'a mut [u8]]) -> i32 { + | ++++ ++ ++ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/async-await/issue-77993-2.rs b/src/test/ui/async-await/issue-77993-2.rs new file mode 100644 index 000000000..4d554a0a1 --- /dev/null +++ b/src/test/ui/async-await/issue-77993-2.rs @@ -0,0 +1,9 @@ +// edition:2018 + +async fn test() -> Result<(), Box<dyn std::error::Error>> { + macro!(); + //~^ ERROR expected identifier, found `!` + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-77993-2.stderr b/src/test/ui/async-await/issue-77993-2.stderr new file mode 100644 index 000000000..64b378f83 --- /dev/null +++ b/src/test/ui/async-await/issue-77993-2.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `!` + --> $DIR/issue-77993-2.rs:4:10 + | +LL | macro!(); + | ^ expected identifier + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-84841.rs b/src/test/ui/async-await/issue-84841.rs new file mode 100644 index 000000000..ba3a1617b --- /dev/null +++ b/src/test/ui/async-await/issue-84841.rs @@ -0,0 +1,16 @@ +// edition:2018 + +fn main() { + +} + +async fn foo() { + // Adding an .await here avoids the ICE + test()?; + //~^ ERROR the `?` operator can only be applied to values that implement `Try` + //~| ERROR the `?` operator can only be used in an async function that returns +} + +// Removing the const generic parameter here avoids the ICE +async fn test<const N: usize>() { +} diff --git a/src/test/ui/async-await/issue-84841.stderr b/src/test/ui/async-await/issue-84841.stderr new file mode 100644 index 000000000..1e22373ba --- /dev/null +++ b/src/test/ui/async-await/issue-84841.stderr @@ -0,0 +1,26 @@ +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/issue-84841.rs:9:5 + | +LL | test()?; + | ^^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = ()>` + | + = help: the trait `Try` is not implemented for `impl Future<Output = ()>` + +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/issue-84841.rs:9:11 + | +LL | async fn foo() { + | ________________- +LL | | // Adding an .await here avoids the ICE +LL | | test()?; + | | ^ cannot use the `?` operator in an async function that returns `()` +LL | | +LL | | +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual<_>` is not implemented for `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-86507.rs b/src/test/ui/async-await/issue-86507.rs new file mode 100644 index 000000000..317f03176 --- /dev/null +++ b/src/test/ui/async-await/issue-86507.rs @@ -0,0 +1,25 @@ +// edition:2018 + +use ::core::pin::Pin; +use ::core::future::Future; +use ::core::marker::Send; + +trait Foo { + fn bar<'me, 'async_trait, T: Send>(x: &'me T) + -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>> + where 'me: 'async_trait; +} + +impl Foo for () { + fn bar<'me, 'async_trait, T: Send>(x: &'me T) + -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>> + where 'me:'async_trait { + Box::pin( //~ ERROR future cannot be sent between threads safely + async move { + let x = x; + } + ) + } +} + +fn main() { } diff --git a/src/test/ui/async-await/issue-86507.stderr b/src/test/ui/async-await/issue-86507.stderr new file mode 100644 index 000000000..0e21dba98 --- /dev/null +++ b/src/test/ui/async-await/issue-86507.stderr @@ -0,0 +1,23 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-86507.rs:17:13 + | +LL | / Box::pin( +LL | | async move { +LL | | let x = x; +LL | | } +LL | | ) + | |_____________^ future created by async block is not `Send` + | +note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` + --> $DIR/issue-86507.rs:19:29 + | +LL | let x = x; + | ^ has type `&T` which is not `Send`, because `T` is not `Sync` + = note: required for the cast from `impl Future<Output = ()>` to the object type `dyn Future<Output = ()> + Send` +help: consider further restricting this bound + | +LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) + | +++++++++++++++++++ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-93197.rs b/src/test/ui/async-await/issue-93197.rs new file mode 100644 index 000000000..c627fe17a --- /dev/null +++ b/src/test/ui/async-await/issue-93197.rs @@ -0,0 +1,16 @@ +// Regression test for #93197 +// check-pass +// edition:2021 +// compile-flags: -Zdrop-tracking + +#![feature(try_blocks)] + +use std::sync::{mpsc, mpsc::SendError}; + +pub async fn foo() { + let (tx, _) = mpsc::channel(); + + let _: Result<(), SendError<&str>> = try { tx.send("hello")?; }; +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-93648.rs b/src/test/ui/async-await/issue-93648.rs new file mode 100644 index 000000000..4ce3ac1e8 --- /dev/null +++ b/src/test/ui/async-await/issue-93648.rs @@ -0,0 +1,12 @@ +// edition:2021 +// build-pass +// compile-flags: -Zdrop-tracking + +fn main() { + let _ = async { + let mut s = (String::new(),); + s.0.push_str("abc"); + std::mem::drop(s); + async {}.await; + }; +} diff --git a/src/test/ui/async-await/issues/auxiliary/issue-60674.rs b/src/test/ui/async-await/issues/auxiliary/issue-60674.rs new file mode 100644 index 000000000..680c6e55e --- /dev/null +++ b/src/test/ui/async-await/issues/auxiliary/issue-60674.rs @@ -0,0 +1,12 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn attr(_args: TokenStream, input: TokenStream) -> TokenStream { + println!("{}", input); + TokenStream::new() +} diff --git a/src/test/ui/async-await/issues/auxiliary/issue_67893.rs b/src/test/ui/async-await/issues/auxiliary/issue_67893.rs new file mode 100644 index 000000000..387966a50 --- /dev/null +++ b/src/test/ui/async-await/issues/auxiliary/issue_67893.rs @@ -0,0 +1,10 @@ +// edition:2018 + +use std::sync::{Arc, Mutex}; + +pub async fn f(_: ()) {} + +pub async fn run() { + let x: Arc<Mutex<()>> = unimplemented!(); + f(*x.lock().unwrap()).await; +} diff --git a/src/test/ui/async-await/issues/issue-51719.rs b/src/test/ui/async-await/issues/issue-51719.rs new file mode 100644 index 000000000..09241f982 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-51719.rs @@ -0,0 +1,12 @@ +// edition:2018 +// +// Tests that the .await syntax can't be used to make a generator + +async fn foo() {} + +fn make_generator() { + let _gen = || foo().await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-51719.stderr b/src/test/ui/async-await/issues/issue-51719.stderr new file mode 100644 index 000000000..f3ce5d1c8 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-51719.stderr @@ -0,0 +1,11 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-51719.rs:8:24 + | +LL | let _gen = || foo().await; + | -- ^^^^^^ only allowed inside `async` functions and blocks + | | + | this is not `async` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/async-await/issues/issue-51751.rs b/src/test/ui/async-await/issues/issue-51751.rs new file mode 100644 index 000000000..bc85a96ce --- /dev/null +++ b/src/test/ui/async-await/issues/issue-51751.rs @@ -0,0 +1,11 @@ +// edition:2018 + +async fn inc(limit: i64) -> i64 { + limit + 1 +} + +fn main() { + let result = inc(10000); + let finished = result.await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks +} diff --git a/src/test/ui/async-await/issues/issue-51751.stderr b/src/test/ui/async-await/issues/issue-51751.stderr new file mode 100644 index 000000000..8696a5b79 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-51751.stderr @@ -0,0 +1,12 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-51751.rs:9:26 + | +LL | fn main() { + | ---- this is not `async` +LL | let result = inc(10000); +LL | let finished = result.await; + | ^^^^^^ only allowed inside `async` functions and blocks + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/async-await/issues/issue-53249.rs b/src/test/ui/async-await/issues/issue-53249.rs new file mode 100644 index 000000000..3a33af2d2 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-53249.rs @@ -0,0 +1,47 @@ +// check-pass +// edition:2018 + +#![feature(arbitrary_self_types)] + +use std::task::{self, Poll}; +use std::future::Future; +use std::marker::Unpin; +use std::pin::Pin; + +// This is a regression test for an ICE/unbounded recursion issue relating to async-await. + +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Lazy<F> { + f: Option<F> +} + +impl<F> Unpin for Lazy<F> {} + +pub fn lazy<F, R>(f: F) -> Lazy<F> + where F: FnOnce(&mut task::Context) -> R, +{ + Lazy { f: Some(f) } +} + +impl<R, F> Future for Lazy<F> + where F: FnOnce(&mut task::Context) -> R, +{ + type Output = R; + + fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<R> { + Poll::Ready((self.f.take().unwrap())(cx)) + } +} + +async fn __receive<WantFn, Fut>(want: WantFn) -> () + where Fut: Future<Output = ()>, WantFn: Fn(&Box<dyn Send + 'static>) -> Fut, +{ + lazy(|_| ()).await; +} + +pub fn basic_spawn_receive() { + async { __receive(|_| async { () }).await }; +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-54752-async-block.rs b/src/test/ui/async-await/issues/issue-54752-async-block.rs new file mode 100644 index 000000000..a8165ae6c --- /dev/null +++ b/src/test/ui/async-await/issues/issue-54752-async-block.rs @@ -0,0 +1,7 @@ +// run-pass + +// edition:2018 +// pp-exact + +fn main() { let _a = (async { }); } +//~^ WARNING unnecessary parentheses around assigned value diff --git a/src/test/ui/async-await/issues/issue-54752-async-block.stderr b/src/test/ui/async-await/issues/issue-54752-async-block.stderr new file mode 100644 index 000000000..8cc849dd9 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-54752-async-block.stderr @@ -0,0 +1,15 @@ +warning: unnecessary parentheses around assigned value + --> $DIR/issue-54752-async-block.rs:6:22 + | +LL | fn main() { let _a = (async { }); } + | ^ ^ + | + = note: `#[warn(unused_parens)]` on by default +help: remove these parentheses + | +LL - fn main() { let _a = (async { }); } +LL + fn main() { let _a = async { }; } + | + +warning: 1 warning emitted + diff --git a/src/test/ui/async-await/issues/issue-54974.rs b/src/test/ui/async-await/issues/issue-54974.rs new file mode 100644 index 000000000..b602ef153 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-54974.rs @@ -0,0 +1,14 @@ +// check-pass +// edition:2018 + +use std::sync::Arc; + +trait SomeTrait: Send + Sync + 'static { + fn do_something(&self); +} + +async fn my_task(obj: Arc<dyn SomeTrait>) { + unimplemented!() +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-55324.rs b/src/test/ui/async-await/issues/issue-55324.rs new file mode 100644 index 000000000..9ecb3b129 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-55324.rs @@ -0,0 +1,11 @@ +// check-pass +// edition:2018 + +use std::future::Future; + +async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 { + let y = future.await; + *x + y +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-55809.rs b/src/test/ui/async-await/issues/issue-55809.rs new file mode 100644 index 000000000..3b271775a --- /dev/null +++ b/src/test/ui/async-await/issues/issue-55809.rs @@ -0,0 +1,28 @@ +// edition:2018 +// run-pass + +trait Foo { } + +impl Foo for () { } + +impl<'a, T> Foo for &'a mut T where T: Foo { } + +async fn foo_async<T>(_v: T) -> u8 where T: Foo { + 0 +} + +async fn bad<T>(v: T) -> u8 where T: Foo { + foo_async(v).await +} + +async fn async_main() { + let mut v = (); + + let _ = bad(&mut v).await; + let _ = foo_async(&mut v).await; + let _ = bad(v).await; +} + +fn main() { + let _ = async_main(); +} diff --git a/src/test/ui/async-await/issues/issue-58885.rs b/src/test/ui/async-await/issues/issue-58885.rs new file mode 100644 index 000000000..11920b072 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-58885.rs @@ -0,0 +1,19 @@ +// check-pass +// edition:2018 + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth<'a>( + &'a self, foo: &'a dyn Foo + ) -> bool + { + true + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-59001.rs b/src/test/ui/async-await/issues/issue-59001.rs new file mode 100644 index 000000000..4ddebcf20 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-59001.rs @@ -0,0 +1,14 @@ +// check-pass +// edition:2018 + +use std::future::Future; + +async fn enter<'a, F, R>(mut callback: F) +where + F: FnMut(&'a mut i32) -> R, + R: Future<Output = ()> + 'a, +{ + unimplemented!() +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-59972.rs b/src/test/ui/async-await/issues/issue-59972.rs new file mode 100644 index 000000000..c2e24a96b --- /dev/null +++ b/src/test/ui/async-await/issues/issue-59972.rs @@ -0,0 +1,34 @@ +// Incorrect handling of uninhabited types could cause us to mark generator +// types as entirely uninhabited, when they were in fact constructible. This +// caused us to hit "unreachable" code (illegal instruction on x86). + +// run-pass + +// compile-flags: --edition=2018 -Aunused + +pub enum Uninhabited { } + +fn uninhabited_async() -> Uninhabited { + unreachable!() +} + +async fn noop() { } + +async fn contains_never() { + let error = uninhabited_async(); + noop().await; + let error2 = error; +} + +async fn overlap_never() { + let error1 = uninhabited_async(); + noop().await; + let error2 = uninhabited_async(); + drop(error1); + noop().await; + drop(error2); +} + +#[allow(unused_must_use)] +fn main() { +} diff --git a/src/test/ui/async-await/issues/issue-60518.rs b/src/test/ui/async-await/issues/issue-60518.rs new file mode 100644 index 000000000..69bbdd0e8 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-60518.rs @@ -0,0 +1,10 @@ +// check-pass +// edition:2018 + +// This is a regression test to ensure that simple bindings (where replacement arguments aren't +// created during async fn lowering) that have their DefId used during HIR lowering (such as impl +// trait) are visited during def collection and thus have a DefId. + +async fn foo(ws: impl Iterator<Item = ()>) {} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs b/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs new file mode 100644 index 000000000..66a3b07c3 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-60655-latebound-regions.rs @@ -0,0 +1,30 @@ +// Test that opaque `impl Trait` types are allowed to contain late-bound regions. + +// check-pass +// edition:2018 + +#![feature(type_alias_impl_trait)] + +use std::future::Future; + +pub type Func = impl Sized; + +// Late bound region should be allowed to escape the function, since it's bound +// in the type. +fn null_function_ptr() -> Func { + None::<for<'a> fn(&'a ())> +} + +async fn async_nop(_: &u8) {} + +pub type ServeFut = impl Future<Output=()>; + +// Late bound regions occur in the generator witness type here. +fn serve() -> ServeFut { + async move { + let x = 5; + async_nop(&x).await + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-60674.rs b/src/test/ui/async-await/issues/issue-60674.rs new file mode 100644 index 000000000..c0e34a8df --- /dev/null +++ b/src/test/ui/async-await/issues/issue-60674.rs @@ -0,0 +1,19 @@ +// aux-build:issue-60674.rs +// build-pass (FIXME(62277): could be check-pass?) +// edition:2018 + +// This is a regression test that ensures that `mut` patterns are not lost when provided as input +// to a proc macro. + +extern crate issue_60674; + +#[issue_60674::attr] +async fn f(mut x: u8) {} + +#[issue_60674::attr] +async fn g((mut x, y, mut z): (u8, u8, u8)) {} + +#[issue_60674::attr] +async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) {} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-60674.stdout b/src/test/ui/async-await/issues/issue-60674.stdout new file mode 100644 index 000000000..6f980e606 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-60674.stdout @@ -0,0 +1,3 @@ +async fn f(mut x : u8) {} +async fn g((mut x, y, mut z) : (u8, u8, u8)) {} +async fn g(mut x : u8, (a, mut b, c) : (u8, u8, u8), y : u8) {} diff --git a/src/test/ui/async-await/issues/issue-61187.rs b/src/test/ui/async-await/issues/issue-61187.rs new file mode 100644 index 000000000..8585a4251 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61187.rs @@ -0,0 +1,7 @@ +// edition:2018 + +fn main() {} + +async fn response(data: Vec<u8>) { + data.reverse(); //~ ERROR E0596 +} diff --git a/src/test/ui/async-await/issues/issue-61187.stderr b/src/test/ui/async-await/issues/issue-61187.stderr new file mode 100644 index 000000000..163053471 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61187.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable + --> $DIR/issue-61187.rs:6:5 + | +LL | async fn response(data: Vec<u8>) { + | ---- help: consider changing this to be mutable: `mut data` +LL | data.reverse(); + | ^^^^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/async-await/issues/issue-61986.rs b/src/test/ui/async-await/issues/issue-61986.rs new file mode 100644 index 000000000..879bc6912 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-61986.rs @@ -0,0 +1,19 @@ +// build-pass (FIXME(62277): could be check-pass?) +// edition:2018 +// +// Tests that we properly handle StorageDead/StorageLives for temporaries +// created in async loop bodies. + +async fn bar() -> Option<()> { + Some(()) +} + +async fn listen() { + while let Some(_) = bar().await { + String::new(); + } +} + +fn main() { + listen(); +} diff --git a/src/test/ui/async-await/issues/issue-62009-1.rs b/src/test/ui/async-await/issues/issue-62009-1.rs new file mode 100644 index 000000000..40ccf2571 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62009-1.rs @@ -0,0 +1,15 @@ +// edition:2018 + +async fn print_dur() {} + +fn main() { + async { let (); }.await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks + async { + let task1 = print_dur().await; + }.await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks + (|_| 2333).await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks + //~| ERROR is not a future +} diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr new file mode 100644 index 000000000..5cbbf89a2 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -0,0 +1,45 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-62009-1.rs:6:22 + | +LL | fn main() { + | ---- this is not `async` +LL | async { let (); }.await; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-62009-1.rs:10:6 + | +LL | fn main() { + | ---- this is not `async` +... +LL | }.await; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-62009-1.rs:12:15 + | +LL | fn main() { + | ---- this is not `async` +... +LL | (|_| 2333).await; + | ^^^^^^ only allowed inside `async` functions and blocks + +error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future + --> $DIR/issue-62009-1.rs:12:15 + | +LL | (|_| 2333).await; + | ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future + | + = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` + = note: [closure@$DIR/issue-62009-1.rs:12:6: 12:9] must be a future or must implement `IntoFuture` to be awaited + = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` +help: remove the `.await` + | +LL - (|_| 2333).await; +LL + (|_| 2333); + | + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0728. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issues/issue-62009-2.rs b/src/test/ui/async-await/issues/issue-62009-2.rs new file mode 100644 index 000000000..cb7336e61 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62009-2.rs @@ -0,0 +1,10 @@ +// edition:2018 + +#![feature(async_closure)] + +async fn print_dur() {} + +fn main() { + (async || 2333)().await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks +} diff --git a/src/test/ui/async-await/issues/issue-62009-2.stderr b/src/test/ui/async-await/issues/issue-62009-2.stderr new file mode 100644 index 000000000..92e9a8a69 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62009-2.stderr @@ -0,0 +1,11 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-62009-2.rs:8:22 + | +LL | fn main() { + | ---- this is not `async` +LL | (async || 2333)().await; + | ^^^^^^ only allowed inside `async` functions and blocks + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/async-await/issues/issue-62097.rs b/src/test/ui/async-await/issues/issue-62097.rs new file mode 100644 index 000000000..a24c84cff --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62097.rs @@ -0,0 +1,21 @@ +// edition:2018 +async fn foo<F>(fun: F) +where + F: FnOnce() + 'static +{ + fun() +} + +struct Struct; + +impl Struct { + pub async fn run_dummy_fn(&self) { + foo(|| self.bar()).await; + //~^ ERROR closure may outlive the current function + //~| ERROR borrowed data escapes outside of associated function + } + + pub fn bar(&self) {} +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr new file mode 100644 index 000000000..786f62132 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -0,0 +1,36 @@ +error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function + --> $DIR/issue-62097.rs:13:13 + | +LL | foo(|| self.bar()).await; + | ^^ ---- `self` is borrowed here + | | + | may outlive borrowed value `self` + | +note: function requires argument type to outlive `'static` + --> $DIR/issue-62097.rs:13:9 + | +LL | foo(|| self.bar()).await; + | ^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword + | +LL | foo(move || self.bar()).await; + | ++++ + +error[E0521]: borrowed data escapes outside of associated function + --> $DIR/issue-62097.rs:13:9 + | +LL | pub async fn run_dummy_fn(&self) { + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` +LL | foo(|| self.bar()).await; + | ^^^^^^^^^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'static` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0373, E0521. +For more information about an error, try `rustc --explain E0373`. diff --git a/src/test/ui/async-await/issues/issue-62517-1.rs b/src/test/ui/async-await/issues/issue-62517-1.rs new file mode 100644 index 000000000..4689ce36a --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62517-1.rs @@ -0,0 +1,21 @@ +// Regression test for #62517. We used to ICE when you had an `async +// fn` with an `impl Trait` return that mentioned a `dyn Bar` with no +// explicit lifetime bound. +// +// edition:2018 +// check-pass + +trait FirstTrait {} +trait SecondTrait { + type Item: ?Sized; +} + +async fn foo(x: &str) -> impl SecondTrait<Item = dyn FirstTrait> { +} + + +impl<T> SecondTrait for T { + type Item = dyn FirstTrait; +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-62517-2.rs b/src/test/ui/async-await/issues/issue-62517-2.rs new file mode 100644 index 000000000..aaf28d6c1 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-62517-2.rs @@ -0,0 +1,16 @@ +// Regression test for #62517. We used to ICE when you had an `async +// fn` with an `impl Trait` return that mentioned a `dyn Bar` with no +// explicit lifetime bound. +// +// edition:2018 +// check-pass + +trait Object {} + +trait Alpha<Param: ?Sized> {} + +async fn foo<'a>(_: &'a ()) -> impl Alpha<dyn Object> {} + +impl<T> Alpha<dyn Object> for T { } + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-63388-1.rs b/src/test/ui/async-await/issues/issue-63388-1.rs new file mode 100644 index 000000000..32bcbb111 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-1.rs @@ -0,0 +1,19 @@ +// edition:2018 + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth<'a>( + &'a self, foo: &dyn Foo + ) -> &dyn Foo + { + //~^ ERROR explicit lifetime required in the type of `foo` [E0621] + foo + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-63388-1.stderr b/src/test/ui/async-await/issues/issue-63388-1.stderr new file mode 100644 index 000000000..88542315e --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-1.stderr @@ -0,0 +1,15 @@ +error[E0621]: explicit lifetime required in the type of `foo` + --> $DIR/issue-63388-1.rs:13:5 + | +LL | &'a self, foo: &dyn Foo + | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` +LL | ) -> &dyn Foo +LL | / { +LL | | +LL | | foo +LL | | } + | |_____^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/async-await/issues/issue-63388-2.rs b/src/test/ui/async-await/issues/issue-63388-2.rs new file mode 100644 index 000000000..90b59f96e --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-2.rs @@ -0,0 +1,19 @@ +// edition:2018 + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth<'a>( + foo: &dyn Foo, bar: &'a dyn Foo + ) -> &dyn Foo //~ ERROR missing lifetime specifier + { + //~^ ERROR explicit lifetime required in the type of `foo` [E0621] + foo + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr new file mode 100644 index 000000000..e515f227c --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -0,0 +1,30 @@ +error[E0106]: missing lifetime specifier + --> $DIR/issue-63388-2.rs:12:10 + | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- ----------- +LL | ) -> &dyn Foo + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` +help: consider using the `'a` lifetime + | +LL | ) -> &'a dyn Foo + | ++ + +error[E0621]: explicit lifetime required in the type of `foo` + --> $DIR/issue-63388-2.rs:13:5 + | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` +LL | ) -> &dyn Foo +LL | / { +LL | | +LL | | foo +LL | | } + | |_____^ lifetime `'a` required + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0106, E0621. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/async-await/issues/issue-63388-3.rs b/src/test/ui/async-await/issues/issue-63388-3.rs new file mode 100644 index 000000000..1a9822e02 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-3.rs @@ -0,0 +1,17 @@ +// edition:2018 +// check-pass + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth( + &self, foo: &dyn Foo + ) { + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-63388-4.rs b/src/test/ui/async-await/issues/issue-63388-4.rs new file mode 100644 index 000000000..58f9dacb3 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-63388-4.rs @@ -0,0 +1,10 @@ +// check-pass +// edition:2018 + +struct A; + +impl A { + async fn foo(&self, f: &u32) -> &A { self } +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-64391-2.rs b/src/test/ui/async-await/issues/issue-64391-2.rs new file mode 100644 index 000000000..eef2c1fb2 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64391-2.rs @@ -0,0 +1,20 @@ +// Regression test for #64391 +// +// As described on the issue, the (spurious) `DROP` inserted for the +// `"".to_string()` value was causing a (spurious) unwind path that +// led us to believe that the future might be dropped after `config` +// had been dropped. This cannot, in fact, happen. +// +// check-pass +// edition:2018 + +async fn connect() { + let config = 666; + connect2(&config, "".to_string()).await +} + +async fn connect2(_config: &u32, _tls: String) { + unimplemented!() +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-64433.rs b/src/test/ui/async-await/issues/issue-64433.rs new file mode 100644 index 000000000..d900f8ed9 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64433.rs @@ -0,0 +1,30 @@ +// Regression test for issue #64433. +// +// See issue-64391-2.rs for more details, as that was fixed by the +// same PR. +// +// check-pass +// edition:2018 + +#[derive(Debug)] +struct A<'a> { + inner: Vec<&'a str>, +} + +struct B {} + +impl B { + async fn something_with_a(&mut self, a: A<'_>) -> Result<(), String> { + println!("{:?}", a); + Ok(()) + } +} + +async fn can_error(some_string: &str) -> Result<(), String> { + let a = A { inner: vec![some_string, "foo"] }; + let mut b = B {}; + Ok(b.something_with_a(a).await.map(drop)?) +} + +fn main() { +} diff --git a/src/test/ui/async-await/issues/issue-64477-2.rs b/src/test/ui/async-await/issues/issue-64477-2.rs new file mode 100644 index 000000000..2360b57cc --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64477-2.rs @@ -0,0 +1,22 @@ +// Another regression test for #64477. +// +// In the past, the code generated by `format!` produced temporaries in the surrounding scope that +// borrowed the arguments through `&dyn Trait`. These temporaries do not implement `Send`, which +// meant that when `format!` was used in an async block, the resulting generator was not `Send`. +// See https://github.com/rust-lang/rust/issues/64477#issuecomment-534669068 for details +// and https://github.com/rust-lang/rust/issues/64477#issuecomment-531882958 for an example. +// +// check-pass +// edition:2018 + +async fn foo(_: String) {} + +fn bar() -> impl Send { + async move { + foo(format!("{}:{}", 1, 2)).await; + } +} + +fn main() { + let _ = bar(); +} diff --git a/src/test/ui/async-await/issues/issue-64477.rs b/src/test/ui/async-await/issues/issue-64477.rs new file mode 100644 index 000000000..5bd52d44a --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64477.rs @@ -0,0 +1,20 @@ +// Regression test for #64477. +// +// We were incorrectly claiming that the `f(x).await` future captured +// a value of type `T`, and hence that `T: Send` would have to hold. +// +// check-pass +// edition:2018 + +use std::future::Future; +use std::pin::Pin; + +fn f<T>(_: &T) -> Pin<Box<dyn Future<Output = ()> + Send>> { + unimplemented!() +} + +pub fn g<T: Sync>(x: &'static T) -> impl Future<Output = ()> + Send { + async move { f(x).await } +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-64964.rs b/src/test/ui/async-await/issues/issue-64964.rs new file mode 100644 index 000000000..6d6eff486 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-64964.rs @@ -0,0 +1,23 @@ +// check-pass +// incremental +// compile-flags: -Z query-dep-graph +// edition:2018 + +// Regression test for ICE related to `await`ing in a method + incr. comp. (#64964) + +struct Body; +impl Body { + async fn next(&mut self) { + async {}.await + } +} + +// Another reproduction: `await`ing with a variable from for-loop. + +async fn bar() { + for x in 0..10 { + async { Some(x) }.await.unwrap(); + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs new file mode 100644 index 000000000..1dbf5db6c --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65159.rs @@ -0,0 +1,12 @@ +// Regression test for #65159. We used to ICE. +// +// edition:2018 + +async fn copy() -> Result<()> +//~^ ERROR this enum takes 2 generic arguments +{ + Ok(()) + //~^ ERROR type annotations needed +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-65159.stderr b/src/test/ui/async-await/issues/issue-65159.stderr new file mode 100644 index 000000000..9918f569c --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65159.stderr @@ -0,0 +1,33 @@ +error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/issue-65159.rs:5:20 + | +LL | async fn copy() -> Result<()> + | ^^^^^^ -- supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: enum defined here, with 2 generic parameters: `T`, `E` + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | pub enum Result<T, E> { + | ^^^^^^ - - +help: add missing generic argument + | +LL | async fn copy() -> Result<(), E> + | +++ + +error[E0282]: type annotations needed + --> $DIR/issue-65159.rs:8:5 + | +LL | Ok(()) + | ^^ cannot infer type of the type parameter `E` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | Ok::<(), E>(()) + | +++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0282. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs b/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs new file mode 100644 index 000000000..ade386a60 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs @@ -0,0 +1,46 @@ +// issue 65419 - Attempting to run an async fn after completion mentions generators when it should +// be talking about `async fn`s instead. + +// run-fail +// error-pattern: thread 'main' panicked at '`async fn` resumed after completion' +// edition:2018 +// ignore-wasm no panic or subprocess support +// ignore-emscripten no panic or subprocess support + +#![feature(generators, generator_trait)] + +async fn foo() { +} + +fn main() { + let mut future = Box::pin(foo()); + executor::block_on(future.as_mut()); + executor::block_on(future.as_mut()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs b/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs new file mode 100644 index 000000000..5e71229be --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs @@ -0,0 +1,53 @@ +// issue 65419 - Attempting to run an async fn after completion mentions generators when it should +// be talking about `async fn`s instead. Should also test what happens when it panics. + +// run-fail +// needs-unwind +// error-pattern: thread 'main' panicked at '`async fn` resumed after panicking' +// edition:2018 +// ignore-wasm no panic or subprocess support +// ignore-emscripten no panic or subprocess support + +#![feature(generators, generator_trait)] + +use std::panic; + +async fn foo() { + panic!(); +} + +fn main() { + let mut future = Box::pin(foo()); + panic::catch_unwind(panic::AssertUnwindSafe(|| { + executor::block_on(future.as_mut()); + })); + + executor::block_on(future.as_mut()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/src/test/ui/async-await/issues/issue-65419/issue-65419-generator-resume-after-completion.rs b/src/test/ui/async-await/issues/issue-65419/issue-65419-generator-resume-after-completion.rs new file mode 100644 index 000000000..9fc5667d6 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65419/issue-65419-generator-resume-after-completion.rs @@ -0,0 +1,25 @@ +// issue 65419 - Attempting to run an `async fn` after completion mentions generators when it should +// be talking about `async fn`s instead. Regression test added to make sure generators still +// panic when resumed after completion. + +// run-fail +// error-pattern:generator resumed after completion +// edition:2018 +// ignore-wasm no panic or subprocess support +// ignore-emscripten no panic or subprocess support + +#![feature(generators, generator_trait)] + +use std::{ + ops::Generator, + pin::Pin, +}; + +fn main() { + let mut g = || { + yield; + }; + Pin::new(&mut g).resume(()); // Yields once. + Pin::new(&mut g).resume(()); // Completes here. + Pin::new(&mut g).resume(()); // Panics here. +} diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.rs b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.rs new file mode 100644 index 000000000..3a814b475 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.rs @@ -0,0 +1,16 @@ +// edition:2018 + +struct Foo(*const u8); + +unsafe impl Send for Foo {} + +async fn bar(_: Foo) {} + +fn assert_send<T: Send>(_: T) {} + +fn main() { + assert_send(async { + //~^ ERROR future cannot be sent between threads safely + bar(Foo(std::ptr::null())).await; + }) +} 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 new file mode 100644 index 000000000..b23093001 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -0,0 +1,32 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-65436-raw-ptr-not-send.rs:12:5 + | +LL | assert_send(async { + | ^^^^^^^^^^^ future created by async block is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const u8` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-65436-raw-ptr-not-send.rs:14:35 + | +LL | bar(Foo(std::ptr::null())).await; + | ---------------- ^^^^^^ await occurs here, with `std::ptr::null()` maybe used later + | | + | has type `*const u8` which is not `Send` +note: `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 + | +LL | bar(Foo(std::ptr::null())).await; + | ^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `assert_send` + --> $DIR/issue-65436-raw-ptr-not-send.rs:9:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issues/issue-66695-static-refs.rs b/src/test/ui/async-await/issues/issue-66695-static-refs.rs new file mode 100644 index 000000000..f0609713b --- /dev/null +++ b/src/test/ui/async-await/issues/issue-66695-static-refs.rs @@ -0,0 +1,24 @@ +// build-pass +// edition:2018 + +static A: [i32; 5] = [1, 2, 3, 4, 5]; + +async fn fun() { + let u = A[async { 1 }.await]; + match A { + i if async { true }.await => (), + _ => (), + } +} + +fn main() { + async { + let u = A[async { 1 }.await]; + }; + async { + match A { + i if async { true }.await => (), + _ => (), + } + }; +} diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs new file mode 100644 index 000000000..b7a976a0a --- /dev/null +++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs @@ -0,0 +1,15 @@ +// edition:2018 + +struct Ia<S>(S); + +impl<S> Ia<S> { + fn partial(_: S) {} + fn full(self) {} + + async fn crash(self) { + Self::partial(self.0); + Self::full(self); //~ ERROR use of partially moved value: `self` + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr new file mode 100644 index 000000000..e2a735398 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr @@ -0,0 +1,13 @@ +error[E0382]: use of partially moved value: `self` + --> $DIR/issue-66958-non-copy-infered-type-arg.rs:11:20 + | +LL | Self::partial(self.0); + | ------ value partially moved here +LL | Self::full(self); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `self.0` has type `S`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/async-await/issues/issue-67611-static-mut-refs.rs b/src/test/ui/async-await/issues/issue-67611-static-mut-refs.rs new file mode 100644 index 000000000..dda4a151d --- /dev/null +++ b/src/test/ui/async-await/issues/issue-67611-static-mut-refs.rs @@ -0,0 +1,33 @@ +// build-pass +// edition:2018 + +static mut A: [i32; 5] = [1, 2, 3, 4, 5]; + +fn is_send_sync<T: Send + Sync>(_: T) {} + +async fn fun() { + let u = unsafe { A[async { 1 }.await] }; + unsafe { + match A { + i if async { true }.await => (), + _ => (), + } + } +} + +fn main() { + let index_block = async { + let u = unsafe { A[async { 1 }.await] }; + }; + let match_block = async { + unsafe { + match A { + i if async { true }.await => (), + _ => (), + } + } + }; + is_send_sync(index_block); + is_send_sync(match_block); + is_send_sync(fun()); +} diff --git a/src/test/ui/async-await/issues/issue-67893.rs b/src/test/ui/async-await/issues/issue-67893.rs new file mode 100644 index 000000000..d73772e5f --- /dev/null +++ b/src/test/ui/async-await/issues/issue-67893.rs @@ -0,0 +1,11 @@ +// aux-build: issue_67893.rs +// edition:2018 + +extern crate issue_67893; + +fn g(_: impl Send) {} + +fn main() { + g(issue_67893::run()) + //~^ ERROR future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/issues/issue-67893.stderr b/src/test/ui/async-await/issues/issue-67893.stderr new file mode 100644 index 000000000..316b6d06f --- /dev/null +++ b/src/test/ui/async-await/issues/issue-67893.stderr @@ -0,0 +1,27 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-67893.rs:9:7 + | +LL | g(issue_67893::run()) + | ^^^^^^^^^^^^^^^^^^ future is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` +note: future is not `Send` as this value is used across an await + --> $DIR/auxiliary/issue_67893.rs:9:26 + | +LL | f(*x.lock().unwrap()).await; + | ----------------- ^^^^^^ await occurs here, with `x.lock().unwrap()` maybe used later + | | + | has type `MutexGuard<'_, ()>` which is not `Send` +note: `x.lock().unwrap()` is later dropped here + --> $DIR/auxiliary/issue_67893.rs:9:32 + | +LL | f(*x.lock().unwrap()).await; + | ^ +note: required by a bound in `g` + --> $DIR/issue-67893.rs:6:14 + | +LL | fn g(_: impl Send) {} + | ^^^^ required by this bound in `g` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issues/issue-69307-nested.rs b/src/test/ui/async-await/issues/issue-69307-nested.rs new file mode 100644 index 000000000..b7cdf3987 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-69307-nested.rs @@ -0,0 +1,30 @@ +// Regression test for #69307 +// +// Having a `async { .. foo.await .. }` block appear inside of a `+=` +// expression was causing an ICE due to a failure to save/restore +// state in the AST numbering pass when entering a nested body. +// +// check-pass +// edition:2018 + +fn block_on<F>(_: F) -> usize { + 0 +} + +fn main() {} + +async fn bar() { + let mut sum = 0; + sum += { + block_on(async { + baz().await; + let mut inner = 1; + inner += block_on(async { + baz().await; + 0 + }) + }) + }; +} + +async fn baz() {} diff --git a/src/test/ui/async-await/issues/issue-69307.rs b/src/test/ui/async-await/issues/issue-69307.rs new file mode 100644 index 000000000..59309a7f2 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-69307.rs @@ -0,0 +1,23 @@ +// Regression test for #69307 +// +// Having an `async { .. foo.await .. }` block appear inside of a `+=` +// expression was causing an ICE due to a failure to save/restore +// state in the AST numbering pass when entering a nested body. +// +// check-pass +// edition:2018 + +fn block_on<F>(_: F) -> usize { + 0 +} + +fn main() {} + +async fn bar() { + let mut sum = 0; + sum += block_on(async { + baz().await; + }); +} + +async fn baz() {} diff --git a/src/test/ui/async-await/issues/issue-72312.rs b/src/test/ui/async-await/issues/issue-72312.rs new file mode 100644 index 000000000..74122cf00 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-72312.rs @@ -0,0 +1,21 @@ +// edition:2018 +fn require_static<T: 'static>(val: T) -> T { + val +} + +struct Problem; + +impl Problem { + pub async fn start(&self) { + //~^ NOTE let's call + //~| NOTE `self` is a reference + require_static(async move { + //~^ ERROR borrowed data escapes + //~| NOTE `self` escapes + //~| NOTE argument requires + &self; + }); + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr new file mode 100644 index 000000000..aa947b690 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-72312.stderr @@ -0,0 +1,23 @@ +error[E0521]: borrowed data escapes outside of associated function + --> $DIR/issue-72312.rs:12:9 + | +LL | pub async fn start(&self) { + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` +... +LL | / require_static(async move { +LL | | +LL | | +LL | | +LL | | &self; +LL | | }); + | | ^ + | | | + | |__________`self` escapes the associated function body here + | argument requires that `'1` must outlive `'static` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/async-await/issues/issue-78600.rs b/src/test/ui/async-await/issues/issue-78600.rs new file mode 100644 index 000000000..8aaeaecf3 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78600.rs @@ -0,0 +1,12 @@ +// edition:2018 + +struct S<'a>(&'a i32); + +impl<'a> S<'a> { + async fn new(i: &'a i32) -> Result<Self, ()> { + //~^ ERROR: `async fn` + Ok(S(&22)) + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-78600.stderr b/src/test/ui/async-await/issues/issue-78600.stderr new file mode 100644 index 000000000..92b661471 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78600.stderr @@ -0,0 +1,11 @@ +error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + --> $DIR/issue-78600.rs:6:33 + | +LL | async fn new(i: &'a i32) -> Result<Self, ()> { + | ^^^^^^^----^^^^^ + | | + | help: consider spelling out the type instead: `S<'a>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0760`. diff --git a/src/test/ui/async-await/issues/issue-78654.full.stderr b/src/test/ui/async-await/issues/issue-78654.full.stderr new file mode 100644 index 000000000..0d12a948c --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78654.full.stderr @@ -0,0 +1,19 @@ +error[E0573]: expected type, found built-in attribute `feature` + --> $DIR/issue-78654.rs:9:15 + | +LL | impl<const H: feature> Foo { + | ^^^^^^^ not a type + +error[E0207]: the const parameter `H` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-78654.rs:9:6 + | +LL | impl<const H: feature> Foo { + | ^^^^^^^^^^^^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0207, E0573. +For more information about an error, try `rustc --explain E0207`. diff --git a/src/test/ui/async-await/issues/issue-78654.min.stderr b/src/test/ui/async-await/issues/issue-78654.min.stderr new file mode 100644 index 000000000..0d12a948c --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78654.min.stderr @@ -0,0 +1,19 @@ +error[E0573]: expected type, found built-in attribute `feature` + --> $DIR/issue-78654.rs:9:15 + | +LL | impl<const H: feature> Foo { + | ^^^^^^^ not a type + +error[E0207]: the const parameter `H` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-78654.rs:9:6 + | +LL | impl<const H: feature> Foo { + | ^^^^^^^^^^^^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0207, E0573. +For more information about an error, try `rustc --explain E0207`. diff --git a/src/test/ui/async-await/issues/issue-78654.rs b/src/test/ui/async-await/issues/issue-78654.rs new file mode 100644 index 000000000..cc6dc3834 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78654.rs @@ -0,0 +1,15 @@ +// edition:2018 +// revisions: full min + +#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, allow(incomplete_features))] + +struct Foo; + +impl<const H: feature> Foo { +//~^ ERROR: expected type, found built-in attribute `feature` +//~^^ ERROR: the const parameter `H` is not constrained by the impl trait, self type, or predicates + async fn biz() {} +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.rs b/src/test/ui/async-await/issues/issue-78938-async-block.rs new file mode 100644 index 000000000..36f716019 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78938-async-block.rs @@ -0,0 +1,33 @@ +// edition:2018 + +use std::{sync::Arc, future::Future, pin::Pin, task::{Context, Poll}}; + +async fn f() { + let room_ref = Arc::new(Vec::new()); + + let gameloop_handle = spawn(async { //~ ERROR E0373 + game_loop(Arc::clone(&room_ref)) + }); + gameloop_handle.await; +} + +fn game_loop(v: Arc<Vec<usize>>) {} + +fn spawn<F>(future: F) -> JoinHandle +where + F: Future + Send + 'static, + F::Output: Send + 'static, +{ + loop {} +} + +struct JoinHandle; + +impl Future for JoinHandle { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + loop {} + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr new file mode 100644 index 000000000..29aa8372f --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr @@ -0,0 +1,19 @@ +error[E0373]: async block may outlive the current function, but it borrows `room_ref`, which is owned by the current function + --> $DIR/issue-78938-async-block.rs:8:39 + | +LL | let gameloop_handle = spawn(async { + | _______________________________________^ +LL | | game_loop(Arc::clone(&room_ref)) + | | -------- `room_ref` is borrowed here +LL | | }); + | |_____^ may outlive borrowed value `room_ref` + | + = note: async blocks are not executed immediately and must either take a reference or ownership of outside variables they use +help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword + | +LL | let gameloop_handle = spawn(async move { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/async-await/issues/issue-95307.rs b/src/test/ui/async-await/issues/issue-95307.rs new file mode 100644 index 000000000..f7e48070c --- /dev/null +++ b/src/test/ui/async-await/issues/issue-95307.rs @@ -0,0 +1,13 @@ +// edition:2018 + +// Regression test for #95307. +// The ICE occurred on all the editions, specifying edition:2018 to reduce diagnostics. + +pub trait C { + async fn new() -> [u8; _]; + //~^ ERROR: functions in traits cannot be declared `async` + //~| ERROR: using `_` for array lengths is unstable + //~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-95307.stderr b/src/test/ui/async-await/issues/issue-95307.stderr new file mode 100644 index 000000000..60fca71eb --- /dev/null +++ b/src/test/ui/async-await/issues/issue-95307.stderr @@ -0,0 +1,30 @@ +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/issue-95307.rs:7:5 + | +LL | async fn new() -> [u8; _]; + | -----^^^^^^^^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/issue-95307.rs:7:28 + | +LL | async fn new() -> [u8; _]; + | ^ + | + = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/issue-95307.rs:7:28 + | +LL | async fn new() -> [u8; _]; + | ^ `_` not allowed here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0658, E0706. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.rs b/src/test/ui/async-await/issues/non-async-enclosing-span.rs new file mode 100644 index 000000000..d47c21377 --- /dev/null +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.rs @@ -0,0 +1,11 @@ +// edition:2018 + +async fn do_the_thing() -> u8 { + 8 +} +// #63398: point at the enclosing scope and not the previously seen closure +fn main() { //~ NOTE this is not `async` + let x = move || {}; + let y = do_the_thing().await; //~ ERROR `await` is only allowed inside `async` functions + //~^ NOTE only allowed inside `async` functions and blocks +} diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr new file mode 100644 index 000000000..20b827479 --- /dev/null +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr @@ -0,0 +1,12 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/non-async-enclosing-span.rs:9:27 + | +LL | fn main() { + | ---- this is not `async` +LL | let x = move || {}; +LL | let y = do_the_thing().await; + | ^^^^^^ only allowed inside `async` functions and blocks + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/async-await/large_moves.attribute.stderr b/src/test/ui/async-await/large_moves.attribute.stderr new file mode 100644 index 000000000..8d3f0b77f --- /dev/null +++ b/src/test/ui/async-await/large_moves.attribute.stderr @@ -0,0 +1,45 @@ +error: moving 10024 bytes + --> $DIR/large_moves.rs:12:13 + | +LL | let x = async { + | _____________^ +LL | | let y = [0; 9999]; +LL | | dbg!(y); +LL | | thing(&y).await; +LL | | dbg!(y); +LL | | }; + | |_____^ value moved from here + | +note: the lint level is defined here + --> $DIR/large_moves.rs:1:9 + | +LL | #![deny(large_assignments)] + | ^^^^^^^^^^^^^^^^^ + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 10024 bytes + --> $DIR/large_moves.rs:18:14 + | +LL | let z = (x, 42); + | ^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 10024 bytes + --> $DIR/large_moves.rs:18:13 + | +LL | let z = (x, 42); + | ^^^^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 10024 bytes + --> $DIR/large_moves.rs:20:13 + | +LL | let a = z.0; + | ^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/async-await/large_moves.option.stderr b/src/test/ui/async-await/large_moves.option.stderr new file mode 100644 index 000000000..8d3f0b77f --- /dev/null +++ b/src/test/ui/async-await/large_moves.option.stderr @@ -0,0 +1,45 @@ +error: moving 10024 bytes + --> $DIR/large_moves.rs:12:13 + | +LL | let x = async { + | _____________^ +LL | | let y = [0; 9999]; +LL | | dbg!(y); +LL | | thing(&y).await; +LL | | dbg!(y); +LL | | }; + | |_____^ value moved from here + | +note: the lint level is defined here + --> $DIR/large_moves.rs:1:9 + | +LL | #![deny(large_assignments)] + | ^^^^^^^^^^^^^^^^^ + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 10024 bytes + --> $DIR/large_moves.rs:18:14 + | +LL | let z = (x, 42); + | ^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 10024 bytes + --> $DIR/large_moves.rs:18:13 + | +LL | let z = (x, 42); + | ^^^^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 10024 bytes + --> $DIR/large_moves.rs:20:13 + | +LL | let a = z.0; + | ^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/async-await/large_moves.rs b/src/test/ui/async-await/large_moves.rs new file mode 100644 index 000000000..18bb538a8 --- /dev/null +++ b/src/test/ui/async-await/large_moves.rs @@ -0,0 +1,26 @@ +#![deny(large_assignments)] +#![feature(large_assignments)] +#![cfg_attr(attribute, move_size_limit = "1000")] +// build-fail +// only-x86_64 +// revisions: attribute option +// [option]compile-flags: -Zmove-size-limit=1000 + +// edition:2018 + +fn main() { + let x = async { //~ ERROR large_assignments + let y = [0; 9999]; + dbg!(y); + thing(&y).await; + dbg!(y); + }; + let z = (x, 42); //~ ERROR large_assignments + //~^ ERROR large_assignments + let a = z.0; //~ ERROR large_assignments + let b = z.1; +} + +async fn thing(y: &[u8]) { + dbg!(y); +} diff --git a/src/test/ui/async-await/move-part-await-return-rest-struct.rs b/src/test/ui/async-await/move-part-await-return-rest-struct.rs new file mode 100644 index 000000000..39ea2aae5 --- /dev/null +++ b/src/test/ui/async-await/move-part-await-return-rest-struct.rs @@ -0,0 +1,18 @@ +// build-pass +// edition:2018 +// compile-flags: --crate-type lib + +struct Small { + x: Vec<usize>, + y: Vec<usize>, +} + +// You are allowed to move out part of a struct to an async fn, you still +// have access to remaining parts after awaiting +async fn move_part_await_return_rest_struct() -> Vec<usize> { + let s = Small { x: vec![31], y: vec![19, 1441] }; + needs_vec(s.x).await; + s.y +} + +async fn needs_vec(_vec: Vec<usize>) {} diff --git a/src/test/ui/async-await/move-part-await-return-rest-tuple.rs b/src/test/ui/async-await/move-part-await-return-rest-tuple.rs new file mode 100644 index 000000000..7b958b98b --- /dev/null +++ b/src/test/ui/async-await/move-part-await-return-rest-tuple.rs @@ -0,0 +1,12 @@ +// build-pass +// edition:2018 +// compile-flags: --crate-type lib + +async fn move_part_await_return_rest_tuple() -> Vec<usize> { + let x = (vec![3], vec![4, 4]); + drop(x.1); + echo(x.0[0]).await; + x.0 +} + +async fn echo(x: usize) -> usize { x } diff --git a/src/test/ui/async-await/multiple-lifetimes/elided.rs b/src/test/ui/async-await/multiple-lifetimes/elided.rs new file mode 100644 index 000000000..8258e2eff --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/elided.rs @@ -0,0 +1,10 @@ +// edition:2018 +// run-pass + +// Test that we can use async fns with multiple arbitrary lifetimes. + +async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} + +fn main() { + let _ = multiple_elided_lifetimes(&22, &44); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs b/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs new file mode 100644 index 000000000..3912b8547 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs @@ -0,0 +1,12 @@ +// edition:2018 +// run-pass + +// Test that we can use async fns with multiple arbitrary lifetimes. + +async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8, _: fn(&u8)) {} + +fn gimme(_: &u8) { } + +fn main() { + let _ = multiple_named_lifetimes(&22, &44, gimme); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/hrtb.rs b/src/test/ui/async-await/multiple-lifetimes/hrtb.rs new file mode 100644 index 000000000..e788ca5ff --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/hrtb.rs @@ -0,0 +1,14 @@ +// edition:2018 +// check-pass + +// Test that we can use async fns with multiple arbitrary lifetimes. + +use std::ops::Add; + +async fn multiple_hrtb_and_single_named_lifetime_ok<'c>( + _: impl for<'a> Add<&'a u8>, + _: impl for<'b> Add<&'b u8>, + _: &'c u8, +) {} + +fn main() {} diff --git a/src/test/ui/async-await/multiple-lifetimes/named.rs b/src/test/ui/async-await/multiple-lifetimes/named.rs new file mode 100644 index 000000000..e8eb98102 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/named.rs @@ -0,0 +1,10 @@ +// edition:2018 +// run-pass + +// Test that we can use async fns with multiple arbitrary lifetimes. + +async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {} + +fn main() { + let _ = multiple_named_lifetimes(&22, &44); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs b/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs new file mode 100644 index 000000000..02b105999 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/partial-relation.rs @@ -0,0 +1,13 @@ +// edition:2018 +// run-pass + +async fn lotsa_lifetimes<'a, 'b, 'c>(a: &'a u32, b: &'b u32, c: &'c u32) -> (&'a u32, &'b u32) + where 'b: 'a +{ + drop((a, c)); + (b, b) +} + +fn main() { + let _ = lotsa_lifetimes(&22, &44, &66); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs new file mode 100644 index 000000000..f1002947f --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs @@ -0,0 +1,17 @@ +// edition:2018 +// run-pass + +// Test member constraints that appear in the `impl Trait` +// return type of an async function. +// (This used to require a feature gate.) + +trait Trait<'a, 'b> { } +impl<T> Trait<'_, '_> for T { } + +async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { + (a, b) +} + +fn main() { + let _ = async_ret_impl_trait(&22, &44); +} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs new file mode 100644 index 000000000..aebc77d26 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs @@ -0,0 +1,31 @@ +// edition:2018 + +// Test that a feature gate is needed to use `impl Trait` as the +// return type of an async. + +trait Trait<'a> { } +impl<T> Trait<'_> for T { } + +// Fails to recognize that both 'a and 'b are mentioned and should thus be accepted +async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { + //~^ ERROR lifetime may not live long enough + (a, b) +} + +// Only `'a` permitted in return type, not `'b`. +async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { + //~^ ERROR captures lifetime that does not appear in bounds + (a, b) +} + +// As above, but `'b: 'a`, so return type can be inferred to `(&'a u8, +// &'a u8)`. +async fn async_ret_impl_trait2<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> +where + 'b: 'a, +{ + (a, b) +} + +fn main() { +} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr new file mode 100644 index 000000000..3128b4df4 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -0,0 +1,35 @@ +error: lifetime may not live long enough + --> $DIR/ret-impl-trait-one.rs:10:85 + | +LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { + | ________________________________--__--_______________________________________________^ + | | | | + | | | lifetime `'b` defined here + | | lifetime `'a` defined here +LL | | +LL | | (a, b) +LL | | } + | |_^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error[E0700]: hidden type for `impl Trait<'a>` captures lifetime that does not appear in bounds + --> $DIR/ret-impl-trait-one.rs:16:80 + | +LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { + | ____________________________________--__________________________________________^ + | | | + | | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here +LL | | +LL | | (a, b) +LL | | } + | |_^ + | +help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs b/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs new file mode 100644 index 000000000..149c020f9 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-ref.rs @@ -0,0 +1,44 @@ +// edition:2018 + +// Test that we get the expected borrow check errors when an async +// function (which takes multiple lifetimes) only returns data from +// one of them. + +async fn multiple_named_lifetimes<'a, 'b>(a: &'a u8, _: &'b u8) -> &'a u8 { + a +} + +// Both are borrowed whilst the future is live. +async fn future_live() { + let mut a = 22; + let mut b = 44; + let future = multiple_named_lifetimes(&a, &b); + a += 1; //~ ERROR cannot assign + b += 1; //~ ERROR cannot assign + let p = future.await; + drop(p); +} + +// Just the return value is live after future is awaited. +async fn just_return_live() { + let mut a = 22; + let mut b = 44; + let future = multiple_named_lifetimes(&a, &b); + let p = future.await; + a += 1; //~ ERROR cannot assign + b += 1; + drop(p); +} + +// Once `p` is dead, both `a` and `b` are unborrowed. +async fn after_both_dead() { + let mut a = 22; + let mut b = 44; + let future = multiple_named_lifetimes(&a, &b); + let p = future.await; + drop(p); + a += 1; + b += 1; +} + +fn main() { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr new file mode 100644 index 000000000..d86e84033 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/ret-ref.stderr @@ -0,0 +1,37 @@ +error[E0506]: cannot assign to `a` because it is borrowed + --> $DIR/ret-ref.rs:16:5 + | +LL | let future = multiple_named_lifetimes(&a, &b); + | -- borrow of `a` occurs here +LL | a += 1; + | ^^^^^^ assignment to borrowed `a` occurs here +LL | b += 1; +LL | let p = future.await; + | ------ borrow later used here + +error[E0506]: cannot assign to `b` because it is borrowed + --> $DIR/ret-ref.rs:17:5 + | +LL | let future = multiple_named_lifetimes(&a, &b); + | -- borrow of `b` occurs here +LL | a += 1; +LL | b += 1; + | ^^^^^^ assignment to borrowed `b` occurs here +LL | let p = future.await; + | ------ borrow later used here + +error[E0506]: cannot assign to `a` because it is borrowed + --> $DIR/ret-ref.rs:28:5 + | +LL | let future = multiple_named_lifetimes(&a, &b); + | -- borrow of `a` occurs here +LL | let p = future.await; +LL | a += 1; + | ^^^^^^ assignment to borrowed `a` occurs here +LL | b += 1; +LL | drop(p); + | - borrow later used here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/async-await/multiple-lifetimes/variance.rs b/src/test/ui/async-await/multiple-lifetimes/variance.rs new file mode 100644 index 000000000..6ed8bef95 --- /dev/null +++ b/src/test/ui/async-await/multiple-lifetimes/variance.rs @@ -0,0 +1,15 @@ +// edition:2018 +// run-pass + +// Test for async fn where the parameters have distinct lifetime +// parameters that appear in all possible variances. + +async fn lotsa_lifetimes<'a, 'b, 'c>(_: fn(&'a u8), _: fn(&'b u8) -> &'b u8, _: fn() -> &'c u8) { } + +fn take_any(_: &u8) { } +fn identify(x: &u8) -> &u8 { x } +fn give_back() -> &'static u8 { &22 } + +fn main() { + let _ = lotsa_lifetimes(take_any, identify, give_back); +} diff --git a/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.rs b/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.rs new file mode 100644 index 000000000..bb2a61f03 --- /dev/null +++ b/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.rs @@ -0,0 +1,13 @@ +// edition:2018 +// Test that impl trait does not allow creating recursive types that are +// otherwise forbidden when using `async` and `await`. + +async fn rec_1() { //~ ERROR recursion in an `async fn` + rec_2().await; +} + +async fn rec_2() { //~ ERROR recursion in an `async fn` + rec_1().await; +} + +fn main() {} diff --git a/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.stderr b/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.stderr new file mode 100644 index 000000000..f789ad2a0 --- /dev/null +++ b/src/test/ui/async-await/mutually-recursive-async-impl-trait-type.stderr @@ -0,0 +1,21 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:5:18 + | +LL | async fn rec_1() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18 + | +LL | async fn rec_2() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0733`. diff --git a/src/test/ui/async-await/nested-in-impl.rs b/src/test/ui/async-await/nested-in-impl.rs new file mode 100644 index 000000000..76ed827d5 --- /dev/null +++ b/src/test/ui/async-await/nested-in-impl.rs @@ -0,0 +1,15 @@ +// Test that async fn works when nested inside of +// impls with lifetime parameters. +// +// check-pass +// edition:2018 + +struct Foo<'a>(&'a ()); + +impl<'a> Foo<'a> { + fn test() { + async fn test() {} + } +} + +fn main() { } diff --git a/src/test/ui/async-await/no-async-const.rs b/src/test/ui/async-await/no-async-const.rs new file mode 100644 index 000000000..963460c11 --- /dev/null +++ b/src/test/ui/async-await/no-async-const.rs @@ -0,0 +1,5 @@ +// edition:2018 +// compile-flags: --crate-type lib + +pub async const fn x() {} +//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const` diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr new file mode 100644 index 000000000..a51dc88a4 --- /dev/null +++ b/src/test/ui/async-await/no-async-const.stderr @@ -0,0 +1,13 @@ +error: expected one of `extern`, `fn`, or `unsafe`, found keyword `const` + --> $DIR/no-async-const.rs:4:11 + | +LL | pub async const fn x() {} + | ------^^^^^ + | | | + | | expected one of `extern`, `fn`, or `unsafe` + | help: `const` must come before `async`: `const async` + | + = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs new file mode 100644 index 000000000..cfb0ef1b3 --- /dev/null +++ b/src/test/ui/async-await/no-const-async.rs @@ -0,0 +1,6 @@ +// edition:2018 +// compile-flags: --crate-type lib + +pub const async fn x() {} +//~^ ERROR functions cannot be both `const` and `async` +//~| ERROR cycle detected diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr new file mode 100644 index 000000000..e6f6e9e9f --- /dev/null +++ b/src/test/ui/async-await/no-const-async.stderr @@ -0,0 +1,42 @@ +error: functions cannot be both `const` and `async` + --> $DIR/no-const-async.rs:4:5 + | +LL | pub const async fn x() {} + | ----^^^^^-^^^^^---------- + | | | + | | `async` because of this + | `const` because of this + +error[E0391]: cycle detected when computing type of `x::{opaque#0}` + --> $DIR/no-const-async.rs:4:24 + | +LL | pub const async fn x() {} + | ^ + | +note: ...which requires borrow-checking `x`... + --> $DIR/no-const-async.rs:4:1 + | +LL | pub const async fn x() {} + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `x`... + --> $DIR/no-const-async.rs:4:1 + | +LL | pub const async fn x() {} + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const checking `x`... + --> $DIR/no-const-async.rs:4:1 + | +LL | pub const async fn x() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze... + = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`... + = note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/no-const-async.rs:4:1 + | +LL | pub const async fn x() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/async-await/no-move-across-await-struct.rs b/src/test/ui/async-await/no-move-across-await-struct.rs new file mode 100644 index 000000000..51c9a42b3 --- /dev/null +++ b/src/test/ui/async-await/no-move-across-await-struct.rs @@ -0,0 +1,16 @@ +// edition:2018 +// compile-flags: --crate-type lib + +async fn no_move_across_await_struct() -> Vec<usize> { + let s = Small { x: vec![31], y: vec![19, 1441] }; + needs_vec(s.x).await; + s.x + //~^ ERROR use of moved value: `s.x` +} + +struct Small { + x: Vec<usize>, + y: Vec<usize>, +} + +async fn needs_vec(_vec: Vec<usize>) {} diff --git a/src/test/ui/async-await/no-move-across-await-struct.stderr b/src/test/ui/async-await/no-move-across-await-struct.stderr new file mode 100644 index 000000000..4eaed1cf1 --- /dev/null +++ b/src/test/ui/async-await/no-move-across-await-struct.stderr @@ -0,0 +1,13 @@ +error[E0382]: use of moved value: `s.x` + --> $DIR/no-move-across-await-struct.rs:7:5 + | +LL | needs_vec(s.x).await; + | --- value moved here +LL | s.x + | ^^^ value used here after move + | + = note: move occurs because `s.x` has type `Vec<usize>`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/async-await/no-move-across-await-tuple.rs b/src/test/ui/async-await/no-move-across-await-tuple.rs new file mode 100644 index 000000000..a65633269 --- /dev/null +++ b/src/test/ui/async-await/no-move-across-await-tuple.rs @@ -0,0 +1,12 @@ +// edition:2018 +// compile-flags: --crate-type lib + +async fn no_move_across_await_tuple() -> Vec<usize> { + let x = (vec![3], vec![4, 4]); + drop(x.1); + nothing().await; + x.1 + //~^ ERROR use of moved value: `x.1` +} + +async fn nothing() {} diff --git a/src/test/ui/async-await/no-move-across-await-tuple.stderr b/src/test/ui/async-await/no-move-across-await-tuple.stderr new file mode 100644 index 000000000..d750df991 --- /dev/null +++ b/src/test/ui/async-await/no-move-across-await-tuple.stderr @@ -0,0 +1,14 @@ +error[E0382]: use of moved value: `x.1` + --> $DIR/no-move-across-await-tuple.rs:8:5 + | +LL | drop(x.1); + | --- value moved here +LL | nothing().await; +LL | x.1 + | ^^^ value used here after move + | + = note: move occurs because `x.1` has type `Vec<usize>`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/async-await/no-non-guaranteed-initialization.rs b/src/test/ui/async-await/no-non-guaranteed-initialization.rs new file mode 100644 index 000000000..c4d81bf83 --- /dev/null +++ b/src/test/ui/async-await/no-non-guaranteed-initialization.rs @@ -0,0 +1,12 @@ +// edition:2018 +// compile-flags: --crate-type lib + +async fn no_non_guaranteed_initialization(x: usize) -> usize { + let y; + if x > 5 { + y = echo(10).await; + } + y //~ ERROR E0381 +} + +async fn echo(x: usize) -> usize { x + 1 } diff --git a/src/test/ui/async-await/no-non-guaranteed-initialization.stderr b/src/test/ui/async-await/no-non-guaranteed-initialization.stderr new file mode 100644 index 000000000..12c15bf56 --- /dev/null +++ b/src/test/ui/async-await/no-non-guaranteed-initialization.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `y` is possibly-uninitialized + --> $DIR/no-non-guaranteed-initialization.rs:9:5 + | +LL | let y; + | - binding declared here but left uninitialized +LL | if x > 5 { + | ----- if this `if` condition is `false`, `y` is not initialized +LL | y = echo(10).await; +LL | } + | - an `else` arm might be missing here, initializing `y` +LL | y + | ^ `y` used here but it is possibly-uninitialized + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/async-await/no-params-non-move-async-closure.rs b/src/test/ui/async-await/no-params-non-move-async-closure.rs new file mode 100644 index 000000000..3b15f35c2 --- /dev/null +++ b/src/test/ui/async-await/no-params-non-move-async-closure.rs @@ -0,0 +1,8 @@ +// edition:2018 + +#![feature(async_closure)] + +fn main() { + let _ = async |x: u8| {}; + //~^ ERROR `async` non-`move` closures with parameters are not currently supported +} diff --git a/src/test/ui/async-await/no-params-non-move-async-closure.stderr b/src/test/ui/async-await/no-params-non-move-async-closure.stderr new file mode 100644 index 000000000..1f589c516 --- /dev/null +++ b/src/test/ui/async-await/no-params-non-move-async-closure.stderr @@ -0,0 +1,11 @@ +error[E0708]: `async` non-`move` closures with parameters are not currently supported + --> $DIR/no-params-non-move-async-closure.rs:6:13 + | +LL | let _ = async |x: u8| {}; + | ^^^^^^^^^^^^^ + | + = help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0708`. diff --git a/src/test/ui/async-await/no-std.rs b/src/test/ui/async-await/no-std.rs new file mode 100644 index 000000000..63e93cdff --- /dev/null +++ b/src/test/ui/async-await/no-std.rs @@ -0,0 +1,13 @@ +// edition:2018 +// check-pass + +#![no_std] +#![crate_type = "rlib"] + +use core::future::Future; + +async fn a(f: impl Future) { + f.await; +} + +fn main() {} diff --git a/src/test/ui/async-await/no-unsafe-async.rs b/src/test/ui/async-await/no-unsafe-async.rs new file mode 100644 index 000000000..f40154e16 --- /dev/null +++ b/src/test/ui/async-await/no-unsafe-async.rs @@ -0,0 +1,11 @@ +// edition:2018 + +struct S; + +impl S { + #[cfg(FALSE)] + unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async` +} + +#[cfg(FALSE)] +unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async` diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr new file mode 100644 index 000000000..f23d17d6b --- /dev/null +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -0,0 +1,29 @@ +error: expected one of `extern` or `fn`, found keyword `async` + --> $DIR/no-unsafe-async.rs:7:12 + | +LL | impl S { + | - while parsing this item list starting here +LL | #[cfg(FALSE)] +LL | unsafe async fn g() {} + | -------^^^^^ + | | | + | | expected one of `extern` or `fn` + | help: `async` must come before `unsafe`: `async unsafe` +LL | } + | - the item list ends here + | + = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` + +error: expected one of `extern` or `fn`, found keyword `async` + --> $DIR/no-unsafe-async.rs:11:8 + | +LL | unsafe async fn f() {} + | -------^^^^^ + | | | + | | expected one of `extern` or `fn` + | help: `async` must come before `unsafe`: `async unsafe` + | + = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/async-await/non-trivial-drop.rs b/src/test/ui/async-await/non-trivial-drop.rs new file mode 100644 index 000000000..a3167215d --- /dev/null +++ b/src/test/ui/async-await/non-trivial-drop.rs @@ -0,0 +1,36 @@ +// build-pass +// edition:2018 +// compile-flags: -Zdrop-tracking=y + +#![feature(generators)] + +fn main() { + let _ = foo(); +} + +fn foo() { + || { + yield drop(Config { + nickname: NonCopy, + b: NonCopy2, + }.nickname); + }; +} + +#[derive(Default)] +struct NonCopy; +impl Drop for NonCopy { + fn drop(&mut self) {} +} + +#[derive(Default)] +struct NonCopy2; +impl Drop for NonCopy2 { + fn drop(&mut self) {} +} + +#[derive(Default)] +struct Config { + nickname: NonCopy, + b: NonCopy2, +} diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.rs b/src/test/ui/async-await/partial-drop-partial-reinit.rs new file mode 100644 index 000000000..fe0fce7af --- /dev/null +++ b/src/test/ui/async-await/partial-drop-partial-reinit.rs @@ -0,0 +1,37 @@ +// edition:2021 +#![feature(negative_impls)] +#![allow(unused)] + +fn main() { + gimme_send(foo()); + //~^ ERROR cannot be sent between threads safely + //~| NOTE cannot be sent + //~| NOTE bound introduced by + //~| NOTE appears within the type + //~| NOTE captures the following types +} + +fn gimme_send<T: Send>(t: T) { +//~^ NOTE required by this bound +//~| NOTE required by a bound + drop(t); +} + +struct NotSend {} + +impl Drop for NotSend { + fn drop(&mut self) {} +} + +impl !Send for NotSend {} + +async fn foo() { +//~^ NOTE used within this `async fn` body +//~| NOTE within this `impl Future + let mut x = (NotSend {},); + drop(x.0); + x.0 = NotSend {}; + bar().await; +} + +async fn bar() {} diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.stderr new file mode 100644 index 000000000..05f535834 --- /dev/null +++ b/src/test/ui/async-await/partial-drop-partial-reinit.stderr @@ -0,0 +1,35 @@ +error[E0277]: `NotSend` cannot be sent between threads safely + --> $DIR/partial-drop-partial-reinit.rs:6:16 + | +LL | gimme_send(foo()); + | ---------- ^^^^^ `NotSend` cannot be sent between threads safely + | | + | required by a bound introduced by this call +... +LL | async fn foo() { + | - within this `impl Future<Output = ()>` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend` + = note: required because it appears within the type `(NotSend,)` + = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `impl Future<Output = ()>`, `()` +note: required because it's used within this `async fn` body + --> $DIR/partial-drop-partial-reinit.rs:28:16 + | +LL | async fn foo() { + | ________________^ +LL | | +LL | | +LL | | let mut x = (NotSend {},); +... | +LL | | bar().await; +LL | | } + | |_^ +note: required by a bound in `gimme_send` + --> $DIR/partial-drop-partial-reinit.rs:14:18 + | +LL | fn gimme_send<T: Send>(t: T) { + | ^^^^ required by this bound in `gimme_send` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/partial-initialization-across-await.rs b/src/test/ui/async-await/partial-initialization-across-await.rs new file mode 100644 index 000000000..7577aee3f --- /dev/null +++ b/src/test/ui/async-await/partial-initialization-across-await.rs @@ -0,0 +1,39 @@ +// Test that we don't allow awaiting from an async fn while a local is partially +// initialized. + +// edition:2018 + +struct S { x: i32, y: i32 } +struct T(i32, i32); + +async fn noop() {} + +async fn test_tuple() { + let mut t: (i32, i32); + t.0 = 42; //~ ERROR E0381 + noop().await; + t.1 = 88; + let _ = t; +} + +async fn test_tuple_struct() { + let mut t: T; + t.0 = 42; //~ ERROR E0381 + noop().await; + t.1 = 88; + let _ = t; +} + +async fn test_struct() { + let mut t: S; + t.x = 42; //~ ERROR E0381 + noop().await; + t.y = 88; + let _ = t; +} + +fn main() { + let _ = test_tuple(); + let _ = test_tuple_struct(); + let _ = test_struct(); +} diff --git a/src/test/ui/async-await/partial-initialization-across-await.stderr b/src/test/ui/async-await/partial-initialization-across-await.stderr new file mode 100644 index 000000000..6a0eeffb9 --- /dev/null +++ b/src/test/ui/async-await/partial-initialization-across-await.stderr @@ -0,0 +1,33 @@ +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/partial-initialization-across-await.rs:13:5 + | +LL | let mut t: (i32, i32); + | ----- binding declared here but left uninitialized +LL | t.0 = 42; + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` + +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/partial-initialization-across-await.rs:21:5 + | +LL | let mut t: T; + | ----- binding declared here but left uninitialized +LL | t.0 = 42; + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` + +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/partial-initialization-across-await.rs:29:5 + | +LL | let mut t: S; + | ----- binding declared here but left uninitialized +LL | t.x = 42; + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/async-await/pin-needed-to-poll-2.rs b/src/test/ui/async-await/pin-needed-to-poll-2.rs new file mode 100644 index 000000000..6ce70336d --- /dev/null +++ b/src/test/ui/async-await/pin-needed-to-poll-2.rs @@ -0,0 +1,48 @@ +use std::{ + future::Future, + pin::Pin, + marker::Unpin, + task::{Context, Poll}, +}; + +struct Sleep(std::marker::PhantomPinned); + +impl Future for Sleep { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Ready(()) + } +} + +impl Drop for Sleep { + fn drop(&mut self) {} +} + +fn sleep() -> Sleep { + Sleep(std::marker::PhantomPinned) +} + + +struct MyFuture { + sleep: Sleep, +} + +impl MyFuture { + fn new() -> Self { + Self { + sleep: sleep(), + } + } +} + +impl Future for MyFuture { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + Pin::new(&mut self.sleep).poll(cx) + //~^ ERROR `PhantomPinned` cannot be unpinned + } +} + +fn main() {} diff --git a/src/test/ui/async-await/pin-needed-to-poll-2.stderr b/src/test/ui/async-await/pin-needed-to-poll-2.stderr new file mode 100644 index 000000000..83d1a02c8 --- /dev/null +++ b/src/test/ui/async-await/pin-needed-to-poll-2.stderr @@ -0,0 +1,23 @@ +error[E0277]: `PhantomPinned` cannot be unpinned + --> $DIR/pin-needed-to-poll-2.rs:43:18 + | +LL | Pin::new(&mut self.sleep).poll(cx) + | -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned` + | | + | required by a bound introduced by this call + | + = note: consider using `Box::pin` +note: required because it appears within the type `Sleep` + --> $DIR/pin-needed-to-poll-2.rs:8:8 + | +LL | struct Sleep(std::marker::PhantomPinned); + | ^^^^^ +note: required by a bound in `Pin::<P>::new` + --> $SRC_DIR/core/src/pin.rs:LL:COL + | +LL | impl<P: Deref<Target: Unpin>> Pin<P> { + | ^^^^^ required by this bound in `Pin::<P>::new` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/pin-needed-to-poll.rs b/src/test/ui/async-await/pin-needed-to-poll.rs new file mode 100644 index 000000000..0d1fe684f --- /dev/null +++ b/src/test/ui/async-await/pin-needed-to-poll.rs @@ -0,0 +1,47 @@ +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; + +struct Sleep; + +impl Future for Sleep { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + Poll::Ready(()) + } +} + +impl Drop for Sleep { + fn drop(&mut self) {} +} + +fn sleep() -> Sleep { + Sleep +} + + +struct MyFuture { + sleep: Sleep, +} + +impl MyFuture { + fn new() -> Self { + Self { + sleep: sleep(), + } + } +} + +impl Future for MyFuture { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + self.sleep.poll(cx) + //~^ ERROR no method named `poll` found for struct `Sleep` in the current scope + } +} + +fn main() {} diff --git a/src/test/ui/async-await/pin-needed-to-poll.stderr b/src/test/ui/async-await/pin-needed-to-poll.stderr new file mode 100644 index 000000000..2e8723b27 --- /dev/null +++ b/src/test/ui/async-await/pin-needed-to-poll.stderr @@ -0,0 +1,22 @@ +error[E0599]: no method named `poll` found for struct `Sleep` in the current scope + --> $DIR/pin-needed-to-poll.rs:42:20 + | +LL | struct Sleep; + | ------------ method `poll` not found for this struct +... +LL | self.sleep.poll(cx) + | ^^^^ method not found in `Sleep` + | + ::: $SRC_DIR/core/src/future/future.rs:LL:COL + | +LL | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>; + | ---- the method is available for `Pin<&mut Sleep>` here + | +help: consider wrapping the receiver expression with the appropriate type + | +LL | Pin::new(&mut self.sleep).poll(cx) + | +++++++++++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/async-await/proper-span-for-type-error.fixed b/src/test/ui/async-await/proper-span-for-type-error.fixed new file mode 100644 index 000000000..7d43b575d --- /dev/null +++ b/src/test/ui/async-await/proper-span-for-type-error.fixed @@ -0,0 +1,12 @@ +// edition:2021 +// run-rustfix +#![allow(dead_code)] + +async fn a() {} + +async fn foo() -> Result<(), i32> { + a().await; + Ok(()) //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/async-await/proper-span-for-type-error.rs b/src/test/ui/async-await/proper-span-for-type-error.rs new file mode 100644 index 000000000..00ccde1bf --- /dev/null +++ b/src/test/ui/async-await/proper-span-for-type-error.rs @@ -0,0 +1,11 @@ +// edition:2021 +// run-rustfix +#![allow(dead_code)] + +async fn a() {} + +async fn foo() -> Result<(), i32> { + a().await //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/async-await/proper-span-for-type-error.stderr b/src/test/ui/async-await/proper-span-for-type-error.stderr new file mode 100644 index 000000000..25f05156c --- /dev/null +++ b/src/test/ui/async-await/proper-span-for-type-error.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/proper-span-for-type-error.rs:8:5 + | +LL | a().await + | ^^^^^^^^^ expected enum `Result`, found `()` + | + = note: expected enum `Result<(), i32>` + found unit type `()` +help: try adding an expression at the end of the block + | +LL ~ a().await; +LL ~ Ok(()) + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/recursive-async-impl-trait-type.rs b/src/test/ui/async-await/recursive-async-impl-trait-type.rs new file mode 100644 index 000000000..edc4cb8ac --- /dev/null +++ b/src/test/ui/async-await/recursive-async-impl-trait-type.rs @@ -0,0 +1,10 @@ +// edition:2018 +// Test that impl trait does not allow creating recursive types that are +// otherwise forbidden when using `async` and `await`. + +async fn recursive_async_function() -> () { + //~^ ERROR recursion in an `async fn` requires boxing + recursive_async_function().await; +} + +fn main() {} diff --git a/src/test/ui/async-await/recursive-async-impl-trait-type.stderr b/src/test/ui/async-await/recursive-async-impl-trait-type.stderr new file mode 100644 index 000000000..63f64f445 --- /dev/null +++ b/src/test/ui/async-await/recursive-async-impl-trait-type.stderr @@ -0,0 +1,12 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/recursive-async-impl-trait-type.rs:5:40 + | +LL | async fn recursive_async_function() -> () { + | ^^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0733`. diff --git a/src/test/ui/async-await/repeat_count_const_in_async_fn.rs b/src/test/ui/async-await/repeat_count_const_in_async_fn.rs new file mode 100644 index 000000000..ebabc3fbf --- /dev/null +++ b/src/test/ui/async-await/repeat_count_const_in_async_fn.rs @@ -0,0 +1,10 @@ +// check-pass +// edition:2018 +// compile-flags: --crate-type=lib + +pub async fn test() { + const C: usize = 4; + foo(&mut [0u8; C]).await; +} + +async fn foo(_: &mut [u8]) {} diff --git a/src/test/ui/async-await/return-ty-raw-ptr-coercion.rs b/src/test/ui/async-await/return-ty-raw-ptr-coercion.rs new file mode 100644 index 000000000..9fe0869ca --- /dev/null +++ b/src/test/ui/async-await/return-ty-raw-ptr-coercion.rs @@ -0,0 +1,25 @@ +// Check that we apply unsizing coercions based on the return type. +// +// Also serves as a regression test for #60424. +// +// edition:2018 +// check-pass + +#![allow(warnings)] + +use std::fmt::Debug; + +const TMP: u32 = 22; + +// Coerce from `&u32` to `*const u32` +fn raw_pointer_coercion() { + fn sync_example() -> *const u32 { + &TMP + } + + async fn async_example() -> *const u32 { + &TMP + } +} + +fn main() {} diff --git a/src/test/ui/async-await/return-ty-unsize-coercion.rs b/src/test/ui/async-await/return-ty-unsize-coercion.rs new file mode 100644 index 000000000..93832ef7e --- /dev/null +++ b/src/test/ui/async-await/return-ty-unsize-coercion.rs @@ -0,0 +1,45 @@ +// Check that we apply unsizing coercions based on the return type. +// +// Also serves as a regression test for #60424. +// +// edition:2018 +// check-pass + +#![allow(warnings)] + +use std::fmt::Debug; + +// Unsizing coercion from `Box<&'static str>` to `Box<dyn Debug>`. +fn unsize_trait_coercion() { + fn sync_example() -> Box<dyn Debug> { + Box::new("asdf") + } + + async fn async_example() -> Box<dyn Debug> { + Box::new("asdf") + } +} + +// Unsizing coercion from `Box<[u32; N]>` to `Box<[32]>`. +fn unsize_slice_coercion() { + fn sync_example() -> Box<[u32]> { + Box::new([0]) + } + + async fn async_example() -> Box<[u32]> { + Box::new([0]) + } +} + +// Unsizing coercion from `&[&str; 1]` to `&[&str]` +fn unsize_slice_str_coercion() { + fn sync_example() -> &'static [&'static str] { + &["hi"] + } + + async fn async_example() -> &'static [&'static str] { + &["hi"] + } +} + +fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await-closure.fixed b/src/test/ui/async-await/suggest-missing-await-closure.fixed new file mode 100644 index 000000000..febcd0218 --- /dev/null +++ b/src/test/ui/async-await/suggest-missing-await-closure.fixed @@ -0,0 +1,23 @@ +// edition:2018 +// run-rustfix + +#![feature(async_closure)] + +fn take_u32(_x: u32) {} + +async fn make_u32() -> u32 { + 22 +} + +#[allow(unused)] +async fn suggest_await_in_async_closure() { + async || { + let x = make_u32(); + take_u32(x.await) + //~^ ERROR mismatched types [E0308] + //~| HELP consider `await`ing on the `Future` + //~| SUGGESTION .await + }; +} + +fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await-closure.rs b/src/test/ui/async-await/suggest-missing-await-closure.rs new file mode 100644 index 000000000..faabf6ee3 --- /dev/null +++ b/src/test/ui/async-await/suggest-missing-await-closure.rs @@ -0,0 +1,23 @@ +// edition:2018 +// run-rustfix + +#![feature(async_closure)] + +fn take_u32(_x: u32) {} + +async fn make_u32() -> u32 { + 22 +} + +#[allow(unused)] +async fn suggest_await_in_async_closure() { + async || { + let x = make_u32(); + take_u32(x) + //~^ ERROR mismatched types [E0308] + //~| HELP consider `await`ing on the `Future` + //~| SUGGESTION .await + }; +} + +fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr new file mode 100644 index 000000000..a5958baff --- /dev/null +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -0,0 +1,28 @@ +error[E0308]: mismatched types + --> $DIR/suggest-missing-await-closure.rs:16:18 + | +LL | take_u32(x) + | -------- ^ expected `u32`, found opaque type + | | + | arguments to this function are incorrect + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await-closure.rs:8:24 + | +LL | async fn make_u32() -> u32 { + | ^^^ checked the `Output` of this `async fn`, found opaque type + = note: expected type `u32` + found opaque type `impl Future<Output = u32>` +note: function defined here + --> $DIR/suggest-missing-await-closure.rs:6:4 + | +LL | fn take_u32(_x: u32) {} + | ^^^^^^^^ ------- +help: consider `await`ing on the `Future` + | +LL | take_u32(x.await) + | ++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs new file mode 100644 index 000000000..796f82e77 --- /dev/null +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -0,0 +1,74 @@ +// edition:2018 + +fn take_u32(_x: u32) {} + +async fn make_u32() -> u32 { + 22 +} + +#[allow(unused)] +async fn suggest_await_in_async_fn() { + let x = make_u32(); + take_u32(x) + //~^ ERROR mismatched types [E0308] + //~| HELP consider `await`ing on the `Future` + //~| SUGGESTION .await +} + +async fn dummy() {} + +#[allow(unused)] +async fn suggest_await_in_async_fn_return() { + dummy() + //~^ ERROR mismatched types [E0308] + //~| HELP consider `await`ing on the `Future` + //~| HELP consider using a semicolon here + //~| SUGGESTION .await +} + +#[allow(unused)] +async fn suggest_await_on_if() { + let _x = if true { + dummy() + //~^ HELP consider `await`ing on the `Future` + } else { + dummy().await + //~^ ERROR `if` and `else` have incompatible types [E0308] + }; +} + +#[allow(unused)] +async fn suggest_await_on_previous_match_arms() { + let _x = match 0usize { + 0 => dummy(), //~ HELP consider `await`ing on the `Future` + 1 => dummy(), + 2 => dummy().await, + //~^ `match` arms have incompatible types [E0308] + }; +} + +#[allow(unused)] +async fn suggest_await_on_match_expr() { + let _x = match dummy() { //~ HELP consider `await`ing on the `Future` + () => {} //~ ERROR mismatched types [E0308] + }; +} + +async fn dummy_result() -> Result<(), ()> { + Ok(()) +} + +#[allow(unused)] +async fn suggest_await_in_generic_pattern() { + match dummy_result() { + //~^ HELP consider `await`ing on the `Future` + //~| HELP consider `await`ing on the `Future` + //~| SUGGESTION .await + Ok(_) => {} + //~^ ERROR mismatched types [E0308] + Err(_) => {} + //~^ ERROR mismatched types [E0308] + } +} + +fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr new file mode 100644 index 000000000..1196601ac --- /dev/null +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -0,0 +1,167 @@ +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:12:14 + | +LL | take_u32(x) + | -------- ^ expected `u32`, found opaque type + | | + | arguments to this function are incorrect + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:5:24 + | +LL | async fn make_u32() -> u32 { + | ^^^ checked the `Output` of this `async fn`, found opaque type + = note: expected type `u32` + found opaque type `impl Future<Output = u32>` +note: function defined here + --> $DIR/suggest-missing-await.rs:3:4 + | +LL | fn take_u32(_x: u32) {} + | ^^^^^^^^ ------- +help: consider `await`ing on the `Future` + | +LL | take_u32(x.await) + | ++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:22:5 + | +LL | dummy() + | ^^^^^^^ expected `()`, found opaque type + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:18:18 + | +LL | async fn dummy() {} + | ^ checked the `Output` of this `async fn`, found opaque type + = note: expected unit type `()` + found opaque type `impl Future<Output = ()>` +help: consider `await`ing on the `Future` + | +LL | dummy().await + | ++++++ +help: consider using a semicolon here + | +LL | dummy(); + | + + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/suggest-missing-await.rs:35:9 + | +LL | let _x = if true { + | ______________- +LL | | dummy() + | | ------- expected because of this +LL | | +LL | | } else { +LL | | dummy().await + | | ^^^^^^^^^^^^^ expected opaque type, found `()` +LL | | +LL | | }; + | |_____- `if` and `else` have incompatible types + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:18:18 + | +LL | async fn dummy() {} + | ^ checked the `Output` of this `async fn`, expected opaque type + = note: expected opaque type `impl Future<Output = ()>` + found unit type `()` +help: consider `await`ing on the `Future` + | +LL | dummy().await + | ++++++ + +error[E0308]: `match` arms have incompatible types + --> $DIR/suggest-missing-await.rs:45:14 + | +LL | let _x = match 0usize { + | ______________- +LL | | 0 => dummy(), + | | ------- this is found to be of type `impl Future<Output = ()>` +LL | | 1 => dummy(), + | | ------- this is found to be of type `impl Future<Output = ()>` +LL | | 2 => dummy().await, + | | ^^^^^^^^^^^^^ expected opaque type, found `()` +LL | | +LL | | }; + | |_____- `match` arms have incompatible types + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:18:18 + | +LL | async fn dummy() {} + | ^ checked the `Output` of this `async fn`, expected opaque type + = note: expected opaque type `impl Future<Output = ()>` + found unit type `()` +help: consider `await`ing on the `Future` + | +LL ~ 0 => dummy().await, +LL ~ 1 => dummy().await, + | + +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:53:9 + | +LL | let _x = match dummy() { + | ------- this expression has type `impl Future<Output = ()>` +LL | () => {} + | ^^ expected opaque type, found `()` + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:18:18 + | +LL | async fn dummy() {} + | ^ checked the `Output` of this `async fn`, expected opaque type + = note: expected opaque type `impl Future<Output = ()>` + found unit type `()` +help: consider `await`ing on the `Future` + | +LL | let _x = match dummy().await { + | ++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:67:9 + | +LL | match dummy_result() { + | -------------- this expression has type `impl Future<Output = Result<(), ()>>` +... +LL | Ok(_) => {} + | ^^^^^ expected opaque type, found enum `Result` + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:57:28 + | +LL | async fn dummy_result() -> Result<(), ()> { + | ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type + = note: expected opaque type `impl Future<Output = Result<(), ()>>` + found enum `Result<_, _>` +help: consider `await`ing on the `Future` + | +LL | match dummy_result().await { + | ++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:69:9 + | +LL | match dummy_result() { + | -------------- this expression has type `impl Future<Output = Result<(), ()>>` +... +LL | Err(_) => {} + | ^^^^^^ expected opaque type, found enum `Result` + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:57:28 + | +LL | async fn dummy_result() -> Result<(), ()> { + | ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type + = note: expected opaque type `impl Future<Output = Result<(), ()>>` + found enum `Result<_, _>` +help: consider `await`ing on the `Future` + | +LL | match dummy_result().await { + | ++++++ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs new file mode 100644 index 000000000..4919e0a05 --- /dev/null +++ b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs @@ -0,0 +1,47 @@ +// rustc-env:CARGO=/usr/bin/cargo + +use std::pin::Pin; +use std::future::Future; + +fn main() {} + +fn await_on_struct_missing() { + struct S; + let x = S; + x.await; + //~^ ERROR no field `await` on type + //~| NOTE unknown field + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2021"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_struct_similar() { + struct S { + awai: u8, + } + let x = S { awai: 42 }; + x.await; + //~^ ERROR no field `await` on type + //~| HELP a field with a similar name exists + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2021"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) { + x.await; + //~^ ERROR no field `await` on type + //~| NOTE unknown field + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2021"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_apit(x: impl Future<Output = ()>) { + x.await; + //~^ ERROR no field `await` on type + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP set `edition = "2021"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr new file mode 100644 index 000000000..409eb179e --- /dev/null +++ b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr @@ -0,0 +1,43 @@ +error[E0609]: no field `await` on type `await_on_struct_missing::S` + --> $DIR/suggest-switching-edition-on-await-cargo.rs:11:7 + | +LL | x.await; + | ^^^^^ unknown field + | + = note: to `.await` a `Future`, switch to Rust 2018 or later + = help: set `edition = "2021"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `await_on_struct_similar::S` + --> $DIR/suggest-switching-edition-on-await-cargo.rs:24:7 + | +LL | x.await; + | ^^^^^ help: a field with a similar name exists: `awai` + | + = note: to `.await` a `Future`, switch to Rust 2018 or later + = help: set `edition = "2021"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>` + --> $DIR/suggest-switching-edition-on-await-cargo.rs:33:7 + | +LL | x.await; + | ^^^^^ unknown field + | + = note: to `.await` a `Future`, switch to Rust 2018 or later + = help: set `edition = "2021"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `impl Future<Output = ()>` + --> $DIR/suggest-switching-edition-on-await-cargo.rs:42:7 + | +LL | x.await; + | ^^^^^ + | + = note: to `.await` a `Future`, switch to Rust 2018 or later + = help: set `edition = "2021"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.rs b/src/test/ui/async-await/suggest-switching-edition-on-await.rs new file mode 100644 index 000000000..9852e8fc9 --- /dev/null +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.rs @@ -0,0 +1,45 @@ +use std::pin::Pin; +use std::future::Future; + +fn main() {} + +fn await_on_struct_missing() { + struct S; + let x = S; + x.await; + //~^ ERROR no field `await` on type + //~| NOTE unknown field + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP pass `--edition 2021` to `rustc` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_struct_similar() { + struct S { + awai: u8, + } + let x = S { awai: 42 }; + x.await; + //~^ ERROR no field `await` on type + //~| HELP a field with a similar name exists + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP pass `--edition 2021` to `rustc` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) { + x.await; + //~^ ERROR no field `await` on type + //~| NOTE unknown field + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP pass `--edition 2021` to `rustc` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} + +fn await_on_apit(x: impl Future<Output = ()>) { + x.await; + //~^ ERROR no field `await` on type + //~| NOTE to `.await` a `Future`, switch to Rust 2018 + //~| HELP pass `--edition 2021` to `rustc` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide +} diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr new file mode 100644 index 000000000..ef3334381 --- /dev/null +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr @@ -0,0 +1,43 @@ +error[E0609]: no field `await` on type `await_on_struct_missing::S` + --> $DIR/suggest-switching-edition-on-await.rs:9:7 + | +LL | x.await; + | ^^^^^ unknown field + | + = note: to `.await` a `Future`, switch to Rust 2018 or later + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `await_on_struct_similar::S` + --> $DIR/suggest-switching-edition-on-await.rs:22:7 + | +LL | x.await; + | ^^^^^ help: a field with a similar name exists: `awai` + | + = note: to `.await` a `Future`, switch to Rust 2018 or later + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>` + --> $DIR/suggest-switching-edition-on-await.rs:31:7 + | +LL | x.await; + | ^^^^^ unknown field + | + = note: to `.await` a `Future`, switch to Rust 2018 or later + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0609]: no field `await` on type `impl Future<Output = ()>` + --> $DIR/suggest-switching-edition-on-await.rs:40:7 + | +LL | x.await; + | ^^^^^ + | + = note: to `.await` a `Future`, switch to Rust 2018 or later + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/async-await/try-on-option-in-async.rs b/src/test/ui/async-await/try-on-option-in-async.rs new file mode 100644 index 000000000..afaaed2ef --- /dev/null +++ b/src/test/ui/async-await/try-on-option-in-async.rs @@ -0,0 +1,28 @@ +#![feature(async_closure)] +// edition:2018 +fn main() {} + +async fn an_async_block() -> u32 { + async { + let x: Option<u32> = None; + x?; //~ ERROR the `?` operator + 22 + } + .await +} + +async fn async_closure_containing_fn() -> u32 { + let async_closure = async || { + let x: Option<u32> = None; + x?; //~ ERROR the `?` operator + 22_u32 + }; + + async_closure().await +} + +async fn an_async_function() -> u32 { + let x: Option<u32> = None; + x?; //~ ERROR the `?` operator + 22 +} diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr new file mode 100644 index 000000000..a55850d76 --- /dev/null +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -0,0 +1,45 @@ +error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-in-async.rs:8:10 + | +LL | async { + | ___________- +LL | | let x: Option<u32> = None; +LL | | x?; + | | ^ cannot use the `?` operator in an async block that returns `{integer}` +LL | | 22 +LL | | } + | |_____- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}` + +error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-in-async.rs:17:10 + | +LL | let async_closure = async || { + | __________________________________- +LL | | let x: Option<u32> = None; +LL | | x?; + | | ^ cannot use the `?` operator in an async closure that returns `u32` +LL | | 22_u32 +LL | | }; + | |_____- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32` + +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-in-async.rs:26:6 + | +LL | async fn an_async_function() -> u32 { + | _____________________________________- +LL | | let x: Option<u32> = None; +LL | | x?; + | | ^ cannot use the `?` operator in an async function that returns `u32` +LL | | 22 +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/type-parameter-send.rs b/src/test/ui/async-await/type-parameter-send.rs new file mode 100644 index 000000000..ab2b62aa5 --- /dev/null +++ b/src/test/ui/async-await/type-parameter-send.rs @@ -0,0 +1,18 @@ +// check-pass +// compile-flags: --crate-type lib +// edition:2018 + +fn assert_send<F: Send>(_: F) {} + +async fn __post<T>() -> T { + if false { + todo!() + } else { + async {}.await; + todo!() + } +} + +fn foo<T>() { + assert_send(__post::<T>()); +} diff --git a/src/test/ui/async-await/unnecessary-await.rs b/src/test/ui/async-await/unnecessary-await.rs new file mode 100644 index 000000000..24673777b --- /dev/null +++ b/src/test/ui/async-await/unnecessary-await.rs @@ -0,0 +1,14 @@ +// edition:2018 + +async fn foo () { } +fn bar() -> impl std::future::Future { async {} } +fn boo() {} + +async fn baz() -> std::io::Result<()> { + foo().await; + boo().await; //~ ERROR `()` is not a future + bar().await; + std::io::Result::Ok(()) +} + +fn main() {} diff --git a/src/test/ui/async-await/unnecessary-await.stderr b/src/test/ui/async-await/unnecessary-await.stderr new file mode 100644 index 000000000..e7e61c2ba --- /dev/null +++ b/src/test/ui/async-await/unnecessary-await.stderr @@ -0,0 +1,24 @@ +error[E0277]: `()` is not a future + --> $DIR/unnecessary-await.rs:9:10 + | +LL | boo().await; + | -----^^^^^^ `()` is not a future + | | + | this call returns `()` + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + = note: required because of the requirements on the impl of `IntoFuture` for `()` +help: remove the `.await` + | +LL - boo().await; +LL + boo(); + | +help: alternatively, consider making `fn boo` asynchronous + | +LL | async fn boo() {} + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/unreachable-lint-1.rs b/src/test/ui/async-await/unreachable-lint-1.rs new file mode 100644 index 000000000..d63d643c4 --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint-1.rs @@ -0,0 +1,12 @@ +// edition:2018 +#![deny(unreachable_code)] + +async fn foo() { + return; bar().await; + //~^ ERROR unreachable statement +} + +async fn bar() { +} + +fn main() { } diff --git a/src/test/ui/async-await/unreachable-lint-1.stderr b/src/test/ui/async-await/unreachable-lint-1.stderr new file mode 100644 index 000000000..e93257889 --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint-1.stderr @@ -0,0 +1,16 @@ +error: unreachable statement + --> $DIR/unreachable-lint-1.rs:5:13 + | +LL | return; bar().await; + | ------ ^^^^^^^^^^^^ unreachable statement + | | + | any code following this expression is unreachable + | +note: the lint level is defined here + --> $DIR/unreachable-lint-1.rs:2:9 + | +LL | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/unreachable-lint.rs b/src/test/ui/async-await/unreachable-lint.rs new file mode 100644 index 000000000..ca18cfde4 --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint.rs @@ -0,0 +1,13 @@ +// check-pass +// edition:2018 +#![deny(unreachable_code)] + +async fn foo() { + endless().await; +} + +async fn endless() -> ! { + loop {} +} + +fn main() { } diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs new file mode 100644 index 000000000..6d6d80614 --- /dev/null +++ b/src/test/ui/async-await/unresolved_type_param.rs @@ -0,0 +1,24 @@ +// Provoke an unresolved type error (T). +// Error message should pinpoint the type parameter T as needing to be bound +// (rather than give a general error message) +// edition:2018 +// compile-flags: -Zdrop-tracking + +async fn bar<T>() -> () {} + +async fn foo() { + bar().await; + //~^ ERROR type inside `async fn` body must be known in this context + //~| ERROR type inside `async fn` body must be known in this context + //~| ERROR type inside `async fn` body must be known in this context + //~| NOTE cannot infer type for type parameter `T` + //~| NOTE cannot infer type for type parameter `T` + //~| NOTE cannot infer type for type parameter `T` + //~| NOTE the type is part of the `async fn` body because of this `await` + //~| NOTE the type is part of the `async fn` body because of this `await` + //~| NOTE the type is part of the `async fn` body because of this `await` + //~| NOTE in this expansion of desugaring of `await` + //~| NOTE in this expansion of desugaring of `await` + //~| NOTE in this expansion of desugaring of `await` +} +fn main() {} diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr new file mode 100644 index 000000000..7236c681f --- /dev/null +++ b/src/test/ui/async-await/unresolved_type_param.stderr @@ -0,0 +1,39 @@ +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:10:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:10:10 + | +LL | bar().await; + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:10:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:10:10 + | +LL | bar().await; + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:10:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:10:10 + | +LL | bar().await; + | ^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0698`. diff --git a/src/test/ui/async-await/unused-lifetime.rs b/src/test/ui/async-await/unused-lifetime.rs new file mode 100644 index 000000000..6cfd36ba9 --- /dev/null +++ b/src/test/ui/async-await/unused-lifetime.rs @@ -0,0 +1,39 @@ +// Check "unused_lifetimes" lint on both async and sync functions +// Both cases should be diagnosed the same way. + +// edition:2018 + +#![deny(unused_lifetimes)] + +async fn async_wrong_without_args<'a>() {} //~ ERROR lifetime parameter `'a` never used + +async fn async_wrong_1_lifetime<'a>(_: &i32) {} //~ ERROR lifetime parameter `'a` never used + +async fn async_wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} //~ ERROR lifetime parameter `'b` never used + +async fn async_right_1_lifetime<'a>(_: &'a i32) {} + +async fn async_right_2_lifetimes<'a, 'b>(_: &'a i32, _: &'b i32) {} + +async fn async_right_trait_bound_lifetime<'a, I>(_: I) +where + I: Iterator<Item = &'a i32> +{} + +fn wrong_without_args<'a>() {} //~ ERROR lifetime parameter `'a` never used + +fn wrong_1_lifetime<'a>(_: &i32) {} //~ ERROR lifetime parameter `'a` never used + +fn wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} //~ ERROR lifetime parameter `'b` never used + +fn right_1_lifetime<'a>(_: &'a i32) {} + +fn right_2_lifetimes<'a, 'b>(_: &'a i32, _: &'b i32) {} + +fn right_trait_bound_lifetime<'a, I>(_: I) +where + I: Iterator<Item = &'a i32> +{} + + +fn main() {} diff --git a/src/test/ui/async-await/unused-lifetime.stderr b/src/test/ui/async-await/unused-lifetime.stderr new file mode 100644 index 000000000..5c00501a6 --- /dev/null +++ b/src/test/ui/async-await/unused-lifetime.stderr @@ -0,0 +1,48 @@ +error: lifetime parameter `'a` never used + --> $DIR/unused-lifetime.rs:8:35 + | +LL | async fn async_wrong_without_args<'a>() {} + | -^^- help: elide the unused lifetime + | +note: the lint level is defined here + --> $DIR/unused-lifetime.rs:6:9 + | +LL | #![deny(unused_lifetimes)] + | ^^^^^^^^^^^^^^^^ + +error: lifetime parameter `'a` never used + --> $DIR/unused-lifetime.rs:10:33 + | +LL | async fn async_wrong_1_lifetime<'a>(_: &i32) {} + | -^^- help: elide the unused lifetime + +error: lifetime parameter `'b` never used + --> $DIR/unused-lifetime.rs:12:38 + | +LL | async fn async_wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} + | --^^ + | | + | help: elide the unused lifetime + +error: lifetime parameter `'a` never used + --> $DIR/unused-lifetime.rs:23:23 + | +LL | fn wrong_without_args<'a>() {} + | -^^- help: elide the unused lifetime + +error: lifetime parameter `'a` never used + --> $DIR/unused-lifetime.rs:25:21 + | +LL | fn wrong_1_lifetime<'a>(_: &i32) {} + | -^^- help: elide the unused lifetime + +error: lifetime parameter `'b` never used + --> $DIR/unused-lifetime.rs:27:26 + | +LL | fn wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} + | --^^ + | | + | help: elide the unused lifetime + +error: aborting due to 6 previous errors + |