https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116639

            Bug ID: 116639
           Summary: "private" access specifier not respected in overloaded
                    SFINAE context
           Product: gcc
           Version: 14.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: admin at hexadigm dot com
  Target Milestone: ---

Given the following code (run it at https://godbolt.org/z/cqv78Pdda), where
"Base::Whatever" is private (both overloads), GCC (incorrectly) fails to
compile when overloaded but correctly compiles when not overloaded (when you
comment out the 2nd occurrence of "Whatever"). The other two compilers I tested
both compile though Clang produces one wrong result when overloaded (I reported
the issue to them as well). MSVC appears to be correct for all cases. See the
behavior table further below (Clang first in the table since I reported it to
them first).

This appears to be erroneous behavior but it's a fuzzy area in this SFINAE
context (but a bug seems likely).

#include <type_traits>
#include <iostream>

class Base
{
private: // Defaults to this anyway but being explicit

    void Whatever(int)
    {
    }

    /////////////////////////////////////////////////
    // Compilation erroneously fails but works when
    // commented out (so no longer overloaded)
    /////////////////////////////////////////////////    
    void Whatever(int, float)
    {
    }
};

class Derived : public Base
{
};

template <typename T, typename U, typename = void>
struct HasFuncWhatever : std::false_type
{
};

template <typename T, typename U>
struct HasFuncWhatever<T,
                       U,
                       std::void_t<decltype(static_cast<U T::*>(&T::Whatever))>
                      >
                      : std::true_type
{
};

int main()
{
    using T = Derived;
    using U = void (int);
    std::cout << std::boolalpha << HasFuncWhatever<T, U>::value;
    return 0;
}


Here's the behavior of the 3 compilers I tested (only MSVC presumably gets it
right):

T          "Whatever" overloaded?   Clang Displays    MSVC Displays     GCC
Displays
-          ----------------------   --------------    -------------    
------------
Base       No                       false (correct)   false (correct)   false
(correct)    
Base       Yes                      false (correct)   false (correct)   Fails
compilation due to private access (incorrect)
Derived    No                       false (correct)   false (correct)   false
(correct)  
Derived    Yes                      true (incorrect)  false (correct)   Fails
compilation due to private access (incorrect)


Unless this is explicitly mentioned in the standard somewhere, or it's
considered undefined behavior (implementation defined), the call to
"&T::Whatever" in the partial specialization of "HasFuncWhatever" should always
presumably fail since "Whatever" is private. The primary template should
therefore always kick in so the code should always display false (and since GCC
does in fact display false in the non-overloaded case but fails to compile when
overloaded it appears to be broken behavior).

Reply via email to