Skip to content

Commit 165a9c3

Browse files
authored
Merge pull request #5304 from rust-lang/rustup-2026-09-04
Automatic Rustup
2 parents 8eed962 + 223a96a commit 165a9c3

2 files changed

Lines changed: 171 additions & 1 deletion

File tree

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2e2b193f8ada105f27608b7be81c293e0d7292cb
1+
a69a63265cfd9e006d43137f98301b8d274ad4c9
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// This test is duplicated (with changes) at
2+
// tests/ui/async-await/track-caller/panic-track-caller.rs
3+
4+
//@ edition:2021
5+
//@ revisions: afn cls afn_cls nofeat
6+
//@ run-native
7+
//
8+
//
9+
//
10+
// Padding comment so that the line numbers are the same as panic-track-caller.rs
11+
#![feature(stmt_expr_attributes)]
12+
#![cfg_attr(any(afn, afn_cls), feature(async_fn_track_caller))]
13+
#![cfg_attr(any(cls, afn_cls), feature(closure_track_caller))]
14+
#![allow(unused)]
15+
16+
use std::future::Future;
17+
use std::panic;
18+
use std::sync::{Arc, Mutex};
19+
use std::task::{Context, Poll, Wake};
20+
use std::thread::{self, Thread};
21+
22+
/// A waker that wakes up the current thread when called.
23+
struct ThreadWaker(Thread);
24+
25+
impl Wake for ThreadWaker {
26+
fn wake(self: Arc<Self>) {
27+
self.0.unpark();
28+
}
29+
}
30+
31+
/// Run a future to completion on the current thread.
32+
fn block_on<T>(fut: impl Future<Output = T>) -> T {
33+
// Pin the future so it can be polled.
34+
let mut fut = Box::pin(fut);
35+
36+
// Create a new context to be passed to the future.
37+
let t = thread::current();
38+
let waker = Arc::new(ThreadWaker(t)).into();
39+
let mut cx = Context::from_waker(&waker);
40+
41+
// Run the future to completion.
42+
loop {
43+
match fut.as_mut().poll(&mut cx) {
44+
Poll::Ready(res) => return res,
45+
Poll::Pending => thread::park(),
46+
}
47+
}
48+
}
49+
50+
async fn bar() {
51+
panic!()
52+
}
53+
54+
async fn foo() {
55+
let future = bar();
56+
future.await;
57+
}
58+
59+
#[cfg_attr(any(cls, nofeat), expect(ungated_async_fn_track_caller))]
60+
#[track_caller]
61+
async fn bar_track_caller() {
62+
panic!()
63+
}
64+
65+
async fn foo_track_caller() {
66+
let future = bar_track_caller();
67+
future.await;
68+
}
69+
70+
struct Foo;
71+
72+
impl Foo {
73+
#[cfg_attr(any(cls, nofeat), expect(ungated_async_fn_track_caller))]
74+
#[track_caller]
75+
async fn bar_assoc() {
76+
panic!();
77+
}
78+
}
79+
80+
async fn foo_assoc() {
81+
let future = Foo::bar_assoc();
82+
future.await;
83+
}
84+
85+
// Since compilation is expected to fail for this fn when `closure_track_caller`
86+
// is disabled, we test that separately in `async-closure-gate.rs`
87+
#[cfg(any(cls, afn_cls))]
88+
async fn foo_closure() {
89+
let closure = #[track_caller]
90+
async || {
91+
panic!();
92+
};
93+
let future = closure();
94+
future.await;
95+
}
96+
97+
// Since compilation is expected to fail for this fn when `closure_track_caller`
98+
// is disabled, we test that separately in `async-closure-gate.rs`
99+
#[cfg(any(cls, afn_cls))]
100+
async fn foo_block() {
101+
let future = #[track_caller]
102+
async {
103+
panic!();
104+
};
105+
future.await;
106+
}
107+
108+
#[cfg_attr(any(cls, nofeat), expect(ungated_async_fn_track_caller))]
109+
#[track_caller]
110+
async fn bar_manual_poll() {
111+
panic!();
112+
}
113+
114+
fn foo_manual_poll() {
115+
let future = bar_manual_poll();
116+
let future = std::pin::pin!(future);
117+
let mut cx = std::task::Context::from_waker(std::task::Waker::noop());
118+
let res = future.poll(&mut cx);
119+
assert_eq!(res, std::task::Poll::Ready(()));
120+
}
121+
122+
fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
123+
let loc = Arc::new(Mutex::new(None));
124+
125+
let hook = panic::take_hook();
126+
{
127+
let loc = loc.clone();
128+
panic::set_hook(Box::new(move |info| {
129+
*loc.lock().unwrap() = info.location().map(|loc| loc.line())
130+
}));
131+
}
132+
panic::catch_unwind(f).unwrap_err();
133+
panic::set_hook(hook);
134+
let x = loc.lock().unwrap().unwrap();
135+
x
136+
}
137+
138+
// FIXME(async_fn_track_caller): Currently, #[track_caller] on an async function
139+
// uses the location where the future is awaited or polled.
140+
// The correct behavior as per T-lang is to use the location where the function is called.
141+
fn main() {
142+
assert_eq!(panicked_at(|| block_on(foo())), 51);
143+
144+
#[cfg(any(afn, afn_cls))]
145+
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 67);
146+
#[cfg(any(cls, nofeat))]
147+
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 62);
148+
149+
#[cfg(any(afn, afn_cls))]
150+
assert_eq!(panicked_at(|| block_on(foo_assoc())), 82);
151+
#[cfg(any(cls, nofeat))]
152+
assert_eq!(panicked_at(|| block_on(foo_assoc())), 76);
153+
154+
// FIXME(closure_track_caller): if closure_track_caller is enabled, but
155+
// async_fn_track_caller is disabled, then #[track_caller] on async closures
156+
// silently do nothing. Either it should function, or we should emit a warning.
157+
// See #161961
158+
#[cfg(cls)]
159+
assert_eq!(panicked_at(|| block_on(foo_closure())), 91);
160+
#[cfg(afn_cls)]
161+
assert_eq!(panicked_at(|| block_on(foo_closure())), 94);
162+
163+
#[cfg(any(cls, afn_cls))]
164+
assert_eq!(panicked_at(|| block_on(foo_block())), 105);
165+
166+
#[cfg(any(afn, afn_cls))]
167+
assert_eq!(panicked_at(|| foo_manual_poll()), 118);
168+
#[cfg(any(cls, nofeat))]
169+
assert_eq!(panicked_at(|| foo_manual_poll()), 111);
170+
}

0 commit comments

Comments
 (0)