https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117174
Bug ID: 117174 Summary: Compiler seems to incorrectly cache SFINAE condition evaluation results Product: gcc Version: 14.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: ivan.solovev at qt dot io Target Milestone: --- https://godbolt.org/z/197vedfYz ``` namespace A { template <typename T> bool func(T *) { return true; } } // namespace A namespace B { namespace C { using A::func; template <typename T, typename = void> constexpr bool inline hasFunc = false; template <typename T> constexpr bool inline hasFunc< T, std::void_t<decltype(func(std::declval<T>()))> > = true; } // namespace C template <typename T, typename = void> constexpr bool inline hasCustomFunc = false; template <typename T> constexpr bool inline hasCustomFunc< T, std::void_t<decltype(func(std::declval<T>()))> > = true; } // namespace B struct S {}; bool func(S *) { return false; } static_assert(B::hasCustomFunc<S*>); static_assert(!B::hasCustomFunc<int*>); // FAILS here! static_assert(B::C::hasFunc<int*>); ``` This code uses the same condition std::void_t<decltype(func(std::declval<T>()))> to figure out if the function overload is available for type T. The difference is that `B::C::hasFunc` also sees the template from namespace A, while `B::hasCustomFunc` should not see it. It looks like GCC evaluates the condition only once and reuses it in the second check, which is incorrect. Updating the second condition to look like std::void_t<decltype(func(std::declval<T>()) == true)> fixes the issue.