aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRichard Trieu <rtrieu@google.com>2011-11-23 22:32:32 +0000
committerRichard Trieu <rtrieu@google.com>2011-11-23 22:32:32 +0000
commit6efd4c55a1a481d92966a91141c03e8145234cf6 (patch)
tree3f834b6ba75ad2d04af5284aa2d1462860096408 /lib
parentbcf8df8a998b6ae01a217cdf2e3f70128ccb44ef (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.cpp9
-rw-r--r--lib/Sema/SemaInit.cpp4
-rw-r--r--lib/Sema/SemaOverload.cpp135
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp14
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;
}