I claim that this program ought to be well-formed: it declares a constexpr member function of S<int>. However, both GCC and Clang reject this program.
template<class T>
struct S {
constexpr int foo() {
if constexpr (std::is_same_v<T, int>) {
return 0;
} else {
try {} catch (...) {}
return 1;
}
}
};
int main()
{
S<int> s;
return s.foo(); // expect "return 0"
}
GCC says:
error: 'try' in 'constexpr' function
Clang says:
error: statement not allowed in constexpr function
Neither of them seem to notice that the "try" statement is located in a discarded branch of the if constexpr statement.
If I factor the try/catch out into a non-constexpr member function void trycatch(), then both Clang and GCC are happy with the code again, even though its behavior ought to be equivalent to the unhappy version.
template<class T>
struct S {
void trycatch() {
try {} catch (...) {}
}
constexpr int foo() {
if constexpr (std::is_same_v<T, int>) {
return 0;
} else {
trycatch(); // This is fine.
return 1;
}
}
};
Is this
- a bug in both GCC and Clang?
- a defect in the Standard, which GCC and Clang are faithfully implementing?
- a Quality of Implementation issue due to the "conditional constexprness" of
foo()?
(Irrelevant background: I'm implementing constexpr any::emplace<T>() for an allocator-aware version of any whose allocator might be constexpr-per-P0639 (i.e. it might lack a deallocate member function) or might not. In the former case we don't want or need the try; in the latter case we need the try in order to call deallocate if the constructor of T throws.)