Index: include/clang/Sema/Overload.h =================================================================== --- include/clang/Sema/Overload.h +++ include/clang/Sema/Overload.h @@ -22,6 +22,7 @@ #include "clang/AST/Type.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Sema/SemaFixItUtils.h" +#include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" @@ -656,53 +657,6 @@ /// \brief The number of call arguments that were explicitly provided, /// to be used while performing partial ordering of function templates. unsigned ExplicitCallArguments; - - /// A structure used to record information about a failed - /// template argument deduction. - struct DeductionFailureInfo { - /// A Sema::TemplateDeductionResult. - unsigned Result : 8; - - /// \brief Indicates whether a diagnostic is stored in Diagnostic. - unsigned HasDiagnostic : 1; - - /// \brief Opaque pointer containing additional data about - /// this deduction failure. - void *Data; - - /// \brief A diagnostic indicating why deduction failed. - union { - void *Align; - char Diagnostic[sizeof(PartialDiagnosticAt)]; - }; - - /// \brief Retrieve the diagnostic which caused this deduction failure, - /// if any. - PartialDiagnosticAt *getSFINAEDiagnostic(); - - /// \brief Retrieve the template parameter this deduction failure - /// 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(); - - /// \brief Return the second template argument this deduction failure - /// refers to, if any. - const TemplateArgument *getSecondArg(); - - /// \brief Return the expression this deduction failure refers to, - /// if any. - Expr *getExpr(); - - /// \brief Free any memory associated with this deduction failure. - void Destroy(); - }; union { DeductionFailureInfo DeductionFailure; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -176,6 +176,8 @@ class VisibilityAttr; class VisibleDeclConsumer; class IndirectFieldDecl; + struct DeductionFailureInfo; + class TemplateSpecCandidateSet; namespace sema { class AccessedEntity; @@ -5773,16 +5775,15 @@ SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments); - UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, - UnresolvedSetIterator SEnd, - TemplatePartialOrderingContext TPOC, - unsigned NumCallArguments, - SourceLocation Loc, - const PartialDiagnostic &NoneDiag, - const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag, - bool Complain = true, - QualType TargetType = QualType()); + UnresolvedSetIterator + getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, + TemplateSpecCandidateSet &FailedCandidates, + TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments, SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag, + bool Complain = true, QualType TargetType = QualType()); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( @@ -7744,6 +7745,10 @@ } }; +DeductionFailureInfo +MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, + sema::TemplateDeductionInfo &Info); + } // end namespace clang #endif Index: include/clang/Sema/TemplateDeduction.h =================================================================== --- include/clang/Sema/TemplateDeduction.h +++ include/clang/Sema/TemplateDeduction.h @@ -20,6 +20,7 @@ namespace clang { class TemplateArgumentList; +class Sema; namespace sema { @@ -162,7 +163,124 @@ Expr *Expression; }; -} -} +} // end namespace sema + +/// A structure used to record information about a failed +/// template argument deduction, for diagnosis. +struct DeductionFailureInfo { + /// A Sema::TemplateDeductionResult. + unsigned Result : 8; + + /// \brief Indicates whether a diagnostic is stored in Diagnostic. + unsigned HasDiagnostic : 1; + + /// \brief Opaque pointer containing additional data about + /// this deduction failure. + void *Data; + + /// \brief A diagnostic indicating why deduction failed. + union { + void *Align; + char Diagnostic[sizeof(PartialDiagnosticAt)]; + }; + + /// \brief Retrieve the diagnostic which caused this deduction failure, + /// if any. + PartialDiagnosticAt *getSFINAEDiagnostic(); + + /// \brief Retrieve the template parameter this deduction failure + /// 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(); + + /// \brief Return the second template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getSecondArg(); + + /// \brief Return the expression this deduction failure refers to, + /// if any. + Expr *getExpr(); + + /// \brief Free any memory associated with this deduction failure. + void Destroy(); +}; + +/// TemplateSpecCandidate - This is a generalization of OverloadCandidate +/// which keeps track of template argument deduction failure info, when +/// handling explicit specializations (and instantiations) of templates +/// beyond function overloading. +/// For now, assume that the candidates are non-matching specializations. +/// TODO: In the future, we may need to unify/generalize this with +/// OverloadCandidate. +struct TemplateSpecCandidate { + /// Specialization - The actual specialization that this candidate + /// represents. When NULL, this may be a built-in candidate. + Decl *Specialization; + + /// Template argument deduction info + DeductionFailureInfo DeductionFailure; + + void set(Decl *Spec, DeductionFailureInfo Info) { + Specialization = Spec; + DeductionFailure = Info; + } + + /// Diagnose a template argument deduction failure. + void NoteDeductionFailure(Sema &S); +}; + +/// TemplateSpecCandidateSet - A set of generalized overload candidates, +/// used in template specializations. +/// TODO: In the future, we may need to unify/generalize this with +/// OverloadCandidateSet. +class TemplateSpecCandidateSet { + SmallVector Candidates; + SourceLocation Loc; + + TemplateSpecCandidateSet( + const TemplateSpecCandidateSet &) LLVM_DELETED_FUNCTION; + void operator=(const TemplateSpecCandidateSet &) LLVM_DELETED_FUNCTION; + + void destroyCandidates(); + +public: + TemplateSpecCandidateSet(SourceLocation Loc) : Loc(Loc) {} + ~TemplateSpecCandidateSet() { destroyCandidates(); } + + SourceLocation getLocation() const { return Loc; } + + /// \brief Clear out all of the candidates. + /// TODO: This may be unnecessary. + void clear(); + + typedef SmallVector::iterator iterator; + iterator begin() { return Candidates.begin(); } + iterator end() { return Candidates.end(); } + + size_t size() const { return Candidates.size(); } + bool empty() const { return Candidates.empty(); } + + /// \brief Add a new candidate with NumConversions conversion sequence slots + /// to the overload set. + TemplateSpecCandidate &addCandidate() { + Candidates.push_back(TemplateSpecCandidate()); + return Candidates.back(); + } + + void NoteCandidates(Sema &S, SourceLocation Loc); + + void NoteCandidates(Sema &S, SourceLocation Loc) const { + const_cast(this)->NoteCandidates(S, Loc); + } +}; + +} // end namespace clang #endif Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -548,13 +548,13 @@ } namespace { - // Structure used by OverloadCandidate::DeductionFailureInfo to store + // Structure used by DeductionFailureInfo to store // template argument information. struct DFIArguments { TemplateArgument FirstArg; TemplateArgument SecondArg; }; - // Structure used by OverloadCandidate::DeductionFailureInfo to store + // Structure used by DeductionFailureInfo to store // template parameter and template argument information. struct DFIParamWithArguments : DFIArguments { TemplateParameter Param; @@ -563,11 +563,10 @@ /// \brief Convert from Sema's representation of template deduction information /// to the form used in overload-candidate information. -OverloadCandidate::DeductionFailureInfo -static MakeDeductionFailureInfo(ASTContext &Context, - Sema::TemplateDeductionResult TDK, - TemplateDeductionInfo &Info) { - OverloadCandidate::DeductionFailureInfo Result; +DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context, + Sema::TemplateDeductionResult TDK, + TemplateDeductionInfo &Info) { + DeductionFailureInfo Result; Result.Result = static_cast(TDK); Result.HasDiagnostic = false; Result.Data = 0; @@ -625,7 +624,7 @@ return Result; } -void OverloadCandidate::DeductionFailureInfo::Destroy() { +void DeductionFailureInfo::Destroy() { switch (static_cast(Result)) { case Sema::TDK_Success: case Sema::TDK_Invalid: @@ -659,15 +658,13 @@ } } -PartialDiagnosticAt * -OverloadCandidate::DeductionFailureInfo::getSFINAEDiagnostic() { +PartialDiagnosticAt *DeductionFailureInfo::getSFINAEDiagnostic() { if (HasDiagnostic) return static_cast(static_cast(Diagnostic)); return 0; } -TemplateParameter -OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { +TemplateParameter DeductionFailureInfo::getTemplateParameter() { switch (static_cast(Result)) { case Sema::TDK_Success: case Sema::TDK_Invalid: @@ -695,8 +692,7 @@ return TemplateParameter(); } -TemplateArgumentList * -OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { +TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { switch (static_cast(Result)) { case Sema::TDK_Success: case Sema::TDK_Invalid: @@ -722,7 +718,7 @@ return 0; } -const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { +const TemplateArgument *DeductionFailureInfo::getFirstArg() { switch (static_cast(Result)) { case Sema::TDK_Success: case Sema::TDK_Invalid: @@ -748,8 +744,7 @@ return 0; } -const TemplateArgument * -OverloadCandidate::DeductionFailureInfo::getSecondArg() { +const TemplateArgument *DeductionFailureInfo::getSecondArg() { switch (static_cast(Result)) { case Sema::TDK_Success: case Sema::TDK_Invalid: @@ -775,8 +770,7 @@ return 0; } -Expr * -OverloadCandidate::DeductionFailureInfo::getExpr() { +Expr *DeductionFailureInfo::getExpr() { if (static_cast(Result) == Sema::TDK_FailedOverloadResolution) return static_cast(Data); @@ -8128,7 +8122,7 @@ return isTemplate ? oc_function_template : oc_function; } -void MaybeEmitInheritedConstructorNote(Sema &S, FunctionDecl *Fn) { +void MaybeEmitInheritedConstructorNote(Sema &S, Decl *Fn) { const CXXConstructorDecl *Ctor = dyn_cast(Fn); if (!Ctor) return; @@ -8414,30 +8408,52 @@ MaybeEmitInheritedConstructorNote(S, Fn); } -void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, - unsigned NumFormalArgs) { - // TODO: treat calls to a missing default constructor as a special case - +/// Additional arity mismatch diagnosis specific to a function overload +/// candidates. This is not covered by the more general DiagnoseArityMismatch() +/// over a candidate in any candidate set. +bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, + unsigned NumArgs) { FunctionDecl *Fn = Cand->Function; - const FunctionProtoType *FnTy = Fn->getType()->getAs(); - unsigned MinParams = Fn->getMinRequiredArguments(); // With invalid overloaded operators, it's possible that we think we - // have an arity mismatch when it fact it looks like we have the + // have an arity mismatch when in fact it looks like we have the // right number of arguments, because only overloaded operators have // the weird behavior of overloading member and non-member functions. // Just don't report anything. if (Fn->isInvalidDecl() && Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) - return; + return true; - // at least / at most / exactly - unsigned mode, modeCount; - if (NumFormalArgs < MinParams) { + if (NumArgs < MinParams) { assert((Cand->FailureKind == ovl_fail_too_few_arguments) || (Cand->FailureKind == ovl_fail_bad_deduction && Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments)); + } else { + assert((Cand->FailureKind == ovl_fail_too_many_arguments) || + (Cand->FailureKind == ovl_fail_bad_deduction && + Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments)); + } + + return false; +} + +/// General arity mismatch diagnosis over a candidate in a candidate set. +void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) { + assert(isa(D) && + "The templated declaration should at least be a function" + " when diagnosing bad template argument deduction due to too many" + " or too few arguments"); + + FunctionDecl* Fn = cast(D); + + // TODO: treat calls to a missing default constructor as a special case + const FunctionProtoType *FnTy = Fn->getType()->getAs(); + unsigned MinParams = Fn->getMinRequiredArguments(); + + // at least / at most / exactly + unsigned mode, modeCount; + if (NumFormalArgs < MinParams) { if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic() || FnTy->isTemplateVariadic()) mode = 0; // "at least" @@ -8445,9 +8461,6 @@ mode = 2; // "exactly" modeCount = MinParams; } else { - assert((Cand->FailureKind == ovl_fail_too_many_arguments) || - (Cand->FailureKind == ovl_fail_bad_deduction && - Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments)); if (MinParams != FnTy->getNumArgs()) mode = 1; // "at most" else @@ -8469,25 +8482,42 @@ MaybeEmitInheritedConstructorNote(S, Fn); } +/// Arity mismatch diagnosis specific to a function overload candidate. +void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, + unsigned NumFormalArgs) { + if (!CheckArityMismatch(S, Cand, NumFormalArgs)) + DiagnoseArityMismatch(S, Cand->Function, NumFormalArgs); +} + +TemplateDecl *getDescribedTemplate(Decl *Templated) { + if (FunctionDecl* FD = dyn_cast(Templated)) + return FD->getDescribedFunctionTemplate(); + else if (CXXRecordDecl* RD = dyn_cast(Templated)) + return RD->getDescribedClassTemplate(); + + llvm_unreachable("Unsupported: Getting the described template declaration" + " for bad deduction diagnosis"); +} + /// Diagnose a failed template-argument deduction. -void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, +void DiagnoseBadDeduction(Sema &S, Decl *Templated, + DeductionFailureInfo &DeductionFailure, unsigned NumArgs) { - FunctionDecl *Fn = Cand->Function; // pattern - - TemplateParameter Param = Cand->DeductionFailure.getTemplateParameter(); + TemplateParameter Param = DeductionFailure.getTemplateParameter(); NamedDecl *ParamD; (ParamD = Param.dyn_cast()) || (ParamD = Param.dyn_cast()) || (ParamD = Param.dyn_cast()); - switch (Cand->DeductionFailure.Result) { + switch (DeductionFailure.Result) { case Sema::TDK_Success: llvm_unreachable("TDK_success while diagnosing bad deduction"); case Sema::TDK_Incomplete: { assert(ParamD && "no parameter found for incomplete deduction result"); - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction) - << ParamD->getDeclName(); - MaybeEmitInheritedConstructorNote(S, Fn); + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_incomplete_deduction) + << ParamD->getDeclName(); + MaybeEmitInheritedConstructorNote(S, Templated); return; } @@ -8495,7 +8525,7 @@ assert(ParamD && "no parameter found for bad qualifiers deduction result"); TemplateTypeParmDecl *TParam = cast(ParamD); - QualType Param = Cand->DeductionFailure.getFirstArg()->getAsType(); + QualType Param = DeductionFailure.getFirstArg()->getAsType(); // Param will have been canonicalized, but it should just be a // qualified version of ParamD, so move the qualifiers to that. @@ -8508,11 +8538,11 @@ // about that. It also doesn't matter as much, because it won't // have any template parameters in it (because deduction isn't // done on dependent types). - QualType Arg = Cand->DeductionFailure.getSecondArg()->getAsType(); + QualType Arg = DeductionFailure.getSecondArg()->getAsType(); - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_underqualified) - << ParamD->getDeclName() << Arg << NonCanonParam; - MaybeEmitInheritedConstructorNote(S, Fn); + S.Diag(Templated->getLocation(), diag::note_ovl_candidate_underqualified) + << ParamD->getDeclName() << Arg << NonCanonParam; + MaybeEmitInheritedConstructorNote(S, Templated); return; } @@ -8527,20 +8557,20 @@ which = 2; } - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction) - << which << ParamD->getDeclName() - << *Cand->DeductionFailure.getFirstArg() - << *Cand->DeductionFailure.getSecondArg(); - MaybeEmitInheritedConstructorNote(S, Fn); + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_inconsistent_deduction) + << which << ParamD->getDeclName() << *DeductionFailure.getFirstArg() + << *DeductionFailure.getSecondArg(); + MaybeEmitInheritedConstructorNote(S, Templated); return; } case Sema::TDK_InvalidExplicitArguments: assert(ParamD && "no parameter found for invalid explicit arguments"); if (ParamD->getDeclName()) - S.Diag(Fn->getLocation(), + S.Diag(Templated->getLocation(), diag::note_ovl_candidate_explicit_arg_mismatch_named) - << ParamD->getDeclName(); + << ParamD->getDeclName(); else { int index = 0; if (TemplateTypeParmDecl *TTP = dyn_cast(ParamD)) @@ -8550,35 +8580,36 @@ index = NTTP->getIndex(); else index = cast(ParamD)->getIndex(); - S.Diag(Fn->getLocation(), + S.Diag(Templated->getLocation(), diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) - << (index + 1); + << (index + 1); } - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Templated); return; case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: - DiagnoseArityMismatch(S, Cand, NumArgs); + DiagnoseArityMismatch(S, Templated, NumArgs); return; case Sema::TDK_InstantiationDepth: - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth); - MaybeEmitInheritedConstructorNote(S, Fn); + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_instantiation_depth); + MaybeEmitInheritedConstructorNote(S, Templated); return; case Sema::TDK_SubstitutionFailure: { // Format the template argument list into the argument string. SmallString<128> TemplateArgString; if (TemplateArgumentList *Args = - Cand->DeductionFailure.getTemplateArgumentList()) { + DeductionFailure.getTemplateArgumentList()) { TemplateArgString = " "; TemplateArgString += S.getTemplateArgumentBindingsText( - Fn->getDescribedFunctionTemplate()->getTemplateParameters(), *Args); + getDescribedTemplate(Templated)->getTemplateParameters(), *Args); } // If this candidate was disabled by enable_if, say so. - PartialDiagnosticAt *PDiag = Cand->DeductionFailure.getSFINAEDiagnostic(); + PartialDiagnosticAt *PDiag = DeductionFailure.getSFINAEDiagnostic(); if (PDiag && PDiag->second.getDiagID() == diag::err_typename_nested_not_found_enable_if) { // FIXME: Use the source range of the condition, and the fully-qualified @@ -8599,25 +8630,25 @@ PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString); } - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure) - << TemplateArgString << SFINAEArgString << R; - MaybeEmitInheritedConstructorNote(S, Fn); + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_substitution_failure) + << TemplateArgString << SFINAEArgString << R; + MaybeEmitInheritedConstructorNote(S, Templated); return; } case Sema::TDK_FailedOverloadResolution: { - OverloadExpr::FindResult R = - OverloadExpr::find(Cand->DeductionFailure.getExpr()); - S.Diag(Fn->getLocation(), + OverloadExpr::FindResult R = OverloadExpr::find(DeductionFailure.getExpr()); + S.Diag(Templated->getLocation(), diag::note_ovl_candidate_failed_overload_resolution) - << R.Expression->getName(); + << R.Expression->getName(); return; } case Sema::TDK_NonDeducedMismatch: { // FIXME: Provide a source location to indicate what we couldn't match. - TemplateArgument FirstTA = *Cand->DeductionFailure.getFirstArg(); - TemplateArgument SecondTA = *Cand->DeductionFailure.getSecondArg(); + TemplateArgument FirstTA = *DeductionFailure.getFirstArg(); + TemplateArgument SecondTA = *DeductionFailure.getSecondArg(); if (FirstTA.getKind() == TemplateArgument::Template && SecondTA.getKind() == TemplateArgument::Template) { TemplateName FirstTN = FirstTA.getAsTemplate(); @@ -8632,26 +8663,38 @@ // 2) The diagnostic printer only attempts to find a better // name for types, not decls. // Ideally, this should folded into the diagnostic printer. - S.Diag(Fn->getLocation(), + S.Diag(Templated->getLocation(), diag::note_ovl_candidate_non_deduced_mismatch_qualified) << FirstTN.getAsTemplateDecl() << SecondTN.getAsTemplateDecl(); return; } } } - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_non_deduced_mismatch) - << FirstTA << SecondTA; + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_non_deduced_mismatch) + << FirstTA << SecondTA; return; } // TODO: diagnose these individually, then kill off // note_ovl_candidate_bad_deduction, which is uselessly vague. case Sema::TDK_MiscellaneousDeductionFailure: - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction); - MaybeEmitInheritedConstructorNote(S, Fn); + S.Diag(Templated->getLocation(), diag::note_ovl_candidate_bad_deduction); + MaybeEmitInheritedConstructorNote(S, Templated); return; } } +/// Diagnose a failed template-argument deduction, for function calls. +void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, unsigned NumArgs) { + unsigned TDK = Cand->DeductionFailure.Result; + if (TDK == Sema::TDK_TooFewArguments || TDK == Sema::TDK_TooManyArguments) { + if (CheckArityMismatch(S, Cand, NumArgs)) + return; + } + DiagnoseBadDeduction(S, Cand->Function, // pattern + Cand->DeductionFailure, NumArgs); +} + /// CUDA: diagnose an invalid call across targets. void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { FunctionDecl *Caller = cast(S.CurContext); @@ -8799,7 +8842,7 @@ } } -SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) { +static SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) { if (Cand->Function) return Cand->Function->getLocation(); if (Cand->IsSurrogate) @@ -8807,8 +8850,7 @@ return SourceLocation(); } -static unsigned -RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) { +static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { switch ((Sema::TemplateDeductionResult)DFI.Result) { case Sema::TDK_Success: llvm_unreachable("TDK_success while diagnosing bad deduction"); @@ -9101,6 +9143,108 @@ S.Diag(OpLoc, diag::note_ovl_too_many_candidates) << int(E - I); } +static SourceLocation +GetLocationForCandidate(const TemplateSpecCandidate *Cand) { + return Cand->Specialization ? Cand->Specialization->getLocation() + : SourceLocation(); +} + +struct CompareTemplateSpecCandidatesForDisplay { + Sema &S; + CompareTemplateSpecCandidatesForDisplay(Sema &S) : S(S) {} + + bool operator()(const TemplateSpecCandidate *L, + const TemplateSpecCandidate *R) { + // Fast-path this check. + if (L == R) + return false; + + // Assuming that both candidates are not matches... + + // Sort by the ranking of deduction failures. + if (L->DeductionFailure.Result != R->DeductionFailure.Result) + return RankDeductionFailure(L->DeductionFailure) < + RankDeductionFailure(R->DeductionFailure); + + // Sort everything else by location. + SourceLocation LLoc = GetLocationForCandidate(L); + SourceLocation RLoc = GetLocationForCandidate(R); + + // Put candidates without locations (e.g. builtins) at the end. + if (LLoc.isInvalid()) + return false; + if (RLoc.isInvalid()) + return true; + + return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc); + } +}; + +/// Diagnose a template argument deduction failure. +/// We are treating these failures as overload failures due to bad +/// deductions. +void TemplateSpecCandidate::NoteDeductionFailure(Sema &S) { + DiagnoseBadDeduction(S, Specialization, // pattern + DeductionFailure, /*NumArgs=*/0); +} + +void TemplateSpecCandidateSet::destroyCandidates() { + for (iterator i = begin(), e = end(); i != e; ++i) { + i->DeductionFailure.Destroy(); + } +} + +void TemplateSpecCandidateSet::clear() { + destroyCandidates(); + Candidates.clear(); +} + +/// NoteCandidates - When no template specialization match is found, prints +/// diagnostic messages containing the non-matching specializations that form +/// the candidate set. +/// This is analoguous to OverloadCandidateSet::NoteCandidates() with +/// OCD == OCD_AllCandidates and Cand->Viable == false. +void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) { + // Sort the candidates by position (assuming no candidate is a match). + // Sorting directly would be prohibitive, so we make a set of pointers + // and sort those. + SmallVector Cands; + Cands.reserve(size()); + for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) { + if (Cand->Specialization) + Cands.push_back(Cand); + // Otherwise, this is a non matching builtin candidate. We do not, + // in general, want to list every possible builtin candidate. + } + + std::sort(Cands.begin(), Cands.end(), + CompareTemplateSpecCandidatesForDisplay(S)); + + // FIXME: Perhaps rename OverloadsShown and getShowOverloads() + // for generalization purposes (?). + const OverloadsShown ShowOverloads = S.Diags.getShowOverloads(); + + SmallVectorImpl::iterator I, E; + unsigned CandsShown = 0; + for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { + TemplateSpecCandidate *Cand = *I; + + // Set an arbitrary limit on the number of candidates we'll spam + // the user with. FIXME: This limit should depend on details of the + // candidate list. + if (CandsShown >= 4 && ShowOverloads == Ovl_Best) + break; + ++CandsShown; + + assert(Cand->Specialization && + "Non-matching built-in candidates are not added to Cands."); + Cand->NoteDeductionFailure(S); + } + + if (I != E) + S.Diag(Loc, diag::note_ovl_too_many_candidates) << int(E - I); +} + // [PossiblyAFunctionType] --> [Return] // NonFunctionType --> NonFunctionType // R (A) --> R(A) @@ -9143,18 +9287,19 @@ OverloadExpr *OvlExpr; TemplateArgumentListInfo OvlExplicitTemplateArgs; SmallVector, 4> Matches; + TemplateSpecCandidateSet FailedCandidates; public: - AddressOfFunctionResolver(Sema &S, Expr* SourceExpr, - const QualType& TargetType, bool Complain) - : S(S), SourceExpr(SourceExpr), TargetType(TargetType), - Complain(Complain), Context(S.getASTContext()), - TargetTypeIsNonStaticMemberFunction( - !!TargetType->getAs()), - FoundNonTemplateFunction(false), - OvlExprInfo(OverloadExpr::find(SourceExpr)), - OvlExpr(OvlExprInfo.Expression) - { + AddressOfFunctionResolver(Sema &S, Expr *SourceExpr, + const QualType &TargetType, bool Complain) + : S(S), SourceExpr(SourceExpr), TargetType(TargetType), + Complain(Complain), Context(S.getASTContext()), + TargetTypeIsNonStaticMemberFunction( + !!TargetType->getAs()), + FoundNonTemplateFunction(false), + OvlExprInfo(OverloadExpr::find(SourceExpr)), + OvlExpr(OvlExprInfo.Expression), + FailedCandidates(OvlExpr->getNameLoc()) { ExtractUnqualifiedFunctionTypeFromTargetType(); if (!TargetFunctionType->isFunctionType()) { @@ -9232,13 +9377,16 @@ // function template specialization, which is added to the set of // overloaded functions considered. FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(OvlExpr->getNameLoc()); + TemplateDeductionInfo Info(FailedCandidates.getLocation()); if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments(FunctionTemplate, &OvlExplicitTemplateArgs, TargetFunctionType, Specialization, Info, /*InOverloadResolution=*/true)) { - // FIXME: make a note of the failed deduction for diagnostics. + // Make a note of the failed deduction for diagnostics. + FailedCandidates.addCandidate() + .set(FunctionTemplate->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, Result, Info)); (void)Result; return false; } @@ -9343,15 +9491,15 @@ for (unsigned I = 0, E = Matches.size(); I != E; ++I) MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess()); - UnresolvedSetIterator Result = - S.getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), - TPOC_Other, 0, SourceExpr->getLocStart(), - S.PDiag(), - S.PDiag(diag::err_addr_ovl_ambiguous) - << Matches[0].second->getDeclName(), - S.PDiag(diag::note_ovl_candidate) - << (unsigned) oc_function_template, - Complain, TargetFunctionType); + // TODO: It looks like FailedCandidates does not serve much purpose + // here, since the no_viable diagnostic has index 0. + UnresolvedSetIterator Result = S.getMostSpecialized( + MatchesCopy.begin(), MatchesCopy.end(), FailedCandidates, TPOC_Other, 0, + SourceExpr->getLocStart(), S.PDiag(), + S.PDiag(diag::err_addr_ovl_ambiguous) << Matches[0] + .second->getDeclName(), + S.PDiag(diag::note_ovl_candidate) << (unsigned)oc_function_template, + Complain, TargetFunctionType); if (Result != MatchesCopy.end()) { // Make it the first and only element @@ -9380,6 +9528,7 @@ S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_no_viable) << OvlExpr->getName() << TargetFunctionType << OvlExpr->getSourceRange(); + FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart()); S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType); } @@ -9496,6 +9645,7 @@ TemplateArgumentListInfo ExplicitTemplateArgs; ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs); + TemplateSpecCandidateSet FailedCandidates(ovl->getNameLoc()); // Look through all of the overloaded functions, searching for one // whose type matches exactly. @@ -9518,12 +9668,16 @@ // function template specialization, which is added to the set of // overloaded functions considered. FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(ovl->getNameLoc()); + TemplateDeductionInfo Info(FailedCandidates.getLocation()); if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info, /*InOverloadResolution=*/true)) { - // FIXME: make a note of the failed deduction for diagnostics. + // Make a note of the failed deduction for diagnostics. + // TODO: Actually use the failed-deduction info? + FailedCandidates.addCandidate() + .set(FunctionTemplate->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, Result, Info)); (void)Result; continue; } Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -5925,13 +5925,13 @@ /// /// \param Previous the set of declarations that may be specialized by /// this function specialization. -bool -Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, - TemplateArgumentListInfo *ExplicitTemplateArgs, - LookupResult &Previous) { +bool Sema::CheckFunctionTemplateSpecialization( + FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous) { // The set of function template specializations that could match this // explicit function template specialization. UnresolvedSet<8> Candidates; + TemplateSpecCandidateSet FailedCandidates(FD->getLocation()); DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext(); for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); @@ -5969,13 +5969,16 @@ // Perform template argument deduction to determine whether we may be // specializing this template. // FIXME: It is somewhat wasteful to build - TemplateDeductionInfo Info(FD->getLocation()); + TemplateDeductionInfo Info(FailedCandidates.getLocation()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, FT, Specialization, Info)) { - // FIXME: Template argument deduction failed; record why it failed, so + // Template argument deduction failed; record why it failed, so // that we can provide nifty diagnostics. + FailedCandidates.addCandidate() + .set(FunTmpl->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, TDK, Info)); (void)TDK; continue; } @@ -5986,14 +5989,14 @@ } // Find the most specialized function template. - UnresolvedSetIterator Result - = getMostSpecialized(Candidates.begin(), Candidates.end(), - TPOC_Other, 0, FD->getLocation(), - PDiag(diag::err_function_template_spec_no_match) - << FD->getDeclName(), - PDiag(diag::err_function_template_spec_ambiguous) - << FD->getDeclName() << (ExplicitTemplateArgs != 0), - PDiag(diag::note_function_template_spec_matched)); + UnresolvedSetIterator Result = getMostSpecialized( + Candidates.begin(), Candidates.end(), FailedCandidates, TPOC_Other, 0, + FD->getLocation(), + PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(), + PDiag(diag::err_function_template_spec_ambiguous) + << FD->getDeclName() << (ExplicitTemplateArgs != 0), + PDiag(diag::note_function_template_spec_matched)); + if (Result == Candidates.end()) return true; @@ -6812,6 +6815,7 @@ // instantiated from the member definition associated with its class // template. UnresolvedSet<8> Matches; + TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc()); for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); P != PEnd; ++P) { NamedDecl *Prev = *P; @@ -6831,13 +6835,16 @@ if (!FunTmpl) continue; - TemplateDeductionInfo Info(D.getIdentifierLoc()); + TemplateDeductionInfo Info(FailedCandidates.getLocation()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK = DeduceTemplateArguments(FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : 0), R, Specialization, Info)) { - // FIXME: Keep track of almost-matches? + // Keep track of almost-matches. + FailedCandidates.addCandidate() + .set(FunTmpl->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, TDK, Info)); (void)TDK; continue; } @@ -6846,12 +6853,12 @@ } // Find the most specialized function template specialization. - UnresolvedSetIterator Result - = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, 0, - D.getIdentifierLoc(), - PDiag(diag::err_explicit_instantiation_not_known) << Name, - PDiag(diag::err_explicit_instantiation_ambiguous) << Name, - PDiag(diag::note_explicit_instantiation_candidate)); + UnresolvedSetIterator Result = getMostSpecialized( + Matches.begin(), Matches.end(), FailedCandidates, TPOC_Other, 0, + D.getIdentifierLoc(), + PDiag(diag::err_explicit_instantiation_not_known) << Name, + PDiag(diag::err_explicit_instantiation_ambiguous) << Name, + PDiag(diag::note_explicit_instantiation_candidate)); if (Result == Matches.end()) return true; Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -4148,23 +4148,18 @@ /// /// \returns the most specialized function template specialization, if /// found. Otherwise, returns SpecEnd. -/// -/// \todo FIXME: Consider passing in the "also-ran" candidates that failed -/// template argument deduction. -UnresolvedSetIterator -Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, - UnresolvedSetIterator SpecEnd, - TemplatePartialOrderingContext TPOC, - unsigned NumCallArguments, - SourceLocation Loc, - const PartialDiagnostic &NoneDiag, - const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag, - bool Complain, - QualType TargetType) { +UnresolvedSetIterator Sema::getMostSpecialized( + UnresolvedSetIterator SpecBegin, UnresolvedSetIterator SpecEnd, + TemplateSpecCandidateSet &FailedCandidates, + TemplatePartialOrderingContext TPOC, unsigned NumCallArguments, + SourceLocation Loc, const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag, + bool Complain, QualType TargetType) { if (SpecBegin == SpecEnd) { - if (Complain) + if (Complain) { Diag(Loc, NoneDiag); + FailedCandidates.NoteCandidates(*this, Loc); + } return SpecEnd; } Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -2263,15 +2263,18 @@ SmallVector Matched; SmallVector PartialSpecs; Template->getPartialSpecializations(PartialSpecs); + TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; - TemplateDeductionInfo Info(PointOfInstantiation); + TemplateDeductionInfo Info(FailedCandidates.getLocation()); if (TemplateDeductionResult Result = DeduceTemplateArguments(Partial, ClassTemplateSpec->getTemplateArgs(), Info)) { - // FIXME: Store the failed-deduction information for use in - // diagnostics, later. + // Store the failed-deduction information for use in diagnostics, later. + // TODO: Actually use the failed-deduction info? + FailedCandidates.addCandidate() + .set(Partial, MakeDeductionFailureInfo(Context, Result, Info)); (void)Result; } else { Matched.push_back(PartialSpecMatchResult()); Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp =================================================================== --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp @@ -72,7 +72,8 @@ template T gt(T t) { return t; } struct S { template constexpr T f(); // expected-warning {{C++1y}} - template T g() const; + template + T g() const; // expected-note {{candidate template ignored: could not match 'T () const' against 'char ()'}} }; // explicit specialization can differ in constepxr Index: test/CXX/expr/expr.const/p3-0x.cpp =================================================================== --- test/CXX/expr/expr.const/p3-0x.cpp +++ test/CXX/expr/expr.const/p3-0x.cpp @@ -93,7 +93,7 @@ break; } } -template int f() { return B; } +template int f() { return B; } // expected-note {{candidate template ignored: invalid explicitly-specified argument for template parameter 'B'}} template int f<&S::operator int>(); // expected-error {{does not refer to a function template}} template int f<(bool)&S::operator int>(); Index: test/CXX/over/over.over/p2.cpp =================================================================== --- test/CXX/over/over.over/p2.cpp +++ test/CXX/over/over.over/p2.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template T f0(T, T); //expected-note{{candidate}} +template +T f0(T, T); // expected-note{{candidate}} expected-note{{candidate function}} void test_f0() { int (*f0a)(int, int) = f0; Index: test/SemaCXX/addr-of-overloaded-function-casting.cpp =================================================================== --- test/SemaCXX/addr-of-overloaded-function-casting.cpp +++ test/SemaCXX/addr-of-overloaded-function-casting.cpp @@ -4,8 +4,12 @@ void f(); // expected-note 9{{candidate function}} void f(int); // expected-note 9{{candidate function}} -template void t(T); // expected-note 6{{candidate function}} -template void t(T*); // expected-note 6{{candidate function}} +template +void t(T); // expected-note 6{{candidate function}} \ + // expected-note 3{{candidate template ignored: could not match 'void' against 'int'}} +template +void t(T *); // expected-note 6{{candidate function}} \ + // expected-note 3{{candidate template ignored: could not match 'void' against 'int'}} template void u(T); Index: test/SemaCXX/cxx1y-deduced-return-type.cpp =================================================================== --- test/SemaCXX/cxx1y-deduced-return-type.cpp +++ test/SemaCXX/cxx1y-deduced-return-type.cpp @@ -112,7 +112,8 @@ int e = fwd_decl(); // expected-error {{cannot be used before it is defined}} template auto fwd_decl() { return 0; } int f = fwd_decl(); - template auto fwd_decl(); + template + auto fwd_decl(); // expected-note {{candidate template ignored: could not match 'auto ()' against 'int ()'}} int g = fwd_decl(); auto (*p)() = f1; // expected-error {{incompatible initializer}} @@ -126,7 +127,8 @@ extern template int fwd_decl(); // expected-error {{does not refer to a function template}} int k2 = fwd_decl(); - template auto instantiate() { T::error; } // expected-error {{has no members}} + template auto instantiate() { T::error; } // expected-error {{has no members}} \ + // expected-note {{candidate template ignored: could not match 'auto ()' against 'void ()'}} extern template auto instantiate(); // ok int k = instantiate(); // expected-note {{in instantiation of}} template<> auto instantiate() {} // ok @@ -157,7 +159,8 @@ double &mem_check4 = take_fn(Outer::arg_multi); namespace Deduce1 { - template auto f() { return 0; } // expected-note {{candidate}} + template auto f() { return 0; } // expected-note {{candidate}} \ + // expected-note {{candidate function has different return type ('int' expected but has 'auto')}} template void g(T(*)()); // expected-note 2{{candidate}} void h() { auto p = f; @@ -170,7 +173,8 @@ } namespace Deduce2 { - template auto f(int) { return 0; } // expected-note {{candidate}} + template auto f(int) { return 0; } // expected-note {{candidate}} \ + // expected-note {{candidate function has different return type ('int' expected but has 'auto')}} template void g(T(*)(int)); // expected-note 2{{candidate}} void h() { auto p = f; @@ -322,7 +326,8 @@ int f(); // expected-error {{functions that differ only in their return type cannot be overloaded}} decltype(auto) f(); // expected-error {{cannot be overloaded}} - template auto g(T t) { return t; } // expected-note {{candidate}} + template auto g(T t) { return t; } // expected-note {{candidate}} \ + // expected-note {{candidate function [with T = int]}} template auto g(int); template char g(char); // expected-error {{does not refer to a function}} template<> auto g(double); Index: test/SemaObjCXX/arc-nsconsumed-errors.mm =================================================================== --- test/SemaObjCXX/arc-nsconsumed-errors.mm +++ test/SemaObjCXX/arc-nsconsumed-errors.mm @@ -29,11 +29,13 @@ releaser_t r2 = releaser; // no-warning template -void templateFunction(T) {} // expected-note {{candidate function}} +void templateFunction(T) { } // expected-note {{candidate function}} \ + // expected-note {{candidate template ignored: could not match 'void (__strong id)' against 'void (id)'}} \ + // expected-note {{candidate template ignored: failed template argument deduction}} releaser_t r3 = templateFunction; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (id)'}} template -void templateReleaser(__attribute__((ns_consumed)) T) {} +void templateReleaser(__attribute__((ns_consumed)) T) { } // expected-note 2{{candidate template ignored: failed template argument deduction}} releaser_t r4 = templateReleaser; // no-warning Index: test/SemaTemplate/explicit-instantiation.cpp =================================================================== --- test/SemaTemplate/explicit-instantiation.cpp +++ test/SemaTemplate/explicit-instantiation.cpp @@ -15,9 +15,9 @@ return x + 1; // expected-error{{invalid operands}} } T* f0(T*, T*) { return T(); } // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} - - template - T f0(T, U) { return T(); } + + template T f0(T, U) { return T(); } // expected-note {{candidate template ignored: could not match 'int (int, U)' against 'int (int) const'}} \ + // expected-note {{candidate template ignored: could not match 'int' against 'int *'}} }; template @@ -59,13 +59,14 @@ template void X2::f2(int *, int *); // expected-error{{ambiguous}} - -template void print_type() { } +template +void print_type() {} // expected-note {{candidate template ignored: could not match 'void ()' against 'void (float *)'}} template void print_type(); template void print_type(); -template void print_type(T*) { } +template +void print_type(T *) {} // expected-note {{candidate template ignored: could not match 'void (int *)' against 'void (float *)'}} template void print_type(int*); template void print_type(float*); // expected-error{{does not refer}} @@ -94,7 +95,7 @@ template struct basic_streambuf{friend bob<>()}; // expected-error{{unknown type name 'bob'}} \ - // expected-error{{expected member name or ';' after declaration specifiers}} + // expected-error{{expected member name or ';' after declaration specifiers}} template struct basic_streambuf; } Index: test/SemaTemplate/function-template-specialization.cpp =================================================================== --- test/SemaTemplate/function-template-specialization.cpp +++ test/SemaTemplate/function-template-specialization.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template void f0(int (&array)[N]); +template +void f0(int (&array)[N]); // expected-note {{candidate template ignored: could not match 'int' against 'char'}} // Simple function template specialization (using overloading) template<> void f0(int (&array)[1]);