diff options
-rw-r--r-- | include/clang/Basic/DiagnosticGroups.td | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/Sema/SemaCast.cpp | 39 | ||||
-rw-r--r-- | test/Sema/warn-bad-function-cast.c | 47 |
4 files changed, 91 insertions, 2 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index d8632dd8c3..e5b5dc99da 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -157,6 +157,7 @@ def OverlengthStrings : DiagGroup<"overlength-strings">; def OverloadedVirtual : DiagGroup<"overloaded-virtual">; def PrivateExtern : DiagGroup<"private-extern">; def SelTypeCast : DiagGroup<"cast-of-sel-type">; +def BadFunctionCast : DiagGroup<"bad-function-cast">; def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">; def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">; def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">; @@ -377,7 +378,8 @@ def Most : DiagGroup<"most", [ ObjCMissingSuperCalls, OverloadedVirtual, PrivateExtern, - SelTypeCast + SelTypeCast, + BadFunctionCast ]>; // Thread Safety warnings diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2d63dc42fd..c00c9a8150 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4968,6 +4968,9 @@ def err_cast_pointer_from_non_pointer_int : Error< def warn_cast_pointer_from_sel : Warning< "cast of type %0 to %1 is deprecated; use sel_getName instead">, InGroup<SelTypeCast>; +def warn_bad_function_cast : Warning< + "cast from function call of type %0 to non-matching type %1">, + InGroup<BadFunctionCast>, DefaultIgnore; def err_cast_pointer_to_non_pointer_int : Error< "pointer cannot be cast to type %0">; def err_typecheck_expect_scalar_operand : Error< diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index d8d51e77ee..6c513b9669 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1903,6 +1903,43 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, SrcExpr = ExprError(); } +/// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a +/// non-matching type. Such as enum function call to int, int call to +/// pointer; etc. Cast to 'void' is an exception. +static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr, + QualType DestType) { + if (Self.Diags.getDiagnosticLevel(diag::warn_bad_function_cast, + SrcExpr.get()->getExprLoc()) + == DiagnosticsEngine::Ignored) + return; + + if (!isa<CallExpr>(SrcExpr.get())) + return; + + QualType SrcType = SrcExpr.get()->getType(); + if (DestType.getUnqualifiedType()->isVoidType()) + return; + if ((SrcType->isAnyPointerType() || SrcType->isBlockPointerType()) + && (DestType->isAnyPointerType() || DestType->isBlockPointerType())) + return; + if (SrcType->isIntegerType() && DestType->isIntegerType() && + (SrcType->isBooleanType() == DestType->isBooleanType()) && + (SrcType->isEnumeralType() == DestType->isEnumeralType())) + return; + if (SrcType->isRealFloatingType() && DestType->isRealFloatingType()) + return; + if (SrcType->isEnumeralType() && DestType->isEnumeralType()) + return; + if (SrcType->isComplexType() && DestType->isComplexType()) + return; + if (SrcType->isComplexIntegerType() && DestType->isComplexIntegerType()) + return; + + Self.Diag(SrcExpr.get()->getExprLoc(), + diag::warn_bad_function_cast) + << SrcType << DestType << SrcExpr.get()->getSourceRange(); +} + /// Check the semantics of a C-style cast operation, in C. void CastOperation::CheckCStyleCast() { assert(!Self.getLangOpts().CPlusPlus); @@ -2076,7 +2113,7 @@ void CastOperation::CheckCStyleCast() { } } DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); - + DiagnoseBadFunctionCast(Self, SrcExpr, DestType); Kind = Self.PrepareScalarCast(SrcExpr, DestType); if (SrcExpr.isInvalid()) return; diff --git a/test/Sema/warn-bad-function-cast.c b/test/Sema/warn-bad-function-cast.c new file mode 100644 index 0000000000..1928e2ae46 --- /dev/null +++ b/test/Sema/warn-bad-function-cast.c @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wbad-function-cast -verify +// rdar://9103192 + +void vf(void); +int if1(void); +char if2(void); +long if3(void); +float rf1(void); +double rf2(void); +_Complex double cf(void); +enum e { E1 } ef(void); +_Bool bf(void); +char *pf1(void); +int *pf2(void); + +void +foo(void) +{ + /* Casts to void types are always OK. */ + (void)vf(); + (void)if1(); + (void)cf(); + (const void)bf(); + /* Casts to the same type or similar types are OK. */ + (int)if1(); + (long)if2(); + (char)if3(); + (float)rf1(); + (long double)rf2(); + (_Complex float)cf(); + (enum f { F1 })ef(); + (_Bool)bf(); + (void *)pf1(); + (char *)pf2(); + /* All following casts issue warning */ + (float)if1(); /* expected-warning {{cast from function call of type 'int' to non-matching type 'float'}} */ + (double)if2(); /* expected-warning {{cast from function call of type 'char' to non-matching type 'double'}} */ + (_Bool)if3(); /* expected-warning {{cast from function call of type 'long' to non-matching type '_Bool'}} */ + (int)rf1(); /* expected-warning {{cast from function call of type 'float' to non-matching type 'int'}} */ + (long)rf2(); /* expected-warning {{cast from function call of type 'double' to non-matching type 'long'}} */ + (double)cf(); /* expected-warning {{cast from function call of type '_Complex double' to non-matching type 'double'}} */ + (int)ef(); /* expected-warning {{cast from function call of type 'enum e' to non-matching type 'int'}} */ + (int)bf(); /* expected-warning {{cast from function call of type '_Bool' to non-matching type 'int'}} */ + (__SIZE_TYPE__)pf1(); /* expected-warning {{cast from function call of type 'char *' to non-matching type 'unsigned long'}} */ + (__PTRDIFF_TYPE__)pf2(); /* expected-warning {{cast from function call of type 'int *' to non-matching type 'long'}} */ +} + |