diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 37 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 6 | ||||
-rw-r--r-- | test/SemaCXX/ambig-user-defined-convesions.cpp | 11 |
4 files changed, 48 insertions, 8 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a3d15fedc3..2ae2cbe009 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -763,6 +763,8 @@ def err_ovl_ambiguous_member_call : Error< def err_ovl_deleted_member_call : Error< "call to %select{unavailable|deleted}0 member function %1">; def err_ovl_candidate : Note<"candidate function">; +def err_ovl_candidate_not_viable : Note<"function not viable because" + " of ambiguity in conversion of argument %0">; def err_ovl_template_candidate : Note< "candidate function template specialization %0">; def err_ovl_candidate_deleted : Note< diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index acfc326236..144cf93d31 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -411,13 +411,15 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, bool InOverloadResolution) { ImplicitConversionSequence ICS; OverloadCandidateSet Conversions; + OverloadingResult UserDefResult = OR_Success; if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; else if (getLangOptions().CPlusPlus && - IsUserDefinedConversion(From, ToType, ICS.UserDefined, + (UserDefResult = IsUserDefinedConversion(From, ToType, + ICS.UserDefined, Conversions, !SuppressUserConversions, AllowExplicit, - ForceRValue) == OR_Success) { + ForceRValue)) == OR_Success) { ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion; // C++ [over.ics.user]p4: // A conversion of an expression of class type to the same class @@ -454,8 +456,14 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, if (SuppressUserConversions && ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) ICS.ConversionKind = ImplicitConversionSequence::BadConversion; - } else + } else { ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + if (UserDefResult == OR_Ambiguous) { + for (OverloadCandidateSet::iterator Cand = Conversions.begin(); + Cand != Conversions.end(); ++Cand) + ICS.ConversionFunctionSet.push_back(Cand->Function); + } + } return ICS; } @@ -3868,8 +3876,27 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, *Cand->Function->getTemplateSpecializationArgs()); } else { // Normal function - // FIXME: Give a better reason! - Diag(Cand->Function->getLocation(), diag::err_ovl_candidate); + bool errReported = false; + if (!Cand->Viable && Cand->Conversions.size() > 0) { + for (int i = Cand->Conversions.size()-1; i >= 0; i--) { + const ImplicitConversionSequence &Conversion = + Cand->Conversions[i]; + if ((Conversion.ConversionKind != + ImplicitConversionSequence::BadConversion) || + Conversion.ConversionFunctionSet.size() == 0) + continue; + Diag(Cand->Function->getLocation(), + diag::err_ovl_candidate_not_viable) << (i+1); + errReported = true; + for (int j = Conversion.ConversionFunctionSet.size()-1; + j >= 0; j--) { + FunctionDecl *Func = Conversion.ConversionFunctionSet[j]; + Diag(Func->getLocation(), diag::err_ovl_candidate); + } + } + } + if (!errReported) + Diag(Cand->Function->getLocation(), diag::err_ovl_candidate); } } else if (Cand->IsSurrogate) { // Desugar the type of the surrogate down to a function type, diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 1f3e4df7cb..17f559870f 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -195,7 +195,11 @@ namespace clang { /// details of the user-defined conversion sequence. UserDefinedConversionSequence UserDefined; }; - + + /// When ConversionKind == BadConversion due to multiple conversion + /// functions, this will list those functions. + llvm::SmallVector<FunctionDecl*, 4> ConversionFunctionSet; + // The result of a comparison between implicit conversion // sequences. Use Sema::CompareImplicitConversionSequences to // actually perform the comparison. diff --git a/test/SemaCXX/ambig-user-defined-convesions.cpp b/test/SemaCXX/ambig-user-defined-convesions.cpp index d391a04d07..1117253d36 100644 --- a/test/SemaCXX/ambig-user-defined-convesions.cpp +++ b/test/SemaCXX/ambig-user-defined-convesions.cpp @@ -1,10 +1,10 @@ // RUN: clang-cc -fsyntax-only -verify %s struct BASE { - operator int &(); // expected-note {{candidate function}} + operator int &(); // expected-note 4 {{candidate function}} }; struct BASE1 { - operator int &(); // expected-note {{candidate function}} + operator int &(); // expected-note 4 {{candidate function}} }; struct B : public BASE, BASE1 { @@ -13,7 +13,14 @@ struct B : public BASE, BASE1 { extern B f(); +B b1; +void func(const int ci, const char cc); // expected-note {{function not viable because of ambiguity in conversion of argument 1}} +void func(const char ci, const B b); // expected-note {{function not viable because of ambiguity in conversion of argument 1}} +void func(const B b, const int ci); // expected-note {{function not viable because of ambiguity in conversion of argument 2}} + + const int main() { + func(b1, f()); // expected-error {{no matching function for call to 'func'}} return f(); // expected-error {{conversion from 'struct B' to 'int const' is ambiguous}} } |