]> granicus.if.org Git - clang/commitdiff
Improve diagnostic for the case where a function template candidate is rejected
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 31 Dec 2015 02:02:54 +0000 (02:02 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 31 Dec 2015 02:02:54 +0000 (02:02 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@256657 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 25fbe2db1ca8ee8dce97ef2ab7d3c7e2eea51d4d..a8e468d956c30759cd373177805dce0c2f681117 100644 (file)
@@ -3112,6 +3112,10 @@ def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note<
 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
index 7873843ab3bd8da1851056dde47cdca47e712fe1..bce2f0c0bad09bef0b2f8c0ecb9248db9680ee3b 100644 (file)
@@ -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,
index 9315ddd89c6beffd309e56f41bd9acb5b27f34d9..c22c703ef73223b0fd0014819b22ba523bd01fdd 100644 (file)
@@ -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();
 };
index 1caa94c9a45883e120ffc12fc8ddf3ef0f3e9daf..e0c10e4479e2550700557eecc7e4664241ed8c60 100644 (file)
@@ -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(ASTContext &Context,
   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(ASTContext &Context,
     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(ASTContext &Context,
   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::getTemplateParameter() {
   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 *DeductionFailureInfo::getTemplateArgumentList() {
   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 *DeductionFailureInfo::getFirstArg() {
 
   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 *DeductionFailureInfo::getSecondArg() {
 
   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, Decl *Templated,
     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(const DeductionFailureInfo &DFI) {
     return 2;
 
   case Sema::TDK_SubstitutionFailure:
+  case Sema::TDK_DeducedMismatch:
   case Sema::TDK_NonDeducedMismatch:
   case Sema::TDK_MiscellaneousDeductionFailure:
     return 3;
index 837e0de4038daa079fb730d33879d93408d8306d..cd54920b08cf91595f70f78f8406c0e090fa4f6f 100644 (file)
@@ -2954,8 +2954,12 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
         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;
+      }
     }
   }
   
index 17b525d96228efe73df964b9fdadbe86fd8ceefc..96d3494bf060f61617b5d70a87dc1d14e355c86f 100644 (file)
@@ -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> {};
index 295f080a75d92e1a5b704de52b9db7c8d3bdbd70..f46ea2e585dc1e72d7fe3d6aecf573944670e6fc 100644 (file)
@@ -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'}}
index 782057d397b931a08175a4f817d4eac8266932f4..b807a0ff9f1127c2dfbbc3d4b3782c5d6a9e345f 100644 (file)
@@ -55,7 +55,7 @@ namespace DeduceNonTypeTemplateArgsInArray {
 }
 
 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.