On 07.11.2018 11:06, Juha Nieminen wrote:
> Is this a bug in clang, or is this intended behavior?
> Consider the following program:
>
> //-----------------------------------------------------------------
> #include <iostream>
>
> template<typename... Params_t>
> constexpr int constexprValue(Params_t...) { return 5; }
>
> int main()
> {
> const bool flag = true;
>
> if constexpr(flag)
> {
> constexpr int value = constexprValue(1, 2, 3);
> std::cout << value << "\n";
> }
> }
> //-----------------------------------------------------------------
>
> This compiles and works fine. However, change flag to false, and clang
> gives an error:
>
> error: constexpr variable 'value' must be initialized by a constant
> expression
> undefined function 'constexprValue<int, int, int>' cannot be used
> in a constant expression
Unable to reproduce with g++ and msvc.
> It must be a bug, right? Because if it's intended, it's incomprehensible
> why they would want that to fail.
Agreed.
But consider:
-------------------------------------------------------------------------
#include <iostream>
using namespace std;
template< class >
struct Baluba;
template<> struct Baluba<int>{}; // Defined.
template< int x >
void foo()
{
if constexpr( x == 666 )
{
Baluba<double> bah;
}
}
void call_foo()
{
foo<42>(); // OK
#ifdef FOO
foo<666>(); // Ungood, doesn't compile.
#endif
}
#ifdef BAR
void bar() // Also ungood, doesn't compile... !
{
if constexpr( false )
{
Baluba<double> x;
}
}
#endif
auto main() -> int {}
-------------------------------------------------------------------------
In the template function `foo` the `if constexpr(x==666)` body is not
entirely compiled when `x!=666`; it just has to pass syntax analysis,
just like with template code in general, and so that compiles nicely.
But in the non-template function `bar` that `if constexpr(false)` body
is fully compiled. It can /then/ be optimized away. And so that code
part, even though it will do nothing, causes a compilation error.
And I suspect that clang's baffling behavior for your example comes from
fully compiling the code in the `if constexpr` body, as it should, but
in an erroneous way where the compiler realizes that it's not necessary
to instantiate the template, it will not actually be used, and then a
double-take, hey, this code uses an un-instantiated template, gah!
Cheers!,
- Alf