//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallVector.h"
#include <set>
using namespace clang;
<< FixItHint::CreateReplacement(BeginLoc, "static_cast");
}
+static bool argTypeIsABIEquivalent(QualType SrcType, QualType DestType,
+ ASTContext &Context) {
+ if (SrcType->isPointerType() && DestType->isPointerType())
+ return true;
+
+ // Allow integral type mismatch if their size are equal.
+ if (SrcType->isIntegralType(Context) && DestType->isIntegralType(Context))
+ if (Context.getTypeInfoInChars(SrcType).Width ==
+ Context.getTypeInfoInChars(DestType).Width)
+ return true;
+
+ return Context.hasSameUnqualifiedType(SrcType, DestType);
+}
+
+static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType) {
+ if (Self.Diags.isIgnored(diag::warn_cast_function_type,
+ SrcExpr.get()->getExprLoc()))
+ return true;
+
+ QualType SrcType = SrcExpr.get()->getType();
+ const FunctionType *SrcFTy = nullptr;
+ const FunctionType *DstFTy = nullptr;
+ if (((SrcType->isBlockPointerType() || SrcType->isFunctionPointerType()) &&
+ DestType->isFunctionPointerType()) ||
+ (SrcType->isMemberFunctionPointerType() &&
+ DestType->isMemberFunctionPointerType())) {
+ SrcFTy = SrcType->getPointeeType()->castAs<FunctionType>();
+ DstFTy = DestType->getPointeeType()->castAs<FunctionType>();
+ } else if (SrcType->isFunctionType() && DestType->isFunctionReferenceType()) {
+ SrcFTy = SrcType->castAs<FunctionType>();
+ DstFTy = DestType.getNonReferenceType()->castAs<FunctionType>();
+ } else {
+ return true;
+ }
+ assert(SrcFTy && DstFTy);
+
+ auto IsVoidVoid = [](const FunctionType *T) {
+ if (!T->getReturnType()->isVoidType())
+ return false;
+ if (const auto *PT = T->getAs<FunctionProtoType>())
+ return !PT->isVariadic() && PT->getNumParams() == 0;
+ return false;
+ };
+
+ // Skip if either function type is void(*)(void)
+ if (IsVoidVoid(SrcFTy) || IsVoidVoid(DstFTy))
+ return true;
+
+ // Check return type.
+ if (!argTypeIsABIEquivalent(SrcFTy->getReturnType(), DstFTy->getReturnType(),
+ Self.Context))
+ return false;
+
+ // Check if either has unspecified number of parameters
+ if (SrcFTy->isFunctionNoProtoType() || DstFTy->isFunctionNoProtoType())
+ return true;
+
+ // Check parameter types.
+
+ const auto *SrcFPTy = cast<FunctionProtoType>(SrcFTy);
+ const auto *DstFPTy = cast<FunctionProtoType>(DstFTy);
+
+ // In a cast involving function types with a variable argument list only the
+ // types of initial arguments that are provided are considered.
+ unsigned NumParams = SrcFPTy->getNumParams();
+ unsigned DstNumParams = DstFPTy->getNumParams();
+ if (NumParams > DstNumParams) {
+ if (!DstFPTy->isVariadic())
+ return false;
+ NumParams = DstNumParams;
+ } else if (NumParams < DstNumParams) {
+ if (!SrcFPTy->isVariadic())
+ return false;
+ }
+
+ for (unsigned i = 0; i < NumParams; ++i)
+ if (!argTypeIsABIEquivalent(SrcFPTy->getParamType(i),
+ DstFPTy->getParamType(i), Self.Context))
+ return false;
+
+ return true;
+}
+
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
/// valid.
/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
checkObjCConversion(Sema::CCK_OtherCast);
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
+
+ if (!checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
+ << SrcExpr.get()->getType() << DestType << OpRange;
} else {
SrcExpr = ExprError();
}
if (isValidCast(tcr)) {
if (Kind == CK_BitCast)
checkCastAlign();
+
+ if (!checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
+ << SrcExpr.get()->getType() << DestType << OpRange;
+
} else {
SrcExpr = ExprError();
}
}
}
+ if (!checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
+ << SrcType << DestType << OpRange;
+
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange);
DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
--- /dev/null
+// RUN: %clang_cc1 -x c++ %s -fblocks -fsyntax-only -Wcast-function-type -triple x86_64-- -verify
+
+int x(long);
+
+typedef int (f1)(long);
+typedef int (f2)(void*);
+typedef int (f3)(...);
+typedef void (f4)(...);
+typedef void (f5)(void);
+typedef int (f6)(long, int);
+typedef int (f7)(long,...);
+typedef int (&f8)(long, int);
+
+f1 *a;
+f2 *b;
+f3 *c;
+f4 *d;
+f5 *e;
+f6 *f;
+f7 *g;
+
+struct S
+{
+ void foo (int*);
+ void bar (int);
+};
+
+typedef void (S::*mf)(int);
+
+void foo() {
+ a = (f1 *)x;
+ b = (f2 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f2 *' (aka 'int (*)(void *)') converts to incompatible function types}} */
+ b = reinterpret_cast<f2 *>(x); /* expected-warning {{cast from 'int (*)(long)' to 'f2 *' (aka 'int (*)(void *)') converts to incompatible function types}} */
+ c = (f3 *)x;
+ d = (f4 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f4 *' (aka 'void (*)(...)') converts to incompatible function types}} */
+ e = (f5 *)x;
+ f = (f6 *)x; /* expected-warning {{cast from 'int (*)(long)' to 'f6 *' (aka 'int (*)(long, int)') converts to incompatible function types}} */
+ g = (f7 *)x;
+
+ mf p1 = (mf)&S::foo; /* expected-warning {{cast from 'void (S::*)(int *)' to 'mf' (aka 'void (S::*)(int)') converts to incompatible function types}} */
+
+ f8 f2 = (f8)x; /* expected-warning {{cast from 'int (long)' to 'f8' (aka 'int (&)(long, int)') converts to incompatible function types}} */
+ (void)f2;
+
+ int (^y)(long);
+ f = (f6 *)y; /* expected-warning {{cast from 'int (^)(long)' to 'f6 *' (aka 'int (*)(long, int)') converts to incompatible function types}} */
+}