https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117272
--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Richard Kellnberger from comment #0)
> Since gcc 13 this is valid code:
>
> ```C++
> template<typename T> void f(){
> static_assert(false);
> }
Only because this function template is never instantiated.
> int main() {
>
> }
> ```
>
> This is as well:
>
> ```C++
> #include <type_traits>
>
> template<typename T> void f(){
> if constexpr(std::is_same_v<T, int>) {
>
> } else {
> static_assert(false);
> }
> }
>
> int main() {
> f<int>();
> }
> ```
>
> The `static_assert(false)` is ignored if it is not reached due to
> templating.
It's not that it's not "reached", because this isn't about control flow. It's
about whether it's in a discarded statement or not. A discarded statement in a
function template is not instantiated at all. The static_assert is not even
part of the function when the type is int.
> If I placed it into the `if` block instead the code would be
> ill-formed.
Yes, because when the type is int the static_assert(false) would be
instantiated.
> By the same logic the following should be valid, but it is not.
No, because it's literally not "the same logic".
In your last example the static_assert(false) is not in a discarded statement
so is always instantiated by every specialization of the function. It's just
like your first example which is ill-formed if ever called. Returning "before"
the static_assert doesn't make any difference. A static_assert is checked when
the function is instantiated at compile time, not when it's executed at
runtime.