Add a warning for when reinterpret_cast leads to undefined behavior.  Also
updated reinterpret_cast tests and turned off this warning for tests that
don't need it.
Index: test/Analysis/cxx-crashes.cpp
===================================================================
--- test/Analysis/cxx-crashes.cpp	(revision 128089)
+++ test/Analysis/cxx-crashes.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -Wno-undefined_reinterpret_cast -verify %s
 
 int f1(char *dst) {
   char *p = dst + 4;
Index: test/CodeGenCXX/reinterpret-cast.cpp
===================================================================
--- test/CodeGenCXX/reinterpret-cast.cpp	(revision 128089)
+++ test/CodeGenCXX/reinterpret-cast.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s -std=c++0x
+// RUN: %clang_cc1 -emit-llvm -o - %s -std=c++0x -Wno-undefined_reinterpret_cast
 void *f1(unsigned long l) {
   return reinterpret_cast<void *>(l);
 }
Index: test/CodeGenCXX/lvalue-bitcasts.cpp
===================================================================
--- test/CodeGenCXX/lvalue-bitcasts.cpp	(revision 128089)
+++ test/CodeGenCXX/lvalue-bitcasts.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -Wno-undefine_reinterpret_cast | FileCheck %s
 
 struct X { int i; float f; };
 struct Y { X x; };
Index: test/CXX/expr/expr.post/expr.reinterpret.cast/p1-0x.cpp
===================================================================
--- test/CXX/expr/expr.post/expr.reinterpret.cast/p1-0x.cpp	(revision 128089)
+++ test/CXX/expr/expr.post/expr.reinterpret.cast/p1-0x.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -Wno-undefined_reinterpret_cast %s
 
 // If T is an lvalue reference type or an rvalue reference to function
 // type, the result is an lvalue; if T is an rvalue reference to
Index: test/SemaCXX/reinterpret-cast.cpp
===================================================================
--- test/SemaCXX/reinterpret-cast.cpp	(revision 128089)
+++ test/SemaCXX/reinterpret-cast.cpp	(working copy)
@@ -108,3 +108,54 @@
   (void)reinterpret_cast<char *>(s); // expected-error {{reinterpret_cast from 'const STRING *' (aka 'char const (*)[10]') to 'char *' casts away constness}}
   (void)reinterpret_cast<const STRING *>(c);
 }
+
+void dereference_reinterpret_cast() {
+  struct A {};
+  struct B {};
+  A a, aa;
+  B b, bb;
+  long x, xx;
+  double z, zz;
+  char c, cc;
+  unsigned char uc;
+  void* v_ptr;
+  z = reinterpret_cast<double&>(x);  // expected-warning {{reinterpret_cast from 'long' to 'double &' has undefined behavior}}
+  c = reinterpret_cast<char&>(x);
+  z = *reinterpret_cast<double*>(&x);  // expected-warning {{dereference of type 'double *' that was reinterpret_cast from type 'long *' has undefined behavior}}
+  c = *reinterpret_cast<char*>(&x);
+
+  a = reinterpret_cast<A&>(b);  // expected-warning {{reinterpret_cast from 'B' to 'A &' has undefined behavior}}
+  a = *reinterpret_cast<A*>(&b);  // expected-warning {{dereference of type 'A *' that was reinterpret_cast from type 'B *' has undefined behavior}}
+
+  a = reinterpret_cast<A&>(aa);
+  a = *reinterpret_cast<A*>(&aa);
+  b = reinterpret_cast<B&>(bb);
+  b = *reinterpret_cast<B*>(&bb);
+  x = reinterpret_cast<long&>(xx);
+  x = *reinterpret_cast<long*>(&xx);
+  z = reinterpret_cast<double&>(zz);
+  z = *reinterpret_cast<double*>(&zz);
+  c = reinterpret_cast<char&>(cc);
+  c = *reinterpret_cast<char*>(&cc);
+
+  // Casting to and from chars are allowable
+  a = reinterpret_cast<A&>(cc);
+  a = *reinterpret_cast<A*>(&cc);
+  b = reinterpret_cast<B&>(cc);
+  b = *reinterpret_cast<B*>(&cc);
+  x = reinterpret_cast<long&>(cc);
+  x = *reinterpret_cast<long*>(&cc);
+  z = reinterpret_cast<double&>(cc);
+  z = *reinterpret_cast<double*>(&cc);
+  c = reinterpret_cast<char&>(xx);
+  c = *reinterpret_cast<char*>(&xx);
+  c = reinterpret_cast<char&>(zz);
+  c = *reinterpret_cast<char*>(&zz);
+
+  // Casting from void pointer.
+  a = *reinterpret_cast<A*>(v_ptr);
+  b = *reinterpret_cast<B*>(v_ptr);
+  x = *reinterpret_cast<long*>(v_ptr);
+  z = *reinterpret_cast<double*>(v_ptr);
+  c = *reinterpret_cast<char*>(v_ptr);
+}
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 128089)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -2562,6 +2562,10 @@
   "indirection of non-volatile null pointer will be deleted, not trap">, InGroup<NullDereference>;
 def note_indirection_through_null : Note<
   "consider using __builtin_trap() or qualifying pointer with 'volatile'">;
+def warn_pointer_indirection_from_incompatible_type : Warning<
+  "dereference of type %0 that was reinterpret_cast from type %1 has undefined "
+  "behavior.">,
+  InGroup<DiagGroup<"undefined_reinterpret_cast">>;
 
 def err_assignment_requires_nonfragile_object : Error<
   "cannot assign to class object in non-fragile ABI (%0 invalid)">;
@@ -2817,6 +2821,9 @@
   "cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer "
   "type %1 to member pointer type %2 of different size">;
 def err_bad_static_cast_incomplete : Error<"%0 is an incomplete type">;
+def warn_undefined_reinterpret_cast : Warning<
+  "reinterpret_cast from %0 to %1 has undefined behavior.">,
+  InGroup<DiagGroup<"undefined_reinterpret_cast">>;
 
 // These messages don't adhere to the pattern.
 // FIXME: Display the path somehow better.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h	(revision 128089)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -2409,6 +2409,10 @@
                                ParsedType ObjectType,
                                bool EnteringContext);
 
+  // Checks that reinterpret casts don't have undefined behavior.
+  // Returns false when the reinterpret cast results in undefined behavior.
+  bool CompatibleReinterpretCast(QualType SrcType, QualType DestPointeeType);
+
   /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
   ExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
                                tok::TokenKind Kind,
Index: lib/Sema/SemaCXXCast.cpp
===================================================================
--- lib/Sema/SemaCXXCast.cpp	(revision 128089)
+++ lib/Sema/SemaCXXCast.cpp	(working copy)
@@ -1249,9 +1249,22 @@
   return TC_Success;
 }
 
+// Returns false if the reinterpret_cast has undefined behavior.
+// SrcType = A, DestType = B
+// *reinterpret_cast<&B>(&A)
+// reinterpret_cast<A&>(B)
+bool Sema::CompatibleReinterpretCast(QualType SrcType,
+                                     QualType DestType) {
+  if (Context.hasSameUnqualifiedType(DestType, SrcType)) {
+    return true;
+  }
+  if (DestType->isAnyCharacterType() || DestType->isVoidType() ||
+      SrcType->isAnyCharacterType() || SrcType->isVoidType()) {
+    return true;
+  }
+  return false;
+}
 
-
-
 static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
                                         QualType DestType, bool CStyle,
                                         const SourceRange &OpRange,
@@ -1268,13 +1281,13 @@
     // ... unless foo<int> resolves to an lvalue unambiguously
     ExprResult SingleFunctionExpr = 
         Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr, 
-          Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr 
+          Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
         );
     if (SingleFunctionExpr.isUsable()) {
       SrcExpr = SingleFunctionExpr.release();
       SrcType = SrcExpr->getType();
-    }      
-    else  
+    }
+    else
       return TC_NotApplicable;
   }
 
@@ -1287,13 +1300,20 @@
       return TC_NotApplicable;
     }
 
+    QualType DestPointeeType = DestTypeTmp->getPointeeType();
+
+    if (!CStyle && !Self.CompatibleReinterpretCast(SrcType, DestPointeeType)) {
+        Self.Diag(OpRange.getBegin(), diag::warn_undefined_reinterpret_cast)
+          << SrcType << DestType << OpRange;
+    }
+
     // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
     //   same effect as the conversion *reinterpret_cast<T*>(&x) with the
     //   built-in & and * operators.
     // This code does this transformation for the checked types.
-    DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
+    DestType = Self.Context.getPointerType(DestPointeeType);
     SrcType = Self.Context.getPointerType(SrcType);
-    
+
     IsLValueCast = true;
   }
 
@@ -1473,7 +1493,7 @@
       Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange;
     return TC_Success;
   }
-  
+
   // C++ 5.2.10p7: A pointer to an object can be explicitly converted to
   //   a pointer to an object of different type.
   // Void pointers are not specified, but supported by every compiler out there.
@@ -1510,7 +1530,7 @@
         Kind = CK_ToVoid;
       }
       else
-        ret = true;  
+        ret = true;
     }
     else
       Kind = CK_ToVoid;
@@ -1566,8 +1586,7 @@
                                 /* Complain */ true,
                                 Found);
       
-      assert(!Fn 
-                && "cast failed but able to resolve overload expression!!");
+      assert(!Fn && "cast failed but able to resolve overload expression!!");
       (void)Fn;
 
     } else {
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 128089)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -7892,7 +7892,18 @@
   S.UsualUnaryConversions(Op);
   QualType OpTy = Op->getType();
   QualType Result;
-  
+
+  if (S.getLangOptions().CPlusPlus && isa<CXXReinterpretCastExpr>(Op)) {
+    QualType OpOrigType = Op->IgnoreParenCasts()->getType();
+    if (OpOrigType->isPointerType() && OpTy->isPointerType()) {
+      if (!S.CompatibleReinterpretCast(OpOrigType->getPointeeType(),
+                                       OpTy->getPointeeType())) {
+          S.Diag(OpLoc, diag::warn_pointer_indirection_from_incompatible_type)
+            << OpTy << OpOrigType << Op->getSourceRange();
+      }
+    }
+  }
+
   // Note that per both C89 and C99, indirection is always legal, even if OpTy
   // is an incomplete type or void.  It would be possible to warn about
   // dereferencing a void pointer, but it's completely well-defined, and such a
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to