diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 26 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 95 | ||||
-rw-r--r-- | test/SemaCXX/overload-call.cpp | 10 |
3 files changed, 79 insertions, 52 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d7f1f2f977..645045e84d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -895,23 +895,23 @@ def err_ovl_ambiguous_member_call : Error< "call to member function %0 is ambiguous">; def err_ovl_deleted_member_call : Error< "call to %select{unavailable|deleted}0 member function %1">; -def note_ovl_candidate : Note<"candidate function">; +def note_ovl_candidate : Note<"candidate " + "%select{function|function|constructor|" + "is the implicit default constructor|" + "is the implicit copy constructor|" + "is the implicit copy assignment operator}0">; +def note_ovl_template_candidate : Note< + "candidate function template specialization %0">; +def note_ovl_candidate_deleted : Note< + "candidate %select{function|function|constructor}0 has been explicitly " + "%select{made unavailable|deleted}1">; +def note_ovl_template_candidate_deleted : Note< + "candidate function template specialization %0 has been explicit " + "&select{made unavailable|deleted}1">; def note_ovl_candidate_not_viable : Note<"function not viable because" " of ambiguity in conversion of argument %0">; -def note_ovl_candidate_ctor : Note<"candidate constructor">; -def note_ovl_candidate_implicit_copy_ctor : Note< - "candidate is the implicit copy constructor">; -def note_ovl_candidate_implicit_default_ctor : Note< - "candidate is the implicit default constructor">; -def note_ovl_candidate_meth : Note<"candidate function">; -def note_ovl_candidate_implicit_copy_assign : Note< - "candidate is the implicit copy assignment operator">; def note_ambiguous_type_conversion: Note< "because of ambiguity in conversion of %0 to %1">; -def note_ovl_template_candidate : Note< - "candidate function template specialization %0">; -def note_ovl_candidate_deleted : Note< - "candidate function has been explicitly %select{made unavailable|deleted}0">; def note_ovl_builtin_binary_candidate : Note< "built-in candidate %0">; def note_ovl_builtin_unary_candidate : Note< diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index a7d4f372d1..26f8c8edda 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4263,42 +4263,62 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, return OR_Success; } -/// Notes the location of an overload candidate. -void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { +namespace { - if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { - // At least call it a 'constructor'. - if (!Ctor->isImplicit()) { - Diag(Ctor->getLocation(), diag::note_ovl_candidate_ctor); - return; - } +enum OverloadCandidateKind { + oc_function, + oc_method, + oc_constructor, + oc_implicit_default_constructor, + oc_implicit_copy_constructor, + oc_implicit_copy_assignment, + oc_template_specialization // function, constructor, or conversion template +}; - CXXRecordDecl *Record = Ctor->getParent(); - if (Ctor->isCopyConstructor()) { - Diag(Record->getLocation(), diag::note_ovl_candidate_implicit_copy_ctor); - return; - } +OverloadCandidateKind ClassifyOverloadCandidate(FunctionDecl *Fn) { + if (Fn->getPrimaryTemplate()) + return oc_template_specialization; - Diag(Record->getLocation(), diag::note_ovl_candidate_implicit_default_ctor); - return; + if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { + if (!Ctor->isImplicit()) + return oc_constructor; + + return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor + : oc_implicit_default_constructor; } if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) { // This actually gets spelled 'candidate function' for now, but // it doesn't hurt to split it out. - if (!Meth->isImplicit()) { - Diag(Meth->getLocation(), diag::note_ovl_candidate_meth); - return; - } + if (!Meth->isImplicit()) + return oc_method; assert(Meth->isCopyAssignment() && "implicit method is not copy assignment operator?"); - Diag(Meth->getParent()->getLocation(), - diag::note_ovl_candidate_implicit_copy_assign); + return oc_implicit_copy_assignment; + } + + return oc_function; +} + +std::string DescribeFunctionTemplate(Sema &S, FunctionDecl *Fn) { + FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate(); + return S.getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(), + *Fn->getTemplateSpecializationArgs()); +} + +} // end anonymous namespace + +// Notes the location of an overload candidate. +void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { + OverloadCandidateKind K = ClassifyOverloadCandidate(Fn); + if (K == oc_template_specialization) { + Diag(Fn->getLocation(), diag::note_ovl_template_candidate) + << DescribeFunctionTemplate(*this, Fn); return; } - Diag(Fn->getLocation(), diag::note_ovl_candidate); + Diag(Fn->getLocation(), diag::note_ovl_candidate) << (unsigned) K; } /// Diagnoses an ambiguous conversion. The partial diagnostic is the @@ -4318,26 +4338,23 @@ void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, namespace { void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand) { + FunctionDecl *Fn = Cand->Function; + // Note deleted candidates, but only if they're viable. - if (Cand->Viable && - (Cand->Function->isDeleted() || - Cand->Function->hasAttr<UnavailableAttr>())) { - S.Diag(Cand->Function->getLocation(), diag::note_ovl_candidate_deleted) - << Cand->Function->isDeleted(); - return; - } + if (Cand->Viable && (Fn->isDeleted() || Fn->hasAttr<UnavailableAttr>())) { + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(Fn); + + if (FnKind == oc_template_specialization) { + S.Diag(Fn->getLocation(), diag::note_ovl_template_candidate_deleted) + << DescribeFunctionTemplate(S, Fn) << Fn->isDeleted(); + return; + } - if (FunctionTemplateDecl *FunTmpl - = Cand->Function->getPrimaryTemplate()) { - // Function template specialization - // FIXME: Give a better reason! - S.Diag(Cand->Function->getLocation(), diag::note_ovl_template_candidate) - << S.getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(), - *Cand->Function->getTemplateSpecializationArgs()); + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) + << FnKind << Fn->isDeleted(); return; } - // Normal function bool errReported = false; if (!Cand->Viable && Cand->Conversions.size() > 0) { for (int i = Cand->Conversions.size()-1; i >= 0; i--) { @@ -4347,14 +4364,14 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand) { if (!Conversion.isAmbiguous()) continue; - S.DiagnoseAmbiguousConversion(Conversion, Cand->Function->getLocation(), + S.DiagnoseAmbiguousConversion(Conversion, Fn->getLocation(), PDiag(diag::note_ovl_candidate_not_viable) << (i+1)); errReported = true; } } if (!errReported) - S.NoteOverloadCandidate(Cand->Function); + S.NoteOverloadCandidate(Fn); } void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp index 299c0a78f9..42bf029bd0 100644 --- a/test/SemaCXX/overload-call.cpp +++ b/test/SemaCXX/overload-call.cpp @@ -301,3 +301,13 @@ namespace PR5756 { (void)ir; } } + +// Tests the exact text used to note the candidates +namespace test1 { + template <class T> void foo(T t, unsigned N); // expected-note {{candidate function template specialization [with T = int]}} + void foo(int n, char N); // expected-note {{candidate function}} + + void test() { + foo(4, "hello"); //expected-error {{no matching function for call to 'foo'}} + } +} |