Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#[track_caller] on closures? #74042

Closed
anp opened this issue Jul 4, 2020 · 9 comments
Closed

#[track_caller] on closures? #74042

anp opened this issue Jul 4, 2020 · 9 comments
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. F-track_caller `#![feature(track_caller)]`

Comments

@anp
Copy link
Member

anp commented Jul 4, 2020

One problem I have is that it's not possible to put #[track_caller] on closures, this is really useful when thread_local is involved because then there's a lot of logic in closures that you might want to propagate
ie

thread_local! {static DONE: bool = false;}

#[track_caller]
fn assert_done() {
    DONE.with(
        #[track_caller]
        |b| assert!(b),
    );
}

fn main() {
    assert_done();
}

Originally posted by @elichai in #47809 (comment)

@anp
Copy link
Member Author

anp commented Jul 4, 2020

cc @eddyb I cant' recall right now whether this restriction is a requirement of the implementation we chose or whether we just left it as-designed in the RFC. Can you?

@jonas-schievink jonas-schievink added C-feature-request Category: A feature request, i.e: not implemented / a PR. F-track_caller `#![feature(track_caller)]` labels Jul 4, 2020
@nikomatsakis
Copy link
Contributor

If there is no technical reason not to support it, I would think we should. I imagine one challenge is that calls to closures are being dispatched through the Fn trait, but I imagine we resolve that because we know the callee at monomorphization time, unless it's a virtual call in which case we use a shim?

@eddyb
Copy link
Member

eddyb commented Jul 17, 2020

I would expect this to "just work", if the attribute syntax parses.

@eddyb
Copy link
Member

eddyb commented Jul 17, 2020

Although... the example is a bit suspect, it doesn't specify what the expected behavior is, but the call of the closure in the with method is what you'll get as the assert! failure location, if #[track_caller] works correctly on closures.

If you want to propagate all the way to main, that's hard.
You want to defer errors until you can panic outside the closure, so that you're not inside the with call.

We could also try to make a way to override the "caller location" of a call (and pass in an outer one), but the ergonomics of that are worse for this example (where assert!(DONE.with(|b| b)) "just works").

@elichai
Copy link
Contributor

elichai commented Jul 17, 2020

Although... the example is a bit suspect, it doesn't specify what the expected behavior is, but the call of the closure in the with method is what you'll get as the assert! failure location, if #[track_caller] works correctly on closures.

Ha! That's interesting, I didn't think about the fact that I'm not actually the one calling the closure, so my #[track_caller] on assert_done doesn't do anything because there's no #[track_caller] on the with method and whatever its internals are.

@nikomatsakis
Copy link
Contributor

I had assumed that, in the example, the with function would also have #[track_caller]. I could see that becoming a common pattern, but yeah, it does rely on that.

@anp
Copy link
Member Author

anp commented Jul 18, 2020

I've opened #74492 with a bare minimum change and test included. It's currently failing because MIR argument counts aren't happy. I'll dig in at some point soon, if anyone has suggestions I'm all ears.

@shepmaster
Copy link
Member

We could also try to make a way to override the "caller location" of a call (and pass in an outer one)

Is there some way of doing that? I'm trying to do something in the same vein as the original post, but using Result::map_err. That function doesn't have #[track_caller] (and I don't think it should), but for this specific usage, I'd like it to.

A made-up example:

use core::panic::Location;

#[track_caller]
fn demo(r: Result<u8, String>) -> Result<u8, String> {
    let location = Location::caller();
    r.map_err(|e| {
        Location::pretend_we_are_at(location);
        another_function();
        e
    })
}

#[track_caller]
fn another_location() {}

Another route would be if I could get access to the inner implementation of another_function... IIRC there was a function that accepted a hidden argument of the location. Then perhaps an attribute like:

r.map_err(|e| {
    #[delegate_caller_location(location)]
    another_function();
    e
})

@dtolnay
Copy link
Member

dtolnay commented Oct 21, 2022

#[track_caller] on closures (and generators) got implemented in #87064, unstable for now. I am closing this issue in favor of #87417 which is the tracking issue for the feature(closure_track_caller) feature.

@dtolnay dtolnay closed this as completed Oct 21, 2022
jamesbornholt added a commit to awslabs/mountpoint-s3 that referenced this issue Nov 18, 2022
track_caller is unstable and seems to now be guarded behind a feature flag:
rust-lang/rust#74042

We also have one test for large objects that is very slow under ASan.
jamesbornholt added a commit to awslabs/mountpoint-s3 that referenced this issue Nov 18, 2022
track_caller is unstable and seems to now be guarded behind a feature flag:
rust-lang/rust#74042

We also have one test for large objects that is very slow under ASan.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. F-track_caller `#![feature(track_caller)]`
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants