Skip to content

(BLOCKED) Stabilize async_fn_track_caller - #161958

Draft
theemathas wants to merge 3 commits into
rust-lang:mainfrom
theemathas:stab-async_fn_track_caller
Draft

(BLOCKED) Stabilize async_fn_track_caller#161958
theemathas wants to merge 3 commits into
rust-lang:mainfrom
theemathas:stab-async_fn_track_caller

Conversation

@theemathas

@theemathas theemathas commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Edit: In the process of trying to stabilize this feature, I found out that the currently implemented behavior is incorrect. #[track_caller] currently reports the location as being at the poll site, but it should report the function call site. That needs to be fixed before stabilization.

Closes #110011


Stabilization report

Summary

This PR proposes stabilization of the async_fn_track_caller feature. This allows applying the #[track_caller] attribute to async fn.

The #[track_caller] attribute allows a function to gain access to the core::panic::Location where it's called. This value is accessible via core::panic::Location::caller. This attribute was previously stabilized for normal functions, but not async functions.

Tracking:

Reference PRs:

  • TODO (Link to Reference PRs.)

cc @rust-lang/lang @rust-lang/lang-advisors

What is stabilized

The #[track_caller] attribute, when applied to an async fn, now works.

use std::panic::Location;

#[track_caller]
async fn new_location() -> &'static Location<'static> {
    // Returns the location of the new_location() call
    // inside constant_location.
    Location::caller()
}

async fn constant_location() -> &'static Location<'static> {
    new_location().await
}

Previously, this attribute was ignored and emitted a lint:

warning: `#[track_caller]` on async functions is a no-op
 --> src/lib.rs:3:1
  |
3 |   #[track_caller]
  |   ^^^^^^^^^^^^^^^
4 | / async fn new_location() -> &'static Location<'static> {
5 | |     Location::caller()
6 | | }
  | |_- this function will not propagate the caller location
  |
  = note: see issue #110011 <https://github.com/rust-lang/rust/issues/110011> for more information
  = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable
  = note: this compiler was built on 2026-08-26; consider upgrading it if it is out of date
  = note: `#[warn(ungated_async_fn_track_caller)]` on by default

The ungated_async_fn_track_caller lint is removed in this PR.

What isn't stabilized

Applying #[track_caller] on async blocks is not stabilized. It is instead part of the closure_track_caller feature, tracked at #87417.

Design

Reference

What updates are needed to the Reference? Link to each PR. If the Reference is missing content needed for describing this feature, discuss that.

  • TODO

RFC history

The #[track_caller] attribute was proposed in RFC 2091, which was accepted in 2018, tracked as #47809, and stabilized in 2020 in #72445. However this only covered using the attribute on normal functions.

Putting the attribute on closures was proposed in #74042, implemented in #87064, and then tracked in #87417, where it remains unstable today as feature(closure_track_caller). This feature currently includes using the attribute on async blocks.

Applying #[track_caller] on async functions was requested as a feature in #78840, without an RFC. This was implemented unstably in #104219. Initially, using this in stable Rust would cause a hard error due to using an unstable feature, but the behavior was changed to a no-op with a lint in #104588, due to backwards-compatibility concerns.

At first, #[track_caller] on async functions was treated as part of feature(closure_track_caller). However, in #112117, it was separated into a new unstable feature: feature(async_fn_track_caller), tracked in #110011, which is where it remains today.

Answers to unresolved questions

There are two possible sites that could be thought of as the "caller" for an async fn: the site where named function is called, and the site where the returned future is polled. This stabilization of #[track_caller] uses the former interpretation.

Key points

What decisions have been most difficult and what behaviors to be stabilized have proved most contentious? Summarize the major arguments on all sides and link to earlier documents and discussions.

TODO

Nightly extensions

Applying #[track_caller] on async blocks is part of feature(closure_track_caller). This feature gating is tested in tests/ui/feature-gates/feature-gate-closure_track_caller.rs.

Doors closed

None. We could later add something like #[track_caller(poll)] if we want the user to be able to specify using the location where the future is polled.

Feedback

Call for testing

N/A

Nightly use

Implementation

Major parts

Summarize the major parts of the implementation and provide links into the code and to relevant PRs.

See, e.g., this breakdown of the major parts of async closures:

TODO

Coverage

tests/ui/async-await/track-caller/panic-track-caller.rs tests the run time behavior. async-block.rs and async-closure-gate.rs in the same directory tests the feature gating of related features.

Outstanding bugs

N/A

Outstanding FIXMEs

There's a FIXME at

// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
// interact with `gen`/`async gen` blocks
, but it involves the unstable gen_blocks feature.

Tool changes

N/A

Breaking changes

This changes run time behavior of code with #[track_caller] on async functions. I believe that this is acceptable because:

  • This feature is intended for diagnostics / error messages only.
  • Such code would have already had the ungated_async_fn_track_caller lint fire already.

Type system, opsem

Compile-time checks

N/A

Type system rules

N/A

Sound by default?

Yes

Breaks the AM?

N/A

Common interactions

Temporaries

N/A

Drop order

N/A

Pre-expansion / post-expansion

N/A

Edition hygiene

N/A. Editions already decide whether async is a keyword or not, but the #[track_caller] attribute doesn't affect that.

SemVer implications

Libraries that wish to use #[track_caller] on an async function, and need it to function correctly for whatever reason, would need to raise the MSRV of the crate to the version where this feature is stabilized. This can be easily missed. I'm not sure how to best mitigate this, although it might not be a big deal anyway.

Exposing other features

The closure_track_calleris adjacent to this feature, due to applying to async blocks, but is not exposed by this stabilization.

History

  • #[track_caller] in general
  • #[track_caller] on closures and async blocks
  • #[track_caller] on async functions
    • #78840 (feature request)
    • #104219 (implementation)
    • #104588 (ungated behavior change to no-op and lint)
    • #112117 (separated to its own unstable feature)
    • #110011 (tracking issue)

Acknowledgments

Thanks to @bryangarza who implemented this feature.

Open items

N/A

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 29, 2026
hir::CoroutineSource::Fn,
);

// FIXME(async_fn_track_caller): Can this be moved above?

@theemathas theemathas Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what this is saying, so I removed it. Am I supposed to do something with it?

View changes since the review

@traviscross traviscross added T-lang Relevant to the language team needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. labels Aug 29, 2026

@theemathas theemathas left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments on the test changes

View changes since this review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file previously tested the wrong feature gate, so I fixed that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file previously tested the wrong feature gate, and it also had some unnecessary type errors, so I fixed those.

Comment on lines -130 to +119
assert_eq!(panicked_at(|| block_on(foo_closure())), 84);
assert_eq!(panicked_at(|| block_on(foo_closure())), 81);

@theemathas theemathas Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[track_caller] on async closures previously just silently didn't work (without any warnings) unless the async_fn_track_caller feature was enabled. This should be filed as an issue if the stabilization were to not go through.

(Note that, both before and after this PR, making #[track_caller] on async closures compile at all requires the closure_track_caller feature.)

@theemathas

Copy link
Copy Markdown
Contributor Author

There are a couple mentions of async_fn_track_caller in src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs. Do I need to do anything about those?

@RalfJung

Copy link
Copy Markdown
Member

Any chance you could add a basic smoke test in Miri to ensure that it can run such code and it behaves correctly?

@theemathas

theemathas commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

@RalfJung I think I'm going to put off this stabilzation attempt until the incorrect behavior (using the call site location vs poll site location) is fixed.

I could add tests in a separate PR though.

@rust-log-analyzer

Copy link
Copy Markdown
Collaborator

The job x86_64-gnu-gcc failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
failures:

---- [ui] tests/ui/async-await/track-caller/panic-track-caller.rs#nofeat stdout ----

error in revision `nofeat`: test did not exit with success! code=Some(101) so test would pass with `run-fail`
status: exit status: 101
command: cd "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/track-caller/panic-track-caller.nofeat" && RUSTC="/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" RUST_TEST_THREADS="4" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/track-caller/panic-track-caller.nofeat/a"
stdout: none
stderr: none

---- [ui] tests/ui/async-await/track-caller/panic-track-caller.rs#nofeat stdout end ----
---- [ui] tests/ui/async-await/track-caller/panic-track-caller.rs#cls stdout ----

error in revision `cls`: test did not exit with success! code=Some(101) so test would pass with `run-fail`
status: exit status: 101
command: cd "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/track-caller/panic-track-caller.cls" && RUSTC="/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" RUST_TEST_THREADS="4" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/async-await/track-caller/panic-track-caller.cls/a"
stdout: none
stderr: none

---- [ui] tests/ui/async-await/track-caller/panic-track-caller.rs#cls stdout end ----

Important

For more information how to resolve CI failures of this job, visit this link.

@theemathas theemathas changed the title Stabilize async_fn_track_caller (BLOCKED) Stabilize async_fn_track_caller Aug 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tracking Issue for #[track_caller] on async fn

5 participants