]> granicus.if.org Git - clang/commitdiff
When printing a non-viable overload candidate that failed due to
authorDouglas Gregor <dgregor@apple.com>
Sat, 8 May 2010 17:41:32 +0000 (17:41 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 8 May 2010 17:41:32 +0000 (17:41 +0000)
conflicting deduced template argument values, give a more specific
reason along with those values, e.g.,

test/SemaTemplate/overload-candidates.cpp:4:10: note: candidate template
      ignored: deduced conflicting types for parameter 'T' ('int' vs. 'long')
const T& min(const T&, const T&);
         ^

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

include/clang/AST/TemplateBase.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/TemplateBase.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaOverload.h
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
test/SemaTemplate/overload-candidates.cpp [new file with mode: 0644]

index 50a100c6af1318d49b0c80c82048680b11fef97a..8b38001bd104cced1599d29e0e7faef84b6e8c77 100644 (file)
@@ -28,6 +28,7 @@ namespace llvm {
 namespace clang {
 
 class Decl;
+class DiagnosticBuilder;
 class Expr;
 class TypeSourceInfo;
 
@@ -473,6 +474,9 @@ public:
   }
 };
 
-}
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+                                    const TemplateArgument &Arg);
+  
+} // end namespace clang
 
 #endif
index 89f892cec13609ba4d6372f8b24b5329c65c86c0..93364845ecd79fe7882028e0fe67a79318fcc2d0 100644 (file)
@@ -1060,7 +1060,10 @@ def note_ovl_candidate_bad_deduction : Note<
     "candidate template ignored: failed template argument deduction">;
 def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
     "couldn't infer template argument %0">;
-
+def note_ovl_candidate_inconsistent_deduction : Note<
+    "candidate template ignored: deduced conflicting %select{types|values|"
+    "templates}0 for parameter %1 (%2 vs. %3)">;
+    
 // Note that we don't treat templates differently for this diagnostic.
 def note_ovl_candidate_arity : Note<"candidate "
     "%select{function|function|constructor|function|function|constructor|"
index e9b17256415febc19e398cb98a6135c5d566db66..0bf9f2fb7c333edd5fc5740b2a661781f88675b8 100644 (file)
@@ -18,6 +18,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/Basic/Diagnostic.h"
 
 using namespace clang;
 
@@ -119,3 +120,42 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
   // Silence bonus gcc warning.
   return SourceRange();
 }
+
+const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
+                                           const TemplateArgument &Arg) {
+  switch (Arg.getKind()) {
+  case TemplateArgument::Null:
+    return DB;
+      
+  case TemplateArgument::Type:
+    return DB << Arg.getAsType();
+      
+  case TemplateArgument::Declaration:
+    return DB << Arg.getAsDecl();
+      
+  case TemplateArgument::Integral:
+    return DB << Arg.getAsIntegral()->toString(10);
+      
+  case TemplateArgument::Template:
+    return DB << Arg.getAsTemplate();
+      
+  case TemplateArgument::Expression: {
+    // This shouldn't actually ever happen, so it's okay that we're
+    // regurgitating an expression here.
+    // FIXME: We're guessing at LangOptions!
+    llvm::SmallString<32> Str;
+    llvm::raw_svector_ostream OS(Str);
+    LangOptions LangOpts;
+    LangOpts.CPlusPlus = true;
+    PrintingPolicy Policy(LangOpts);
+    Arg.getAsExpr()->printPretty(OS, 0, Policy);
+    return DB << OS.str();
+  }
+      
+  case TemplateArgument::Pack:
+    // FIXME: Format arguments in a list!
+    return DB << "<parameter pack>";
+  }
+  
+  return DB;
+}
index dec9854c72ebef73e862187b14f0ff6af577b3eb..c08095fae4e1a20677cb9a99f654d651b8d0851d 100644 (file)
@@ -275,7 +275,166 @@ AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
   new (&conversions()) ConversionSet(O.conversions());
 }
 
+namespace {
+  // Structure used by OverloadCandidate::DeductionFailureInfo to store
+  // template parameter and template argument information.
+  struct DFIParamWithArguments {
+    TemplateParameter Param;
+    TemplateArgument FirstArg;
+    TemplateArgument SecondArg;
+  };
+}
+  
+/// \brief Convert from Sema's representation of template deduction information
+/// to the form used in overload-candidate information.
+OverloadCandidate::DeductionFailureInfo
+static MakeDeductionFailureInfo(Sema::TemplateDeductionResult TDK,
+                                const Sema::TemplateDeductionInfo &Info) {
+  OverloadCandidate::DeductionFailureInfo Result;
+  Result.Result = static_cast<unsigned>(TDK);
+  Result.Data = 0;
+  switch (TDK) {
+  case Sema::TDK_Success:
+  case Sema::TDK_InstantiationDepth:
+    break;
+      
+  case Sema::TDK_Incomplete:
+    Result.Data = Info.Param.getOpaqueValue();
+    break;
+      
+  // Unhandled
+  case Sema::TDK_Inconsistent:
+  case Sema::TDK_InconsistentQuals: {
+    DFIParamWithArguments *Saved = new DFIParamWithArguments;
+    Saved->Param = Info.Param;
+    Saved->FirstArg = Info.FirstArg;
+    Saved->SecondArg = Info.SecondArg;
+    Result.Data = Saved;
+    break;
+  }
+      
+  case Sema::TDK_SubstitutionFailure:
+  case Sema::TDK_NonDeducedMismatch:
+  case Sema::TDK_TooManyArguments:
+  case Sema::TDK_TooFewArguments:
+  case Sema::TDK_InvalidExplicitArguments:
+  case Sema::TDK_FailedOverloadResolution:
+    break;  
+  }
+  
+  return Result;
+}
+
+void OverloadCandidate::DeductionFailureInfo::Destroy() {
+  switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+  case Sema::TDK_Success:
+  case Sema::TDK_InstantiationDepth:
+  case Sema::TDK_Incomplete:
+    break;
+      
+  // Unhandled
+  case Sema::TDK_Inconsistent:
+  case Sema::TDK_InconsistentQuals:
+    delete static_cast<DFIParamWithArguments*>(Data);
+    Data = 0;
+    break;
+      
+  case Sema::TDK_SubstitutionFailure:
+  case Sema::TDK_NonDeducedMismatch:
+  case Sema::TDK_TooManyArguments:
+  case Sema::TDK_TooFewArguments:
+  case Sema::TDK_InvalidExplicitArguments:
+  case Sema::TDK_FailedOverloadResolution:
+    break;
+  }
+}
+  
+TemplateParameter 
+OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
+  switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+  case Sema::TDK_Success:
+  case Sema::TDK_InstantiationDepth:
+    return TemplateParameter();
+    
+  case Sema::TDK_Incomplete:
+    return TemplateParameter::getFromOpaqueValue(Data);    
 
+  case Sema::TDK_Inconsistent:
+  case Sema::TDK_InconsistentQuals:
+    return static_cast<DFIParamWithArguments*>(Data)->Param;
+      
+  // Unhandled
+  case Sema::TDK_SubstitutionFailure:
+  case Sema::TDK_NonDeducedMismatch:
+  case Sema::TDK_TooManyArguments:
+  case Sema::TDK_TooFewArguments:
+  case Sema::TDK_InvalidExplicitArguments:
+  case Sema::TDK_FailedOverloadResolution:
+    break;
+  }
+  
+  return TemplateParameter();
+}
+  
+const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
+  switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+  case Sema::TDK_Success:
+  case Sema::TDK_InstantiationDepth:
+  case Sema::TDK_Incomplete:
+    return 0;
+
+  // Unhandled
+  case Sema::TDK_Inconsistent:
+  case Sema::TDK_InconsistentQuals:
+    return &static_cast<DFIParamWithArguments*>(Data)->FirstArg;      
+
+  case Sema::TDK_SubstitutionFailure:
+  case Sema::TDK_NonDeducedMismatch:
+  case Sema::TDK_TooManyArguments:
+  case Sema::TDK_TooFewArguments:
+  case Sema::TDK_InvalidExplicitArguments:
+  case Sema::TDK_FailedOverloadResolution:
+    break;
+  }
+  
+  return 0;
+}    
+
+const TemplateArgument *
+OverloadCandidate::DeductionFailureInfo::getSecondArg() {
+  switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+  case Sema::TDK_Success:
+  case Sema::TDK_InstantiationDepth:
+  case Sema::TDK_Incomplete:
+    return 0;
+
+  // Unhandled
+  case Sema::TDK_Inconsistent:
+  case Sema::TDK_InconsistentQuals:
+    return &static_cast<DFIParamWithArguments*>(Data)->SecondArg;
+
+  case Sema::TDK_SubstitutionFailure:
+  case Sema::TDK_NonDeducedMismatch:
+  case Sema::TDK_TooManyArguments:
+  case Sema::TDK_TooFewArguments:
+  case Sema::TDK_InvalidExplicitArguments:
+  case Sema::TDK_FailedOverloadResolution:
+    break;
+  }
+  
+  return 0;
+}
+
+void OverloadCandidateSet::clear() {
+  for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
+    if (C->FailureKind == ovl_fail_bad_deduction)
+      C->DeductionFailure.Destroy();
+  }
+       
+  inherited::clear();
+  Functions.clear();
+}
+  
 // IsOverload - Determine whether the given New declaration is an
 // overload of the declarations in Old. This routine returns false if
 // New and Old cannot be overloaded, e.g., if New has the same
@@ -3028,7 +3187,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
     }
   }
 }
-
+  
 /// \brief Add a C++ member function template as a candidate to the candidate
 /// set, using template argument deduction to produce an appropriate member
 /// function template specialization.
@@ -3109,10 +3268,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
     Candidate.FailureKind = ovl_fail_bad_deduction;
     Candidate.IsSurrogate = false;
     Candidate.IgnoreObjectArgument = false;
-
-    // TODO: record more information about failed template arguments
-    Candidate.DeductionFailure.Result = Result;
-    Candidate.DeductionFailure.TemplateParameter = Info.Param.getOpaqueValue();
+    Candidate.DeductionFailure = MakeDeductionFailureInfo(Result, Info);
     return;
   }
 
@@ -4929,9 +5085,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
                           Expr **Args, unsigned NumArgs) {
   FunctionDecl *Fn = Cand->Function; // pattern
 
-  TemplateParameter Param = TemplateParameter::getFromOpaqueValue(
-                                   Cand->DeductionFailure.TemplateParameter);
-
+  TemplateParameter Param = Cand->DeductionFailure.getTemplateParameter();
   switch (Cand->DeductionFailure.Result) {
   case Sema::TDK_Success:
     llvm_unreachable("TDK_success while diagnosing bad deduction");
@@ -4947,11 +5101,29 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
     return;
   }
 
+  case Sema::TDK_Inconsistent:
+  case Sema::TDK_InconsistentQuals: {
+    NamedDecl *ParamD;
+    int which = 0;
+    if ((ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()))
+      which = 0;
+    else if ((ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()))
+      which = 1;
+    else {
+      ParamD = Param.get<TemplateTemplateParmDecl*>();
+      which = 2;
+    }
+    
+    S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction)
+      << which << ParamD->getDeclName() 
+      << *Cand->DeductionFailure.getFirstArg()
+      << *Cand->DeductionFailure.getSecondArg();
+    return;
+  }
+      
   // TODO: diagnose these individually, then kill off
   // note_ovl_candidate_bad_deduction, which is uselessly vague.
   case Sema::TDK_InstantiationDepth:
-  case Sema::TDK_Inconsistent:
-  case Sema::TDK_InconsistentQuals:
   case Sema::TDK_SubstitutionFailure:
   case Sema::TDK_NonDeducedMismatch:
   case Sema::TDK_TooManyArguments:
index 5e611113083f1a6586c1f672c73d2ad52bcc4b12..b7b628886ca6edc2ebe132d776df4e41a605407c 100644 (file)
@@ -16,7 +16,9 @@
 #define LLVM_CLANG_SEMA_OVERLOAD_H
 
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/TemplateBase.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/UnresolvedSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -529,8 +531,24 @@ namespace clang {
       // A Sema::TemplateDeductionResult.
       unsigned Result;
 
-      // A TemplateParameter.
-      void *TemplateParameter;
+      /// \brief Opaque pointer containing additional data about
+      /// this deduction failure.
+      void *Data;
+      
+      /// \brief Retrieve the template parameter this deduction failure
+      /// refers to, if any.
+      TemplateParameter getTemplateParameter();
+      
+      /// \brief Return the first template argument this deduction failure
+      /// refers to, if any.
+      const TemplateArgument *getFirstArg();
+
+      /// \brief Return the second template argument this deduction failure
+      /// refers to, if any.
+      const TemplateArgument *getSecondArg();
+      
+      /// \brief Free any memory associated with this deduction failure.
+      void Destroy();
     };
 
     union {
@@ -574,10 +592,9 @@ namespace clang {
     }
 
     /// \brief Clear out all of the candidates.
-    void clear() {
-      inherited::clear();
-      Functions.clear();
-    }
+    void clear();
+    
+    ~OverloadCandidateSet() { clear(); }
   };
 } // end namespace clang
 
index 1b7310f00055f2aaf58786f3cf3c451faa2a1bda..90d29497f4b226d851ac74a295160c7d35111e4b 100644 (file)
@@ -16,7 +16,8 @@ void test_f1(int *ip, float fv) {
 }
 
 // TODO: this diagnostic can and should improve
-template<typename T> void f2(T*, T*); // expected-note 2 {{candidate template ignored: failed template argument deduction}}
+template<typename T> void f2(T*, T*); // expected-note {{candidate template ignored: failed template argument deduction}} \
+// expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'float')}}
 
 struct ConvToIntPtr {
   operator int*() const;
index 6edf079b3524f4561daef55ce5df8ef7449d2078..1b240cc98fc7c3a17fd6b700c1f32d3519012284 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
 namespace test0 {
-  template<class T> void apply(T x, void (*f)(T)) { f(x); } // expected-note 2 {{failed template argument deduction}}\
+  template<class T> void apply(T x, void (*f)(T)) { f(x); } // expected-note 2 {{candidate template ignored: deduced conflicting types for parameter 'T'}}\
   // expected-note {{no overload of 'temp2' matching 'void (*)(int)'}}
 
   template<class A> void temp(A);
diff --git a/test/SemaTemplate/overload-candidates.cpp b/test/SemaTemplate/overload-candidates.cpp
new file mode 100644 (file)
index 0000000..84e2371
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T>
+const T& min(const T&, const T&); // expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'long')}}
+
+void test_min() {
+  (void)min(1, 2l); // expected-error{{no matching function for call to 'min'}}
+}