Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
tchaikov opened this issue Oct 12, 2023 · 2 comments
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid

Comments

@tchaikov
Copy link
Contributor

tchaikov commented Oct 12, 2023

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.

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 12, 2023

@llvm/issue-subscribers-clang-frontend

Author: Kefu Chai (tchaikov)

i notice that following program fails to compile: ```c++ template <typename> struct templ_foo;

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

template <typename> struct templ_bar;

template <> class templ_bar<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_bar<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):

```console
$ clang++ -Werror -c -std=c++20 test.cc
test.cc:12:7: error: 'bar_func' is a private member of 'templ_foo&lt;int&gt;'
    u.bar_func(set);
      ^
test.cc:33:12: note: in instantiation of function template specialization
      'templ_foo&lt;bool&gt;::maybe_call_foo&lt;templ_foo&lt;int&gt;&gt;' 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&lt;int&gt;'
      -&gt; 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 specialization 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

@dtcxzyw dtcxzyw self-assigned this Oct 13, 2023
avikivity added a commit to avikivity/seastar that referenced this issue Oct 17, 2023
fmt 10 detects if a formatter provides some method (set_debug_format()),
but the detection fails if the method is private and compilation breaks
on clang [1].

Work around the clang bug by inheriting publicly.

[1] llvm/llvm-project#68849

A test case reproducing the problem is included (thanks
Kefu Chai <kefu.chai@scylladb.com>).
avikivity added a commit to avikivity/seastar that referenced this issue Oct 17, 2023
fmt 10 detects if a formatter provides some method (set_debug_format()),
but the detection fails if the method is private and compilation breaks
on clang [1].

Work around the clang bug by inheriting publicly.

[1] llvm/llvm-project#68849

A test case reproducing the problem is included (thanks
Kefu Chai <kefu.chai@scylladb.com>).
avikivity added a commit to avikivity/seastar that referenced this issue Oct 18, 2023
fmt 10 detects if a formatter provides some method (set_debug_format()),
but the detection fails if the method is private and compilation breaks
on clang [1].

Work around the clang bug by inheriting publicly.

[1] llvm/llvm-project#68849

A test case reproducing the problem is included (thanks
Kefu Chai <kefu.chai@scylladb.com>).
nyh pushed a commit to scylladb/seastar that referenced this issue Oct 19, 2023
fmt 10 detects if a formatter provides some method (set_debug_format()),
but the detection fails if the method is private and compilation breaks
on clang [1].

Work around the clang bug by inheriting publicly.

[1] llvm/llvm-project#68849

A test case reproducing the problem is included (thanks
Kefu Chai <kefu.chai@scylladb.com>).

Closes #1855
@dtcxzyw
Copy link
Member

dtcxzyw commented Oct 23, 2023

I will take a look at this. Thank @SuperSodaSea for providing a minimal reproducer.
Godbolt: https://godbolt.org/z/hbfx5x9Wv

@dtcxzyw dtcxzyw removed their assignment Mar 5, 2024
graphcareful pushed a commit to graphcareful/seastar that referenced this issue Mar 20, 2024
fmt 10 detects if a formatter provides some method (set_debug_format()),
but the detection fails if the method is private and compilation breaks
on clang [1].

Work around the clang bug by inheriting publicly.

[1] llvm/llvm-project#68849

A test case reproducing the problem is included (thanks
Kefu Chai <kefu.chai@scylladb.com>).

Closes scylladb#1855
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid
Projects
None yet
Development

No branches or pull requests

3 participants