1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
//@ run-pass
//@ edition:2021
//@ revisions: afn cls nofeat
//@ needs-unwind
// gate-test-async_fn_track_caller
#![feature(async_closure, stmt_expr_attributes)]
#![cfg_attr(afn, feature(async_fn_track_caller))]
#![cfg_attr(cls, feature(closure_track_caller))]
#![allow(unused)]
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]
//[cls]~^ WARN `#[track_caller]` on async functions is a no-op
//[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]
//[cls]~^ WARN `#[track_caller]` on async functions is a no-op
//[nofeat]~^^ WARN `#[track_caller]` on async functions is a no-op
async fn bar_assoc() {
panic!();
}
}
async fn foo_assoc() {
Foo::bar_assoc().await
}
// Since compilation is expected to fail for this fn when using
// `nofeat`, we test that separately in `async-closure-gate.rs`
#[cfg(cls)]
async fn foo_closure() {
let c = #[track_caller] async || {
panic!();
};
c().await
}
// Since compilation is expected to fail for this fn when using
// `nofeat`, we test that separately in `async-block.rs`
#[cfg(cls)]
async fn foo_block() {
let a = #[track_caller] async {
panic!();
};
a.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())), 46
);
#[cfg(afn)]
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 61);
#[cfg(any(cls, nofeat))]
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 57);
#[cfg(afn)]
assert_eq!(panicked_at(|| block_on(foo_assoc())), 76);
#[cfg(any(cls, nofeat))]
assert_eq!(panicked_at(|| block_on(foo_assoc())), 71);
#[cfg(cls)]
assert_eq!(panicked_at(|| block_on(foo_closure())), 84);
#[cfg(cls)]
assert_eq!(panicked_at(|| block_on(foo_block())), 96);
}
|