diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1235,7 +1235,7 @@ } bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, - bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs, + bool IsForUsingDecl, bool ConsiderCudaAttrs, bool ConsiderRequiresClauses) { // C++ [basic.start.main]p2: This function shall not be overloaded. if (New->isMain()) @@ -1280,26 +1280,46 @@ !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()); + auto IsConstructorOrAssignment = [](FunctionDecl *FD) { + auto *CMD = dyn_cast(FD); + if (!CMD) + return false; + if (CMD->isCopyAssignmentOperator() || CMD->isMoveAssignmentOperator()) + return true; + return isa(CMD); + }; + // C++ [namespace.udecl]p4: + // The member from the base class is hidden or overridden by the + // implicitly-declared copy/move constructor or assignment operator of the + // derived class. + // 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 (IsForUsingDecl && !IsConstructorOrAssignment(New) && + !SameTemplateParameterList) + return true; + if (!IsForUsingDecl && (!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. // @@ -1313,9 +1333,8 @@ if (OldMethod && NewMethod && !OldMethod->isStatic() && !NewMethod->isStatic()) { if (OldMethod->getRefQualifier() != NewMethod->getRefQualifier()) { - if (!UseMemberUsingDeclRules && - (OldMethod->getRefQualifier() == RQ_None || - NewMethod->getRefQualifier() == RQ_None)) { + if (!IsForUsingDecl && (OldMethod->getRefQualifier() == RQ_None || + NewMethod->getRefQualifier() == RQ_None)) { // C++0x [over.load]p2: // - Member function declarations with the same name and the same // parameter-type-list as well as member function template diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp --- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp @@ -9,7 +9,7 @@ // parameter types in a base class (rather than conflicting). template struct Opaque {}; -template void expect(Opaque _) {} // expected-note 4 {{candidate function template not viable}} +template void expect(Opaque _) {} // PR5727 // This just shouldn't crash. @@ -113,35 +113,35 @@ struct Derived1 : Base { using Base::foo; - template Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} + template Opaque<2> foo() { return Opaque<2>(); } }; struct Derived2 : Base { - template Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} + template Opaque<2> foo() { return Opaque<2>(); } using Base::foo; }; struct Derived3 : Base { using Base::foo; - template Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} + template Opaque<3> foo() { return Opaque<3>(); } }; struct Derived4 : Base { - template Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} + template Opaque<3> foo() { return Opaque<3>(); } using Base::foo; }; void test() { expect<0>(Base().foo()); expect<1>(Base().foo<0>()); - expect<0>(Derived1().foo()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}} + expect<0>(Derived1().foo()); expect<2>(Derived1().foo<0>()); - expect<0>(Derived2().foo()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}} + expect<0>(Derived2().foo()); expect<2>(Derived2().foo<0>()); expect<3>(Derived3().foo()); - expect<1>(Derived3().foo<0>()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}} + expect<1>(Derived3().foo<0>()); expect<3>(Derived4().foo()); - expect<1>(Derived4().foo<0>()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}} + expect<1>(Derived4().foo<0>()); } } diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp --- a/clang/test/CXX/drs/dr2xx.cpp +++ b/clang/test/CXX/drs/dr2xx.cpp @@ -719,11 +719,11 @@ using A::g; using A::h; int &f(int); - template int &g(int); // expected-note {{candidate}} + template int &g(int); int &h(); } b; int &w = b.f(0); - int &x = b.g(0); // expected-error {{no match}} + int &x = b.g(0); // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'void'}} int &y = b.h(); float &z = const_cast(b).h(); diff --git a/clang/test/SemaTemplate/concepts-using-decl.cpp b/clang/test/SemaTemplate/concepts-using-decl.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaTemplate/concepts-using-decl.cpp @@ -0,0 +1,97 @@ +// RUN: %clang_cc1 -std=c++20 -verify %s +// expected-no-diagnostics + +namespace heads_without_concepts { +struct base { + template + int foo() { return 1; }; +}; + +struct bar : public base { + using base::foo; + template + int foo() { return 2; }; +}; + +void func() { + bar f; + f.foo<10>(); + f.foo<10, 10>(); +} +} + +namespace static_methods { +template 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 members_not_hidden { +template struct Opaque {}; +template void expect(Opaque _) {} + +struct Empty{}; +constexpr int EmptySize = sizeof(Empty); + +template concept IsEmpty = sizeof(T) == EmptySize; + +namespace base_members_not_hidden { +struct base { + template + Opaque<0> foo() { return Opaque<0>(); }; +}; + +struct bar1 : public base { + using base::foo; + template requires IsEmpty + Opaque<1> foo() { return Opaque<1>(); }; +}; + +struct bar2 : public base { + using base::foo; + template + Opaque<1> foo() { return Opaque<1>(); }; +}; + +struct bar3 : public base { + using base::foo; + template + Opaque<1> foo() requires IsEmpty { return Opaque<1>(); }; +}; + +void func() { + expect<0>(base{}.foo()); + expect<0>(base{}.foo()); + expect<1>(bar1{}.foo()); + expect<0>(bar1{}.foo()); + expect<1>(bar2{}.foo()); + expect<0>(bar2{}.foo()); + expect<1>(bar3{}.foo()); + expect<0>(bar3{}.foo()); +} +} +namespace base_members_hidden { +struct base { + template requires IsEmpty + Opaque<0> foo() { return Opaque<0>(); }; +}; +struct bar : public base { + using base::foo; + template requires IsEmpty + Opaque<1> foo() { return Opaque<1>(); }; +}; +void func() { + expect<0>(base{}.foo()); + expect<1>(bar{}.foo()); +} +} +} \ No newline at end of file