Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Instantiating a template function inside a false if constexpr

26 views
Skip to first unread message

Juha Nieminen

unread,
Nov 7, 2018, 5:06:42 AM11/7/18
to
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

It must be a bug, right? Because if it's intended, it's incomprehensible
why they would want that to fail.

Chris Vine

unread,
Nov 7, 2018, 6:08:41 AM11/7/18
to
Your code works for me with clang-7.0.0 and gcc-8.2.0 with the
-std=c++17 compiler flag. constexprValue() is defined whether or not
'flag' evaluates to false or true and is instantiated here for literal
types, and 'flag' is initialized by a literal, so I think it must be a
bug.

Öö Tiib

unread,
Nov 7, 2018, 6:10:34 AM11/7/18
to
Yes, it is most probably a bug.

It compiles with clang 3.9 , with clangs 4, 5 and 6 it fails and
with 7 it compiles again.

Alf P. Steinbach

unread,
Nov 7, 2018, 6:40:50 AM11/7/18
to
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

Juha Nieminen

unread,
Nov 7, 2018, 7:19:29 AM11/7/18
to
Öö Tiib <oot...@hot.ee> wrote:
> It compiles with clang 3.9 , with clangs 4, 5 and 6 it fails and
> with 7 it compiles again.

I noticed that I forgot to mention the exact clang version, which is
Apple LLVM version 10.0.0 (clang-1000.10.44.4)

For some years now Apple has stopped telling exactly which version
of clang their version is based on, so I have no idea which one
it is. I'm assuming it's probably clang 5 or 6.

Öö Tiib

unread,
Nov 7, 2018, 8:13:07 AM11/7/18
to
On Wednesday, 7 November 2018 13:40:50 UTC+2, Alf P. Steinbach wrote:
>
> 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!

In clang 3.9 it was implemented as reasonable replacement to
#if. That was somehow bad since it may not be useful outside
of templates and so they broke it in 4 ... but most likely bit too
lot since it compiles with other compilers and so they repaired
it a bit in clang 7.

Öö Tiib

unread,
Nov 7, 2018, 8:56:45 AM11/7/18
to
Yes. Apple has its modified version of unknown LLVM/clang
Tried with "Apple LLVM version 10.0.0 (clang-1000.11.45.2)".
That does not compile it either and is perhaps latest so ... bad news.

Chris Vine

unread,
Nov 7, 2018, 9:29:00 AM11/7/18
to
I imagine it probably compiles if 'if (flag)' is substituted for
'if constexpr (flag)' (I can't test here as I cannot reproduce the bug),
and I bet it still optimizes out the unreachable branch where 'flag' is
a constant expression evaluating to false. So the news may not be
completely bad.

Furthermore, with 'if (flag)' my versions of clang and gcc with default
warnings do not warn about the unreachable branch (which you wouldn't
want it to do in this case).
0 new messages