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

Reply via email to