!FunctionParamTypesAreEqual(OldType, NewType)))
return true;
- // C++ [temp.over.link]p4:
- // The signature of a function template consists of its function
- // signature, its return type and its template parameter list. The names
- // of the template parameters are significant only for establishing the
- // relationship between the template parameters and the rest of the
- // signature.
- //
- // We check the return type and template parameter lists for function
- // templates first; the remaining checks follow.
- //
- // However, we don't consider either of these when deciding whether
- // a member introduced by a shadow declaration is hidden.
- if (!UseMemberUsingDeclRules && NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- false, TPL_TemplateMatch) ||
- !Context.hasSameType(Old->getDeclaredReturnType(),
- New->getDeclaredReturnType())))
- return true;
-
+ if (NewTemplate) {
+ // C++ [temp.over.link]p4:
+ // The signature of a function template consists of its function
+ // signature, its return type and its template parameter list. The names
+ // of the template parameters are significant only for establishing the
+ // relationship between the template parameters and the rest of the
+ // signature.
+ //
+ // We check the return type and template parameter lists for function
+ // templates first; the remaining checks follow.
+ bool SameTemplateParameterList = TemplateParameterListsAreEqual(
+ NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(), false, TPL_TemplateMatch);
+ bool SameReturnType = Context.hasSameType(Old->getDeclaredReturnType(),
+ New->getDeclaredReturnType());
+ // FIXME(GH58571): Match template parameter list even for non-constrained
+ // template heads. This currently ensures that the code prior to C++20 is
+ // not newly broken.
+ bool ConstraintsInTemplateHead =
+ NewTemplate->getTemplateParameters()->hasAssociatedConstraints() ||
+ OldTemplate->getTemplateParameters()->hasAssociatedConstraints();
+ // C++ [namespace.udecl]p11:
+ // The set of declarations named by a using-declarator that inhabits a
+ // class C does not include member functions and member function
+ // templates of a base class that "correspond" to (and thus would
+ // conflict with) a declaration of a function or function template in
+ // C.
+ // Comparing return types is not required for the "correspond" check to
+ // decide whether a member introduced by a shadow declaration is hidden.
+ if (UseMemberUsingDeclRules && ConstraintsInTemplateHead &&
+ !SameTemplateParameterList)
+ return true;
+ if (!UseMemberUsingDeclRules &&
+ (!SameTemplateParameterList || !SameReturnType))
+ return true;
+ }
// If the function is a class member, its signature includes the
// cv-qualifiers (if any) and ref-qualifier (if any) on the function itself.
//
--- /dev/null
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+namespace static_methods {
+template<class> concept False = false;
+
+struct Base {
+ static void foo(auto);
+};
+struct Derived : public Base {
+ using Base::foo;
+ static void foo(False auto);
+};
+void func() {
+ Derived::foo(42);
+}
+} // namespace static_methods
+
+namespace constrained_members {
+template <unsigned n> struct Opaque {};
+template <unsigned n> void expect(Opaque<n> _) {}
+
+struct Empty{};
+constexpr int EmptySize = sizeof(Empty);
+
+template<typename T> concept IsEmpty = sizeof(T) == EmptySize;
+
+namespace base_members_not_hidden {
+struct base {
+ template <typename T>
+ Opaque<0> foo() { return Opaque<0>(); };
+};
+
+struct bar1 : public base {
+ using base::foo;
+ template <typename T> requires IsEmpty<T>
+ Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar2 : public base {
+ using base::foo;
+ template <IsEmpty T>
+ Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar3 : public base {
+ using base::foo;
+ template <typename T>
+ Opaque<1> foo() requires IsEmpty<T> { return Opaque<1>(); };
+};
+
+void func() {
+ expect<0>(base{}.foo<Empty>());
+ expect<0>(base{}.foo<int>());
+ expect<1>(bar1{}.foo<Empty>());
+ expect<0>(bar1{}.foo<int>());
+ expect<1>(bar2{}.foo<Empty>());
+ expect<0>(bar2{}.foo<int>());
+ expect<1>(bar3{}.foo<Empty>());
+ expect<0>(bar3{}.foo<int>());
+}
+}
+namespace base_members_hidden {
+struct base1 {
+ template <typename T> requires IsEmpty<T>
+ Opaque<0> foo() { return Opaque<0>(); }; // expected-note {{candidate function}}
+};
+struct bar1 : public base1 {
+ using base1::foo;
+ template <typename T> requires IsEmpty<T>
+ Opaque<1> foo() { return Opaque<1>(); };
+};
+struct base2 {
+ template <IsEmpty T>
+ Opaque<0> foo() { return Opaque<0>(); };
+};
+struct bar2 : public base2 {
+ using base2::foo;
+ template <IsEmpty T>
+ Opaque<1> foo() { return Opaque<1>(); };
+};
+struct baz : public base1 {
+ using base1::foo;
+ template <typename T> requires IsEmpty<T> && IsEmpty<T>
+ Opaque<1> foo() { return Opaque<1>(); }; // expected-note {{candidate function}}
+};
+void func() {
+ expect<0>(base1{}.foo<Empty>());
+ expect<1>(bar1{}.foo<Empty>());
+ expect<0>(base2{}.foo<Empty>());
+ expect<1>(bar2{}.foo<Empty>());
+ baz{}.foo<Empty>(); // expected-error {{call to member function 'foo' is ambiguous}}
+}
+} // namespace base_members_hidden
+
+namespace same_contraint_at_different_place {
+struct base {
+ template <IsEmpty T>
+ void foo1() {}; // expected-note 2 {{candidate function}}
+ template <typename T> requires IsEmpty<T>
+ void foo2() {}; // expected-note 2 {{candidate function}}
+ template <typename T>
+ void foo3() requires IsEmpty<T> {}; // expected-note 2 {{candidate function}}
+};
+struct bar1 : public base {
+ using base::foo1;
+ using base::foo2;
+ using base::foo3;
+ template <typename T> requires IsEmpty<T>
+ void foo1() {}; // expected-note {{candidate function}}
+ template <IsEmpty T>
+ void foo2() {}; // expected-note {{candidate function}}
+ template <IsEmpty T>
+ void foo3() {}; // expected-note {{candidate function}}
+};
+struct bar2 : public base {
+ using base::foo1;
+ using base::foo2;
+ using base::foo3;
+ template <typename T>
+ void foo1() requires IsEmpty<T> {}; // expected-note {{candidate function}}
+ template <typename T>
+ void foo2() requires IsEmpty<T> {}; // expected-note {{candidate function}}
+ template <typename T> requires IsEmpty<T>
+ void foo3() {}; // expected-note {{candidate function}}
+};
+void func() {
+ bar1{}.foo1<Empty>(); // expected-error {{call to member function 'foo1' is ambiguous}}
+ bar1{}.foo2<Empty>(); // expected-error {{call to member function 'foo2' is ambiguous}}
+ bar1{}.foo3<Empty>(); // expected-error {{call to member function 'foo3' is ambiguous}}
+ bar2{}.foo1<Empty>(); // expected-error {{call to member function 'foo1' is ambiguous}}
+ bar2{}.foo2<Empty>(); // expected-error {{call to member function 'foo2' is ambiguous}}
+ bar2{}.foo3<Empty>(); // expected-error {{call to member function 'foo3' is ambiguous}}
+}
+} // namespace same_constraint_at_different_place
+
+namespace more_constrained {
+struct base1 {
+ template <class T> Opaque<0> foo() { return Opaque<0>(); }
+};
+struct derived1 : base1 {
+ using base1::foo;
+ template <IsEmpty T> Opaque<1> foo() { return Opaque<1>(); }
+};
+struct base2 {
+ template <IsEmpty T> Opaque<0> foo() { return Opaque<0>(); }
+};
+struct derived2 : base2 {
+ using base2::foo;
+ template <class T> Opaque<1> foo() { return Opaque<1>(); }
+};
+void func() {
+ expect<0>(derived1{}.foo<int>());
+ expect<1>(derived1{}.foo<Empty>());
+ expect<0>(derived2{}.foo<Empty>());
+ expect<1>(derived2{}.foo<int>());
+}
+} // namespace more_constrained
+} // namespace constrained_members
+
+namespace heads_without_concepts {
+struct base {
+ template <int N, int M>
+ int foo() { return 1; };
+};
+
+struct bar : public base {
+ using base::foo;
+ template <int N>
+ int foo() { return 2; }; // expected-note {{candidate template ignored: substitution failure: too many template arguments for function template 'foo'}}
+};
+
+void func() {
+ bar f;
+ f.foo<10>();
+ // FIXME(GH58571): bar::foo should not hide base::foo.
+ f.foo<10, 10>(); // expected-error {{no matching member function for call to 'foo'}}
+}
+} // namespace heads_without_concepts.