r256657 - Improve diagnostic for the case where a function template candidate is rejected

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 30 18:02:56 PST 2015


Author: rsmith
Date: Wed Dec 30 20:02:54 2015
New Revision: 256657

URL: http://llvm.org/viewvc/llvm-project?rev=256657&view=rev
Log:
Improve diagnostic for the case where a function template candidate is rejected
by overload resolution because deduction succeeds, but the substituted
parameter type for some parameter (with deduced type) doesn't exactly match the
corresponding adjusted argument type.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Sema/TemplateDeduction.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/CXX/drs/dr5xx.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=256657&r1=256656&r2=256657&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Dec 30 20:02:54 2015
@@ -3112,6 +3112,10 @@ def note_addrof_ovl_candidate_disabled_b
 def note_ovl_candidate_failed_overload_resolution : Note<
     "candidate template ignored: couldn't resolve reference to overloaded "
     "function %0">;
+def note_ovl_candidate_deduced_mismatch : Note<
+    "candidate template ignored: deduced type "
+    "%diff{$ of %ordinal0 parameter does not match adjusted type $ of argument"
+    "|of %ordinal0 parameter does not match adjusted type of argument}1,2%3">;
 def note_ovl_candidate_non_deduced_mismatch : Note<
     "candidate template ignored: could not match %diff{$ against $|types}0,1">;
 // This note is needed because the above note would sometimes print two

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=256657&r1=256656&r2=256657&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Dec 30 20:02:54 2015
@@ -6302,6 +6302,9 @@ public:
     /// \brief Substitution of the deduced template argument values
     /// resulted in an error.
     TDK_SubstitutionFailure,
+    /// \brief After substituting deduced template arguments, a dependent
+    /// parameter type did not match the corresponding argument.
+    TDK_DeducedMismatch,
     /// \brief A non-depnedent component of the parameter did not match the
     /// corresponding component of the argument.
     TDK_NonDeducedMismatch,

Modified: cfe/trunk/include/clang/Sema/TemplateDeduction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/TemplateDeduction.h?rev=256657&r1=256656&r2=256657&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/TemplateDeduction.h (original)
+++ cfe/trunk/include/clang/Sema/TemplateDeduction.h Wed Dec 30 20:02:54 2015
@@ -140,6 +140,9 @@ public:
   ///   TDK_SubstitutionFailure: this argument is the template
   ///   argument we were instantiating when we encountered an error.
   ///
+  ///   TDK_DeducedMismatch: this is the parameter type, after substituting
+  ///   deduced arguments.
+  ///
   ///   TDK_NonDeducedMismatch: this is the component of the 'parameter'
   ///   of the deduction, directly provided in the source code.
   TemplateArgument FirstArg;
@@ -147,18 +150,32 @@ public:
   /// \brief The second template argument to which the template
   /// argument deduction failure refers.
   ///
+  ///   TDK_Inconsistent: this argument is the second value deduced
+  ///   for the corresponding template parameter.
+  ///
+  ///   TDK_DeducedMismatch: this is the (adjusted) call argument type.
+  ///
   ///   TDK_NonDeducedMismatch: this is the mismatching component of the
   ///   'argument' of the deduction, from which we are deducing arguments.
   ///
   /// FIXME: Finish documenting this.
   TemplateArgument SecondArg;
 
-  /// \brief The expression which caused a deduction failure.
-  ///
-  ///   TDK_FailedOverloadResolution: this argument is the reference to
-  ///   an overloaded function which could not be resolved to a specific
-  ///   function.
-  Expr *Expression;
+  union {
+    /// \brief The expression which caused a deduction failure.
+    ///
+    ///   TDK_FailedOverloadResolution: this argument is the reference to
+    ///   an overloaded function which could not be resolved to a specific
+    ///   function.
+    Expr *Expression;
+
+    /// \brief The index of the function argument that caused a deduction
+    /// failure.
+    ///
+    ///   TDK_DeducedMismatch: this is the index of the argument that had a
+    ///   different argument type from its substituted parameter type.
+    unsigned CallArgIndex;
+  };
 
   /// \brief Information on packs that we're currently expanding.
   ///
@@ -211,6 +228,10 @@ struct DeductionFailureInfo {
   /// if any.
   Expr *getExpr();
 
+  /// \brief Return the index of the call argument that this deduction
+  /// failure refers to, if any.
+  llvm::Optional<unsigned> getCallArgIndex();
+
   /// \brief Free any memory associated with this deduction failure.
   void Destroy();
 };

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=256657&r1=256656&r2=256657&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Dec 30 20:02:54 2015
@@ -543,6 +543,12 @@ namespace {
   struct DFIParamWithArguments : DFIArguments {
     TemplateParameter Param;
   };
+  // Structure used by DeductionFailureInfo to store template argument
+  // information and the index of the problematic call argument.
+  struct DFIDeducedMismatchArgs : DFIArguments {
+    TemplateArgumentList *TemplateArgs;
+    unsigned CallArgIndex;
+  };
 }
 
 /// \brief Convert from Sema's representation of template deduction information
@@ -554,13 +560,14 @@ clang::MakeDeductionFailureInfo(ASTConte
   DeductionFailureInfo Result;
   Result.Result = static_cast<unsigned>(TDK);
   Result.HasDiagnostic = false;
-  Result.Data = nullptr;
   switch (TDK) {
   case Sema::TDK_Success:
   case Sema::TDK_Invalid:
   case Sema::TDK_InstantiationDepth:
   case Sema::TDK_TooManyArguments:
   case Sema::TDK_TooFewArguments:
+  case Sema::TDK_MiscellaneousDeductionFailure:
+    Result.Data = nullptr;
     break;
 
   case Sema::TDK_Incomplete:
@@ -568,6 +575,17 @@ clang::MakeDeductionFailureInfo(ASTConte
     Result.Data = Info.Param.getOpaqueValue();
     break;
 
+  case Sema::TDK_DeducedMismatch: {
+    // FIXME: Should allocate from normal heap so that we can free this later.
+    auto *Saved = new (Context) DFIDeducedMismatchArgs;
+    Saved->FirstArg = Info.FirstArg;
+    Saved->SecondArg = Info.SecondArg;
+    Saved->TemplateArgs = Info.take();
+    Saved->CallArgIndex = Info.CallArgIndex;
+    Result.Data = Saved;
+    break;
+  }
+
   case Sema::TDK_NonDeducedMismatch: {
     // FIXME: Should allocate from normal heap so that we can free this later.
     DFIArguments *Saved = new (Context) DFIArguments;
@@ -601,9 +619,6 @@ clang::MakeDeductionFailureInfo(ASTConte
   case Sema::TDK_FailedOverloadResolution:
     Result.Data = Info.Expression;
     break;
-
-  case Sema::TDK_MiscellaneousDeductionFailure:
-    break;
   }
 
   return Result;
@@ -623,6 +638,7 @@ void DeductionFailureInfo::Destroy() {
 
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
+  case Sema::TDK_DeducedMismatch:
   case Sema::TDK_NonDeducedMismatch:
     // FIXME: Destroy the data?
     Data = nullptr;
@@ -657,6 +673,7 @@ TemplateParameter DeductionFailureInfo::
   case Sema::TDK_TooManyArguments:
   case Sema::TDK_TooFewArguments:
   case Sema::TDK_SubstitutionFailure:
+  case Sema::TDK_DeducedMismatch:
   case Sema::TDK_NonDeducedMismatch:
   case Sema::TDK_FailedOverloadResolution:
     return TemplateParameter();
@@ -692,6 +709,9 @@ TemplateArgumentList *DeductionFailureIn
   case Sema::TDK_FailedOverloadResolution:
     return nullptr;
 
+  case Sema::TDK_DeducedMismatch:
+    return static_cast<DFIDeducedMismatchArgs*>(Data)->TemplateArgs;
+
   case Sema::TDK_SubstitutionFailure:
     return static_cast<TemplateArgumentList*>(Data);
 
@@ -718,6 +738,7 @@ const TemplateArgument *DeductionFailure
 
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
+  case Sema::TDK_DeducedMismatch:
   case Sema::TDK_NonDeducedMismatch:
     return &static_cast<DFIArguments*>(Data)->FirstArg;
 
@@ -744,6 +765,7 @@ const TemplateArgument *DeductionFailure
 
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
+  case Sema::TDK_DeducedMismatch:
   case Sema::TDK_NonDeducedMismatch:
     return &static_cast<DFIArguments*>(Data)->SecondArg;
 
@@ -763,6 +785,14 @@ Expr *DeductionFailureInfo::getExpr() {
   return nullptr;
 }
 
+llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
+  if (static_cast<Sema::TemplateDeductionResult>(Result) ==
+        Sema::TDK_DeducedMismatch)
+    return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex;
+
+  return llvm::None;
+}
+
 void OverloadCandidateSet::destroyCandidates() {
   for (iterator i = begin(), e = end(); i != e; ++i) {
     for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
@@ -9397,6 +9427,23 @@ static void DiagnoseBadDeduction(Sema &S
     return;
   }
 
+  case Sema::TDK_DeducedMismatch: {
+    // Format the template argument list into the argument string.
+    SmallString<128> TemplateArgString;
+    if (TemplateArgumentList *Args =
+            DeductionFailure.getTemplateArgumentList()) {
+      TemplateArgString = " ";
+      TemplateArgString += S.getTemplateArgumentBindingsText(
+          getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+    }
+
+    S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch)
+        << (*DeductionFailure.getCallArgIndex() + 1)
+        << *DeductionFailure.getFirstArg() << *DeductionFailure.getSecondArg()
+        << TemplateArgString;
+    break;
+  }
+
   case Sema::TDK_NonDeducedMismatch: {
     // FIXME: Provide a source location to indicate what we couldn't match.
     TemplateArgument FirstTA = *DeductionFailure.getFirstArg();
@@ -9686,6 +9733,7 @@ static unsigned RankDeductionFailure(con
     return 2;
 
   case Sema::TDK_SubstitutionFailure:
+  case Sema::TDK_DeducedMismatch:
   case Sema::TDK_NonDeducedMismatch:
   case Sema::TDK_MiscellaneousDeductionFailure:
     return 3;

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=256657&r1=256656&r2=256657&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Dec 30 20:02:54 2015
@@ -2954,8 +2954,12 @@ Sema::FinishTemplateArgumentDeduction(Fu
         continue;
       
       QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
-      if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA))
-        return Sema::TDK_SubstitutionFailure;
+      if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
+        Info.FirstArg = TemplateArgument(DeducedA);
+        Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
+        Info.CallArgIndex = OriginalArg.ArgIdx;
+        return TDK_DeducedMismatch;
+      }
     }
   }
   

Modified: cfe/trunk/test/CXX/drs/dr5xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr5xx.cpp?rev=256657&r1=256656&r2=256657&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr5xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr5xx.cpp Wed Dec 30 20:02:54 2015
@@ -148,8 +148,7 @@ namespace dr522 { // dr522: yes
   template<typename T> void b2(volatile T * const *);
   template<typename T> void b2(volatile T * const S::*);
   template<typename T> void b2(volatile T * const S::* const *);
-  // FIXME: This diagnostic isn't very good. The problem is not substitution failure.
-  template<typename T> void b2a(volatile T *S::* const *); // expected-note {{substitution failure}}
+  template<typename T> void b2a(volatile T *S::* const *); // expected-note {{candidate template ignored: deduced type 'volatile int *dr522::S::*const *' of 1st parameter does not match adjusted type 'int *dr522::S::**' of argument}}
 
   template<typename T> struct Base {};
   struct Derived : Base<int> {};

Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp?rev=256657&r1=256656&r2=256657&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp Wed Dec 30 20:02:54 2015
@@ -139,7 +139,7 @@ namespace N {
 }
 
 namespace PR9233 {
-  template<typename T> void f(const T **q); // expected-note{{candidate template ignored: substitution failure [with T = int]}}
+  template<typename T> void f(const T **q); // expected-note{{candidate template ignored: deduced type 'const int **' of 1st parameter does not match adjusted type 'int **' of argument [with T = int]}}
 
   void g(int **p) {
     f(p); // expected-error{{no matching function for call to 'f'}}

Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp?rev=256657&r1=256656&r2=256657&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp Wed Dec 30 20:02:54 2015
@@ -55,7 +55,7 @@ namespace DeduceNonTypeTemplateArgsInArr
 }
 
 namespace DeduceWithDefaultArgs {
-  template<template<typename...> class Container> void f(Container<int>); // expected-note {{substitution failure [with Container = X]}}
+  template<template<typename...> class Container> void f(Container<int>); // expected-note {{deduced type 'X<[...], (default) int>' of 1st parameter does not match adjusted type 'X<[...], double>' of argument [with Container = X]}}
   template<typename, typename = int> struct X {};
   void g() {
     // OK, use default argument for the second template parameter.




More information about the cfe-commits mailing list