Skip to content

private member function in the template specialization does not sfinae out overload #68849

@tchaikov

Description

@tchaikov

i notice that following program fails to compile:

template <typename> struct templ_foo;

template <> class templ_foo<int> {
  void bar_func(bool);
};

template <> class templ_foo<bool> {
public:
  template <class U>
  auto maybe_call_foo(U u, bool set)
      -> decltype(u.bar_func(set)) {
    u.bar_func(set);
  }
  template <class U> void maybe_call_foo(U...);
};

  template <class U>
  auto maybe_call_foo(U u, bool set)
      -> decltype(u.bar_func(set)) {
    u.bar_func(set);
  }
  template <class U> void maybe_call_foo(U...);

void parse_format_specs() {
  templ_foo<int> foo_int;

#define GLOBAL_OVERLOAD 0

#if GLOBAL_OVERLOAD
  maybe_call_foo(foo_int, true);
#else
  templ_foo<bool> foo_bool;
  foo_bool.maybe_call_foo(foo_int, true);
#endif
}

when i compile it using Clang (tested with clang-16, clang-17 and the latest clang trunk):

$ clang++ -Werror -c -std=c++20 test.cc
test.cc:12:7: error: 'bar_func' is a private member of 'templ_foo<int>'
    u.bar_func(set);
      ^
test.cc:33:12: note: in instantiation of function template specialization
      'templ_foo<bool>::maybe_call_foo<templ_foo<int>>' requested here
  foo_bool.maybe_call_foo(foo_int, true);
           ^
test.cc:4:8: note: implicitly declared private here
  void bar_func(bool);
       ^
test.cc:11:21: error: 'bar_func' is a private member of 'templ_foo<int>'
      -> decltype(u.bar_func(set)) {
                    ^
test.cc:4:8: note: implicitly declared private here
  void bar_func(bool);
       ^
2 errors generated.

but if i

#define GLOBAL_OVERLOAD 1

the source code compiles. the same source code compiles with gcc 13.2.1 with GLOBAL_OVERLOAD defined to 1 or 0.

my guess is that clang fails to take the member access check into consideration if the member is accessed by the template specialization of the same template. in this case, both full specializations specialize the template of templ_foo with int and bool respectively. if i declare another template templ_baz, and specialize it using bool, and then define the same overloads in it, clang is able to sfinae out the overload accessing the private member function.

the reproducer is also available at godbolt. see https://godbolt.org/z/EW6EPPqz3

EDIT, i changed the code in the description of this issue to match the one in the godbolt. i was experimenting the case where the caller was a specialization of another template.

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:frontendLanguage frontend issues, e.g. anything involving "Sema"rejects-valid

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions