diff options
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 149 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 63 | ||||
-rw-r--r-- | test/SemaCXX/overload-call.cpp | 10 | ||||
-rw-r--r-- | test/SemaCXX/overload-member-call.cpp | 19 |
6 files changed, 184 insertions, 65 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e10398af85..edeb7c13e1 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4389,7 +4389,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); // Most paths end in a failed conversion. - if (ICS) ICS->setBad(); + if (ICS) { + ICS->setBad(); + ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType); + } // C++ [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d6947986a4..d10e11fdb4 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1076,6 +1076,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, bool Elidable, ImplicitConversionSequence& ICS) { ICS.setBad(); + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); if (Elidable && getLangOptions().CPlusPlus0x) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, @@ -1942,7 +1943,7 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { ImplicitConversionSequence E1ToC2, E2ToC2; E1ToC2.setBad(); - E2ToC2.setBad(); + E2ToC2.setBad(); if (Context.getCanonicalType(Composite1) != Context.getCanonicalType(Composite2)) { E1ToC2 = TryImplicitConversion(E1, Composite2, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 4f299ff5b0..ffcf8d4609 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -489,8 +489,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or // 13.3.1.6 in all cases, only standard conversion sequences and // ellipsis conversion sequences are allowed. - if (SuppressUserConversions && ICS.isUserDefined()) + if (SuppressUserConversions && ICS.isUserDefined()) { ICS.setBad(); + ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType); + } } else if (UserDefResult == OR_Ambiguous) { ICS.setAmbiguous(); ICS.Ambiguous.setFromType(From->getType()); @@ -501,6 +503,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, ICS.Ambiguous.addConversion(Cand->Function); } else { ICS.setBad(); + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); } return ICS; @@ -2129,6 +2132,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType, bool InOverloadResolution) { if (ToType->isReferenceType()) { ImplicitConversionSequence ICS; + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); CheckReferenceInit(From, ToType, /*FIXME:*/From->getLocStart(), SuppressUserConversions, @@ -2223,8 +2227,10 @@ Sema::TryObjectArgumentInitialization(QualType FromType, QualType FromTypeCanon = Context.getCanonicalType(FromType); if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && - !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) + !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { + ICS.Bad.init(BadConversionSequence::bad_qualifiers, FromType, ImplicitParamType); return ICS; + } // Check that we have either the same type or a derived type. It // affects the conversion rank. @@ -2233,8 +2239,10 @@ Sema::TryObjectArgumentInitialization(QualType FromType, ICS.Standard.Second = ICK_Identity; else if (IsDerivedFrom(FromType, ClassType)) ICS.Standard.Second = ICK_Derived_To_Base; - else + else { + ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType); return ICS; + } // Success. Mark this as a reference binding. ICS.setStandard(); @@ -2385,6 +2393,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2397,6 +2406,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if (NumArgs < MinRequiredArgs && !PartialOverloading) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2416,6 +2426,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } else { @@ -2532,6 +2543,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, // list (8.3.5). if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2544,6 +2556,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, if (NumArgs < MinRequiredArgs) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2560,6 +2573,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, = TryObjectArgumentInitialization(ObjectType, Method, ActingContext); if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } } @@ -2579,6 +2593,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } else { @@ -2670,6 +2685,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, OverloadCandidate &Candidate = CandidateSet.back(); Candidate.Function = FunctionTemplate->getTemplatedDecl(); Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; return; @@ -2726,6 +2742,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.Conversions[0].Standard.Second = ICK_Identity; if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } @@ -2737,6 +2754,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } @@ -2774,6 +2792,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, case ImplicitConversionSequence::BadConversion: Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; default: @@ -2847,6 +2866,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, = TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext); if (ObjectInit.isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } @@ -2869,6 +2889,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // list (8.3.5). if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2877,6 +2898,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, if (NumArgs < NumArgsInProto) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2896,6 +2918,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, /*InOverloadResolution=*/false); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } else { @@ -3038,6 +3061,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, } if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } @@ -4336,36 +4360,69 @@ void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, namespace { -void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I, - Expr **Args, unsigned NumArgs) { +void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { + const ImplicitConversionSequence &Conv = Cand->Conversions[I]; + assert(Conv.isBad()); assert(Cand->Function && "for now, candidate must be a function"); FunctionDecl *Fn = Cand->Function; // There's a conversion slot for the object argument if this is a // non-constructor method. Note that 'I' corresponds the // conversion-slot index. + bool isObjectArgument = false; if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) { - // FIXME: talk usefully about bad conversions for object arguments. - if (I == 0) return S.NoteOverloadCandidate(Fn); - else I--; + if (I == 0) + isObjectArgument = true; + else + I--; } - // FIXME: can we have a bad conversion on an ellipsis parameter? - assert(I < NumArgs && "index exceeds number of formal arguments"); - assert(I < Fn->getType()->getAs<FunctionProtoType>()->getNumArgs() && - "index exceeds number of formal parameters"); - std::string FnDesc; OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); - QualType FromTy = Args[I]->getType(); - QualType ToTy = Fn->getType()->getAs<FunctionProtoType>()->getArgType(I); + Expr *FromExpr = Conv.Bad.FromExpr; + QualType FromTy = Conv.Bad.getFromType(); + QualType ToTy = Conv.Bad.getToType(); // TODO: specialize based on the kind of mismatch S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) << (unsigned) FnKind << FnDesc - << Args[I]->getSourceRange() << FromTy << ToTy - << I+1; + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << I+1; +} + +void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, + unsigned NumFormalArgs) { + // TODO: treat calls to a missing default constructor as a special case + + FunctionDecl *Fn = Cand->Function; + const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>(); + + unsigned MinParams = Fn->getMinRequiredArguments(); + + // at least / at most / exactly + unsigned mode, modeCount; + if (NumFormalArgs < MinParams) { + assert(Cand->FailureKind == ovl_fail_too_few_arguments); + if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic()) + mode = 0; // "at least" + else + mode = 2; // "exactly" + modeCount = MinParams; + } else { + assert(Cand->FailureKind == ovl_fail_too_many_arguments); + if (MinParams != FnTy->getNumArgs()) + mode = 1; // "at most" + else + mode = 2; // "exactly" + modeCount = FnTy->getNumArgs(); + } + + std::string Description; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) + << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs; } void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, @@ -4388,52 +4445,24 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, return; } - // Diagnose arity mismatches. - // TODO: treat calls to a missing default constructor as a special case - unsigned NumFormalArgs = NumArgs; - if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) - NumFormalArgs--; - const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>(); - unsigned MinParams = Fn->getMinRequiredArguments(); - if (NumFormalArgs < MinParams || - (NumFormalArgs > FnTy->getNumArgs() && !FnTy->isVariadic())) { - std::string Description; - OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); - - // at least / at most / exactly - unsigned mode, modeCount; - if (NumFormalArgs < MinParams) { - if (MinParams != FnTy->getNumArgs()) - mode = 0; // "at least" - else - mode = 2; // "exactly" - modeCount = MinParams; - } else { - if (MinParams != FnTy->getNumArgs()) - mode = 1; // "at most" - else - mode = 2; // "exactly" - modeCount = FnTy->getNumArgs(); - } + switch (Cand->FailureKind) { + case ovl_fail_too_many_arguments: + case ovl_fail_too_few_arguments: + return DiagnoseArityMismatch(S, Cand, NumArgs); - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) - << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs; - return; - } - - // Look for bad conversions. - if (!Cand->Conversions.empty()) { - for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I) { - if (!Cand->Conversions[I].isBad()) - continue; + case ovl_fail_bad_deduction: + return S.NoteOverloadCandidate(Fn); - DiagnoseBadConversion(S, Cand, I, Args, NumArgs); - return; - } + case ovl_fail_bad_conversion: + for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I) + if (Cand->Conversions[I].isBad()) + return DiagnoseBadConversion(S, Cand, I); + + // FIXME: this currently happens when we're called from SemaInit + // when user-conversion overload fails. Figure out how to handle + // those conditions and diagnose them well. + return S.NoteOverloadCandidate(Fn); } - - // Give up and give the generic message. - S.NoteOverloadCandidate(Fn); } void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 78fa05b24c..20add007f7 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_SEMA_OVERLOAD_H #include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -241,6 +242,51 @@ namespace clang { void copyFrom(const AmbiguousConversionSequence &); }; + /// BadConversionSequence - Records information about an invalid + /// conversion sequence. + struct BadConversionSequence { + enum FailureKind { + no_conversion, + unrelated_class, + suppressed_user, + bad_qualifiers + }; + + // This can be null, e.g. for implicit object arguments. + Expr *FromExpr; + + FailureKind Kind; + + private: + // The type we're converting from (an opaque QualType). + void *FromTy; + + // The type we're converting to (an opaque QualType). + void *ToTy; + + public: + void init(FailureKind K, Expr *From, QualType To) { + init(K, From->getType(), To); + FromExpr = From; + } + void init(FailureKind K, QualType From, QualType To) { + Kind = K; + FromExpr = 0; + setFromType(From); + setToType(To); + } + + QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); } + QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); } + + void setFromExpr(Expr *E) { + FromExpr = E; + setFromType(E->getType()); + } + void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); } + }; + /// ImplicitConversionSequence - Represents an implicit conversion /// sequence, which may be a standard conversion sequence /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), @@ -280,6 +326,10 @@ namespace clang { /// When ConversionKind == AmbiguousConversion, provides the /// details of the ambiguous conversion. AmbiguousConversionSequence Ambiguous; + + /// When ConversionKind == BadConversion, provides the details + /// of the bad conversion. + BadConversionSequence Bad; }; ImplicitConversionSequence() : ConversionKind(BadConversion) {} @@ -294,7 +344,7 @@ namespace clang { case UserDefinedConversion: UserDefined = Other.UserDefined; break; case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; case EllipsisConversion: break; - case BadConversion: break; + case BadConversion: Bad = Other.Bad; break; } } @@ -336,6 +386,13 @@ namespace clang { void DebugPrint() const; }; + enum OverloadFailureKind { + ovl_fail_too_many_arguments, + ovl_fail_too_few_arguments, + ovl_fail_bad_conversion, + ovl_fail_bad_deduction + }; + /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). struct OverloadCandidate { /// Function - The actual function that this candidate @@ -376,6 +433,10 @@ namespace clang { /// object argument. bool IgnoreObjectArgument; + /// FailureKind - The reason why this candidate is not viable. + /// Actually an OverloadFailureKind. + unsigned char FailureKind; + /// 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 diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp index fbd26b2fd8..0a2508d4b8 100644 --- a/test/SemaCXX/overload-call.cpp +++ b/test/SemaCXX/overload-call.cpp @@ -304,10 +304,16 @@ namespace PR5756 { // Tests the exact text used to note the candidates namespace test1 { - template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int]}} - void foo(int n, char N); // expected-note {{candidate function}} + template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'char const [6]' to 'unsigned int' for argument 2}} + void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'char const [6]' to 'char' for argument 2}} + void foo(int n); // expected-note {{candidate function not viable: requires 1 argument, but 2 were provided}} + void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most 1 argument, but 2 were provided}} + void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}} + void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} + void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} void test() { foo(4, "hello"); //expected-error {{no matching function for call to 'foo'}} } } + diff --git a/test/SemaCXX/overload-member-call.cpp b/test/SemaCXX/overload-member-call.cpp index 4bb3ff3a54..8eb189850b 100644 --- a/test/SemaCXX/overload-member-call.cpp +++ b/test/SemaCXX/overload-member-call.cpp @@ -66,3 +66,22 @@ void test_X2(X2 *x2p, const X2 *cx2p) { int &ir = x2p->member(); float &fr = cx2p->member(); } + +// Tests the exact text used to note the candidates +namespace test1 { + class A { + template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'char const [6]' to 'unsigned int' for argument 2}} + void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'char const [6]' to 'char' for argument 2}} + void foo(int n); // expected-note {{candidate function not viable: requires 1 argument, but 2 were provided}} + void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most 1 argument, but 2 were provided}} + void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}} + void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} + void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} + }; + + void test() { + A a; + a.foo(4, "hello"); //expected-error {{no matching member function for call to 'foo'}} + } +} + |