aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-05-08 17:41:32 +0000
committerDouglas Gregor <dgregor@apple.com>2010-05-08 17:41:32 +0000
commita933319ebf754396623165f9dc0a29c2a48879f5 (patch)
treef4da84917a89d1ea3f04e9f848ed5839304a515b
parent40e629920b1eb0585e28b4418b95fc5aacbeeb26 (diff)
When printing a non-viable overload candidate that failed due to
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
-rw-r--r--include/clang/AST/TemplateBase.h6
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--lib/AST/TemplateBase.cpp40
-rw-r--r--lib/Sema/SemaOverload.cpp192
-rw-r--r--lib/Sema/SemaOverload.h29
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp3
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp2
-rw-r--r--test/SemaTemplate/overload-candidates.cpp8
8 files changed, 265 insertions, 20 deletions
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 50a100c6af..8b38001bd1 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -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
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 89f892cec1..93364845ec 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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|"
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index e9b1725641..0bf9f2fb7c 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -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;
+}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index dec9854c72..c08095fae4 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -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:
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 5e61111308..b7b628886c 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -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
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
index 1b7310f000..90d29497f4 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
@@ -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;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
index 6edf079b35..1b240cc98f 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
@@ -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
index 0000000000..84e23716a9
--- /dev/null
+++ b/test/SemaTemplate/overload-candidates.cpp
@@ -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'}}
+}