diff options
author | John McCall <rjmccall@apple.com> | 2010-01-13 09:16:55 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-01-13 09:16:55 +0000 |
commit | adbb8f8aa44216d30d204e843c4a74abab929dae (patch) | |
tree | 52a11a4600c35d7f7970ae77e432df0c27e1c0ad /lib/Sema/SemaOverload.cpp | |
parent | a6c058dd75c5563cced821fc16766a7cc179e00c (diff) |
Record some basic information about bad conversion sequences. Use that
information to feed diagnostics instead of regenerating it. Much room for
improvement here, but fixes some unfortunate problems reporting on method calls.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93316 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 149 |
1 files changed, 89 insertions, 60 deletions
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) { |