[cfe-commits] r94283 - in /cfe/trunk/lib/Sema: SemaOverload.cpp SemaOverload.h

John McCall rjmccall at apple.com
Fri Jan 22 21:17:44 PST 2010


Author: rjmccall
Date: Fri Jan 22 23:17:32 2010
New Revision: 94283

URL: http://llvm.org/viewvc/llvm-project?rev=94283&view=rev
Log:
During overload resolution diagnostics, sort non-viable candidates by the quality of their
conversions.  To make this work, fill out all conversions for all candidates
(but only when diagnosing overload failure).  Split out a few cases from
ovl_fail_bad_conversion which didn't actually involve a failed argument
conversion.

I'm pretty sure this is not a well-founded ordering, but I'm not sure it matters.


Modified:
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaOverload.h

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=94283&r1=94282&r2=94283&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Jan 22 23:17:32 2010
@@ -2783,7 +2783,7 @@
   QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
   if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
     Candidate.Viable = false;
-    Candidate.FailureKind = ovl_fail_bad_conversion;
+    Candidate.FailureKind = ovl_fail_trivial_conversion;
     return;
   }
   
@@ -2821,7 +2821,7 @@
 
   case ImplicitConversionSequence::BadConversion:
     Candidate.Viable = false;
-    Candidate.FailureKind = ovl_fail_bad_conversion;
+    Candidate.FailureKind = ovl_fail_bad_final_conversion;
     break;
 
   default:
@@ -2896,6 +2896,7 @@
   if (ObjectInit.isBad()) {
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_bad_conversion;
+    Candidate.Conversions[0] = ObjectInit;
     return;
   }
 
@@ -4530,6 +4531,8 @@
     return DiagnoseArityMismatch(S, Cand, NumArgs);
 
   case ovl_fail_bad_deduction:
+  case ovl_fail_trivial_conversion:
+  case ovl_fail_bad_final_conversion:
     return S.NoteOverloadCandidate(Fn);
 
   case ovl_fail_bad_conversion:
@@ -4650,6 +4653,38 @@
           R->FailureKind == ovl_fail_too_few_arguments)
         return true;
 
+      // 2. Bad conversions come first and are ordered by the number
+      // of bad conversions and quality of good conversions.
+      if (L->FailureKind == ovl_fail_bad_conversion) {
+        if (R->FailureKind != ovl_fail_bad_conversion)
+          return true;
+
+        // If there's any ordering between the defined conversions...
+        // FIXME: this might not be transitive.
+        assert(L->Conversions.size() == R->Conversions.size());
+
+        int leftBetter = 0;
+        for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) {
+          switch (S.CompareImplicitConversionSequences(L->Conversions[I],
+                                                       R->Conversions[I])) {
+          case ImplicitConversionSequence::Better:
+            leftBetter++;
+            break;
+
+          case ImplicitConversionSequence::Worse:
+            leftBetter--;
+            break;
+
+          case ImplicitConversionSequence::Indistinguishable:
+            break;
+          }
+        }
+        if (leftBetter > 0) return true;
+        if (leftBetter < 0) return false;
+
+      } else if (R->FailureKind == ovl_fail_bad_conversion)
+        return false;
+
       // TODO: others?
     }
 
@@ -4665,6 +4700,73 @@
   }
 };
 
+/// CompleteNonViableCandidate - Normally, overload resolution only
+/// computes up to the first
+void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
+                                Expr **Args, unsigned NumArgs) {
+  assert(!Cand->Viable);
+
+  // Don't do anything on failures other than bad conversion.
+  if (Cand->FailureKind != ovl_fail_bad_conversion) return;
+
+  // Skip forward to the first bad conversion.
+  unsigned ConvIdx = 0;
+  unsigned ConvCount = Cand->Conversions.size();
+  while (true) {
+    assert(ConvIdx != ConvCount && "no bad conversion in candidate");
+    ConvIdx++;
+    if (Cand->Conversions[ConvIdx - 1].isBad())
+      break;
+  }
+
+  if (ConvIdx == ConvCount)
+    return;
+
+  // FIXME: these should probably be preserved from the overload
+  // operation somehow.
+  bool SuppressUserConversions = false;
+  bool ForceRValue = false;
+
+  const FunctionProtoType* Proto;
+  unsigned ArgIdx = ConvIdx;
+
+  if (Cand->IsSurrogate) {
+    QualType ConvType
+      = Cand->Surrogate->getConversionType().getNonReferenceType();
+    if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+      ConvType = ConvPtrType->getPointeeType();
+    Proto = ConvType->getAs<FunctionProtoType>();
+    ArgIdx--;
+  } else if (Cand->Function) {
+    Proto = Cand->Function->getType()->getAs<FunctionProtoType>();
+    if (isa<CXXMethodDecl>(Cand->Function) &&
+        !isa<CXXConstructorDecl>(Cand->Function))
+      ArgIdx--;
+  } else {
+    // Builtin binary operator with a bad first conversion.
+    assert(ConvCount <= 3);
+    for (; ConvIdx != ConvCount; ++ConvIdx)
+      Cand->Conversions[ConvIdx]
+        = S.TryCopyInitialization(Args[ConvIdx],
+                                  Cand->BuiltinTypes.ParamTypes[ConvIdx],
+                                  SuppressUserConversions, ForceRValue,
+                                  /*InOverloadResolution*/ true);
+    return;
+  }
+
+  // Fill in the rest of the conversions.
+  unsigned NumArgsInProto = Proto->getNumArgs();
+  for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
+    if (ArgIdx < NumArgsInProto)
+      Cand->Conversions[ConvIdx]
+        = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx),
+                                  SuppressUserConversions, ForceRValue,
+                                  /*InOverloadResolution=*/true);
+    else
+      Cand->Conversions[ConvIdx].setEllipsis();
+  }
+}
+
 } // end anonymous namespace
 
 /// PrintOverloadCandidates - When overload resolution fails, prints
@@ -4682,9 +4784,15 @@
   if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size());
   for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
                                   LastCand = CandidateSet.end();
-       Cand != LastCand; ++Cand)
-    if (Cand->Viable || OCD == OCD_AllCandidates)
+       Cand != LastCand; ++Cand) {
+    if (Cand->Viable)
+      Cands.push_back(Cand);
+    else if (OCD == OCD_AllCandidates) {
+      CompleteNonViableCandidate(*this, Cand, Args, NumArgs);
       Cands.push_back(Cand);
+    }
+  }
+
   std::sort(Cands.begin(), Cands.end(),
             CompareOverloadCandidatesForDisplay(*this));
   

Modified: cfe/trunk/lib/Sema/SemaOverload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=94283&r1=94282&r2=94283&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Fri Jan 22 23:17:32 2010
@@ -390,7 +390,16 @@
     ovl_fail_too_many_arguments,
     ovl_fail_too_few_arguments,
     ovl_fail_bad_conversion,
-    ovl_fail_bad_deduction
+    ovl_fail_bad_deduction,
+
+    /// This conversion candidate was not considered because it
+    /// duplicates the work of a trivial or derived-to-base
+    /// conversion.
+    ovl_fail_trivial_conversion,
+
+    /// This conversion candidate is not viable because its result
+    /// type is not implicitly convertible to the desired type.
+    ovl_fail_bad_final_conversion
   };
 
   /// OverloadCandidate - A single candidate in an overload set (C++ 13.3).





More information about the cfe-commits mailing list