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).