usaxena95 created this revision. Herald added a project: All. usaxena95 requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D136440 Files: clang/lib/Sema/SemaOverload.cpp clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp clang/test/CXX/drs/dr2xx.cpp clang/test/SemaTemplate/concepts-using-decl.cpp
Index: clang/test/SemaTemplate/concepts-using-decl.cpp =================================================================== --- /dev/null +++ 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 N, int M> + int foo() { return 1; }; +}; + +struct bar : public base { + using base::foo; + template <int N> + int foo() { return 2; }; +}; + +void func() { + bar f; + f.foo<10>(); + f.foo<10, 10>(); +} +} + +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 members_not_hidden { +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 base { + template <typename T> requires IsEmpty<T> + Opaque<0> foo() { return Opaque<0>(); }; +}; +struct bar : public base { + using base::foo; + template <typename T> requires IsEmpty<T> + Opaque<1> foo() { return Opaque<1>(); }; +}; +void func() { + expect<0>(base{}.foo<Empty>()); + expect<1>(bar{}.foo<Empty>()); +} +} +} \ No newline at end of file Index: clang/test/CXX/drs/dr2xx.cpp =================================================================== --- clang/test/CXX/drs/dr2xx.cpp +++ clang/test/CXX/drs/dr2xx.cpp @@ -719,11 +719,11 @@ using A::g; using A::h; int &f(int); - template<int> int &g(int); // expected-note {{candidate}} + template<int> int &g(int); int &h(); } b; int &w = b.f(0); - int &x = b.g<int>(0); // expected-error {{no match}} + int &x = b.g<int>(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<const B&>(b).h(); Index: clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp =================================================================== --- clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp +++ 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 <unsigned n> struct Opaque {}; -template <unsigned n> void expect(Opaque<n> _) {} // expected-note 4 {{candidate function template not viable}} +template <unsigned n> void expect(Opaque<n> _) {} // PR5727 // This just shouldn't crash. @@ -113,35 +113,35 @@ struct Derived1 : Base { using Base::foo; - template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} + template <int n> Opaque<2> foo() { return Opaque<2>(); } }; struct Derived2 : Base { - template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} + template <int n> Opaque<2> foo() { return Opaque<2>(); } using Base::foo; }; struct Derived3 : Base { using Base::foo; - template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} + template <class T> Opaque<3> foo() { return Opaque<3>(); } }; struct Derived4 : Base { - template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} + template <class T> Opaque<3> foo() { return Opaque<3>(); } using Base::foo; }; void test() { expect<0>(Base().foo<int>()); expect<1>(Base().foo<0>()); - expect<0>(Derived1().foo<int>()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}} + expect<0>(Derived1().foo<int>()); expect<2>(Derived1().foo<0>()); - expect<0>(Derived2().foo<int>()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}} + expect<0>(Derived2().foo<int>()); expect<2>(Derived2().foo<0>()); expect<3>(Derived3().foo<int>()); - 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<int>()); - 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>()); } } Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ 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<CXXMethodDecl>(FD); + if (!CMD) + return false; + if (CMD->isCopyAssignmentOperator() || CMD->isMoveAssignmentOperator()) + return true; + return isa<CXXConstructorDecl>(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
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits