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.