Added the level check.  There's two warning messages, so I added a check for
each one.

On Thu, Apr 28, 2011 at 7:36 PM, Argyrios Kyrtzidis <[email protected]>wrote:

> You don't check whether the warning is turned off to skip the checks
> completely, something like
>
> Diags.getDiagnosticLevel(diag::warn_pointer_indirection_from_incompatible_type,
> OpLoc) != Diagnostic::Ignored)
>
>
> On Apr 28, 2011, at 7:16 PM, Richard Trieu wrote:
>
> Changes to support the white list in [basic.lval]p10.  There should be a
> corresponding test to each list item, except when those dealing with tag
> types since we are skipping them for now.
>
> On Wed, Apr 27, 2011 at 6:11 PM, John McCall <[email protected]> wrote:
>
>> On Apr 27, 2011, at 6:07 PM, Richard Trieu wrote:
>> > Is there a way that Clang can check if the warning is turned off and
>> skip the expensive checking?
>>
>> Yes, you can check whether the current mapping for the diagnostic is still
>> "ignore".
>>
>> > And did you mean the list in [basic.lval]p15?  [basic.lval]p10 doesn't
>> have a list.
>>
>> We're just looking at different standards. :)  C++11's [basic.lval]p10 is
>> just minor wording differences from C++03's [basic.lval]p15.
>>
>> John.
>>
>
> <undefined-reinterpret-cast3.patch>
> _______________________________________________
>
> cfe-commits mailing list
> [email protected]
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
>
>
Index: test/SemaCXX/reinterpret-cast.cpp
===================================================================
--- test/SemaCXX/reinterpret-cast.cpp	(revision 130335)
+++ test/SemaCXX/reinterpret-cast.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding -Wundefined-reinterpret-cast %s
 
 #include <stdint.h>
 
@@ -116,3 +116,136 @@
   __attribute((ext_vector_type(4))) typedef float v4;
   float& w(v4 &a) { return reinterpret_cast<float&>(a[1]); } // expected-error {{not allowed}}
 }
+
+void dereference_reinterpret_cast() {
+  struct A {};
+  class 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);
+  a = *reinterpret_cast<A*>(&b);
+  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);
+}
+
+void reinterpret_cast_whitelist () {
+  // the dynamic type of the object
+  int a;
+  float b;
+  (void)reinterpret_cast<int&>(a);
+  (void)*reinterpret_cast<int*>(&a);
+  (void)reinterpret_cast<float&>(b);
+  (void)*reinterpret_cast<float*>(&b);
+
+  // a cv-qualified version of the dynamic object
+  (void)reinterpret_cast<const int&>(a);
+  (void)*reinterpret_cast<const int*>(&a);
+  (void)reinterpret_cast<volatile int&>(a);
+  (void)*reinterpret_cast<volatile int*>(&a);
+  (void)reinterpret_cast<const volatile int&>(a);
+  (void)*reinterpret_cast<const volatile int*>(&a);
+  (void)reinterpret_cast<const float&>(b);
+  (void)*reinterpret_cast<const float*>(&b);
+  (void)reinterpret_cast<volatile float&>(b);
+  (void)*reinterpret_cast<volatile float*>(&b);
+  (void)reinterpret_cast<const volatile float&>(b);
+  (void)*reinterpret_cast<const volatile float*>(&b);
+
+  // a type that is the signed or unsigned type corresponding to the dynamic
+  // type of the object
+  signed d;
+  unsigned e;
+  (void)reinterpret_cast<signed&>(d);
+  (void)*reinterpret_cast<signed*>(&d);
+  (void)reinterpret_cast<signed&>(e);
+  (void)*reinterpret_cast<signed*>(&e);
+  (void)reinterpret_cast<unsigned&>(d);
+  (void)*reinterpret_cast<unsigned*>(&d);
+  (void)reinterpret_cast<unsigned&>(e);
+  (void)*reinterpret_cast<unsigned*>(&e);
+
+  // a type that is the signed or unsigned type corresponding a cv-qualified
+  // version of the dynamic type the object
+  (void)reinterpret_cast<const signed&>(d);
+  (void)*reinterpret_cast<const signed*>(&d);
+  (void)reinterpret_cast<const signed&>(e);
+  (void)*reinterpret_cast<const signed*>(&e);
+  (void)reinterpret_cast<const unsigned&>(d);
+  (void)*reinterpret_cast<const unsigned*>(&d);
+  (void)reinterpret_cast<const unsigned&>(e);
+  (void)*reinterpret_cast<const unsigned*>(&e);
+  (void)reinterpret_cast<volatile signed&>(d);
+  (void)*reinterpret_cast<volatile signed*>(&d);
+  (void)reinterpret_cast<volatile signed&>(e);
+  (void)*reinterpret_cast<volatile signed*>(&e);
+  (void)reinterpret_cast<volatile unsigned&>(d);
+  (void)*reinterpret_cast<volatile unsigned*>(&d);
+  (void)reinterpret_cast<volatile unsigned&>(e);
+  (void)*reinterpret_cast<volatile unsigned*>(&e);
+  (void)reinterpret_cast<const volatile signed&>(d);
+  (void)*reinterpret_cast<const volatile signed*>(&d);
+  (void)reinterpret_cast<const volatile signed&>(e);
+  (void)*reinterpret_cast<const volatile signed*>(&e);
+  (void)reinterpret_cast<const volatile unsigned&>(d);
+  (void)*reinterpret_cast<const volatile unsigned*>(&d);
+  (void)reinterpret_cast<const volatile unsigned&>(e);
+  (void)*reinterpret_cast<const volatile unsigned*>(&e);
+
+  // an aggregate or union type that includes one of the aforementioned types
+  // among its members (including, recursively, a member of a subaggregate or
+  // contained union)
+  // TODO: checking is not implemented for tag types
+
+  // a type that is a (possible cv-qualified) base class type of the dynamic
+  // type of the object
+  // TODO: checking is not implemented for tag types
+
+  // a char or unsigned char type
+  (void)reinterpret_cast<char&>(a);
+  (void)*reinterpret_cast<char*>(&a);
+  (void)reinterpret_cast<unsigned char&>(a);
+  (void)*reinterpret_cast<unsigned char*>(&a);
+  (void)reinterpret_cast<char&>(b);
+  (void)*reinterpret_cast<char*>(&b);
+  (void)reinterpret_cast<unsigned char&>(b);
+  (void)*reinterpret_cast<unsigned char*>(&b);
+}
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 130335)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -2637,6 +2637,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">>, DefaultIgnore;
 
 def err_assignment_requires_nonfragile_object : Error<
   "cannot assign to class object in non-fragile ABI (%0 invalid)">;
@@ -2900,6 +2904,9 @@
 def err_bad_static_cast_incomplete : Error<"%0 is an incomplete type">;
 def err_bad_reinterpret_cast_reference : Error<
   "reinterpret_cast of a %0 to %1 needs its address which is not allowed">;
+def warn_undefined_reinterpret_cast : Warning<
+  "reinterpret_cast from %0 to %1 has undefined behavior.">,
+  InGroup<DiagGroup<"undefined-reinterpret-cast">>, DefaultIgnore;
 
 // 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 130335)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -2574,6 +2574,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 isCompatibleReinterpretCast(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 130335)
+++ lib/Sema/SemaCXXCast.cpp	(working copy)
@@ -1288,7 +1288,46 @@
   return TC_Success;
 }
 
+// Returns false if the reinterpret_cast has undefined behavior.
+// Given types SrcType, the original type and DestType, the type to cast to
+// and A, which is of type SrcType:
+// *reinterpret_cast<DestType*>(&A)
+// reinterpret_cast<DestType&>(A)
+bool Sema::isCompatibleReinterpretCast(QualType SrcType,
+                                       QualType DestType) {
+  // If the warning is not turned on, skip the check.
+  if (Diags.getDiagnosticLevel(
+          diag::warn_pointer_indirection_from_incompatible_type,
+          SourceLocation()) == Diagnostic::Ignored &&
+      Diags.getDiagnosticLevel(diag::warn_undefined_reinterpret_cast,
+                               SourceLocation()) == Diagnostic::Ignored) {
+    return true;
+  }
 
+  // Cast is compatible if the types are the same.
+  if (Context.hasSameUnqualifiedType(DestType, SrcType)) {
+    return true;
+  }
+  // or one of the types is a char or void type
+  if (DestType->isAnyCharacterType() || DestType->isVoidType() ||
+      SrcType->isAnyCharacterType() || SrcType->isVoidType()) {
+    return true;
+  }
+  // or one of the types is a tag type.
+  if (isa<TagType>(SrcType) || isa<TagType>(DestType)) {
+    return true;
+  }
+
+  if ((SrcType->isUnsignedIntegerType() && DestType->isSignedIntegerType()) ||
+      (SrcType->isSignedIntegerType() && DestType->isUnsignedIntegerType())) {
+    if (Context.getTypeSize(DestType) == Context.getTypeSize(SrcType)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
                                         QualType DestType, bool CStyle,
                                         const SourceRange &OpRange,
@@ -1324,6 +1363,14 @@
       return TC_NotApplicable;
     }
 
+    QualType DestPointeeType = DestTypeTmp->getPointeeType();
+
+    if (!CStyle && !Self.isCompatibleReinterpretCast(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.
@@ -1345,7 +1392,7 @@
     }
 
     // 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;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 130335)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -8393,7 +8393,18 @@
   Op = ConvResult.take();
   QualType OpTy = Op->getType();
   QualType Result;
-  
+
+  if (isa<CXXReinterpretCastExpr>(Op)) {
+    QualType OpOrigType = Op->IgnoreParenCasts()->getType();
+    const PointerType *OpOrigPointer = OpOrigType->getAs<PointerType>();
+    const PointerType *OpPointer = OpTy->getAs<PointerType>();
+    if (OpOrigPointer && OpPointer)
+      if (!S.isCompatibleReinterpretCast(OpOrigPointer->getPointeeType(),
+                                         OpPointer->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