Skip to content

A macro to get the current function name. #2818

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

Closed
wants to merge 6 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions text/0000-fn_name_macro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
- Feature Name: fn_name_macro
- Start Date: 2019-11-14
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)

<!-- https://github.com/rust-lang/rfcs/issues/1743 -->

# Summary
[summary]: #summary

This RFC adds an additional macro, `function!`, to the `core` crate. When invoked, the macro expands to the name of the function that contains the call site.

# Motivation
[motivation]: #motivation

This is a useful extension of Rust's existing debug reporting: `file!`, `line!`, `column!` and `module_path!`.

For many people, the name of the function is a much more immediate way to understand the context of a message than file name and line number. Often when discussing a log message or panic message with others (in a chat, forum, github issue, etc) the source code might not be immediately available.

As an example, it's a lot easier to understand what's going on when a message comes from "f32::floor" instead of from "src/libcore/f32.rs:45".

# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation

For debug information about what's happening within the program there are several useful macros that you might use. One of them is the `function!` macro, which expands to the name of the current function.

```rust
// this prints "entering my_func" before doing the work
fn my_func() {
println!("entering {}", function!());
// work here
}
```

If used outside of a function it causes a compilation error.

# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation
Copy link
Contributor

Choose a reason for hiding this comment

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

This section needs some elaboration to consider the various cases (e.g. like the one @kennytm raised) and give examples of code and what the result is.

Also, looking at the implementation of module_path! in libsyntax_ext https://github.com/rust-lang/rust/blob/9e8c4e6fb1c952048fb823e59f4c9c6487bf9a58/src/libsyntax_ext/source_util.rs#L65-L73 it looks like the information is readily available. In this case however, the information is not available in cx or reachable fields. Some elaboration on the implementation would be good. cc @petrochenkov since they are the most likely T-compiler reviewer for this RFC. Also, this probably has little to do with "debuginfo" -- that's a different part of the compiler that comes into play much later in the compilation process.


Use of the `function!` macro expands to the compiler's internal name for the function. This will generally be the name that the user wrote into the file but in the case of a closure or similar it will be something like the function's name with a unique suffix.
Copy link
Member

Choose a reason for hiding this comment

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

What about a closure in a static?

static F: &(dyn Fn() -> &'static str + Sync) = &|| "1";

(the fully-qualified name is currently playground::F::{{closure}})

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@eddyb know this one (i hope)


The exact text is considered "debug" information and not subject to Rust's stability guarantee.

# Drawbacks
[drawbacks]: #drawbacks

* Doing this adds another macro to `core`.
* This macro in particular cannot be implemented in Rust itself, it requires special support from `rustc`, as well as from all potential alternative compilers for the Rust language.

# Rationale and alternatives
[rationale-and-alternatives]: #rationale-and-alternatives

Previous discussion was within an issue of the RFCs repo: https://github.com/rust-lang/rfcs/issues/1743

In summary, this is useful for debug purposes, and has been desired for nearly two years.

Alternative: we could call it `fn_name!` instead.

Alternative (centril): We could introduce a much more general `item_path!()` macro that is useful in non-function contexts.

```rust
mod foo { // item_path!() ==> foo
const X: &str = item_path!(); // foo::X
struct A;
impl A {
const Y: &str = item_path!(); // foo::A::Y
fn fun() {
// item_path!() ==> foo::A::fun
}
}
type T = Stuff<{item_path!()}> // Stuff<"foo::T">
}
```

# Prior art
[prior-art]: #prior-art

* C99 has a `__func__` pre-processor macro that expands to the current funciton name. [link](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1642.html)
Copy link
Contributor

Choose a reason for hiding this comment

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

(Luckily) This is not a pre-processor macro, just a predefined identifier provided by the C compiler


# Unresolved questions
[unresolved-questions]: #unresolved-questions

* Do type methods and type associated functions include their type in the printed name? eg: `Vec::new`

# Future possibilities
[future-possibilities]: #future-possibilities

None that are specifically improvements of this macro.

We could of course add additional debugging macros.