rnk created this revision. rnk added reviewers: thakis, rtrieu. rnk added a subscriber: cfe-commits.
This only warns on casts of the address of a function defined in the current TU. In this case, the fix is likely to be local and the warning useful. Here are some things we could experiment with in the future: - Fire on declarations as well as definitions - Limit the warning to non-void function prototypes - Limit the warning to mismatches of caller and callee cleanup CCs This warning is currently off by default while we study its usefulness. http://reviews.llvm.org/D17348 Files: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaCast.cpp test/Sema/callingconv-cast.c
Index: test/Sema/callingconv-cast.c =================================================================== --- /dev/null +++ test/Sema/callingconv-cast.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -verify -triple i686-pc-windows-msvc -Wcast-calling-convention -x c %s +// RUN: %clang_cc1 -verify -triple i686-pc-windows-msvc -Wcast-calling-convention -x c++ %s + +// expected-note@+1 2 {{consider defining 'mismatched' with the 'stdcall' calling convention}} +void mismatched(int x) {} + +typedef void (__stdcall *callback_t)(int); +void take_callback(callback_t callback); + +int main() { + // expected-warning@+1 {{cast between incompatible calling conventions 'cdecl' and 'stdcall'}} + take_callback((callback_t)mismatched); + + // expected-warning@+1 {{cast between incompatible calling conventions 'cdecl' and 'stdcall'}} + callback_t callback = (callback_t)mismatched; // warns + (void)callback; + + // Probably a bug, but we don't warn. + void (*callback2)(int) = mismatched; + take_callback((callback_t)callback2); + + // Another way to suppress the warning. + take_callback((callback_t)(void*)mismatched); +} Index: lib/Sema/SemaCast.cpp =================================================================== --- lib/Sema/SemaCast.cpp +++ lib/Sema/SemaCast.cpp @@ -1724,6 +1724,57 @@ } } +/// Diagnose casts that change the calling convention of a pointer to a function +/// defined in the current TU. +static void diagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr, + QualType DstType, SourceRange OpRange) { + if (Self.Diags.isIgnored(diag::warn_cast_calling_conv, OpRange.getBegin())) + return; + + // Check if this cast would change the calling convention of a function + // pointer type. + QualType SrcType = SrcExpr.get()->getType(); + if (Self.Context.hasSameType(SrcType, DstType) || + !SrcType->isFunctionPointerType() || !DstType->isFunctionPointerType()) + return; + const auto *SrcFTy = + SrcType->castAs<PointerType>()->getPointeeType()->castAs<FunctionType>(); + const auto *DstFTy = + DstType->castAs<PointerType>()->getPointeeType()->castAs<FunctionType>(); + CallingConv SrcCC = SrcFTy->getCallConv(); + CallingConv DstCC = DstFTy->getCallConv(); + if (SrcCC == DstCC) + return; + + // We have a calling convention cast. Check if the source is a pointer to a + // known, specific function that has already been defined. + Expr *Src = SrcExpr.get()->IgnoreParenImpCasts(); + if (auto *AddrOf = dyn_cast<UnaryOperator>(Src)) + Src = AddrOf->getSubExpr()->IgnoreParenImpCasts(); + auto *DRE = dyn_cast<DeclRefExpr>(Src); + if (!DRE) + return; + auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()); + const FunctionDecl *Definition; + if (!FD || !FD->hasBody(Definition)) + return; + + // The source expression is a pointer to a known function defined in this TU. + // Diagnose this cast, as it is probably bad. + StringRef SrcCCName = FunctionType::getNameForCallConv(SrcCC); + StringRef DstCCName = FunctionType::getNameForCallConv(DstCC); + Self.Diag(OpRange.getBegin(), diag::warn_cast_calling_conv) + << SrcCCName << DstCCName << OpRange; + SourceLocation NameLoc = Definition->getNameInfo().getLoc(); + SmallString<64> CCAttrText; + if (Self.getLangOpts().MicrosoftExt) + (Twine("__") + DstCCName + " ").toVector(CCAttrText); + else + (Twine("__attribute__((") + DstCCName + ")) ").toVector(CCAttrText); + Self.Diag(NameLoc, diag::note_change_calling_conv_fixit) + << FD << DstCCName << FixItHint::CreateInsertion(NameLoc, CCAttrText); +} + static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, const Expr *SrcExpr, QualType DestType, Sema &Self) { @@ -2008,7 +2059,9 @@ } if (CStyle) DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); - + + diagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange); + // Not casting away constness, so the only remaining check is for compatible // pointer categories. @@ -2427,6 +2480,7 @@ } DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); + diagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange); DiagnoseBadFunctionCast(Self, SrcExpr, DestType); Kind = Self.PrepareScalarCast(SrcExpr, DestType); if (SrcExpr.isInvalid()) Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6510,7 +6510,12 @@ def warn_function_def_in_objc_container : Warning< "function definition inside an Objective-C container is deprecated">, InGroup<FunctionDefInObjCContainer>; - + +def warn_cast_calling_conv : Warning< + "cast between incompatible calling conventions '%0' and '%1'">, + InGroup<CastCallingConvention>, DefaultIgnore; +def note_change_calling_conv_fixit : Note< + "consider defining %0 with the '%1' calling convention">; def warn_bad_function_cast : Warning< "cast from function call of type %0 to non-matching type %1">, InGroup<BadFunctionCast>, DefaultIgnore; Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -291,6 +291,7 @@ def OverloadedVirtual : DiagGroup<"overloaded-virtual">; def PrivateExtern : DiagGroup<"private-extern">; def SelTypeCast : DiagGroup<"cast-of-sel-type">; +def CastCallingConvention : DiagGroup<"cast-calling-convention">; def FunctionDefInObjCContainer : DiagGroup<"function-def-in-objc-container">; def BadFunctionCast : DiagGroup<"bad-function-cast">; def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits