Search code examples
c++c++17clang++if-constexpr

Instantiating template function in a false if constexpr gives error


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, if flag is changed to false, then clang (Apple LLVM version 10.0.0 (clang-1000.10.44.4)) gives a compiler 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

Is this a bug in clang?


Solution

  • Yes this is a bug it was fixed by this commmit to clang: [Sema] Discarded statment should be an evaluatable context. which has the following description:

    The constexpr evaluator was erroring out because these templates weren't defined. Despite being used in a discarded statement, we still need to constexpr evaluate them, which means that we need to instantiate them. Fixes PR37585.

    Differential revision: https://reviews.llvm.org/D48322

    and includes the following test:

    namespace PR37585 {
    template <class T> struct S { static constexpr bool value = true; };
    template <class T> constexpr bool f() { return true; }
    template <class T> constexpr bool v = true;
    
    void test() {
      if constexpr (true) {}
      else if constexpr (f<int>()) {}
      else if constexpr (S<int>::value) {}
      else if constexpr (v<int>) {}
    }
    }
    

    If we try the test live with godbolt with an older clang version we obtain a very similar erroneous diagnostic that your example is seeing:

    error: constexpr if condition is not a constant expression
    else if constexpr (f<int>()) {}
                       ^~~~~~~~
    
    note: undefined function 'f<int>' cannot be used in a constant expression
    

    the fix originated from bug report: constexpr if condition is not a constant expression and std::is_same.