diff options
Diffstat (limited to '')
-rw-r--r-- | src/test/ui/async-await/track-caller/panic-track-caller.rs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.rs b/src/test/ui/async-await/track-caller/panic-track-caller.rs new file mode 100644 index 000000000..118361d6c --- /dev/null +++ b/src/test/ui/async-await/track-caller/panic-track-caller.rs @@ -0,0 +1,100 @@ +// run-pass +// edition:2021 +// revisions: feat nofeat +// needs-unwind +#![feature(async_closure, stmt_expr_attributes)] +#![cfg_attr(feat, feature(closure_track_caller))] + +use std::future::Future; +use std::panic; +use std::sync::{Arc, Mutex}; +use std::task::{Context, Poll, Wake}; +use std::thread::{self, Thread}; + +/// A waker that wakes up the current thread when called. +struct ThreadWaker(Thread); + +impl Wake for ThreadWaker { + fn wake(self: Arc<Self>) { + self.0.unpark(); + } +} + +/// Run a future to completion on the current thread. +fn block_on<T>(fut: impl Future<Output = T>) -> T { + // Pin the future so it can be polled. + let mut fut = Box::pin(fut); + + // Create a new context to be passed to the future. + let t = thread::current(); + let waker = Arc::new(ThreadWaker(t)).into(); + let mut cx = Context::from_waker(&waker); + + // Run the future to completion. + loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(res) => return res, + Poll::Pending => thread::park(), + } + } +} + +async fn bar() { + panic!() +} + +async fn foo() { + bar().await +} + +#[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op +async fn bar_track_caller() { + panic!() +} + +async fn foo_track_caller() { + bar_track_caller().await +} + +struct Foo; + +impl Foo { + #[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op + async fn bar_assoc() { + panic!(); + } +} + +async fn foo_assoc() { + Foo::bar_assoc().await +} + +fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { + let loc = Arc::new(Mutex::new(None)); + + let hook = panic::take_hook(); + { + let loc = loc.clone(); + panic::set_hook(Box::new(move |info| { + *loc.lock().unwrap() = info.location().map(|loc| loc.line()) + })); + } + panic::catch_unwind(f).unwrap_err(); + panic::set_hook(hook); + let x = loc.lock().unwrap().unwrap(); + x +} + +fn main() { + assert_eq!(panicked_at(|| block_on(foo())), 43); + + #[cfg(feat)] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 56); + #[cfg(nofeat)] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 52); + + #[cfg(feat)] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 69); + #[cfg(nofeat)] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 64); +} |