[cfe-commits] r130703 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Sema/SemaCXXCast.cpp lib/Sema/SemaExpr.cpp test/SemaCXX/reinterpret-cast.cpp
Argyrios Kyrtzidis
akyrtzi at gmail.com
Mon May 2 11:21:19 PDT 2011
Author: akirtzidis
Date: Mon May 2 13:21:19 2011
New Revision: 130703
URL: http://llvm.org/viewvc/llvm-project?rev=130703&view=rev
Log:
Add a warning for when reinterpret_cast leads to undefined behavior, patch by Richard Trieu!
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaCXXCast.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/SemaCXX/reinterpret-cast.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=130703&r1=130702&r2=130703&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon May 2 13:21:19 2011
@@ -2641,6 +2641,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 %1 that was reinterpret_cast from type %0 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)">;
@@ -2904,6 +2908,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.
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=130703&r1=130702&r2=130703&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon May 2 13:21:19 2011
@@ -2587,6 +2587,10 @@
ParsedType ObjectType,
bool EnteringContext);
+ // Checks that reinterpret casts don't have undefined behavior.
+ void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
+ bool IsDereference, SourceRange Range);
+
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
ExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
tok::TokenKind Kind,
Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=130703&r1=130702&r2=130703&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Mon May 2 13:21:19 2011
@@ -1288,6 +1288,61 @@
return TC_Success;
}
+// Checks for undefined behavior in reinterpret_cast.
+// The cases that is checked for is:
+// *reinterpret_cast<T*>(&a)
+// reinterpret_cast<T&>(a)
+// where accessing 'a' as type 'T' will result in undefined behavior.
+void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
+ bool IsDereference,
+ SourceRange Range) {
+ unsigned DiagID = IsDereference ?
+ diag::warn_pointer_indirection_from_incompatible_type :
+ diag::warn_undefined_reinterpret_cast;
+
+ if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) ==
+ Diagnostic::Ignored) {
+ return;
+ }
+
+ QualType SrcTy, DestTy;
+ if (IsDereference) {
+ if (!SrcType->getAs<PointerType>() || !DestType->getAs<PointerType>()) {
+ return;
+ }
+ SrcTy = SrcType->getPointeeType();
+ DestTy = DestType->getPointeeType();
+ } else {
+ if (!DestType->getAs<ReferenceType>()) {
+ return;
+ }
+ SrcTy = SrcType;
+ DestTy = DestType->getPointeeType();
+ }
+
+ // Cast is compatible if the types are the same.
+ if (Context.hasSameUnqualifiedType(DestTy, SrcTy)) {
+ return;
+ }
+ // or one of the types is a char or void type
+ if (DestTy->isAnyCharacterType() || DestTy->isVoidType() ||
+ SrcTy->isAnyCharacterType() || SrcTy->isVoidType()) {
+ return;
+ }
+ // or one of the types is a tag type.
+ if (isa<TagType>(SrcTy) || isa<TagType>(DestTy)) {
+ return;
+ }
+
+ if ((SrcTy->isUnsignedIntegerType() && DestTy->isSignedIntegerType()) ||
+ (SrcTy->isSignedIntegerType() && DestTy->isUnsignedIntegerType())) {
+ if (Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy)) {
+ return;
+ }
+ }
+
+ Diag(Range.getBegin(), DiagID) << SrcType << DestType << Range;
+}
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
@@ -1324,6 +1379,11 @@
return TC_NotApplicable;
}
+ if (!CStyle) {
+ Self.CheckCompatibleReinterpretCast(SrcType, DestType,
+ /*isDereference=*/false, 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.
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=130703&r1=130702&r2=130703&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon May 2 13:21:19 2011
@@ -8404,7 +8404,13 @@
Op = ConvResult.take();
QualType OpTy = Op->getType();
QualType Result;
-
+
+ if (isa<CXXReinterpretCastExpr>(Op)) {
+ QualType OpOrigType = Op->IgnoreParenCasts()->getType();
+ S.CheckCompatibleReinterpretCast(OpOrigType, OpTy, /*IsDereference*/true,
+ 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
Modified: cfe/trunk/test/SemaCXX/reinterpret-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/reinterpret-cast.cpp?rev=130703&r1=130702&r2=130703&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/reinterpret-cast.cpp (original)
+++ cfe/trunk/test/SemaCXX/reinterpret-cast.cpp Mon May 2 13:21:19 2011
@@ -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,155 @@
__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;
+ B b;
+ long l;
+ double d;
+ float f;
+ char c;
+ unsigned char uc;
+ void* v_ptr;
+ (void)reinterpret_cast<double&>(l); // expected-warning {{reinterpret_cast from 'long' to 'double &' has undefined behavior}}
+ (void)*reinterpret_cast<double*>(&l); // expected-warning {{dereference of type 'double *' that was reinterpret_cast from type 'long *' has undefined behavior}}
+ (void)reinterpret_cast<double&>(f); // expected-warning {{reinterpret_cast from 'float' to 'double &' has undefined behavior}}
+ (void)*reinterpret_cast<double*>(&f); // expected-warning {{dereference of type 'double *' that was reinterpret_cast from type 'float *' has undefined behavior}}
+ (void)reinterpret_cast<float&>(l); // expected-warning {{reinterpret_cast from 'long' to 'float &' has undefined behavior}}
+ (void)*reinterpret_cast<float*>(&l); // expected-warning {{dereference of type 'float *' that was reinterpret_cast from type 'long *' has undefined behavior}}
+ (void)reinterpret_cast<float&>(d); // expected-warning {{reinterpret_cast from 'double' to 'float &' has undefined behavior}}
+ (void)*reinterpret_cast<float*>(&d); // expected-warning {{dereference of type 'float *' that was reinterpret_cast from type 'double *' has undefined behavior}}
+
+ // TODO: add warning for tag types
+ (void)reinterpret_cast<A&>(b);
+ (void)*reinterpret_cast<A*>(&b);
+ (void)reinterpret_cast<B&>(a);
+ (void)*reinterpret_cast<B*>(&a);
+
+ // Casting to itself is allowed
+ (void)reinterpret_cast<A&>(a);
+ (void)*reinterpret_cast<A*>(&a);
+ (void)reinterpret_cast<B&>(b);
+ (void)*reinterpret_cast<B*>(&b);
+ (void)reinterpret_cast<long&>(l);
+ (void)*reinterpret_cast<long*>(&l);
+ (void)reinterpret_cast<double&>(d);
+ (void)*reinterpret_cast<double*>(&d);
+ (void)reinterpret_cast<char&>(c);
+ (void)*reinterpret_cast<char*>(&c);
+
+ // Casting to and from chars are allowable
+ (void)reinterpret_cast<A&>(c);
+ (void)*reinterpret_cast<A*>(&c);
+ (void)reinterpret_cast<B&>(c);
+ (void)*reinterpret_cast<B*>(&c);
+ (void)reinterpret_cast<long&>(c);
+ (void)*reinterpret_cast<long*>(&c);
+ (void)reinterpret_cast<double&>(c);
+ (void)*reinterpret_cast<double*>(&c);
+ (void)reinterpret_cast<char&>(l);
+ (void)*reinterpret_cast<char*>(&l);
+ (void)reinterpret_cast<char&>(d);
+ (void)*reinterpret_cast<char*>(&d);
+ (void)reinterpret_cast<char&>(f);
+ (void)*reinterpret_cast<char*>(&f);
+
+ // Casting from void pointer.
+ (void)*reinterpret_cast<A*>(v_ptr);
+ (void)*reinterpret_cast<B*>(v_ptr);
+ (void)*reinterpret_cast<long*>(v_ptr);
+ (void)*reinterpret_cast<double*>(v_ptr);
+ (void)*reinterpret_cast<float*>(v_ptr);
+
+ // Casting to void pointer
+ (void)*reinterpret_cast<void*>(&a);
+ (void)*reinterpret_cast<void*>(&b);
+ (void)*reinterpret_cast<void*>(&l);
+ (void)*reinterpret_cast<void*>(&d);
+ (void)*reinterpret_cast<void*>(&f);
+}
+
+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);
+}
More information about the cfe-commits
mailing list