When diagnosing the lack of a viable conversion function, also list
authorRichard Smith <richard@metafoo.co.uk>
Thu, 9 Jan 2020 20:27:48 +0000 (12:27 -0800)
committerRichard Smith <richard@metafoo.co.uk>
Thu, 9 Jan 2020 23:15:02 +0000 (15:15 -0800)
explicit functions that are not candidates.

It's not always obvious that the reason a conversion was not possible is
because the function you wanted to call is 'explicit', so explicitly say
if that's the case.

It would be nice to rank the explicit candidates higher in the
diagnostic if an implicit conversion sequence exists for their
arguments, but unfortunately we can't determine that without potentially
triggering non-immediate-context errors that we're not permitted to
produce.

21 files changed:
clang/include/clang/AST/DeclCXX.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Overload.h
clang/lib/Sema/SemaInit.cpp
clang/lib/Sema/SemaOverload.cpp
clang/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
clang/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
clang/test/CXX/drs/dr15xx.cpp
clang/test/CXX/drs/dr1xx.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
clang/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp
clang/test/CXX/special/class.inhctor/p3.cpp
clang/test/PCH/cxx-explicit-specifier.cpp
clang/test/SemaCXX/conversion-function.cpp
clang/test/SemaCXX/convert-to-bool.cpp
clang/test/SemaCXX/converting-constructor.cpp
clang/test/SemaCXX/copy-initialization.cpp
clang/test/SemaCXX/cxx2a-explicit-bool.cpp
clang/test/SemaCXX/default1.cpp
clang/test/SemaCXX/explicit.cpp

index aba33e3..73b4fb9 100644 (file)
@@ -1783,7 +1783,7 @@ public:
 };
 
 /// Store information needed for an explicit specifier.
-/// used by CXXDeductionGuideDecl, CXXConstructorDecl and CXXConversionDecl.
+/// Used by CXXDeductionGuideDecl, CXXConstructorDecl and CXXConversionDecl.
 class ExplicitSpecifier {
   llvm::PointerIntPair<Expr *, 2, ExplicitSpecKind> ExplicitSpec{
       nullptr, ExplicitSpecKind::ResolvedFalse};
@@ -1796,20 +1796,22 @@ public:
   const Expr *getExpr() const { return ExplicitSpec.getPointer(); }
   Expr *getExpr() { return ExplicitSpec.getPointer(); }
 
-  /// Return true if the ExplicitSpecifier isn't defaulted.
+  /// Determine if the declaration had an explicit specifier of any kind.
   bool isSpecified() const {
     return ExplicitSpec.getInt() != ExplicitSpecKind::ResolvedFalse ||
            ExplicitSpec.getPointer();
   }
 
-  /// Check for Equivalence of explicit specifiers.
-  /// Return True if the explicit specifier are equivalent false otherwise.
+  /// Check for equivalence of explicit specifiers.
+  /// \return true if the explicit specifier are equivalent, false otherwise.
   bool isEquivalent(const ExplicitSpecifier Other) const;
-  /// Return true if the explicit specifier is already resolved to be explicit.
+  /// Determine whether this specifier is known to correspond to an explicit
+  /// declaration. Returns false if the specifier is absent or has an
+  /// expression that is value-dependent or evaluates to false.
   bool isExplicit() const {
     return ExplicitSpec.getInt() == ExplicitSpecKind::ResolvedTrue;
   }
-  /// Return true if the ExplicitSpecifier isn't valid.
+  /// Determine if the explicit specifier is invalid.
   /// This state occurs after a substitution failures.
   bool isInvalid() const {
     return ExplicitSpec.getInt() == ExplicitSpecKind::Unresolved &&
@@ -1817,9 +1819,7 @@ public:
   }
   void setKind(ExplicitSpecKind Kind) { ExplicitSpec.setInt(Kind); }
   void setExpr(Expr *E) { ExplicitSpec.setPointer(E); }
-  // getFromDecl - retrieve the explicit specifier in the given declaration.
-  // if the given declaration has no explicit. the returned explicit specifier
-  // is defaulted. .isSpecified() will be false.
+  // Retrieve the explicit specifier in the given declaration, if any.
   static ExplicitSpecifier getFromDecl(FunctionDecl *Function);
   static const ExplicitSpecifier getFromDecl(const FunctionDecl *Function) {
     return getFromDecl(const_cast<FunctionDecl *>(Function));
index e71bddc..53d4571 100644 (file)
@@ -3871,10 +3871,9 @@ def note_ovl_candidate : Note<
     "| has different qualifiers (expected %5 but found %6)"
     "| has different exception specification}4">;
 
-def note_ovl_candidate_explicit_forbidden : Note<
-    "candidate %0 ignored: cannot be explicit">;
-def note_explicit_bool_resolved_to_true : Note<
-    "explicit(bool) specifier resolved to true">;
+def note_ovl_candidate_explicit : Note<
+    "explicit %select{constructor|conversion function|deduction guide}0 "
+    "is not a candidate%select{| (explicit specifier evaluates to true)}1">;
 def note_ovl_candidate_inherited_constructor : Note<
     "constructor from base class %0 inherited here">;
 def note_ovl_candidate_inherited_constructor_slice : Note<
index 0ccb658..1394c62 100644 (file)
@@ -732,10 +732,9 @@ class Sema;
     /// attribute disabled it.
     ovl_fail_enable_if,
 
-    /// This candidate constructor or conversion fonction
-    /// is used implicitly but the explicit(bool) specifier
-    /// was resolved to true
-    ovl_fail_explicit_resolved,
+    /// This candidate constructor or conversion function is explicit but
+    /// the context doesn't permit explicit functions.
+    ovl_fail_explicit,
 
     /// This candidate was not viable because its address could not be taken.
     ovl_fail_addr_not_available,
index 94d524a..d89d37d 100644 (file)
@@ -3877,9 +3877,6 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
     if (!Info.Constructor || Info.Constructor->isInvalidDecl())
       continue;
 
-    if (!AllowExplicit && Info.Constructor->isExplicit())
-      continue;
-
     if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor))
       continue;
 
@@ -3951,18 +3948,16 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
         else
           Conv = cast<CXXConversionDecl>(D);
 
-        if (AllowExplicit || !Conv->isExplicit()) {
-          if (ConvTemplate)
-            S.AddTemplateConversionCandidate(
-                ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
-                CandidateSet, AllowExplicit, AllowExplicit,
-                /*AllowResultConversion*/ false);
-          else
-            S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
-                                     DestType, CandidateSet, AllowExplicit,
-                                     AllowExplicit,
-                                     /*AllowResultConversion*/ false);
-        }
+        if (ConvTemplate)
+          S.AddTemplateConversionCandidate(
+              ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+              CandidateSet, AllowExplicit, AllowExplicit,
+              /*AllowResultConversion*/ false);
+        else
+          S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+                                   DestType, CandidateSet, AllowExplicit,
+                                   AllowExplicit,
+                                   /*AllowResultConversion*/ false);
       }
     }
   }
@@ -4495,7 +4490,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
         continue;
 
       if (!Info.Constructor->isInvalidDecl() &&
-          Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
+          Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
         if (Info.ConstructorTmpl)
           S.AddTemplateOverloadCandidate(
               Info.ConstructorTmpl, Info.FoundDecl,
@@ -4540,8 +4535,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
       // FIXME: Do we need to make sure that we only consider conversion
       // candidates with reference-compatible results? That might be needed to
       // break recursion.
-      if ((AllowExplicitConvs || !Conv->isExplicit()) &&
-          (AllowRValues ||
+      if ((AllowRValues ||
            Conv->getConversionType()->isLValueReferenceType())) {
         if (ConvTemplate)
           S.AddTemplateConversionCandidate(
@@ -5153,7 +5147,7 @@ static void TryUserDefinedConversion(Sema &S,
           continue;
 
         if (!Info.Constructor->isInvalidDecl() &&
-            Info.Constructor->isConvertingConstructor(AllowExplicit)) {
+            Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
           if (Info.ConstructorTmpl)
             S.AddTemplateOverloadCandidate(
                 Info.ConstructorTmpl, Info.FoundDecl,
@@ -5197,16 +5191,14 @@ static void TryUserDefinedConversion(Sema &S,
         else
           Conv = cast<CXXConversionDecl>(D);
 
-        if (AllowExplicit || !Conv->isExplicit()) {
-          if (ConvTemplate)
-            S.AddTemplateConversionCandidate(
-                ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
-                CandidateSet, AllowExplicit, AllowExplicit);
-          else
-            S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
-                                     DestType, CandidateSet, AllowExplicit,
-                                     AllowExplicit);
-        }
+        if (ConvTemplate)
+          S.AddTemplateConversionCandidate(
+              ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+              CandidateSet, AllowExplicit, AllowExplicit);
+        else
+          S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+                                   DestType, CandidateSet, AllowExplicit,
+                                   AllowExplicit);
       }
     }
   }
@@ -9778,9 +9770,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
       // C++ [over.match.copy]p1: (non-list copy-initialization from class)
       //   The converting constructors of T are candidate functions.
       if (!AllowExplicit) {
-        // Only consider converting constructors.
-        if (GD->isExplicit())
-          continue;
+        // Overload resolution checks whether the deduction guide is declared
+        // explicit for us.
 
         // When looking for a converting constructor, deduction guides that
         // could never be called with one argument are not interesting to
index fa811ee..6960998 100644 (file)
@@ -3320,8 +3320,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
       continue;
 
     bool Usable = !Info.Constructor->isInvalidDecl() &&
-                  S.isInitListConstructor(Info.Constructor) &&
-                  (AllowExplicit || !Info.Constructor->isExplicit());
+                  S.isInitListConstructor(Info.Constructor);
     if (Usable) {
       // If the first argument is (a reference to) the target type,
       // suppress conversions.
@@ -3443,11 +3442,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
           continue;
 
         bool Usable = !Info.Constructor->isInvalidDecl();
-        if (ListInitializing)
-          Usable = Usable && (AllowExplicit || !Info.Constructor->isExplicit());
-        else
-          Usable = Usable &&
-                   Info.Constructor->isConvertingConstructor(AllowExplicit);
+        if (!ListInitializing)
+          Usable = Usable && Info.Constructor->isConvertingConstructor(
+                                 /*AllowExplicit*/ true);
         if (Usable) {
           bool SuppressUserConversions = !ConstructorsOnly;
           if (SuppressUserConversions && ListInitializing) {
@@ -3501,16 +3498,14 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
         else
           Conv = cast<CXXConversionDecl>(D);
 
-        if (AllowExplicit || !Conv->isExplicit()) {
-          if (ConvTemplate)
-            S.AddTemplateConversionCandidate(
-                ConvTemplate, FoundDecl, ActingContext, From, ToType,
-                CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
-          else
-            S.AddConversionCandidate(
-                Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
-                AllowObjCConversionOnExplicit, AllowExplicit);
-        }
+        if (ConvTemplate)
+          S.AddTemplateConversionCandidate(
+              ConvTemplate, FoundDecl, ActingContext, From, ToType,
+              CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
+        else
+          S.AddConversionCandidate(
+              Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
+              AllowObjCConversionOnExplicit, AllowExplicit);
       }
     }
   }
@@ -4543,11 +4538,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
     else
       Conv = cast<CXXConversionDecl>(D);
 
-    // If this is an explicit conversion, and we're not allowed to consider
-    // explicit conversions, skip it.
-    if (!AllowExplicit && Conv->isExplicit())
-      continue;
-
     if (AllowRvalues) {
       // If we are initializing an rvalue reference, don't permit conversion
       // functions that return lvalues.
@@ -6183,6 +6173,15 @@ void Sema::AddOverloadCandidate(
   Candidate.IgnoreObjectArgument = false;
   Candidate.ExplicitCallArguments = Args.size();
 
+  // Explicit functions are not actually candidates at all if we're not
+  // allowing them in this context, but keep them around so we can point
+  // to them in diagnostics.
+  if (!AllowExplicit && ExplicitSpecifier::getFromDecl(Function).isExplicit()) {
+    Candidate.Viable = false;
+    Candidate.FailureKind = ovl_fail_explicit;
+    return;
+  }
+
   if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
       !Function->getAttr<TargetAttr>()->isDefaultVersion()) {
     Candidate.Viable = false;
@@ -6316,15 +6315,6 @@ void Sema::AddOverloadCandidate(
     }
   }
 
-  if (!AllowExplicit) {
-    ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function);
-    if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) {
-      Candidate.Viable = false;
-      Candidate.FailureKind = ovl_fail_explicit_resolved;
-      return;
-    }
-  }
-
   if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_enable_if;
@@ -6923,6 +6913,12 @@ void Sema::AddMethodTemplateCandidate(
                      Conversions, PO);
 }
 
+/// Determine whether a given function template has a simple explicit specifier
+/// or a non-value-dependent explicit-specification that evaluates to true.
+static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) {
+  return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit();
+}
+
 /// Add a C++ function template specialization as a candidate
 /// in the candidate set, using template argument deduction to produce
 /// an appropriate function template specialization.
@@ -6935,6 +6931,18 @@ void Sema::AddTemplateOverloadCandidate(
   if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
     return;
 
+  // If the function template has a non-dependent explicit specification,
+  // exclude it now if appropriate; we are not permitted to perform deduction
+  // and substitution in this case.
+  if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
+    OverloadCandidate &Candidate = CandidateSet.addCandidate();
+    Candidate.FoundDecl = FoundDecl;
+    Candidate.Function = FunctionTemplate->getTemplatedDecl();
+    Candidate.Viable = false;
+    Candidate.FailureKind = ovl_fail_explicit;
+    return;
+  }
+
   // C++ [over.match.funcs]p7:
   //   In each case where a candidate is a function template, candidate
   //   function template specializations are generated using template argument
@@ -7122,6 +7130,9 @@ void Sema::AddConversionCandidate(
   // Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
   // operator is only a candidate if its return type is the target type or
   // can be converted to the target type with a qualification conversion.
+  //
+  // FIXME: Include such functions in the candidate list and explain why we
+  // can't select them.
   if (Conversion->isExplicit() &&
       !isAllowableExplicitConversion(*this, ConvType, ToType,
                                      AllowObjCConversionOnExplicit))
@@ -7143,6 +7154,15 @@ void Sema::AddConversionCandidate(
   Candidate.Viable = true;
   Candidate.ExplicitCallArguments = 1;
 
+  // Explicit functions are not actually candidates at all if we're not
+  // allowing them in this context, but keep them around so we can point
+  // to them in diagnostics.
+  if (!AllowExplicit && Conversion->isExplicit()) {
+    Candidate.Viable = false;
+    Candidate.FailureKind = ovl_fail_explicit;
+    return;
+  }
+
   // C++ [over.match.funcs]p4:
   //   For conversion functions, the function is considered to be a member of
   //   the class of the implicit implied object argument for the purpose of
@@ -7267,13 +7287,6 @@ void Sema::AddConversionCandidate(
            "Can only end up with a standard conversion sequence or failure");
   }
 
-  if (!AllowExplicit && Conversion->getExplicitSpecifier().getKind() !=
-                            ExplicitSpecKind::ResolvedFalse) {
-    Candidate.Viable = false;
-    Candidate.FailureKind = ovl_fail_explicit_resolved;
-    return;
-  }
-
   if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_enable_if;
@@ -7304,6 +7317,18 @@ void Sema::AddTemplateConversionCandidate(
   if (!CandidateSet.isNewCandidate(FunctionTemplate))
     return;
 
+  // If the function template has a non-dependent explicit specification,
+  // exclude it now if appropriate; we are not permitted to perform deduction
+  // and substitution in this case.
+  if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
+    OverloadCandidate &Candidate = CandidateSet.addCandidate();
+    Candidate.FoundDecl = FoundDecl;
+    Candidate.Function = FunctionTemplate->getTemplatedDecl();
+    Candidate.Viable = false;
+    Candidate.FailureKind = ovl_fail_explicit;
+    return;
+  }
+
   TemplateDeductionInfo Info(CandidateSet.getLocation());
   CXXConversionDecl *Specialization = nullptr;
   if (TemplateDeductionResult Result
@@ -10764,30 +10789,36 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
 }
 
 static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
-  ExplicitSpecifier ES;
-  const char *DeclName;
+  ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Cand->Function);
+  assert(ES.isExplicit() && "not an explicit candidate");
+
+  unsigned Kind;
   switch (Cand->Function->getDeclKind()) {
   case Decl::Kind::CXXConstructor:
-    ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier();
-    DeclName = "constructor";
+    Kind = 0;
     break;
   case Decl::Kind::CXXConversion:
-    ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier();
-    DeclName = "conversion operator";
+    Kind = 1;
     break;
   case Decl::Kind::CXXDeductionGuide:
-    ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier();
-    DeclName = "deductiong guide";
+    Kind = Cand->Function->isImplicit() ? 0 : 2;
     break;
   default:
     llvm_unreachable("invalid Decl");
   }
-  assert(ES.getExpr() && "null expression should be handled before");
-  S.Diag(Cand->Function->getLocation(),
-         diag::note_ovl_candidate_explicit_forbidden)
-      << DeclName;
-  S.Diag(ES.getExpr()->getBeginLoc(),
-         diag::note_explicit_bool_resolved_to_true);
+
+  // Note the location of the first (in-class) declaration; a redeclaration
+  // (particularly an out-of-class definition) will typically lack the
+  // 'explicit' specifier.
+  // FIXME: This is probably a good thing to do for all 'candidate' notes.
+  FunctionDecl *First = Cand->Function->getFirstDecl();
+  if (FunctionDecl *Pattern = First->getTemplateInstantiationPattern())
+    First = Pattern->getFirstDecl();
+
+  S.Diag(First->getLocation(),
+         diag::note_ovl_candidate_explicit)
+      << Kind << (ES.getExpr() ? 1 : 0)
+      << (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
 }
 
 static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
@@ -10888,7 +10919,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
   case ovl_fail_enable_if:
     return DiagnoseFailedEnableIfAttr(S, Cand);
 
-  case ovl_fail_explicit_resolved:
+  case ovl_fail_explicit:
     return DiagnoseFailedExplicitSpec(S, Cand);
 
   case ovl_fail_ext_disabled:
@@ -11053,6 +11084,23 @@ struct CompareOverloadCandidatesForDisplay {
       OverloadCandidateSet::CandidateSetKind CSK)
       : S(S), NumArgs(NArgs), CSK(CSK) {}
 
+  OverloadFailureKind EffectiveFailureKind(const OverloadCandidate *C) const {
+    // If there are too many or too few arguments, that's the high-order bit we
+    // want to sort by, even if the immediate failure kind was something else.
+    if (C->FailureKind == ovl_fail_too_many_arguments ||
+        C->FailureKind == ovl_fail_too_few_arguments)
+      return static_cast<OverloadFailureKind>(C->FailureKind);
+
+    if (C->Function) {
+      if (NumArgs > C->Function->getNumParams() && !C->Function->isVariadic())
+        return ovl_fail_too_many_arguments;
+      if (NumArgs < C->Function->getMinRequiredArguments())
+        return ovl_fail_too_few_arguments;
+    }
+
+    return static_cast<OverloadFailureKind>(C->FailureKind);
+  }
+
   bool operator()(const OverloadCandidate *L,
                   const OverloadCandidate *R) {
     // Fast-path this check.
@@ -11076,34 +11124,37 @@ struct CompareOverloadCandidatesForDisplay {
 
     // Criteria by which we can sort non-viable candidates:
     if (!L->Viable) {
+      OverloadFailureKind LFailureKind = EffectiveFailureKind(L);
+      OverloadFailureKind RFailureKind = EffectiveFailureKind(R);
+
       // 1. Arity mismatches come after other candidates.
-      if (L->FailureKind == ovl_fail_too_many_arguments ||
-          L->FailureKind == ovl_fail_too_few_arguments) {
-        if (R->FailureKind == ovl_fail_too_many_arguments ||
-            R->FailureKind == ovl_fail_too_few_arguments) {
+      if (LFailureKind == ovl_fail_too_many_arguments ||
+          LFailureKind == ovl_fail_too_few_arguments) {
+        if (RFailureKind == ovl_fail_too_many_arguments ||
+            RFailureKind == ovl_fail_too_few_arguments) {
           int LDist = std::abs((int)L->getNumParams() - (int)NumArgs);
           int RDist = std::abs((int)R->getNumParams() - (int)NumArgs);
           if (LDist == RDist) {
-            if (L->FailureKind == R->FailureKind)
+            if (LFailureKind == RFailureKind)
               // Sort non-surrogates before surrogates.
               return !L->IsSurrogate && R->IsSurrogate;
             // Sort candidates requiring fewer parameters than there were
             // arguments given after candidates requiring more parameters
             // than there were arguments given.
-            return L->FailureKind == ovl_fail_too_many_arguments;
+            return LFailureKind == ovl_fail_too_many_arguments;
           }
           return LDist < RDist;
         }
         return false;
       }
-      if (R->FailureKind == ovl_fail_too_many_arguments ||
-          R->FailureKind == ovl_fail_too_few_arguments)
+      if (RFailureKind == ovl_fail_too_many_arguments ||
+          RFailureKind == 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)
+      if (LFailureKind == ovl_fail_bad_conversion) {
+        if (RFailureKind != ovl_fail_bad_conversion)
           return true;
 
         // The conversion that can be fixed with a smaller number of changes,
@@ -11141,17 +11192,17 @@ struct CompareOverloadCandidatesForDisplay {
         if (leftBetter > 0) return true;
         if (leftBetter < 0) return false;
 
-      } else if (R->FailureKind == ovl_fail_bad_conversion)
+      } else if (RFailureKind == ovl_fail_bad_conversion)
         return false;
 
-      if (L->FailureKind == ovl_fail_bad_deduction) {
-        if (R->FailureKind != ovl_fail_bad_deduction)
+      if (LFailureKind == ovl_fail_bad_deduction) {
+        if (RFailureKind != ovl_fail_bad_deduction)
           return true;
 
         if (L->DeductionFailure.Result != R->DeductionFailure.Result)
           return RankDeductionFailure(L->DeductionFailure)
                < RankDeductionFailure(R->DeductionFailure);
-      } else if (R->FailureKind == ovl_fail_bad_deduction)
+      } else if (RFailureKind == ovl_fail_bad_deduction)
         return false;
 
       // TODO: others?
@@ -11180,7 +11231,8 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
   assert(!Cand->Viable);
 
   // Don't do anything on failures other than bad conversion.
-  if (Cand->FailureKind != ovl_fail_bad_conversion) return;
+  if (Cand->FailureKind != ovl_fail_bad_conversion)
+    return;
 
   // We only want the FixIts if all the arguments can be corrected.
   bool Unfixable = false;
index ed6c6c0..f4e8521 100644 (file)
@@ -38,7 +38,7 @@ namespace Numbers {
   // expected-note@-2 2 {{candidate constructor (the implicit move constructor) not viable}}
 #endif
 
-    explicit Number(double d) : d(d) {}
+    explicit Number(double d) : d(d) {} // expected-note 2{{explicit constructor is not a candidate}}
     double d;
   };
   Number zero(0.0f);
index 869fc4f..3e8f18c 100644 (file)
@@ -65,7 +65,7 @@ namespace test3 {
 namespace explicit_ctor {
   struct A {};
   struct B { // expected-note 2{{candidate}}
-    explicit B(const A&);
+    explicit B(const A&); // expected-note {{explicit constructor is not a candidate}}
   };
   A a;
   const B &b(a); // expected-error {{no viable conversion}}
index 419f2bf..e7f5013 100644 (file)
@@ -5,7 +5,7 @@ struct NoDefault {
   NoDefault(int);
 };
 struct Explicit { // expected-note 2 {{candidate}} expected-note {{here}}
-  explicit Explicit(int);
+  explicit Explicit(int); // expected-note {{not a candidate}}
 };
 struct NoCopy {
   NoCopy();
index 80a27e7..55d838e 100644 (file)
@@ -142,7 +142,7 @@ struct Z0 { // expected-note 0+ {{candidate}}
 };
 struct Z { // expected-note 0+ {{candidate}}
   explicit Z(); // expected-note 0+ {{here}}
-  explicit Z(int);
+  explicit Z(int); // expected-note {{not a candidate}}
   explicit Z(int, int); // expected-note 0+ {{here}}
 };
 template <class T> int Eat(T); // expected-note 0+ {{candidate}}
index 26ab67d..1e78c03 100644 (file)
@@ -600,7 +600,7 @@ namespace dr151 { // dr151: yes
 namespace dr152 { // dr152: yes
   struct A {
     A(); // expected-note 0-2{{not viable}}
-    explicit A(const A&);
+    explicit A(const A&); // expected-note 1-2{{not a candidate}}
   };
   A a1 = A();
 #if __cplusplus <= 201402L
index 63e51a7..7fd94b6 100644 (file)
@@ -27,7 +27,7 @@ void hiding() {
 
 struct ExplicitCopy {
   ExplicitCopy(); // expected-note 2{{not viable}}
-  explicit ExplicitCopy(const ExplicitCopy&);
+  explicit ExplicitCopy(const ExplicitCopy&); // expected-note 2{{not a candidate}}
 };
 auto init_kind_1 = [ec(ExplicitCopy())] {};
 auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching constructor}}
index 31a679f..c63f309 100644 (file)
@@ -4,7 +4,7 @@ namespace ExplicitConv {
   struct X { }; // expected-note 2{{candidate constructor}}
 
   struct Y {
-    explicit operator X() const;
+    explicit operator X() const; // expected-note {{not a candidate}}
   };
 
   void test(const Y& y) {
@@ -18,8 +18,8 @@ namespace DR899 {
   struct C { }; // expected-note 2 {{candidate constructor}}
 
   struct A {
-    explicit operator int() const;
-    explicit operator C() const;
+    explicit operator int() const; // expected-note {{not a candidate}}
+    explicit operator C() const; // expected-note {{not a candidate}}
   };
 
   struct B {
index 19f15eb..9d50e0c 100644 (file)
@@ -15,7 +15,7 @@ D1 d1a(1), d1b(1, 1);
 D1 fd1() { return 1; }
 
 struct B2 {
-  explicit B2(int, int = 0, int = 0);
+  explicit B2(int, int = 0, int = 0); // expected-note {{not a candidate}}
 };
 struct D2 : B2 { // expected-note 2{{candidate constructor}}
   using B2::B2;
index a800cfc..9c7b056 100644 (file)
@@ -40,7 +40,9 @@ struct A {
 #else
 //expected-note@-6+ {{candidate constructor}}
 //expected-note@-9+ {{candidate constructor}}
-//expected-note@-6+ {{candidate function}}
+//expected-note-re@-7+ {{explicit constructor is not a candidate{{$}}}}
+//expected-note@-7+ {{candidate function}}
+//expected-note@-7+ {{explicit conversion function is not a candidate (explicit specifier evaluates to true)}}
 
 //CHECK: explicit{{ +}}A(
 //CHECK-NEXT: explicit(false){{ +}}operator
@@ -73,12 +75,10 @@ B<true> b_true;
 B<false> b_false;
 #else
 //expected-note@-8 {{candidate template ignored}}
-//expected-note@-8+ {{explicit constructor}}
+//expected-note@-8 {{explicit constructor declared here}}
 //expected-note@-15+ {{candidate constructor}}
-//expected-note@-8+ {{candidate conversion operator ignored}}
-//expected-note@-9+ {{explicit(bool) specifier resolved to true}}
-//expected-note@-12 {{explicit(bool) specifier resolved to true}}
-//expected-note@-13+ {{candidate deductiong guide ignored}}
+//expected-note@-8+ {{explicit conversion function is not a candidate (explicit specifier}}
+//expected-note@-11 {{explicit constructor is not a candidate (explicit specifier}}
 
 //CHECK: explicit(b){{ +}}A
 //CHECK: explicit(b{{ +}}^{{ +}}T::value){{ +}}operator
index 1d3593d..1486abe 100644 (file)
@@ -211,7 +211,7 @@ namespace smart_ptr {
   // expected-note@-2 {{candidate constructor (the implicit move constructor) not}}
 #endif
 
-    explicit X(Y);
+    explicit X(Y); // expected-note {{not a candidate}}
   };
 
   Y make_Y();
index 117b508..94d9941 100644 (file)
@@ -11,7 +11,7 @@ struct ConvToInt {
 };
 
 struct ExplicitConvToBool {
-  explicit operator bool();
+  explicit operator bool(); // expected-note {{explicit}}
 #if __cplusplus <= 199711L // C++03 or earlier modes
   // expected-warning@-2{{explicit conversion functions are a C++11 extension}}
 #endif
@@ -45,7 +45,7 @@ void test_conv_to_bool(ConvToBool ctb, ConvToInt cti, ExplicitConvToBool ecb) {
 void accepts_bool(bool) { } // expected-note{{candidate function}}
 
 struct ExplicitConvToRef {
-  explicit operator int&();
+  explicit operator int&(); // expected-note {{explicit}}
 #if (__cplusplus <= 199711L) // C++03 or earlier modes
   // expected-warning@-2{{explicit conversion functions are a C++11 extension}}
 #endif
@@ -58,14 +58,14 @@ void test_explicit_bool(ExplicitConvToBool ecb) {
 }
 
 void test_explicit_conv_to_ref(ExplicitConvToRef ecr) {
-  int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'ExplicitConvToRef'}}
+  int& i1 = ecr; // expected-error{{no viable conversion from 'ExplicitConvToRef' to 'int'}}
   int& i2(ecr); // okay
 }
 
 struct A { };
 struct B { };
 struct C {
-  explicit operator A&(); 
+  explicit operator A&();  // expected-note {{explicit}}
 #if __cplusplus <= 199711L // C++03 or earlier modes
 // expected-warning@-2{{explicit conversion functions are a C++11 extension}}
 #endif
index 75002fa..d66e09e 100644 (file)
@@ -36,7 +36,7 @@ class FromShortExplicitly { // expected-note{{candidate constructor (the implici
 #endif
 
 public:
-  explicit FromShortExplicitly(short s);
+  explicit FromShortExplicitly(short s); // expected-note {{explicit constructor is not a candidate}}
 };
 
 void explicit_constructor(short s) {
index 8866fe7..29c91ba 100644 (file)
@@ -4,9 +4,9 @@
 
 class X {
 public:
-  explicit X(const X&);
+  explicit X(const X&); // expected-note 2{{not a candidate}}
   X(int*); // expected-note 3{{candidate constructor}}
-  explicit X(float*); // expected-note {{candidate constructor}}
+  explicit X(float*); // expected-note {{candidate constructor}} expected-note 2{{not a candidate}}
 };
 
 class Y : public X { };
index 56fa76f..df776b3 100644 (file)
@@ -55,8 +55,8 @@ template<int a>
   // expected-note@-1 {{candidate constructor}} expected-note@-1 {{candidate constructor}}
   // expected-note@-2 {{candidate constructor}} expected-note@-2 {{candidate constructor}}
   explicit(a == 0)
-C(int),
-C(double);
+C(int), // expected-note 2{{not a candidate}}
+C(double); // expected-note 2{{not a candidate}}
 };
 
 C<0> c0 = 0.0; // expected-error {{no viable conversion}}
@@ -105,7 +105,7 @@ template<bool b>
   struct A {
     // expected-note@-1+ {{candidate constructor}}
     // expected-note@-2+ {{candidate function}}
-    explicit(b) A(int, int = 0);
+    explicit(b) A(int, int = 0); // expected-note {{not a candidate}}
   // expected-note@-1+ {{explicit constructor declared here}}
 };
 
@@ -154,10 +154,9 @@ struct A {
   // expected-note@-2 {{candidate constructor}} expected-note@-2 {{candidate constructor}}
   template<typename T2>
   explicit(a ^ is_same<T1, T2>::value)
-  // expected-note@-1+ {{explicit(bool) specifier resolved to true}}
   A(T2) {}
   // expected-note@-1+ {{explicit constructor declared here}}
-  // expected-note@-2+ {{candidate constructor ignored}}
+  // expected-note@-2+ {{not a candidate}}
 };
 
 A<true, int> a0 = 0.0; // expected-error {{no viable conversion}}
@@ -196,17 +195,15 @@ struct A {
   // expected-note@-1+ {{candidate constructor}}
   template<typename T>
   explicit(enable_ifv<is_same<int, T>::value, a>::value)
-  //expected-note@-1 {{explicit(bool) specifier resolved to true}}
   A(T) {}
   // expected-note@-1+ {{substitution failure}}
-  // expected-note@-2 {{candidate constructor ignored}}
+  // expected-note@-2 {{not a candidate}}
   // expected-note@-3 {{explicit constructor declared here}}
   template<typename T, bool c = true>
   explicit(enable_ifv<is_same<bool, T>::value, a>::value)
-  //expected-note@-1 {{explicit(bool) specifier resolved to true}}
   A(T) {}
   // expected-note@-1+ {{substitution failure}}
-  // expected-note@-2 {{candidate constructor ignored}}
+  // expected-note@-2 {{not a candidate}}
   // expected-note@-3 {{explicit constructor declared here}}
 };
 
@@ -236,7 +233,7 @@ namespace conversion {
 
 template<bool a>
 struct A {
-  explicit(a) operator int ();
+  explicit(a) operator int (); // expected-note+ {{not a candidate}}
 };
 
 template<bool a>
@@ -293,10 +290,9 @@ template<bool a>
 struct A {
   template<typename T2>
   explicit(enable_ifv<is_same<B, T2>::value, a>::value)
-  // expected-note@-1+ {{explicit(bool) specifier resolved to true}}
   operator T2() { return T2(); };
   // expected-note@-1+ {{substitution failure}}
-  // expected-note@-2+ {{candidate conversion}}
+  // expected-note@-2+ {{not a candidate}}
 };
 
 A<false> A_false;
@@ -348,9 +344,8 @@ struct A {
   // expected-note@-2+ {{candidate function}}
   template<typename ... Ts>
   explicit((is_same<T, Ts>::value && ...))
-  // expected-note@-1 {{explicit(bool) specifier resolved to true}}
   A(Ts...);
-  // expected-note@-1 {{candidate constructor}}
+  // expected-note@-1 {{not a candidate}}
   // expected-note@-2 {{explicit constructor}}
 };
 
@@ -517,8 +512,8 @@ class Y { }; // expected-note+ {{candidate constructor (the implicit}}
 template<bool b>
 struct Z {
   explicit(b) operator X() const;
-  explicit(b) operator Y() const;
-  explicit(b) operator int() const;
+  explicit(b) operator Y() const; // expected-note 2{{not a candidate}}
+  explicit(b) operator int() const; // expected-note {{not a candidate}}
 };
 
 void testExplicit()
@@ -559,9 +554,7 @@ template<typename T1>
 struct C {
   template<typename T>
   explicit(!is_same<T1, T>::value)
-  // expected-note@-1+ {{explicit(bool) specifier resolved to true}}
-  operator T();
-  // expected-note@-1+ {{candidate conversion operator ignored}}
+  operator T(); // expected-note+ {{explicit conversion function is not a candidate}}
 };
 
 using Bool = C<bool>;
@@ -684,10 +677,9 @@ template<typename T1 = int, typename T2 = int>
 struct A {
   // expected-note@-1+ {{candidate template ignored}}
   explicit(!is_same<T1, T2>::value)
-  // expected-note@-1+ {{explicit(bool) specifier resolved to true}}
   A(T1 = 0, T2 = 0) {}
-  // expected-note@-1 {{explicit constructor}}
-  // expected-note@-2+ {{candidate deductiong guide ignored}}
+  // expected-note@-1 {{explicit constructor declared here}}
+  // expected-note@-2 2{{explicit constructor is not a candidate}}
 };
 
 A a0 = 0;
@@ -723,15 +715,14 @@ using size_t = decltype(sizeof(0));
 
 struct Str {// expected-note+ {{candidate constructor}}
   template <size_t N>
-  explicit(N > 7)// expected-note {{resolved to true}}
-  Str(char const (&str)[N]);
+  explicit(N > 7)
+  Str(char const (&str)[N]); // expected-note {{explicit constructor is not a candidate}}
 };
 
 template <size_t N>
 Str::Str(char const(&str)[N]) { }
-// expected-note@-1 {{candidate constructor}}
 
 Str a = "short";
 Str b = "not so short";// expected-error {{no viable conversion}}
 
-}
\ No newline at end of file
+}
index 3bc6f83..457cada 100644 (file)
@@ -31,7 +31,7 @@ struct Y { // expected-note 2{{candidate constructor (the implicit copy construc
 // expected-note@-2 2 {{candidate constructor (the implicit move constructor) not viable}}
 #endif
 
-  explicit Y(int);
+  explicit Y(int); // expected-note 2{{explicit constructor is not a candidate}}
 };
 
 void k(Y y = 17); // expected-error{{no viable conversion}} \
index 58760d3..ba2c36d 100644 (file)
@@ -7,7 +7,7 @@ struct A {
 };
 
 struct B { // expected-note+ {{candidate}}
-  explicit B(int);
+  explicit B(int); // expected-note {{not a candidate}}
 };
 
 B::B(int) { } // expected-note+ {{here}}
@@ -78,8 +78,8 @@ namespace Conversion {
 
     struct Z {
       explicit operator X() const;
-      explicit operator Y() const;
-      explicit operator int() const;
+      explicit operator Y() const; // expected-note 2{{not a candidate}}
+      explicit operator int() const; // expected-note {{not a candidate}}
     };
     
     Z z;
@@ -118,7 +118,7 @@ namespace Conversion {
     };
 
     struct NotBool {
-      explicit operator bool(); // expected-note {{conversion to integral type 'bool'}}
+      explicit operator bool(); // expected-note {{conversion to integral type 'bool'}} expected-note 4{{explicit conversion function is not a candidate}}
     };
     Bool    b;
     NotBool n;