c++templatesconstexprc++17static-assert

How does a failed static_assert work in an if constexpr (false) block?


P0292R1 constexpr if has been included, on track for C++17. It seems useful (and can replace use of SFINAE), but a comment regarding static_assert being ill-formed, no diagnostic required in the false branch scares me:

Disarming static_assert declarations in the non-taken branch of a
constexpr if is not proposed.

void f() {
  if constexpr (false)
    static_assert(false);   // ill-formed
}

template<class T>
void g() {
  if constexpr (false)
    static_assert(false);   // ill-formed; no 
               // diagnostic required for template definition
}

I take it that it's completely forbidden to use static_assert inside constexpr if (at least the false / non-taken branch, but that in practice means it's not a safe or useful thing to do).

How does this come about from the standard text? I find no mentioning of static_assert in the proposal wording, and C++14 constexpr functions do allow static_assert (details at cppreference: constexpr).

Is it hiding in this new sentence (after 6.4.1) ? :

When a constexpr if statement appears in a templated entity, during an instantiation of the enclosing template or generic lambda, a discarded statement is not instantiated.

From there on, I assume that it is also forbidden, no diagnostic required, to call other constexpr (template) functions which somewhere down the call graph may call static_assert.

Bottom line:

If my understanding is correct, doesn't that put a quite hard limit on the safety and usefulness of constexpr if as we would have to know (from documentation or code inspection) about any use of static_assert? Are my worries misplaced?

Update:

This code compiles without warning (clang head 3.9.0) but is to my understanding ill-formed, no diagnostic required. Valid or not?

template< typename T>
constexpr void other_library_foo(){
    static_assert(std::is_same<T,int>::value);
}

template<class T>
void g() {
  if constexpr (false)
    other_library_foo<T>(); 
}

int main(){
    g<float>();
    g<int>();
}

Solution

  • This has been found to be a defect, CWG 2518. Static asserts now are ignored in template declarations, so now are delayed until instantiation. Failing static asserts are no longer ill-formed no diagnostic required during template resolution.

    It is being applied to all C++ modes in clang and GCC 13.