ychen updated this revision to Diff 440789.
ychen added a comment.

- add release notes
- update www-status


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D128750

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Sema/Sema.h
  clang/include/clang/Sema/TemplateDeduction.h
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp
  clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p6.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -959,7 +959,7 @@
       </tr>
       <tr>
         <td><a href="https://wg21.link/p2113r0";>P2113R0</a></td>
-        <td rowspan="1" class="none" align="center">No</td>
+        <td rowspan="1" class="full" align="center">Clang 15</td>
       </tr>
     <!-- Albuquerque papers -->
     <tr>
Index: clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p6.cpp
===================================================================
--- clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p6.cpp
+++ clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p6.cpp
@@ -15,12 +15,32 @@
 
 template <typename T, typename U> struct X {};
 
+namespace p6_2_1_1 {
+template <typename T, C U, typename V, typename Y = int>
+                                       bool operator==(X<T, U>, V);
+template <C T, C U, C V>               bool operator==(T, X<U, V>) = delete;
+
+bool h() {
+  // Prefer the first operator== since it is not a rewritten candidate.
+  return X<void *, int>{} == 0;
+}
+}
+
+namespace p6 {
 template <typename T, C U, typename V> bool operator==(X<T, U>, V) = delete;
 template <C T, C U, C V>               bool operator==(T, X<U, V>);
 
 bool h() {
   return X<void *, int>{} == 0;
 }
+} // namespace p6
+
+namespace PR49964 {
+  template <C T, C U> int f(T, U); // expected-note {{candidate function [with T = int, U = int]}}
+  template <C T, C U> int f(U, T); // expected-note {{candidate function [with T = int, U = int]}}
+
+  int x = f(0, 0); // expected-error {{call to 'f' is ambiguous}}
+}
 
 namespace PR53640 {
 
Index: clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp
===================================================================
--- clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp
+++ clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
 // expected-no-diagnostics
 
 namespace OrderWithStaticMember {
@@ -37,3 +38,17 @@
   void f(S s, V<int> v) { s >> v; }
 }
 #endif
+
+#if __cplusplus >= 202002L
+namespace CWG2445 {
+  template <typename T> struct A { };
+
+  template <typename T, typename U>
+  bool operator==(T, A<U *>);
+
+  template <typename T, typename U>
+  bool operator!=(A<T>, U) = delete;
+
+  bool f(A<int> ax, A<int *> ay) { return ay != ax; }
+}
+#endif
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -386,6 +386,7 @@
     return Sema::TDK_Inconsistent;
   }
 
+  Info.DeduceOrder.push_back(NTTP->getIndex());
   Deduced[NTTP->getIndex()] = Result;
   if (!S.getLangOpts().CPlusPlus17)
     return Sema::TDK_Success;
@@ -512,6 +513,7 @@
       return Sema::TDK_Inconsistent;
     }
 
+    Info.DeduceOrder.push_back(TempParam->getIndex());
     Deduced[TempParam->getIndex()] = Result;
     return Sema::TDK_Success;
   }
@@ -1517,6 +1519,7 @@
       return Sema::TDK_Inconsistent;
     }
 
+    Info.DeduceOrder.push_back(Index);
     Deduced[Index] = Result;
     return Sema::TDK_Success;
   }
@@ -4942,7 +4945,7 @@
 /// Determine whether the function template \p FT1 is at least as
 /// specialized as \p FT2.
 static bool isAtLeastAsSpecializedAs(Sema &S,
-                                     SourceLocation Loc,
+                                     TemplateDeductionInfo &Info,
                                      FunctionTemplateDecl *FT1,
                                      FunctionTemplateDecl *FT2,
                                      TemplatePartialOrderingContext TPOC,
@@ -4963,7 +4966,6 @@
   // C++0x [temp.deduct.partial]p3:
   //   The types used to determine the ordering depend on the context in which
   //   the partial ordering is done:
-  TemplateDeductionInfo Info(Loc);
   SmallVector<QualType, 4> Args2;
   switch (TPOC) {
   case TPOC_Call: {
@@ -5111,16 +5113,7 @@
     return false;
 
   ParmVarDecl *Last = Function->getParamDecl(NumParams - 1);
-  if (!Last->isParameterPack())
-    return false;
-
-  // Make sure that no previous parameter is a parameter pack.
-  while (--NumParams > 0) {
-    if (Function->getParamDecl(NumParams - 1)->isParameterPack())
-      return false;
-  }
-
-  return true;
+  return Last->isParameterPack();
 }
 
 /// Returns the more specialized function template according
@@ -5154,33 +5147,20 @@
     unsigned NumCallArguments2, bool Reversed,
     bool AllowOrderingByConstraints) {
 
-  auto JudgeByConstraints = [&]() -> FunctionTemplateDecl * {
-    if (!AllowOrderingByConstraints)
-      return nullptr;
-    llvm::SmallVector<const Expr *, 3> AC1, AC2;
-    FT1->getAssociatedConstraints(AC1);
-    FT2->getAssociatedConstraints(AC2);
-    bool AtLeastAsConstrained1, AtLeastAsConstrained2;
-    if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1))
-      return nullptr;
-    if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2))
-      return nullptr;
-    if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
-      return nullptr;
-    return AtLeastAsConstrained1 ? FT1 : FT2;
-  };
-
-  bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
+  TemplateDeductionInfo Info1(Loc), Info2(Loc);
+  bool Better1 = isAtLeastAsSpecializedAs(*this, Info1, FT1, FT2, TPOC,
                                           NumCallArguments1, Reversed);
-  bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
+  bool Better2 = isAtLeastAsSpecializedAs(*this, Info2, FT2, FT1, TPOC,
                                           NumCallArguments2, Reversed);
 
+  // C++ [temp.deduct.partial]p10:
+  //   F is more specialized than G if F is at least as specialized as G and G
+  //   is not at least as specialized as F.
   if (Better1 != Better2) // We have a clear winner
     return Better1 ? FT1 : FT2;
 
-  if (!Better1 && !Better2) // Neither is better than the other
-    return JudgeByConstraints();
-
+  TemplateParameterList *TPL1 = FT1->getTemplateParameters();
+  TemplateParameterList *TPL2 = FT2->getTemplateParameters();
   const unsigned NumParams1 = FT1->getTemplatedDecl()->getNumParams();
   const unsigned NumParams2 = FT2->getTemplatedDecl()->getNumParams();
 
@@ -5188,16 +5168,67 @@
   //   ... and if G has a trailing function parameter pack for which F does not
   //   have a corresponding parameter, and if F does not have a trailing
   //   function parameter pack, then F is more specialized than G.
-  bool Variadic1 = isVariadicFunctionTemplate(FT1);
-  bool Variadic2 = isVariadicFunctionTemplate(FT2);
-  if (Variadic1 != Variadic2) {
-    if (Variadic1 && NumParams1 > NumParams2)
-      return FT2;
-    if (Variadic2 && NumParams2 > NumParams1)
-      return FT1;
+  if (Better1 && Better2) {
+    bool Variadic1 = isVariadicFunctionTemplate(FT1);
+    bool Variadic2 = isVariadicFunctionTemplate(FT2);
+    if (Variadic1 != Variadic2) {
+      if (Variadic1 && NumParams1 > NumParams2)
+        return FT2;
+      if (Variadic2 && NumParams2 > NumParams1)
+        return FT1;
+    }
   }
 
-  return JudgeByConstraints();
+  // C++ [temp.func.order]p6.1:
+  // If their template-parameter-lists (possibly including template-parameters
+  // invented for an abbreviated function template ([dcl.fct])) or function
+  // parameter lists differ in length, neither template is more specialized than
+  // the other.
+  if (TPL1->size() != TPL2->size() || NumParams1 != NumParams2)
+    return nullptr;
+
+  if (Reversed) {
+    // C++ [temp.func.order]p6.2.1.1:
+    // If, for either template, some of the template parameters are not
+    // deducible from their function parameters, neither template is more
+    // specialized than the other.
+    llvm::SmallBitVector Deduced1, Deduced2;
+    MarkDeducedTemplateParameters(Context, FT1, Deduced1);
+    MarkDeducedTemplateParameters(Context, FT2, Deduced2);
+    if (!Deduced1.all() || !Deduced2.all())
+      return nullptr;
+  }
+
+  // C++ [temp.func.order]p6.2.1.2:
+  // If there is either no reordering or more than one reordering of the
+  // associated template-parameter-list such that ...
+  //
+  // C++ [temp.func.order]p6.2.2:
+  // Otherwise, if the corresponding template-parameters of the
+  // template-parameter-lists are not equivalent ([temp.over.link]) or if the
+  // function parameters that positionally correspond between the two
+  // templates are not of the same type, neither template is more specialized
+  // than the other.
+  if (!Reversed && !llvm::equal(Info1.DeduceOrder, Info2.DeduceOrder))
+    return nullptr;
+  if (!TemplateParametersAreEquivalent(TPL1, TPL2))
+    return nullptr;
+
+  if (AllowOrderingByConstraints) {
+    llvm::SmallVector<const Expr *, 3> AC1, AC2;
+    FT1->getAssociatedConstraints(AC1);
+    FT2->getAssociatedConstraints(AC2);
+    bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+    if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1))
+      return nullptr;
+    if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2))
+      return nullptr;
+    if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+      return nullptr;
+    return AtLeastAsConstrained1 ? FT1 : FT2;
+  }
+
+  return nullptr;
 }
 
 /// Determine if the two templates are equivalent.
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -38,6 +38,7 @@
 #include "llvm/ADT/StringExtras.h"
 
 #include <iterator>
+#include <numeric>
 using namespace clang;
 using namespace sema;
 
@@ -7446,10 +7447,10 @@
 
     if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template,
                                                           Arg.getLocation())) {
-      // C++2a[temp.func.order]p2
+      // P2113
+      // C++20[temp.func.order]p2
       //   [...] If both deductions succeed, the partial ordering selects the
-      //   more constrained template as described by the rules in
-      //   [temp.constr.order].
+      // more constrained template (if one exists) as determined below.
       SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
       Params->getAssociatedConstraints(ParamsAC);
       // C++2a[temp.arg.template]p3
@@ -7653,10 +7654,10 @@
 }
 
 /// Match two template parameters within template parameter lists.
-static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
-                                       bool Complain,
-                                     Sema::TemplateParameterListEqualKind Kind,
-                                       SourceLocation TemplateArgLoc) {
+static bool MatchTemplateParameterKind(
+    Sema &S, NamedDecl *New, NamedDecl *Old, bool Complain,
+    Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc,
+    bool PartialOrdering) {
   // Check the actual kind (type, non-type, template).
   if (Old->getKind() != New->getKind()) {
     if (Complain) {
@@ -7744,9 +7745,10 @@
                                         (Kind == Sema::TPL_TemplateMatch
                                            ? Sema::TPL_TemplateTemplateParmMatch
                                            : Kind),
-                                          TemplateArgLoc))
+                                          TemplateArgLoc, PartialOrdering))
       return false;
-  } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
+  } else if (!PartialOrdering &&
+             Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
     const Expr *NewC = nullptr, *OldC = nullptr;
     if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
       NewC = TC->getImmediatelyDeclaredConstraint();
@@ -7803,6 +7805,17 @@
     << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
 }
 
+bool Sema::TemplateParametersAreEquivalent(TemplateParameterList *New,
+                                           TemplateParameterList *Old) {
+  SmallVector<unsigned, 4> IterIdxs(Old->size());
+  std::iota(IterIdxs.begin(), IterIdxs.end(), 0);
+  return llvm::all_of(IterIdxs, [&](unsigned i) {
+    return MatchTemplateParameterKind(*this, New->getParam(i), Old->getParam(i),
+                                      false, Sema::TPL_TemplateMatch,
+                                      SourceLocation(), true);
+  });
+}
+
 /// Determine whether the given template parameter lists are
 /// equivalent.
 ///
@@ -7831,7 +7844,8 @@
                                      TemplateParameterList *Old,
                                      bool Complain,
                                      TemplateParameterListEqualKind Kind,
-                                     SourceLocation TemplateArgLoc) {
+                                     SourceLocation TemplateArgLoc,
+                                     bool PartialOrdering) {
   if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) {
     if (Complain)
       DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
@@ -7861,8 +7875,8 @@
         return false;
       }
 
-      if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
-                                      Kind, TemplateArgLoc))
+      if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, Kind,
+                                      TemplateArgLoc, PartialOrdering))
         return false;
 
       ++NewParm;
@@ -7877,8 +7891,8 @@
     //   template parameter pack in P (ignoring whether those template
     //   parameters are template parameter packs).
     for (; NewParm != NewParmEnd; ++NewParm) {
-      if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
-                                      Kind, TemplateArgLoc))
+      if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, Kind,
+                                      TemplateArgLoc, PartialOrdering))
         return false;
     }
   }
@@ -7892,7 +7906,7 @@
     return false;
   }
 
-  if (Kind != TPL_TemplateTemplateArgumentMatch) {
+  if (!PartialOrdering && Kind != TPL_TemplateTemplateArgumentMatch) {
     const Expr *NewRC = New->getRequiresClause();
     const Expr *OldRC = Old->getRequiresClause();
 
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -9646,13 +9646,10 @@
 /// [over.match.best]p2.6
 /// F1 and F2 are non-template functions with the same parameter-type-lists,
 /// and F1 is more constrained than F2 [...]
-static bool canCompareFunctionConstraints(Sema &S,
+static bool sameFunctionParameterTypeLists(Sema &S,
                                           const OverloadCandidate &Cand1,
                                           const OverloadCandidate &Cand2) {
-  // FIXME: Per P2113R0 we also need to compare the template parameter lists
-  // when comparing template functions. 
-  if (Cand1.Function && Cand2.Function && Cand1.Function->hasPrototype() &&
-      Cand2.Function->hasPrototype()) {
+  if (Cand1.Function && Cand2.Function) {
     auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType());
     auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType());
     if (PT1->getNumParams() == PT2->getNumParams() &&
@@ -9896,14 +9893,14 @@
                                                    : TPOC_Call,
             Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments,
             Cand1.isReversed() ^ Cand2.isReversed(),
-            canCompareFunctionConstraints(S, Cand1, Cand2)))
+            sameFunctionParameterTypeLists(S, Cand1, Cand2)))
       return BetterTemplate == Cand1.Function->getPrimaryTemplate();
   }
 
   //   -— F1 and F2 are non-template functions with the same
   //      parameter-type-lists, and F1 is more constrained than F2 [...],
   if (!Cand1IsSpecialization && !Cand2IsSpecialization &&
-      canCompareFunctionConstraints(S, Cand1, Cand2)) {
+      sameFunctionParameterTypeLists(S, Cand1, Cand2)) {
     Expr *RC1 = Cand1.Function->getTrailingRequiresClause();
     Expr *RC2 = Cand2.Function->getTrailingRequiresClause();
     if (RC1 && RC2) {
Index: clang/include/clang/Sema/TemplateDeduction.h
===================================================================
--- clang/include/clang/Sema/TemplateDeduction.h
+++ clang/include/clang/Sema/TemplateDeduction.h
@@ -232,6 +232,8 @@
   /// \brief The constraint satisfaction details resulting from the associated
   /// constraints satisfaction tests.
   ConstraintSatisfaction AssociatedConstraintsSatisfaction;
+
+  SmallVector<unsigned, 4> DeduceOrder;
 };
 
 } // namespace sema
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -8101,12 +8101,14 @@
     TPL_TemplateTemplateArgumentMatch
   };
 
-  bool TemplateParameterListsAreEqual(TemplateParameterList *New,
-                                      TemplateParameterList *Old,
-                                      bool Complain,
-                                      TemplateParameterListEqualKind Kind,
-                                      SourceLocation TemplateArgLoc
-                                        = SourceLocation());
+  bool TemplateParametersAreEquivalent(TemplateParameterList *New,
+                                       TemplateParameterList *Old);
+
+  bool TemplateParameterListsAreEqual(
+      TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
+      TemplateParameterListEqualKind Kind,
+      SourceLocation TemplateArgLoc = SourceLocation(),
+      bool PartialOrdering = false);
 
   bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams);
 
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -460,6 +460,8 @@
   now possible to overload destructors using concepts. Note that the rest
   of the paper about other special member functions is not yet implemented.
 
+- Implemented `P2113R0: Proposed resolution for 2019 comment CA 112 <https://wg21.link/P2113R0>`_.
+
 C++2b Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to