diff options
author | Richard Trieu <rtrieu@google.com> | 2011-11-23 22:32:32 +0000 |
---|---|---|
committer | Richard Trieu <rtrieu@google.com> | 2011-11-23 22:32:32 +0000 |
commit | 6efd4c55a1a481d92966a91141c03e8145234cf6 (patch) | |
tree | 3f834b6ba75ad2d04af5284aa2d1462860096408 /lib | |
parent | bcf8df8a998b6ae01a217cdf2e3f70128ccb44ef (diff) |
Add feature to diagnostics that will provide more information on function
pointer mismatch. Cases covered are: initialization, assignment, and function
arguments. Additional text will give the extra information about the nature
of the mismatch: different classes for member functions, wrong number of
parameters, different parameter type, different return type, and function
qualifier mismatch.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145114 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 135 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 14 |
4 files changed, 143 insertions, 19 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ba9dbedd8d..ef9d787fe4 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9028,6 +9028,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, FixItHint Hint; ConversionFixItGenerator ConvHints; bool MayHaveConvFixit = false; + bool MayHaveFunctionDiff = false; switch (ConvTy) { default: llvm_unreachable("Unknown conversion type"); @@ -9117,6 +9118,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; isInvalid = true; + MayHaveFunctionDiff = true; break; } @@ -9155,8 +9157,15 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, } if (MayHaveConvFixit) { FDiag << (unsigned) (ConvHints.Kind); } + if (MayHaveFunctionDiff) + HandleFunctionTypeMismatch(FDiag, SecondType, FirstType); + Diag(Loc, FDiag); + if (SecondType == Context.OverloadTy) + NoteAllOverloadCandidates(OverloadExpr::find(SrcExpr).Expression, + FirstType); + if (CheckInferredResultType) EmitRelatedResultTypeNote(SrcExpr); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 85cb76f8a0..9480f63712 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -5118,12 +5118,14 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_ConversionFailed: { QualType FromType = Args[0]->getType(); - S.Diag(Kind.getLocation(), diag::err_init_conversion_failed) + PartialDiagnostic PDiag = S.PDiag(diag::err_init_conversion_failed) << (int)Entity.getKind() << DestType << Args[0]->isLValue() << FromType << Args[0]->getSourceRange(); + S.HandleFunctionTypeMismatch(PDiag, FromType, DestType); + S.Diag(Kind.getLocation(), PDiag); if (DestType.getNonReferenceType()->isObjCObjectPointerType() && Args[0]->getType()->isObjCObjectPointerType()) S.EmitRelatedResultTypeNote(Args[0]); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 11b10a581a..9b605c9319 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2163,22 +2163,126 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType, return true; } +enum { + ft_default, + ft_different_class, + ft_parameter_arity, + ft_parameter_mismatch, + ft_return_type, + ft_qualifer_mismatch +}; + +/// HandleFunctionTypeMismatch - Gives diagnostic information for differeing +/// function types. Catches different number of parameter, mismatch in +/// parameter types, and different return types. +void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, + QualType FromType, QualType ToType) { + // Get the function type from the pointers. + if (FromType->isMemberPointerType() && ToType->isMemberPointerType()) { + const MemberPointerType *FromMember = FromType->getAs<MemberPointerType>(), + *ToMember = ToType->getAs<MemberPointerType>(); + if (FromMember->getClass() != ToMember->getClass()) { + PDiag << ft_different_class << QualType(ToMember->getClass(), 0) + << QualType(FromMember->getClass(), 0); + return; + } + FromType = FromMember->getPointeeType(); + ToType = ToMember->getPointeeType(); + } else if (FromType->isPointerType() && ToType->isPointerType()) { + FromType = FromType->getPointeeType(); + ToType = ToType->getPointeeType(); + } else { + PDiag << ft_default; + return; + } + + FromType = FromType.getNonReferenceType(); + ToType = ToType.getNonReferenceType(); + + // If either type is not valid, of the types are the same, no extra info. + if (FromType.isNull() || ToType.isNull() || + Context.hasSameType(FromType, ToType)) { + PDiag << ft_default; + return; + } + + // Don't print extra info for non-specialized template functions. + if (FromType->isInstantiationDependentType() && + !FromType->getAs<TemplateSpecializationType>()) { + PDiag << ft_default; + return; + } + + const FunctionProtoType *FromFunction = FromType->getAs<FunctionProtoType>(), + *ToFunction = ToType->getAs<FunctionProtoType>(); + + // Both types need to be function types. + if (!FromFunction || !ToFunction) { + PDiag << ft_default; + return; + } + + if (FromFunction->getNumArgs() != ToFunction->getNumArgs()) { + PDiag << ft_parameter_arity << ToFunction->getNumArgs() + << FromFunction->getNumArgs(); + return; + } + + // Handle different parameter types. + unsigned ArgPos; + if (!FunctionArgTypesAreEqual(FromFunction, ToFunction, &ArgPos)) { + PDiag << ft_parameter_mismatch << ArgPos + 1 + << ToFunction->getArgType(ArgPos) + << FromFunction->getArgType(ArgPos); + return; + } + + // Handle different return type. + if (!Context.hasSameType(FromFunction->getResultType(), + ToFunction->getResultType())) { + PDiag << ft_return_type << ToFunction->getResultType() + << FromFunction->getResultType(); + return; + } + + unsigned FromQuals = FromFunction->getTypeQuals(), + ToQuals = ToFunction->getTypeQuals(); + if (FromQuals != ToQuals) { + PDiag << ft_qualifer_mismatch << ToQuals << FromQuals; + return; + } + + // Unable to find a difference, so add no extra info. + PDiag << ft_default; +} + /// FunctionArgTypesAreEqual - This routine checks two function proto types /// for equlity of their argument types. Caller has already checked that /// they have same number of arguments. This routine assumes that Objective-C /// pointer types which only differ in their protocol qualifiers are equal. +/// If the parameters are different, ArgPos will have the the parameter index +/// of the first different parameter. bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType, - const FunctionProtoType *NewType) { - if (!getLangOptions().ObjC1) - return std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), - NewType->arg_type_begin()); + const FunctionProtoType *NewType, + unsigned *ArgPos) { + if (!getLangOptions().ObjC1) { + for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(), + N = NewType->arg_type_begin(), + E = OldType->arg_type_end(); O && (O != E); ++O, ++N) { + if (!Context.hasSameType(*O, *N)) { + if (ArgPos) *ArgPos = O - OldType->arg_type_begin(); + return false; + } + } + return true; + } for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(), N = NewType->arg_type_begin(), E = OldType->arg_type_end(); O && (O != E); ++O, ++N) { QualType ToType = (*O); QualType FromType = (*N); - if (ToType != FromType) { + if (!Context.hasSameType(ToType, FromType)) { if (const PointerType *PTTo = ToType->getAs<PointerType>()) { if (const PointerType *PTFr = FromType->getAs<PointerType>()) if ((PTTo->getPointeeType()->isObjCQualifiedIdType() && @@ -2194,6 +2298,7 @@ bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType, if (PTTo->getInterfaceDecl() == PTFr->getInterfaceDecl()) continue; } + if (ArgPos) *ArgPos = O - OldType->arg_type_begin(); return false; } } @@ -7015,17 +7120,19 @@ void MaybeEmitInheritedConstructorNote(Sema &S, FunctionDecl *Fn) { } // end anonymous namespace // Notes the location of an overload candidate. -void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { +void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType) { std::string FnDesc; OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc); - Diag(Fn->getLocation(), diag::note_ovl_candidate) - << (unsigned) K << FnDesc; + PartialDiagnostic PD = PDiag(diag::note_ovl_candidate) + << (unsigned) K << FnDesc; + HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); + Diag(Fn->getLocation(), PD); MaybeEmitInheritedConstructorNote(*this, Fn); } //Notes the location of all overload candidates designated through // OverloadedExpr -void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr) { +void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr, QualType DestType) { assert(OverloadedExpr->getType() == Context.OverloadTy); OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr); @@ -7036,10 +7143,10 @@ void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr) { I != IEnd; ++I) { if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(FunTmpl->getTemplatedDecl()); + NoteOverloadCandidate(FunTmpl->getTemplatedDecl(), DestType); } else if (FunctionDecl *Fun = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(Fun); + NoteOverloadCandidate(Fun, DestType); } } } @@ -8132,7 +8239,7 @@ private: << Matches[0].second->getDeclName(), S.PDiag(diag::note_ovl_candidate) << (unsigned) oc_function_template, - Complain); + Complain, TargetFunctionType); if (Result != MatchesCopy.end()) { // Make it the first and only element @@ -8161,7 +8268,7 @@ public: S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_no_viable) << OvlExpr->getName() << TargetFunctionType << OvlExpr->getSourceRange(); - S.NoteAllOverloadCandidates(OvlExpr); + S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType); } bool IsInvalidFormOfPointerToMemberFunction() const { @@ -8187,7 +8294,7 @@ public: S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_ambiguous) << OvlExpr->getName() << OvlExpr->getSourceRange(); - S.NoteAllOverloadCandidates(OvlExpr); + S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType); } bool hadMultipleCandidates() const { return (OvlExpr->getNumDecls() > 1); } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 17987da16a..28f489a43b 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -3783,7 +3783,8 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag, - bool Complain) { + bool Complain, + QualType TargetType) { if (SpecBegin == SpecEnd) { if (Complain) Diag(Loc, NoneDiag); @@ -3837,11 +3838,16 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, if (Complain) // FIXME: Can we order the candidates in some sane way? - for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) - Diag((*I)->getLocation(), CandidateDiag) - << getTemplateArgumentBindingsText( + for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) { + PartialDiagnostic PD = CandidateDiag; + PD << getTemplateArgumentBindingsText( cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(), *cast<FunctionDecl>(*I)->getTemplateSpecializationArgs()); + if (!TargetType.isNull()) + HandleFunctionTypeMismatch(PD, cast<FunctionDecl>(*I)->getType(), + TargetType); + Diag((*I)->getLocation(), PD); + } return SpecEnd; } |