]> granicus.if.org Git - clang/commitdiff
Implement GCC's -Wint-to-pointer-cast.
authorDavid Blaikie <dblaikie@gmail.com>
Tue, 16 Oct 2012 18:53:14 +0000 (18:53 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Tue, 16 Oct 2012 18:53:14 +0000 (18:53 +0000)
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

13 files changed:
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaCast.cpp
test/Analysis/CFContainers.mm
test/Analysis/idempotent-operations.c
test/Analysis/misc-ps-region-store.m
test/Analysis/taint-tester.c
test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
test/Sema/block-return.c
test/Sema/cast.c
test/Sema/i-c-e.c
test/SemaCXX/cast-conversion.cpp
test/SemaCXX/decl-expr-ambiguity.cpp

index 4b0f4f13c0d229449a93e7acbc01f5381456690d..7951e35778a7060f221dcdec097dd46880580ae3 100644 (file)
@@ -365,6 +365,8 @@ def Format2 : DiagGroup<"format=2",
 
 def TypeSafety : DiagGroup<"type-safety">;
 
+def IntToPointerCast : DiagGroup<"int-to-pointer-cast">;
+
 def Extra : DiagGroup<"extra", [
     MissingFieldInitializers,
     IgnoredQualifiers,
@@ -412,7 +414,7 @@ def ThreadSafety : DiagGroup<"thread-safety",
 // 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">;
index 953aab6983f9b2950f4921a413aa495c5d841b8e..8389e4e10fa5d4cc54c34454283ea66ca5bb755d 100644 (file)
@@ -1995,6 +1995,10 @@ def warn_cast_align : Warning<
   "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>;
index 0c3757821eb06c1be8b4c1fb87a3d29ec66d4c13..bf25c617854172aacff9ccf7837ab3af9b7d196b 100644 (file)
@@ -1491,6 +1491,22 @@ static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr,
     }
 }
 
+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,
@@ -1689,6 +1705,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
 
   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
@@ -2071,6 +2089,8 @@ void CastOperation::CheckCStyleCast() {
       SrcExpr = ExprError();
       return;
     }
+    checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(),
+                          DestType, Self);
   } else if (!SrcType->isArithmeticType()) {
     if (!DestType->isIntegralType(Self.Context) &&
         DestType->isArithmeticType()) {
index e1431df47a0fd7ae262c96aa463fd6037f421487..b01942310f7b23f89e44fb0a770f21f8fe6dcf8c 100644 (file)
@@ -125,7 +125,7 @@ void CreateDict(int *elems) {
   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}}
 }
 
index 793e7cd324b91da815a2a15a21f6d6815884448c..04c9bc1893e8dac6e806204921660de0172bbe2f 100644 (file)
@@ -1,4 +1,4 @@
-// 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
 
index 800a008d17c1fa175a4507d37f7836ec82155986..f772894ff8201f9e5a8c3629fca3b2b2d6515d02 100644 (file)
@@ -1086,6 +1086,9 @@ pr8052(u_int boot_addr)
     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)
index 67383accb2abb070118add09be5c23c7b345fd7d..7b0ab2a5fd34b28730c57e1b4c3c237c7985e51f 100644 (file)
@@ -1,4 +1,4 @@
-// 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>
 
index fd17d35677dcc1283c6915a229482da2631c2327..3c1152c631b8c740a30334f2a018c70ca1a2129e 100644 (file)
@@ -1,5 +1,5 @@
-// 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 {
 
@@ -80,7 +80,7 @@ constexpr int Conditional2(bool b, int n) { return b ? n * ng : n + ng; } // exp
 
 // __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), "");
 
index 6967955b08789c7f145329b71d74cb1d3f2dc15b..2ea4d813ab0161b8ff966b3789bcd90ee0169f1a 100644 (file)
@@ -1,4 +1,4 @@
-// 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);
 
index 71c44b4b816b7fa799df39c5014e8d1ac8c8253e..25ef1d03a4fe7b6e47761783a33c8c721137b1b8 100644 (file)
@@ -1,4 +1,4 @@
-// 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;
@@ -52,8 +52,8 @@ void testInt(Int v) {
   (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) {
@@ -157,3 +157,12 @@ void testCharPtr(CharPtr 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);
+}
index ee61ac34a81a4a01765047fc2d9c67d2a02d3b48..e7b42c4e9a14422631141fe80f2ea3f1a6f9bb10 100644 (file)
@@ -1,4 +1,4 @@
-// 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>
index dd2bc98e02cc7fa1685c9dcc983727a79e98f08c..270f96831bd4e6b206e9eaf4d088b9ea80436a41 100644 (file)
@@ -1,4 +1,4 @@
-// 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);
@@ -45,3 +45,23 @@ protected:
     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;
+}
index 0980c40cbfd5700c5138ba04471dc14edd211f42..87fd2dad316ce57f3f204840f5ad0c36c4b07cd4 100644 (file)
@@ -1,4 +1,4 @@
-// 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;