From 342fec43c515184a3c0d0600323dfec2b059e74e Mon Sep 17 00:00:00 2001 From: John McCall Date: Mon, 1 Feb 2010 18:53:26 +0000 Subject: [PATCH] Note that an overload candidate was non-viable because template argument deduction failed. Right now there's a very vague diagnostic for most cases and a good diagnostic for incomplete deduction. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94988 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 6 ++ lib/Sema/SemaOverload.cpp | 62 +++++++++++++++++-- lib/Sema/SemaOverload.h | 24 +++++-- .../temp.fct.spec/temp.arg.explicit/p3.cpp | 2 +- .../temp.deduct/temp.deduct.call/basic.cpp | 3 +- .../recursive-template-instantiation.cpp | 2 +- 6 files changed, 87 insertions(+), 12 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index c4ce6affc6..7da597de6f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -925,6 +925,12 @@ def note_ovl_candidate : Note<"candidate " "is the implicit default constructor|" "is the implicit copy constructor|" "is the implicit copy assignment operator}0%1">; + +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">; + // 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/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 24cad2a9c5..1eb5b38889 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2742,10 +2742,6 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args, NumArgs, Specialization, Info)) { - // FIXME: Record what happened with template argument deduction, so - // that we can give the user a beautiful diagnostic. - (void) Result; - CandidateSet.push_back(OverloadCandidate()); OverloadCandidate &Candidate = CandidateSet.back(); Candidate.Function = FunctionTemplate->getTemplatedDecl(); @@ -2754,6 +2750,10 @@ 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(); return; } @@ -4556,6 +4556,58 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs; } +/// Diagnose a failed template-argument deduction. +void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, + Expr **Args, unsigned NumArgs) { + FunctionDecl *Fn = Cand->Function; // pattern + + TemplateParameter Param = TemplateParameter::getFromOpaqueValue( + Cand->DeductionFailure.TemplateParameter); + + switch (Cand->DeductionFailure.Result) { + case Sema::TDK_Success: + llvm_unreachable("TDK_success while diagnosing bad deduction"); + + case Sema::TDK_Incomplete: { + NamedDecl *ParamD; + (ParamD = Param.dyn_cast()) || + (ParamD = Param.dyn_cast()) || + (ParamD = Param.dyn_cast()); + assert(ParamD && "no parameter found for incomplete deduction result"); + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction) + << ParamD->getDeclName(); + 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: + case Sema::TDK_TooFewArguments: + case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_FailedOverloadResolution: + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction); + return; + } +} + +/// Generates a 'note' diagnostic for an overload candidate. We've +/// already generated a primary error at the call site. +/// +/// It really does need to be a single diagnostic with its caret +/// pointed at the candidate declaration. Yes, this creates some +/// major challenges of technical writing. Yes, this makes pointing +/// out problems with specific arguments quite awkward. It's still +/// better than generating twenty screens of text for every failed +/// overload. +/// +/// It would be great to be able to express per-candidate problems +/// more richly for those diagnostic clients that cared, but we'd +/// still have to be just as careful with the default diagnostics. void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, Expr **Args, unsigned NumArgs) { FunctionDecl *Fn = Cand->Function; @@ -4582,6 +4634,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, return DiagnoseArityMismatch(S, Cand, NumArgs); case ovl_fail_bad_deduction: + return DiagnoseBadDeduction(S, Cand, Args, NumArgs); + case ovl_fail_trivial_conversion: case ovl_fail_bad_final_conversion: return S.NoteOverloadCandidate(Fn); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 66ed2259bd..cc26277825 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -465,11 +465,25 @@ namespace clang { return AccessSpecifier(Access); } - /// FinalConversion - For a conversion function (where Function is - /// a CXXConversionDecl), the standard conversion that occurs - /// after the call to the overload candidate to convert the result - /// of calling the conversion function to the required type. - StandardConversionSequence FinalConversion; + /// A structure used to record information about a failed + /// template argument deduction. + struct DeductionFailureInfo { + // A Sema::TemplateDeductionResult. + unsigned Result; + + // A TemplateParameter. + void *TemplateParameter; + }; + + union { + DeductionFailureInfo DeductionFailure; + + /// FinalConversion - For a conversion function (where Function is + /// a CXXConversionDecl), the standard conversion that occurs + /// after the call to the overload candidate to convert the result + /// of calling the conversion function to the required type. + StandardConversionSequence FinalConversion; + }; /// hasAmbiguousConversion - Returns whether this overload /// candidate requires an ambiguous conversion or not. diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp index 8fb736ca03..95f9640a0b 100644 --- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp +++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template X f(Y,Z); // expected-note {{candidate function}} +template X f(Y,Z); // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} void g() { f("aa",3.0); 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 bcfb71c987..1b7310f000 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 @@ -15,7 +15,8 @@ void test_f1(int *ip, float fv) { f1(ip, fv); } -template void f2(T*, T*); // expected-note 2 {{candidate function}} +// TODO: this diagnostic can and should improve +template void f2(T*, T*); // expected-note 2 {{candidate template ignored: failed template argument deduction}} struct ConvToIntPtr { operator int*() const; diff --git a/test/SemaTemplate/recursive-template-instantiation.cpp b/test/SemaTemplate/recursive-template-instantiation.cpp index 0ddedaf235..d6a0b247dd 100644 --- a/test/SemaTemplate/recursive-template-instantiation.cpp +++ b/test/SemaTemplate/recursive-template-instantiation.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template void f(T* t) { // expected-note{{candidate function}} +template void f(T* t) { // expected-note{{failed template argument deduction}} f(*t); // expected-error{{no matching function}}\ // expected-note 3{{requested here}} } -- 2.40.0