From d09efd43d3f849f3d836e46f9fc61013449c816a Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 8 May 2010 20:07:26 +0000 Subject: [PATCH] When printing an overload candidate that failed due to SFINAE, print a specific message that includes the template arguments, e.g., test/SemaTemplate/overload-candidates.cpp:27:20: note: candidate template ignored: substitution failure [with T = int *] typename T::type get_type(const T&); // expected-note{{candidate ... ^ llvm-svn: 103348 --- .../clang/Basic/DiagnosticSemaKinds.td | 7 ++- clang/lib/Sema/SemaOverload.cpp | 62 ++++++++++++++++--- clang/lib/Sema/SemaOverload.h | 4 ++ clang/lib/Sema/SemaTemplateDeduction.cpp | 13 ++-- .../temp.deduct/temp.deduct.type/p17.cpp | 4 +- .../test/SemaTemplate/overload-candidates.cpp | 7 +++ 6 files changed, 82 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 235ac86a22c2..95dce63c0553 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1069,7 +1069,12 @@ def note_ovl_candidate_explicit_arg_mismatch_named : Note< def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< "candidate template ignored: invalid explicitly-specified argument " "for %ordinal0 template parameter">; - +def note_ovl_candidate_instantiation_depth : Note< + "candidate template ignored: substitution exceeded maximum template " + "instantiation depth">; +def note_ovl_candidate_substitution_failure : Note< + "candidate template ignored: substitution failure %0">; + // 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/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index f73823613331..b86719e15b97 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -289,7 +289,7 @@ namespace { /// to the form used in overload-candidate information. OverloadCandidate::DeductionFailureInfo static MakeDeductionFailureInfo(Sema::TemplateDeductionResult TDK, - const Sema::TemplateDeductionInfo &Info) { + Sema::TemplateDeductionInfo &Info) { OverloadCandidate::DeductionFailureInfo Result; Result.Result = static_cast(TDK); Result.Data = 0; @@ -316,6 +316,9 @@ static MakeDeductionFailureInfo(Sema::TemplateDeductionResult TDK, } case Sema::TDK_SubstitutionFailure: + Result.Data = Info.take(); + break; + case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; @@ -339,9 +342,13 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() { delete static_cast(Data); Data = 0; break; + + case Sema::TDK_SubstitutionFailure: + // FIXME: Destroy the template arugment list? + Data = 0; + break; // Unhandled - case Sema::TDK_SubstitutionFailure: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; @@ -355,6 +362,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { case Sema::TDK_InstantiationDepth: case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: + case Sema::TDK_SubstitutionFailure: return TemplateParameter(); case Sema::TDK_Incomplete: @@ -366,7 +374,6 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { return static_cast(Data)->Param; // Unhandled - case Sema::TDK_SubstitutionFailure: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; @@ -374,7 +381,32 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { return TemplateParameter(); } - + +TemplateArgumentList * +OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { + switch (static_cast(Result)) { + case Sema::TDK_Success: + case Sema::TDK_InstantiationDepth: + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + case Sema::TDK_Incomplete: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_Inconsistent: + case Sema::TDK_InconsistentQuals: + return 0; + + case Sema::TDK_SubstitutionFailure: + return static_cast(Data); + + // Unhandled + case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_FailedOverloadResolution: + break; + } + + return 0; +} + const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { switch (static_cast(Result)) { case Sema::TDK_Success: @@ -383,6 +415,7 @@ const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_SubstitutionFailure: return 0; case Sema::TDK_Inconsistent: @@ -390,7 +423,6 @@ const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { return &static_cast(Data)->FirstArg; // Unhandled - case Sema::TDK_SubstitutionFailure: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; @@ -408,6 +440,7 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() { case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_SubstitutionFailure: return 0; case Sema::TDK_Inconsistent: @@ -415,7 +448,6 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() { return &static_cast(Data)->SecondArg; // Unhandled - case Sema::TDK_SubstitutionFailure: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: break; @@ -5151,11 +5183,25 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, case Sema::TDK_TooFewArguments: DiagnoseArityMismatch(S, Cand, NumArgs); return; + + case Sema::TDK_InstantiationDepth: + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth); + return; + + case Sema::TDK_SubstitutionFailure: { + std::string ArgString; + if (TemplateArgumentList *Args + = Cand->DeductionFailure.getTemplateArgumentList()) + ArgString = S.getTemplateArgumentBindingsText( + Fn->getDescribedFunctionTemplate()->getTemplateParameters(), + *Args); + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure) + << ArgString; + return; + } // TODO: diagnose these individually, then kill off // note_ovl_candidate_bad_deduction, which is uselessly vague. - case Sema::TDK_InstantiationDepth: - case Sema::TDK_SubstitutionFailure: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction); diff --git a/clang/lib/Sema/SemaOverload.h b/clang/lib/Sema/SemaOverload.h index c13fb17b8584..cf1694382613 100644 --- a/clang/lib/Sema/SemaOverload.h +++ b/clang/lib/Sema/SemaOverload.h @@ -539,6 +539,10 @@ namespace clang { /// refers to, if any. TemplateParameter getTemplateParameter(); + /// \brief Retrieve the template argument list associated with this + /// deduction failure, if any. + TemplateArgumentList *getTemplateArgumentList(); + /// \brief Return the first template argument this deduction failure /// refers to, if any. const TemplateArgument *getFirstArg(); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index f716ccd6f7ff..aca820dec6e7 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1030,10 +1030,8 @@ FinishTemplateArgumentDeduction(Sema &S, ClassTemplate->getTemplateParameters(), N); if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), - InstArgs, false, ConvertedInstArgs)) { - // FIXME: fail with more useful information? + InstArgs, false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; - } for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I]; @@ -1377,6 +1375,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, NTTP->getDeclName()); if (NTTPType.isNull()) { Info.Param = makeTemplateParameter(Param); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } } @@ -1402,6 +1402,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, : CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } @@ -1432,6 +1434,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); + Info.reset(new (Context) TemplateArgumentList(Context, Builder, + /*TakeArgs=*/true)); return TDK_SubstitutionFailure; } @@ -1459,7 +1463,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // If the template argument list is owned by the function template // specialization, release it. - if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList) + if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList && + !Trap.hasErrorOccurred()) Info.take(); // There may have been an error that did not prevent us from constructing a diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp index af8bb3924487..bf5f96225dad 100644 --- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s template class A { }; -template void f(A); // expected-note{{failed template argument deduction}} +template void f(A); // expected-note{{candidate template ignored: substitution failure}} void k1() { A<1> a; @@ -22,7 +22,7 @@ void k3() { h<5>(array); } -template void h(int (&)[s], A); // expected-note{{failed template argument deduction}} +template void h(int (&)[s], A); // expected-note{{candidate template ignored: substitution failure}} void k4() { A<5> a; int array[5]; diff --git a/clang/test/SemaTemplate/overload-candidates.cpp b/clang/test/SemaTemplate/overload-candidates.cpp index 936a6d7aaf58..937d633e68b0 100644 --- a/clang/test/SemaTemplate/overload-candidates.cpp +++ b/clang/test/SemaTemplate/overload-candidates.cpp @@ -22,3 +22,10 @@ template class, typename T> void test_get(void *ptr) { get(ptr); // expected-error{{no matching function for call to 'get'}} } + +template + typename T::type get_type(const T&); // expected-note{{candidate template ignored: substitution failure [with T = int *]}} + +void test_get_type(int *ptr) { + (void)get_type(ptr); // expected-error{{no matching function for call to 'get_type'}} +}