This implementation doesn't warn on anything that GCC doesn't warn on with the
exception of templates specializations (GCC doesn't warn, Clang does). The
specific skipped cases (boolean, constant expressions, enums) are open for
debate/adjustment if anyone wants to demonstrate that GCC is being overly
conservative here. The only really obvious false positive I found was in the
Clang regression suite's MPI test - apparently MPI uses specific flag values in
pointer constants. (eg: #define FOO (void*)~0)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166039
91177308-0d34-0410-b5e6-
96231b3b80d8
def TypeSafety : DiagGroup<"type-safety">;
+def IntToPointerCast : DiagGroup<"int-to-pointer-cast">;
+
def Extra : DiagGroup<"extra", [
MissingFieldInitializers,
IgnoredQualifiers,
// Note that putting warnings in -Wall will not disable them by default. If a
// warning should be active _only_ when -Wall is passed in, mark it as
// DefaultIgnore in addition to putting it here.
-def : DiagGroup<"all", [Most, Parentheses, Switch]>;
+def : DiagGroup<"all", [Most, Parentheses, Switch, IntToPointerCast]>;
// Warnings enabled by -pedantic. This is magically filled in by TableGen.
def Pedantic : DiagGroup<"pedantic">;
"cast from %0 to %1 increases required alignment from %2 to %3">,
InGroup<CastAlign>, DefaultIgnore;
+def warn_int_to_pointer_cast : Warning<
+ "cast to %1 from smaller integer type %0">,
+ InGroup<IntToPointerCast>;
+
def warn_attribute_ignored_for_field_of_type : Warning<
"%0 attribute ignored for field of type %1">,
InGroup<IgnoredAttributes>;
}
}
+static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
+ const Expr *SrcExpr, QualType DestType,
+ Sema &Self) {
+ QualType SrcType = SrcExpr->getType();
+
+ // Not warning on reinterpret_cast, boolean, constant expressions, etc
+ // are not explicit design choices, but consistent with GCC's behavior.
+ // Feel free to modify them if you've reason/evidence for an alternative.
+ if (CStyle && SrcType->isIntegralType(Self.Context)
+ && !SrcType->isBooleanType()
+ && !SrcType->isEnumeralType()
+ && !SrcExpr->isIntegerConstantExpr(Self.Context)
+ && Self.Context.getTypeSize(DestType) > Self.Context.getTypeSize(SrcType))
+ Self.Diag(Loc, diag::warn_int_to_pointer_cast) << SrcType << DestType;
+}
+
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
if (SrcType->isIntegralOrEnumerationType()) {
assert(destIsPtr && "One type must be a pointer");
+ checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType,
+ Self);
// C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
// converted to a pointer.
// C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not
SrcExpr = ExprError();
return;
}
+ checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(),
+ DestType, Self);
} else if (!SrcType->isArithmeticType()) {
if (!DestType->isIntegralType(Self.Context) &&
DestType->isArithmeticType()) {
const CFDictionaryKeyCallBacks keyCB = kCFCopyStringDictionaryKeyCallBacks;
const CFDictionaryValueCallBacks valCB = kCFTypeDictionaryValueCallBacks;
CFDictionaryRef dict1 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, numValues, &keyCB, &valCB); // no warning
- CFDictionaryRef dict2 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)elems[0], (const void**)values, numValues, &keyCB, &valCB); //expected-warning {{The second argument to 'CFDictionaryCreate' must be a C array of}}
+ CFDictionaryRef dict2 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)elems[0], (const void**)values, numValues, &keyCB, &valCB); //expected-warning {{The second argument to 'CFDictionaryCreate' must be a C array of}} expected-warning {{cast to 'const void **' from smaller integer type 'int'}}
CFDictionaryRef dict3 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)elems, numValues, &keyCB, &valCB); // expected-warning {{The third argument to 'CFDictionaryCreate' must be a C array of pointer-sized values}}
}
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=alpha.deadcode.IdempotentOperations -verify %s
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=alpha.deadcode.IdempotentOperations -verify %s
// Basic tests
u_char *src = (u_char *) ((u_long) bootMP);
u_char *dst = (u_char *) boot_addr + ((vm_offset_t) ((((((((1 <<
12) / (sizeof(pd_entry_t))) - 1) - 1) - (260 - 2))) << 22) | ((0) << 12)));
+#ifdef TEST_64
+// expected-warning@-3 {{cast to 'u_char *' (aka 'unsigned char *') from smaller integer type 'u_int' (aka 'unsigned int')}}
+#endif
for (x = 0;
x < size;
++x)
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
#include <stdarg.h>
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fcxx-exceptions -Wno-invalid-constexpr %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -std=c++11 -fcxx-exceptions -Wno-invalid-constexpr %s
namespace StdExample {
// __builtin_constant_p ? : is magical, and is always a potential constant.
constexpr bool BcpCall(int n) {
- return __builtin_constant_p((int*)n != &n) ? (int*)n != &n : (int*)n != &n;
+ return __builtin_constant_p((int*)n != &n) ? (int*)n != &n : (int*)n != &n; // expected-warning 3 {{cast to 'int *' from smaller integer type 'int'}}
}
static_assert(BcpCall(0), "");
-// RUN: %clang_cc1 -pedantic -fsyntax-only %s -verify -fblocks
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -pedantic -fsyntax-only %s -verify -fblocks
typedef void (^CL)(void);
-// RUN: %clang_cc1 -fsyntax-only %s -verify
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown %s -verify
typedef struct { unsigned long bits[(((1) + (64) - 1) / (64))]; } cpumask_t;
cpumask_t x;
(void) (CLong) v;
(void) (CFloat) v;
(void) (CDouble) v;
- (void) (VoidPtr) v;
- (void) (CharPtr) v;
+ (void) (VoidPtr) v; // expected-warning{{cast to 'VoidPtr' (aka 'void *') from smaller integer type 'Int' (aka 'int')}}
+ (void) (CharPtr) v; // expected-warning{{cast to 'CharPtr' (aka 'char *') from smaller integer type 'Int' (aka 'int')}}
}
void testLong(Long v) {
(void) (VoidPtr) v;
(void) (CharPtr) v;
}
+
+typedef enum { x_a, x_b } X;
+void *intToPointerCast2(X x) {
+ return (void*)x;
+}
+
+void *intToPointerCast3() {
+ return (void*)(1 + 3);
+}
-// RUN: %clang %s -ffreestanding -fsyntax-only -Xclang -verify -pedantic -fpascal-strings -std=c99
+// RUN: %clang %s -ffreestanding -Wno-int-to-pointer-cast -fsyntax-only -Xclang -verify -pedantic -fpascal-strings -std=c99
#include <stdint.h>
#include <limits.h>
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -verify %s -std=c++11
struct R {
R(int);
static_cast<float*>(f0<0>()); // expected-error{{ambiguous}}
}
};
+
+void *intToPointer1(short s) {
+ return (void*)s; // expected-warning{{cast to 'void *' from smaller integer type 'short'}}
+}
+
+void *intToPointer2(short s) {
+ return reinterpret_cast<void*>(s);
+}
+
+void *intToPointer3(bool b) {
+ return (void*)b;
+}
+
+void *intToPointer4() {
+ return (void*)(3 + 7);
+}
+
+void *intToPointer5(long l) {
+ return (void*)l;
+}
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -fsyntax-only -verify -pedantic-errors %s
void f() {
int a;