6

I would like to write a function that accesses the file and line number of the location in which it gets called.

It would look like this:

fn main() {
    prints_calling_location(); // would print `called from line: 2`
    prints_calling_location(); // would print `called from line: 3`
}

fn prints_calling_location() {
    let caller_line_number = /* ??? */;
    println!("called from line: {}", caller_line_number);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
timotree
  • 1,325
  • 9
  • 29
  • You can manually write a procedural macro to accomplish like in [here](https://stackoverflow.com/questions/60692131/can-we-get-location-of-source-caller-in-proc-macro-attribute-in-rust/60731879#60731879). It works by parsing a backtrace at runtime – Victor Deleau Mar 18 '20 at 00:24

2 Answers2

13

RFC 2091: Implicit caller location adds the track_caller feature which enables a function to access the location of its caller.

Short answer: to obtain the location in which your function gets called, mark it with #[track_caller] and use std::panic::Location::caller in its body.

Following from that answer, your example would look like this:

fn main() {
    prints_calling_location(); // would print `called from line: 2`
    prints_calling_location(); // would print `called from line: 3`
}

#[track_caller]
fn prints_calling_location() {
    let caller_location = std::panic::Location::caller();
    let caller_line_number = caller_location.line();
    println!("called from line: {}", caller_line_number);
}

playground link

More specifically, the function std::panic::Location::caller has two behaviors:

  • Within a function marked #[track_caller], it returns a &'static Location<'static> which you can use to find out the file, line number, and column number in which your function gets called.

  • Within a function that doesn't have #[track_caller], it has the error-prone behavior of returning the actual location where you've invoked it, not where your function gets called, for example:

    fn main() {
        oops();
        // ^ prints `line: 8` instead of the expected `line: 2`
    }
    
    // note: missing #[track_caller] here
    fn oops() {
        println!("line: {}", std::panic::Location::caller().line());
    }
    

    playground link

timotree
  • 1,325
  • 9
  • 29
2

An alternative to using the "Implicit caller location" (which may not be available/suitable to you for whatever reason) is to do things the C way. I.e. hide your function behind a macro.

macro_rules! prints_calling_location {
    () => { 
        let caller_line_number = line!();
        println!("called from line: {}", caller_line_number);
    };
}

fn main() {
    prints_calling_location!(); // prints `called from line: 10`
    prints_calling_location!(); // prints `called from line: 11`
}

playground link

Michael Anderson
  • 70,661
  • 7
  • 134
  • 187