[clang] [clang] Bugfix for choosing the more specialized overload (PR #83279)

Botond István Horváth via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 5 09:37:05 PST 2024


================
@@ -5548,13 +5504,100 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
 FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
     FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
     TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
-    unsigned NumCallArguments2, bool Reversed) {
+    unsigned NumCallArguments2, QualType RawObjType1, QualType RawObjType2,
+    bool Reversed) {
+  SmallVector<QualType, 4> Args1;
+  SmallVector<QualType, 4> Args2;
+  const FunctionDecl *FD1 = FT1->getTemplatedDecl();
+  const FunctionDecl *FD2 = FT2->getTemplatedDecl();
+  bool shouldConvert1 = false;
+  bool shouldConvert2 = false;
+  QualType ObjType1;
+  QualType ObjType2;
+  if (TPOC == TPOC_Call) {
+    const FunctionProtoType *Proto1 =
+        FD1->getType()->getAs<FunctionProtoType>();
+    const FunctionProtoType *Proto2 =
+        FD2->getType()->getAs<FunctionProtoType>();
+
+    //   - In the context of a function call, the function parameter types are
+    //     used.
+    const CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
+    const CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
+
+    if (getLangOpts().CPlusPlus20) {
+      // C++20 [temp.func.order]p3
+      //   [...] Each function template M that is a member function is
+      //   considered to have a new first parameter of type
+      //   X(M), described below, inserted in its function parameter list.
+      //
+      // Note that we interpret "that is a member function" as
+      // "that is a member function with no expicit object argument".
+      // Otherwise the ordering rules for methods with expicit objet arguments
+      // against anything else make no sense.
+      shouldConvert1 = Method1 && !Method1->isExplicitObjectMemberFunction();
+      shouldConvert2 = Method2 && !Method2->isExplicitObjectMemberFunction();
+    } else {
+      // C++11 [temp.func.order]p3:
+      //   [...] If only one of the function templates is a non-static
+      //   member, that function template is considered to have a new
+      //   first parameter inserted in its function parameter list.
+      //
+      // Note that we interpret this to mean "if one of the function
+      // templates is a non-static member and the other is a non-member";
+      // otherwise, the ordering rules for static functions against non-static
+      // functions don't make any sense.
+      //
+      // C++98/03 doesn't have this provision but we've extended DR532 to cover
+      // it as wording was broken prior to it.
+      shouldConvert1 =
+          !Method2 && Method1 && Method1->isImplicitObjectMemberFunction();
+      shouldConvert2 =
+          !Method1 && Method2 && Method2->isImplicitObjectMemberFunction();
+    }
+    if (shouldConvert1) {
+      bool isR2 =
+          getLangOpts().CPlusPlus20 &&
+          (shouldConvert1
+               ? Method2->getRefQualifier() == RQ_RValue
+               : Proto2->param_type_begin()[0]->isRValueReferenceType());
+      // Compare 'this' from Method1 against first parameter from Method2.
+      ObjType1 = GetImplicitObjectParameterType(this->Context, Method1,
+                                                RawObjType1, isR2);
+      Args1.push_back(ObjType1);
+    }
+    if (shouldConvert2) {
+      bool isR1 =
+          getLangOpts().CPlusPlus20 &&
+          (shouldConvert2
+               ? Method1->getRefQualifier() == RQ_RValue
+               : Proto1->param_type_begin()[0]->isRValueReferenceType());
+      // Compare 'this' from Method2 against first parameter from Method1.
+      ObjType2 = GetImplicitObjectParameterType(this->Context, Method2,
+                                                RawObjType2, isR1);
+      Args2.push_back(ObjType2);
+    }
+    unsigned NumComparedArguments = NumCallArguments1 + shouldConvert1;
 
-  bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
-                                          NumCallArguments1, Reversed);
-  bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
-                                          NumCallArguments2, Reversed);
+    Args1.insert(Args1.end(), Proto1->param_type_begin(),
+                 Proto1->param_type_end());
+    Args2.insert(Args2.end(), Proto2->param_type_begin(),
+                 Proto2->param_type_end());
 
+    // C++ [temp.func.order]p5:
+    //   The presence of unused ellipsis and default arguments has no effect on
+    //   the partial ordering of function templates.
+    if (Args1.size() > NumComparedArguments)
----------------
HoBoIs wrote:

Done

https://github.com/llvm/llvm-project/pull/83279


More information about the cfe-commits mailing list