r229965 - PR22435: Correctly implement tiebreaker for reference ordering in function

Richard Smith richard-llvm at metafoo.co.uk
Thu Feb 19 20:45:22 PST 2015


Author: rsmith
Date: Thu Feb 19 22:45:22 2015
New Revision: 229965

URL: http://llvm.org/viewvc/llvm-project?rev=229965&view=rev
Log:
PR22435: Correctly implement tiebreaker for reference ordering in function
template partial ordering rules. This rule applies per pair of types being
compared, not per pair of function templates being compared.

Modified:
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=229965&r1=229964&r2=229965&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Feb 19 22:45:22 2015
@@ -91,30 +91,6 @@ DeduceTemplateArguments(Sema &S,
                         TemplateDeductionInfo &Info,
                         SmallVectorImpl<DeducedTemplateArgument> &Deduced);
 
-/// \brief Whether template argument deduction for two reference parameters
-/// resulted in the argument type, parameter type, or neither type being more
-/// qualified than the other.
-enum DeductionQualifierComparison {
-  NeitherMoreQualified = 0,
-  ParamMoreQualified,
-  ArgMoreQualified
-};
-
-/// \brief Stores the result of comparing two reference parameters while
-/// performing template argument deduction for partial ordering of function
-/// templates.
-struct RefParamPartialOrderingComparison {
-  /// \brief Whether the parameter type is an rvalue reference type.
-  bool ParamIsRvalueRef;
-  /// \brief Whether the argument type is an rvalue reference type.
-  bool ArgIsRvalueRef;
-
-  /// \brief Whether the parameter or argument (or neither) is more qualified.
-  DeductionQualifierComparison Qualifiers;
-};
-
-
-
 static Sema::TemplateDeductionResult
 DeduceTemplateArgumentsByTypeMatch(Sema &S,
                                    TemplateParameterList *TemplateParams,
@@ -124,9 +100,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
                                    SmallVectorImpl<DeducedTemplateArgument> &
                                                       Deduced,
                                    unsigned TDF,
-                                   bool PartialOrdering = false,
-                            SmallVectorImpl<RefParamPartialOrderingComparison> *
-                                                 RefParamComparisons = nullptr);
+                                   bool PartialOrdering = false);
 
 static Sema::TemplateDeductionResult
 DeduceTemplateArguments(Sema &S,
@@ -784,9 +758,6 @@ private:
 /// deduction for during partial ordering for a call
 /// (C++0x [temp.deduct.partial]).
 ///
-/// \param RefParamComparisons If we're performing template argument deduction
-/// in the context of partial ordering, the set of qualifier comparisons.
-///
 /// \returns the result of template argument deduction so far. Note that a
 /// "success" result means that template argument deduction has not yet failed,
 /// but it may still fail, later, for other reasons.
@@ -798,9 +769,7 @@ DeduceTemplateArguments(Sema &S,
                         TemplateDeductionInfo &Info,
                         SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                         unsigned TDF,
-                        bool PartialOrdering = false,
-                        SmallVectorImpl<RefParamPartialOrderingComparison> *
-                                                RefParamComparisons = nullptr) {
+                        bool PartialOrdering = false) {
   // Fast-path check to see if we have too many/too few arguments.
   if (NumParams != NumArgs &&
       !(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) &&
@@ -836,8 +805,7 @@ DeduceTemplateArguments(Sema &S,
             = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
                                                  Params[ParamIdx], Args[ArgIdx],
                                                  Info, Deduced, TDF,
-                                                 PartialOrdering,
-                                                 RefParamComparisons))
+                                                 PartialOrdering))
         return Result;
 
       ++ArgIdx;
@@ -869,8 +837,7 @@ DeduceTemplateArguments(Sema &S,
       if (Sema::TemplateDeductionResult Result
             = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern,
                                                  Args[ArgIdx], Info, Deduced,
-                                                 TDF, PartialOrdering,
-                                                 RefParamComparisons))
+                                                 TDF, PartialOrdering))
         return Result;
 
       PackScope.nextPackElement();
@@ -967,9 +934,6 @@ bool Sema::isSameOrCompatibleFunctionTyp
 /// \param PartialOrdering Whether we're performing template argument deduction
 /// in the context of partial ordering (C++0x [temp.deduct.partial]).
 ///
-/// \param RefParamComparisons If we're performing template argument deduction
-/// in the context of partial ordering, the set of qualifier comparisons.
-///
 /// \returns the result of template argument deduction so far. Note that a
 /// "success" result means that template argument deduction has not yet failed,
 /// but it may still fail, later, for other reasons.
@@ -980,9 +944,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
                                    TemplateDeductionInfo &Info,
                             SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                                    unsigned TDF,
-                                   bool PartialOrdering,
-                            SmallVectorImpl<RefParamPartialOrderingComparison> *
-                                                          RefParamComparisons) {
+                                   bool PartialOrdering) {
   // We only want to look at the canonical types, since typedefs and
   // sugar are not part of template argument deduction.
   QualType Param = S.Context.getCanonicalType(ParamIn);
@@ -995,7 +957,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
     Arg = ArgExpansion->getPattern();
 
   if (PartialOrdering) {
-    // C++0x [temp.deduct.partial]p5:
+    // C++11 [temp.deduct.partial]p5:
     //   Before the partial ordering is done, certain transformations are
     //   performed on the types used for partial ordering:
     //     - If P is a reference type, P is replaced by the type referred to.
@@ -1008,42 +970,42 @@ DeduceTemplateArgumentsByTypeMatch(Sema
     if (ArgRef)
       Arg = ArgRef->getPointeeType();
 
-    if (RefParamComparisons && ParamRef && ArgRef) {
-      // C++0x [temp.deduct.partial]p6:
-      //   If both P and A were reference types (before being replaced with the
-      //   type referred to above), determine which of the two types (if any) is
-      //   more cv-qualified than the other; otherwise the types are considered
-      //   to be equally cv-qualified for partial ordering purposes. The result
-      //   of this determination will be used below.
+    if (ParamRef && ArgRef && S.Context.hasSameUnqualifiedType(Param, Arg)) {
+      // C++11 [temp.deduct.partial]p9:
+      //   If, for a given type, deduction succeeds in both directions (i.e.,
+      //   the types are identical after the transformations above) and both
+      //   P and A were reference types [...]:
+      //     - if [one type] was an lvalue reference and [the other type] was
+      //       not, [the other type] is not considered to be at least as
+      //       specialized as [the first type]
+      //     - if [one type] is more cv-qualified than [the other type],
+      //       [the other type] is not considered to be at least as specialized
+      //       as [the first type]
+      // Objective-C ARC adds:
+      //     - [one type] has non-trivial lifetime, [the other type] has
+      //       __unsafe_unretained lifetime, and the types are otherwise
+      //       identical
       //
-      // We save this information for later, using it only when deduction
-      // succeeds in both directions.
-      RefParamPartialOrderingComparison Comparison;
-      Comparison.ParamIsRvalueRef = ParamRef->getAs<RValueReferenceType>();
-      Comparison.ArgIsRvalueRef = ArgRef->getAs<RValueReferenceType>();
-      Comparison.Qualifiers = NeitherMoreQualified;
-      
+      // A is "considered to be at least as specialized" as P iff deduction
+      // succeeds, so we model this as a deduction failure. Note that
+      // [the first type] is P and [the other type] is A here; the standard
+      // gets this backwards.
       Qualifiers ParamQuals = Param.getQualifiers();
       Qualifiers ArgQuals = Arg.getQualifiers();
-      if (ParamQuals.isStrictSupersetOf(ArgQuals))
-        Comparison.Qualifiers = ParamMoreQualified;
-      else if (ArgQuals.isStrictSupersetOf(ParamQuals))
-        Comparison.Qualifiers = ArgMoreQualified;
-      else if (ArgQuals.getObjCLifetime() != ParamQuals.getObjCLifetime() &&
-               ArgQuals.withoutObjCLifetime()
-                 == ParamQuals.withoutObjCLifetime()) {
-        // Prefer binding to non-__unsafe_autoretained parameters.
-        if (ArgQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
-            ParamQuals.getObjCLifetime())
-          Comparison.Qualifiers = ParamMoreQualified;
-        else if (ParamQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
-                 ArgQuals.getObjCLifetime())
-          Comparison.Qualifiers = ArgMoreQualified;
+      if ((ParamRef->isLValueReferenceType() &&
+           !ArgRef->isLValueReferenceType()) ||
+          ParamQuals.isStrictSupersetOf(ArgQuals) ||
+          (ParamQuals.hasNonTrivialObjCLifetime() &&
+           ArgQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
+           ParamQuals.withoutObjCLifetime() ==
+               ArgQuals.withoutObjCLifetime())) {
+        Info.FirstArg = TemplateArgument(ParamIn);
+        Info.SecondArg = TemplateArgument(ArgIn);
+        return Sema::TDK_NonDeducedMismatch;
       }
-      RefParamComparisons->push_back(Comparison);
     }
 
-    // C++0x [temp.deduct.partial]p7:
+    // C++11 [temp.deduct.partial]p7:
     //   Remove any top-level cv-qualifiers:
     //     - If P is a cv-qualified type, P is replaced by the cv-unqualified
     //       version of P.
@@ -4146,8 +4108,7 @@ static bool isAtLeastAsSpecializedAs(Sem
                                      FunctionTemplateDecl *FT1,
                                      FunctionTemplateDecl *FT2,
                                      TemplatePartialOrderingContext TPOC,
-                                     unsigned NumCallArguments1,
-    SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
+                                     unsigned NumCallArguments1) {
   FunctionDecl *FD1 = FT1->getTemplatedDecl();
   FunctionDecl *FD2 = FT2->getTemplatedDecl();
   const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
@@ -4212,8 +4173,7 @@ static bool isAtLeastAsSpecializedAs(Sem
       Args2.resize(NumComparedArguments);
     if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
                                 Args1.data(), Args1.size(), Info, Deduced,
-                                TDF_None, /*PartialOrdering=*/true,
-                                RefParamComparisons))
+                                TDF_None, /*PartialOrdering=*/true))
       return false;
 
     break;
@@ -4225,7 +4185,7 @@ static bool isAtLeastAsSpecializedAs(Sem
     if (DeduceTemplateArgumentsByTypeMatch(
             S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(),
             Info, Deduced, TDF_None,
-            /*PartialOrdering=*/true, RefParamComparisons))
+            /*PartialOrdering=*/true))
       return false;
     break;
 
@@ -4235,8 +4195,7 @@ static bool isAtLeastAsSpecializedAs(Sem
     if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
                                            FD2->getType(), FD1->getType(),
                                            Info, Deduced, TDF_None,
-                                           /*PartialOrdering=*/true,
-                                           RefParamComparisons))
+                                           /*PartialOrdering=*/true))
       return false;
     break;
   }
@@ -4335,83 +4294,17 @@ Sema::getMoreSpecializedTemplate(Functio
                                  TemplatePartialOrderingContext TPOC,
                                  unsigned NumCallArguments1,
                                  unsigned NumCallArguments2) {
-  SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons;
   bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
-                                          NumCallArguments1, nullptr);
+                                          NumCallArguments1);
   bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
-                                          NumCallArguments2,
-                                          &RefParamComparisons);
+                                          NumCallArguments2);
 
   if (Better1 != Better2) // We have a clear winner
-    return Better1? FT1 : FT2;
+    return Better1 ? FT1 : FT2;
 
   if (!Better1 && !Better2) // Neither is better than the other
     return nullptr;
 
-  // C++0x [temp.deduct.partial]p10:
-  //   If for each type being considered a given template is at least as
-  //   specialized for all types and more specialized for some set of types and
-  //   the other template is not more specialized for any types or is not at
-  //   least as specialized for any types, then the given template is more
-  //   specialized than the other template. Otherwise, neither template is more
-  //   specialized than the other.
-  Better1 = false;
-  Better2 = false;
-  for (unsigned I = 0, N = RefParamComparisons.size(); I != N; ++I) {
-    // C++0x [temp.deduct.partial]p9:
-    //   If, for a given type, deduction succeeds in both directions (i.e., the
-    //   types are identical after the transformations above) and both P and A
-    //   were reference types (before being replaced with the type referred to
-    //   above):
-
-    //     -- if the type from the argument template was an lvalue reference
-    //        and the type from the parameter template was not, the argument
-    //        type is considered to be more specialized than the other;
-    //        otherwise,
-    if (!RefParamComparisons[I].ArgIsRvalueRef &&
-        RefParamComparisons[I].ParamIsRvalueRef) {
-      Better2 = true;
-      if (Better1)
-        return nullptr;
-      continue;
-    } else if (!RefParamComparisons[I].ParamIsRvalueRef &&
-               RefParamComparisons[I].ArgIsRvalueRef) {
-      Better1 = true;
-      if (Better2)
-        return nullptr;
-      continue;
-    }
-
-    //     -- if the type from the argument template is more cv-qualified than
-    //        the type from the parameter template (as described above), the
-    //        argument type is considered to be more specialized than the
-    //        other; otherwise,
-    switch (RefParamComparisons[I].Qualifiers) {
-    case NeitherMoreQualified:
-      break;
-
-    case ParamMoreQualified:
-      Better1 = true;
-      if (Better2)
-        return nullptr;
-      continue;
-
-    case ArgMoreQualified:
-      Better2 = true;
-      if (Better1)
-        return nullptr;
-      continue;
-    }
-
-    //     -- neither type is more specialized than the other.
-  }
-
-  assert(!(Better1 && Better2) && "Should have broken out in the loop above");
-  if (Better1)
-    return FT1;
-  else if (Better2)
-    return FT2;
-
   // FIXME: This mimics what GCC implements, but doesn't match up with the
   // proposed resolution for core issue 692. This area needs to be sorted out,
   // but for now we attempt to maintain compatibility.
@@ -4584,8 +4477,7 @@ Sema::getMoreSpecializedPartialSpecializ
   bool Better1 = !DeduceTemplateArgumentsByTypeMatch(*this,
                                             PS2->getTemplateParameters(),
                                             PT2, PT1, Info, Deduced, TDF_None,
-                                            /*PartialOrdering=*/true,
-                                            /*RefParamComparisons=*/nullptr);
+                                            /*PartialOrdering=*/true);
   if (Better1) {
     SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end());
     InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info);
@@ -4598,8 +4490,7 @@ Sema::getMoreSpecializedPartialSpecializ
   Deduced.resize(PS1->getTemplateParameters()->size());
   bool Better2 = !DeduceTemplateArgumentsByTypeMatch(
       *this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None,
-      /*PartialOrdering=*/true,
-      /*RefParamComparisons=*/nullptr);
+      /*PartialOrdering=*/true);
   if (Better2) {
     SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
                                                  Deduced.end());
@@ -4642,8 +4533,7 @@ Sema::getMoreSpecializedPartialSpecializ
   Deduced.resize(PS2->getTemplateParameters()->size());
   bool Better1 = !DeduceTemplateArgumentsByTypeMatch(
       *this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None,
-      /*PartialOrdering=*/true,
-      /*RefParamComparisons=*/nullptr);
+      /*PartialOrdering=*/true);
   if (Better1) {
     SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
                                                  Deduced.end());
@@ -4659,8 +4549,7 @@ Sema::getMoreSpecializedPartialSpecializ
   bool Better2 = !DeduceTemplateArgumentsByTypeMatch(*this,
                                             PS1->getTemplateParameters(),
                                             PT1, PT2, Info, Deduced, TDF_None,
-                                            /*PartialOrdering=*/true,
-                                            /*RefParamComparisons=*/nullptr);
+                                            /*PartialOrdering=*/true);
   if (Better2) {
     SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end());
     InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info);

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp?rev=229965&r1=229964&r2=229965&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp Thu Feb 19 22:45:22 2015
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
 template<class T> struct A { A(); };
 template<class T> int &f(T); 
@@ -21,3 +22,23 @@ void m() {
   const A<int> z2; 
   int &ir1 = h(z2);
 }
+
+
+namespace core_26909 {
+  template<typename T> struct A {};
+  template<typename T, typename U> void f(T&, U); // expected-note {{candidate}}
+  template<typename T, typename U> void f(T&&, A<U>); // expected-note {{candidate}} expected-warning 0-1{{extension}}
+  template<typename T, typename U> void g(const T&, U); // expected-note {{candidate}}
+  template<typename T, typename U> void g(T&, A<U>); // expected-note {{candidate}}
+
+  void h(int a, const char b, A<int> c) {
+    f(a, c); // expected-error{{ambiguous}}
+    g(b, c); // expected-error{{ambiguous}}
+  }
+}
+
+namespace PR22435 {
+  template<typename T, typename U> void foo(void (*)(T), const U &); // expected-note {{candidate}}
+  template<typename T, typename U> bool foo(void (*)(T &), U &); // expected-note {{candidate}}
+  void bar(const int x) { bool b = foo<char>(0, x); } // expected-error {{ambiguous}}
+}





More information about the cfe-commits mailing list