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.
>
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,37 @@
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) {
+ // 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 +1354,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 +1383,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