Skip to content

Tracking issue for RFC 2091: Implicit caller location #47809

@aturon

Description

@aturon
Contributor

This is a tracking issue for the RFC "Implicit caller location" (rust-lang/rfcs#2091).

Steps:

  • Implement the RFC (cc @rust-lang/compiler -- can anyone write up mentoring instructions?)
    Adjust documentation ()
    Stabilization PR ()

Unresolved questions:

  • If we want to support adding #[track_caller] to trait methods, the redirection
    pass/query/whatever should be placed after monomorphization, not before. Currently the RFC
    simply prohibits applying #[track_caller] to trait methods as a future-proofing measure.

  • Diverging functions should be supported.

  • The closure foo::{{closure}} should inherit most attributes applied to the function foo, in
    particular #[inline], #[cold], #[naked] and also the ABI. Currently a procedural macro
    won't see any of these, nor would there be anyway to apply these attributes to a closure.
    Therefore, #[rustc_implicit_caller_location] currently will reject #[naked] and ABI, and
    leaving #[inline] and #[cold] mean no-op. There is no semantic reason why these cannot be
    used though.

Activity

added
B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.
T-langRelevant to the language team
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
on Jan 27, 2018
eddyb

eddyb commented on Jan 27, 2018

@eddyb
Member

If we want to support adding #[track_caller] to trait methods,

This refers to impl of a trait, not the declarations within the trait, right?

IMO the easiest way to implement this involves no procedural macros or MIR passes.
We'd just pass extra arguments on direct calls, and require a shim to get function pointers of the function. That would also surely work with trait methods, since it'd be post-monomorphization.

To explain, the shim (which we may already have some variation of) would "just" do the direct call to the function, which would pass the location of the shim, the same as the original function.

nikomatsakis

nikomatsakis commented on Jan 29, 2018

@nikomatsakis
Contributor

This refers to impl of a trait, not the declarations within the trait, right?

I can't remember. =) But I suspect so. I don't think there's anything special about "trait methods" per se -- it's really about dynamic dispatch.

nikomatsakis

nikomatsakis commented on Apr 25, 2018

@nikomatsakis
Contributor

@kennytm had a prototype implementation:

https://github.com/kennytm/rust/tree/caller-info-4

Maybe @kennytm you can summarize the approach you took? Do you think you'll have time to rebase etc? I'd like ideally to get @eddyb to buy in to the overall approach. =)

kennytm

kennytm commented on Apr 25, 2018

@kennytm
Member

The prototype implementation works like this (note that #[track_caller] was called #[implicit_caller_location] there):

  1. First there will be an AST transformation pass (implemented as an attribute proc-macro in src/libsyntax_ext/implicit_caller_location.rs) which expands:

    #[track_caller]
    #[...attributes...]
    fn foo(...) -> T {
        /* code... */
    }

    into

    #[rustc_track_caller]
    #[inline]
    #[...attributes...]
    fn foo(...) -> T {
        let __closure = |__location| { /* code... */ };
        FnOnce::call_once(__closure, intrinsics::caller_location())
    }

    The purpose of this pass is to conveniently make up a new DefId.

  2. Create a new MIR inlining pass (main implementation in src/librustc_mir/transform/inline.rs). This pass does two things:

    1. Force-inline any functions calls foo() where the attributes of the callee foo contains #[rustc_track_caller].

    2. If intrinsics::caller_location() is called :-

      • If it is used from the __closure, replace it by the argument __location. This is to propagate the caller location.
      • Otherwise, replace the call with the caller's location span.
  3. Define the caller_location() intrinsic.

    fn caller_location() -> core::panic::Location<'static>;
  4. Because Location now needs to be known by the compiler, make the Location struct a lang-item.

  5. Update the standard library to use track-caller features:

    1. Change panic! to use caller_location() (or its safe counterpart, Location::caller())
    2. Add #[track_caller] to unwrap() and expect() etc.
  6. Implement the -Z location-detail flag (search for location_detail) so that the filename/line/column can be redacted.

eddyb

eddyb commented on Apr 25, 2018

@eddyb
Member

I think a syntactical transformations is unnecessary because we can instead change the "direct call ABI" (vs reifying to a fn pointer, including trait vtables via miri, which could go through a MIR shim).
MIR inlining should also not be needed.

kennytm

kennytm commented on Apr 26, 2018

@kennytm
Member

@eddyb So you are suggesting to change the extern "Rust" ABI to always pass an extra argument?

eddyb

eddyb commented on Apr 26, 2018

@eddyb
Member

@kennytm Only for functions declared with the attribute and called through static dispatch, everything else would use a shim when reifying (which I think we do already in some other cases).

kennytm

kennytm commented on Apr 26, 2018

@kennytm
Member

@eddyb Maybe you could write down some mentoring instructions i.e. which files to look at 😊

nikomatsakis

nikomatsakis commented on May 2, 2018

@nikomatsakis
Contributor

@eddyb do it! do it! I want this feature.

131 remaining items

nikomatsakis

nikomatsakis commented on Jul 29, 2020

@nikomatsakis
Contributor

Sure, I guess so. Thanks again @anp for seeing this through!

schreter

schreter commented on Mar 31, 2022

@schreter

Hi. I know this is a bit off-topic and this particular issue is already closed, but I suppose, the right people are involved here :-), so someone might help.

I implemented for our project a version of Result which uses Try trait in such a way as to track the error handling locations, so we get a "call stack" of the error at the end. This works in conjunction with #[track_caller] very well and we see the locations the error handling took.

However, there is one major deficiency in Location - it only gives us the source name and line. Yes, with that, it's possible to manually look up the function where it happened, but it would be significantly simpler to evaluate bug reports by looking at the call trace with function names (we have practiced this in a large C++ project, where basically the dev support standardized on initially evaluating everything by function names call trace, ignoring line numbers). So it would come extremely handy if the Location could be extended with another &str containing the function name (ideally with generics). It can be also a mangled name, I don't care much, but the function name is important.

Before you should "backtrace!" - yes, but... We are using heavy asynchronous processing handling errors across awaits, where the backtrace has about zero value. Similar for tracing, we can't just always trace due to performance reasons. So the error handling "call stack" is a perfect compromise - cheap and sufficiently valuable (except that it's missing the function name).

Any suggestion where/how to address this issue (Location extension by file name)? According to my code study of the Rust compiler code, it should basically boil down to getting the function name from the current Span and adding it in addition to the file name to the generated const Location here:

let const_loc = self.tcx.const_caller_location((

Thanks & regards,

Ivan

jplatte

jplatte commented on Mar 31, 2022

@jplatte
Contributor

I remember asking about this quite a while ago and getting a response along the lines of "unlikely to happen for perf or code size reasons". Unfortunately I can't find an issue about it, so I guess it must have been on Zulip.

I think creating a separate issue would be more useful than continuing this conversation here, in any case.

schreter

schreter commented on Mar 31, 2022

@schreter

I remember asking about this quite a while ago and getting a response along the lines of "unlikely to happen for perf or code size reasons". Unfortunately I can't find an issue about it, so I guess it must have been on Zulip.

Well, it's clear that this will increase generated constants segment by potentially quite a bit, because instead of a single string per file we'll need to store many strings per file. So it could be made optional at compilation time. But I personally don't think it'll be significantly slower (during compilation; runtime is obviously unaffected).

I think creating a separate issue would be more useful than continuing this conversation here, in any case.

Sure. Simply a new top-level issue w/o any special tags? The question is how to get it to the attention of relevant people who could do something about it.

est31

est31 commented on Mar 31, 2022

@est31
Member

If you have the source code, it should be quite easy to build a tool that translates the Location to the name of the function. Location contains the file name, as well as line and column, so all you need to do is go to that specific line and column, and then parse the next ident. Done easily with syn where you can write a custom visitor with a visit_ident function, like this. Then you just compare the line/col number with the line/col number of the Location, done. Maybe if the source code is not public you can export the Location via e.g. json and import it via the tool.

schreter

schreter commented on Mar 31, 2022

@schreter

If you have the source code, it should be quite easy to build a tool that translates the Location to the name of the function.

Of course it could be translated. But that's another step, which makes it quite cumbersome. The compiler already knows it at compile time and aside from costing more space in the generated executable (string section), there should be no adverse effects of having the function name in the Location. It would in general allow building various tools which use the location for debugging purposes, which in turn would help the community in general.

Let me move this to a new issue, for further discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.B-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCE-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.F-track_caller`#![feature(track_caller)]`T-langRelevant to the language teamT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @ggriffiniii@ayosec@comex@eddyb@kennytm

      Issue actions

        Tracking issue for RFC 2091: Implicit caller location · Issue #47809 · rust-lang/rust