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.

Reply via email to