usaxena95 updated this revision to Diff 470174.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136440/new/

https://reviews.llvm.org/D136440

Files:
  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,114 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+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 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 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 [with T = constrained_members::Empty]}}
+};
+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 [with T = constrained_members::Empty]}}
+};
+void func() { 
+  expect<0>(base1{}.foo<Empty>());
+  expect<1>(bar1{}.foo<Empty>());
+  expect<0>(base2{}.foo<Empty>());
+  expect<1>(bar2{}.foo<Empty>());
+  expect<1>(baz{}.foo<Empty>()); // expected-error {{call to member function 'foo' is ambiguous}}
+}
+}
+}
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -1280,26 +1280,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 contrained
+    // template heads. This currently ensures that the code prior to C++20 is
+    // not newly broken.
+    bool ContraintsInTemplateHead =
+        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 && ContraintsInTemplateHead &&
+        !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
@@ -3675,8 +3675,8 @@
                              const LookupResult &OldDecls,
                              NamedDecl *&OldDecl,
                              bool IsForUsingDecl);
-  bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl,
-                  bool ConsiderCudaAttrs = true,
+  bool IsOverload(FunctionDecl *New, FunctionDecl *Old,
+                  bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs = true,
                   bool ConsiderRequiresClauses = true);
 
   // Calculates whether the expression Constraint depends on an enclosing
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to