]> git.lizzy.rs Git - rust.git/blob - tests/ui/async-await/track-caller/panic-track-caller.rs
Rollup merge of #107027 - GuillaumeGomez:rm-extra-removal, r=tmiasko
[rust.git] / tests / ui / async-await / track-caller / panic-track-caller.rs
1 // run-pass
2 // edition:2021
3 // revisions: feat nofeat
4 // needs-unwind
5 #![feature(async_closure, stmt_expr_attributes)]
6 #![cfg_attr(feat, feature(closure_track_caller))]
7
8 use std::future::Future;
9 use std::panic;
10 use std::sync::{Arc, Mutex};
11 use std::task::{Context, Poll, Wake};
12 use std::thread::{self, Thread};
13
14 /// A waker that wakes up the current thread when called.
15 struct ThreadWaker(Thread);
16
17 impl Wake for ThreadWaker {
18     fn wake(self: Arc<Self>) {
19         self.0.unpark();
20     }
21 }
22
23 /// Run a future to completion on the current thread.
24 fn block_on<T>(fut: impl Future<Output = T>) -> T {
25     // Pin the future so it can be polled.
26     let mut fut = Box::pin(fut);
27
28     // Create a new context to be passed to the future.
29     let t = thread::current();
30     let waker = Arc::new(ThreadWaker(t)).into();
31     let mut cx = Context::from_waker(&waker);
32
33     // Run the future to completion.
34     loop {
35         match fut.as_mut().poll(&mut cx) {
36             Poll::Ready(res) => return res,
37             Poll::Pending => thread::park(),
38         }
39     }
40 }
41
42 async fn bar() {
43     panic!()
44 }
45
46 async fn foo() {
47     bar().await
48 }
49
50 #[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op
51 async fn bar_track_caller() {
52     panic!()
53 }
54
55 async fn foo_track_caller() {
56     bar_track_caller().await
57 }
58
59 struct Foo;
60
61 impl Foo {
62     #[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op
63     async fn bar_assoc() {
64         panic!();
65     }
66 }
67
68 async fn foo_assoc() {
69     Foo::bar_assoc().await
70 }
71
72 // Since compilation is expected to fail for this fn when using
73 // `nofeat`, we test that separately in `async-closure-gate.rs`
74 #[cfg(feat)]
75 async fn foo_closure() {
76     let c = #[track_caller] async || {
77         panic!();
78     };
79     c().await
80 }
81
82 fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
83     let loc = Arc::new(Mutex::new(None));
84
85     let hook = panic::take_hook();
86     {
87         let loc = loc.clone();
88         panic::set_hook(Box::new(move |info| {
89             *loc.lock().unwrap() = info.location().map(|loc| loc.line())
90         }));
91     }
92     panic::catch_unwind(f).unwrap_err();
93     panic::set_hook(hook);
94     let x = loc.lock().unwrap().unwrap();
95     x
96 }
97
98 fn main() {
99     assert_eq!(panicked_at(|| block_on(foo())), 43);
100
101     #[cfg(feat)]
102     assert_eq!(panicked_at(|| block_on(foo_track_caller())), 56);
103     #[cfg(nofeat)]
104     assert_eq!(panicked_at(|| block_on(foo_track_caller())), 52);
105
106     #[cfg(feat)]
107     assert_eq!(panicked_at(|| block_on(foo_assoc())), 69);
108     #[cfg(nofeat)]
109     assert_eq!(panicked_at(|| block_on(foo_assoc())), 64);
110
111     #[cfg(feat)]
112     assert_eq!(panicked_at(|| block_on(foo_closure())), 79);
113 }