usaxena95 updated this revision to Diff 471086. usaxena95 marked 2 inline comments as done. usaxena95 added a comment.
Addressed comments. Added release notes. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D136440/new/ https://reviews.llvm.org/D136440 Files: clang/docs/ReleaseNotes.rst clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaOverload.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,178 @@ +// 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. Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -1184,26 +1184,42 @@ !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. // Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -3661,9 +3661,9 @@ FunctionDecl *New, const LookupResult &OldDecls, NamedDecl *&OldDecl, - bool IsForUsingDecl); - bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, - bool ConsiderCudaAttrs = true, + bool UseMemberUsingDeclRules); + bool IsOverload(FunctionDecl *New, FunctionDecl *Old, + bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs = true, bool ConsiderRequiresClauses = true); enum class AllowedExplicit { Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -227,6 +227,9 @@ `GH54872 <https://github.com/llvm/llvm-project/issues/54872>`_, `GH54587 <https://github.com/llvm/llvm-project/issues/54587>`_. +- Do not hide templated base members introduced via using-decl in derived class + (useful specially for constrained members). Fixes `GH50886 <https://github.com/llvm/llvm-project/issues/50886>`_. + C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits