Auto merge of #104219 - bryangarza:async-track-caller-dup, r=eholk

Support `#[track_caller]` on async fns

Adds `#[track_caller]` to the generator that is created when we desugar the async fn.

Fixes #78840

Open questions:
- What is the performance impact of adding `#[track_caller]` to every `GenFuture`'s `poll(...)` function, even if it's unused (i.e., the parent span does not set `#[track_caller]`)? We might need to set it only conditionally, if the indirection causes overhead we don't want.
This commit is contained in:
bors 2022-11-17 13:47:03 +00:00
commit b6097f2e1b
4 changed files with 110 additions and 8 deletions

View file

@ -0,0 +1,76 @@
// run-pass
// edition:2021
// needs-unwind
#![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]
async fn bar_track_caller() {
panic!()
}
async fn foo_track_caller() {
bar_track_caller().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())), 41);
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 54);
}