Bug 116639 - "private" access specifier not respected in overloaded SFINAE context
Summary: "private" access specifier not respected in overloaded SFINAE context
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 14.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-09-07 15:34 UTC by Larry Smith
Modified: 2024-09-08 01:53 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2024-09-07 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Larry Smith 2024-09-07 15:34:27 UTC
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).
Comment 1 Larry Smith 2024-09-07 15:41:28 UTC
FYI that the behavior table I posted above is a bit long but appeared correct in the preview window when I submitted it (after expanding it using the window's sizing grip). Wrapping now occurring instead in the final posted version (there's no sizing grip in that window but copying and pasting it into a text editor still shows it correctly)
Comment 2 Andrew Pinski 2024-09-07 18:17:17 UTC
Confirmed. Note GCC had also an issue before with static member fields (PR 90880).
Comment 3 Larry Smith 2024-09-08 01:53:28 UTC
Thanks for the quick turnaround (and reference to the similar issue a few years back). Appreciated. I see you also found (and cited) my Clang post. Credit for your thoroughness :)