Reputation: 29985
Is this valid C++?
int main() {
constexpr auto sz = __func__ - __func__;
return sz;
}
GCC and MSVC think it's OK, Clang thinks it's not: Compiler Explorer.
All compilers agree that this one is OK: Compiler Explorer.
int main() {
constexpr auto p = __func__;
constexpr auto p2 = p;
constexpr auto sz = p2 - p;
return sz;
}
Clang again doesn't like this one, but the others are OK with it: Compiler Explorer
int main() {
constexpr auto p = __func__;
constexpr auto p2 = __func__;
constexpr auto sz = p2 - p;
return sz;
}
What is up here? I think arithmetic on unrelated pointers is undefined behavior but __func__
returns the same pointer, no? I am not sure, so I thought I may test it. If I recall correctly, std::equal_to
can compare unrelated pointers without undefined behavior:
#include <functional>
int main() {
constexpr std::equal_to<const char*> eq{};
static_assert(eq(__func__, __func__));
}
Clang thinks eq(__func__, __func__)
isn't a constant expression, even though std::equal_to::operator()
is constexpr. Other compilers don't complain: Compiler Explorer
Clang won't compile this one either. Complains that __func__ == __func__
is not a constant expression: Compiler Explorer
int main() {
static_assert(__func__ == __func__);
}
Upvotes: 14
Views: 441
Reputation: 474266
__func__
in C++ is an identifier. In particular, it references a specific object. From [dcl.fct.def.general]/8:
The function-local predefined variable
__func__
is defined as if a definition of the formstatic const char __func__[] = "function-name";
had been provided, where function-name is an implementation-defined string. It is unspecified whether such a variable has an address distinct from that of any other object in the program.
As a function-local predefined variable, this definition (as if) appears at the beginning of the function block. As such, any uses of __func__
within that block will refer to that variable.
As for the "any other object" part, a variable defines an object. __func__
names the object defined by that variable. Therefore, within a function, all uses of __func__
name the same variable. What is undefined is whether that variable is a distinct object from other objects.
That is, if you're in a function named foo
, and you used the literal "foo"
somewhere else in the problem, it is not forbidden for an implementation to have the variable __func__
also be the same object that the literal "foo"
returns. That is, the standard doesn't require that every function in which __func__
appears must store data separate from the string literal itself.
Now, C++'s "as if" rule allows implementations to deviate from this, but they cannot do it in a way that would be detectable. So, while the variable itself may or may not have a distinct address from other objects, uses of __func__
in the same function must behave as if they are referring to the same object.
Clang does not seem to implement __func__
this way. It appears to implement it as if it returned a prvalue string literal of the function's name. Two distinct string literals don't have to refer to the same object, so subtracting pointers to them is UB. And undefined behavior in a constant expression context is ill-formed.
The only thing that makes me hesitant to say that Clang is 100% wrong here is [temp.arg.nontype]/2:
For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
...
- a predefined
__func__
variable.
See, this seems to allow some fudging by the implementation. That is, while __func__
can technically be a constant expression, you can't use it in a template parameter. It is treated like a string literal, even though it is technically a variable.
So on some level, I would say that the standard is talking out of both sides of its mouth.
Upvotes: 13