5

In C++20 a new feature was added to get the source location information: https://en.cppreference.com/w/cpp/utility/source_location

Here is a slightly modified example from that page, where an addition immediate function loc is used to get the source location:

#include <iostream>
#include <string_view>
#include <source_location>
 
consteval auto loc(std::source_location x = std::source_location::current() ) { return x; }

void log(const std::string_view message,
         const std::source_location location = loc()) {
    std::cout << "file: "
              << location.file_name() << "("
              << location.line() << ":"
              << location.column() << ") `"
              << location.function_name() << "`: "
              << message << '\n';
}
 
template <typename T> void fun(T x) { log(x); }
 
int main(int, char*[]) {
    log("Hello world!");
    fun("Hello C++20!");
}

In the latest MSVC 2019 it prints as in the original example from cppreference.com:

file: main.cpp(25:5) `main`: Hello world!
file: main.cpp(20:5) `fun`: Hello C++20!

But in GCC the same line is indicated twice in the output:

file: /app/example.cpp(8:51) ``: Hello world!
file: /app/example.cpp(8:51) ``: Hello C++20!

demo: https://gcc.godbolt.org/z/nqE4cr9d4

Which of the compilers is right here?

And if define loc function not as immediate one:

auto loc(std::source_location x = std::source_location::current() ) { return x; }

then the output of GCC changes and resembles the original example:

file: /app/example.cpp(20:8) `int main(int, char**)`: Hello world!
file: /app/example.cpp(17:42) `void fun(T) [with T = const char*]`: Hello C++20!

While MSVC refuses to compile it with the error:

error C7595: 'std::source_location::current': call to immediate function is not a constant expression

demo: https://gcc.godbolt.org/z/vorW4f9ax

Please also suggest, which compiler is right in not-immediate case as well?

Fedor
  • 17,146
  • 13
  • 40
  • 131
  • It is **undefined behavior** unless the standard says how it should behave in such cases. You make the code harder to read to anyone who don't know what `loc` does. Declare `log` function as intended using `std::source_location::current()` as the default value. – Phil1970 Aug 13 '21 at 12:58

1 Answers1

3

This is explained in 17.8.2.1.2 [support.srcloc.class] (emphasis mine):

Remarks: Any call to current that appears as a default member initializer (11.4), or as a subexpression thereof, should correspond to the location of the constructor definition or aggregate initialization that uses the default member initializer. Any call to current that appears as a default argument (9.3.3.6), or as a subexpression thereof, should correspond to the location of the invocation of the function that uses the default argument (7.6.1.2).

From this, I deduce that GCC is right.

When the call to current happens in line 5, it returns a source_location object that "correspond[s] to the location of the invocation of the function (in this case the function loc) that uses the default argument".

In this case the invocation location is 8:51 (the expression const std::source_location location = loc()).

Why the function name is empty is explained by the following:

  1. 17.8.2.1.1.1 (Table 38) tells us that the function name should be "such as in" __func__.
Element Value
function_name_ A name of the current function such as in __func__ (9.5.1) if any, an empty string otherwise.
  1. 9.5.1.8 Example shows that if __func__ appears as a default argument, the name is undefined. I know that examples are nonnormative text, but this clearly describes the intent:

[Example:

struct S {
S() : s(__func__) { } // OK
const char* s;
};
void f(const char* s = __func__); // error: __func__ is undeclared

— end example]

janekb04
  • 4,304
  • 2
  • 20
  • 51
  • [dcl.fct.def.general]/7 explains (normatively) that `__func__` is usable only in the *function-body*; this way the function type is known should the implementation want to include it in the name. – Davis Herring Aug 13 '21 at 14:50
  • 1
    This doesn’t address the non-`consteval` `loc` case (which I don’t think *should* change anything). – Davis Herring Aug 13 '21 at 14:51
  • @DavisHerring I know it doesn't address the second issue, but I wanted to at least help with the first question, as I wasn't able to find an answer for the second one yet. I thought that maybe the issue in `g++` was caused by inlining and MSVC had a bug. However, no matter what I did - marking the function as `noinline` or using `-O0` - nothing changed. – janekb04 Aug 13 '21 at 15:05
  • I believe the quoted remark relates to default initialization of class members and not to default values of a function argument. But good idea, let us consider this example as well. Here GCC prints the third distinct result, pointing now to function `log`: https://gcc.godbolt.org/z/GsW1586n1 – Fedor Aug 14 '21 at 11:46
  • @Fedor The excerpt from 17.8.2.1.2 `[support.srcloc.class]` refers to both in-class initialization and default function arguments. The emphasized part says that it refers to "Any call to `current` that **appears as a default argument (9.3.3.6)**, or as a subexpression thereof". The referenced section 9.3.3.6 is `[dcl.fct.default]`, which should dispel any ambiguity whether the excerpt applies to the situation in question. – janekb04 Aug 14 '21 at 12:31
  • The described behavior in the question was with GCC 12, while it was changed in GCC 13, which now resembles MSVC 2019: https://gcc.godbolt.org/z/Tazfd8K4M – Fedor Aug 02 '23 at 18:55