diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticGroups.td | 2 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaCXXCast.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 45 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 4 | ||||
| -rw-r--r-- | clang/test/Sema/warn-cast-align.c | 41 | ||||
| -rw-r--r-- | clang/test/SemaCXX/warn-cast-align.cpp | 45 |
8 files changed, 147 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 6849349a91b..f0ad0ab4371 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -26,7 +26,7 @@ def : DiagGroup<"attributes">; def : DiagGroup<"bad-function-cast">; def BoolConversions : DiagGroup<"bool-conversions">; def CXXCompat: DiagGroup<"c++-compat">; -def : DiagGroup<"cast-align">; +def CastAlign : DiagGroup<"cast-align">; def : DiagGroup<"cast-qual">; def : DiagGroup<"char-align">; def Comment : DiagGroup<"comment">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a9e976f434a..9663acc6a3c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -971,6 +971,10 @@ def warn_impcast_integer_64_32 : Warning< "implicit conversion loses integer precision: %0 to %1">, InGroup<DiagGroup<"shorten-64-to-32">>, DefaultIgnore; +def warn_cast_align : Warning< + "cast from %0 to %1 increases required alignment from %2 to %3">, + InGroup<CastAlign>, DefaultIgnore; + def warn_attribute_ignored_for_field_of_type : Warning< "%0 attribute ignored for field of type %1">; def warn_transparent_union_attribute_field_size_align : Warning< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0d7ac70881a..f3d15657a17 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -860,6 +860,7 @@ public: void DiagnoseFunctionSpecifiers(Declarator& D); void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); void CheckShadow(Scope *S, VarDecl *D); + void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index 5753e7bce47..59df294772e 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -468,6 +468,8 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret << SrcExpr->getType() << DestType << OpRange; + else if (Kind == CastExpr::CK_Unknown || Kind == CastExpr::CK_BitCast) + Self.CheckCastAlign(SrcExpr, DestType, OpRange); } @@ -494,6 +496,8 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, Kind, BasePath) != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Static << SrcExpr->getType() << DestType << OpRange; + else if (Kind == CastExpr::CK_Unknown || Kind == CastExpr::CK_BitCast) + Self.CheckCastAlign(SrcExpr, DestType, OpRange); } /// TryStaticCast - Check if a static cast can be performed, and do so if @@ -1303,6 +1307,8 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, if (tcr != TC_Success && msg != 0) Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle) << CastExpr->getType() << CastTy << R; + else if (Kind == CastExpr::CK_Unknown || Kind == CastExpr::CK_BitCast) + CheckCastAlign(CastExpr, CastTy, R); return tcr != TC_Success; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 7e1eebebdbf..14c0d87ffb7 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2796,3 +2796,48 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { return HasInvalidParm; } + +/// CheckCastAlign - Implements -Wcast-align, which warns when a +/// pointer cast increases the alignment requirements. +void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { + // This is actually a lot of work to potentially be doing on every + // cast; don't do it if we're ignoring -Wcast_align (as is the default). + if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align) + == Diagnostic::Ignored) + return; + + // Ignore dependent types. + if (T->isDependentType() || Op->getType()->isDependentType()) + return; + + // Require that the destination be a pointer type. + const PointerType *DestPtr = T->getAs<PointerType>(); + if (!DestPtr) return; + + // If the destination has alignment 1, we're done. + QualType DestPointee = DestPtr->getPointeeType(); + if (DestPointee->isIncompleteType()) return; + CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee); + if (DestAlign.isOne()) return; + + // Require that the source be a pointer type. + const PointerType *SrcPtr = Op->getType()->getAs<PointerType>(); + if (!SrcPtr) return; + QualType SrcPointee = SrcPtr->getPointeeType(); + + // Whitelist casts from cv void*. We already implicitly + // whitelisted casts to cv void*, since they have alignment 1. + // Also whitelist casts involving incomplete types, which implicitly + // includes 'void'. + if (SrcPointee->isIncompleteType()) return; + + CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee); + if (SrcAlign >= DestAlign) return; + + Diag(TRange.getBegin(), diag::warn_cast_align) + << Op->getType() << T + << static_cast<unsigned>(SrcAlign.getQuantity()) + << static_cast<unsigned>(DestAlign.getQuantity()) + << TRange << Op->getSourceRange(); +} + diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 8643dd8386d..f87d39fd8f0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3995,6 +3995,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, } Kind = getScalarCastKind(Context, castExpr->getType(), castType); + + if (Kind == CastExpr::CK_Unknown || Kind == CastExpr::CK_BitCast) + CheckCastAlign(castExpr, castType, TyR); + return false; } diff --git a/clang/test/Sema/warn-cast-align.c b/clang/test/Sema/warn-cast-align.c new file mode 100644 index 00000000000..11e3c416364 --- /dev/null +++ b/clang/test/Sema/warn-cast-align.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -Wcast-align -verify %s + +// Simple casts. +void test0(char *P) { + char *a = (char*) P; + short *b = (short*) P; // expected-warning {{cast from 'char *' to 'short *' increases required alignment from 1 to 2}} + int *c = (int*) P; // expected-warning {{cast from 'char *' to 'int *' increases required alignment from 1 to 4}} +} + +// Casts from void* are a special case. +void test1(void *P) { + char *a = (char*) P; + short *b = (short*) P; + int *c = (int*) P; + + const volatile void *P2 = P; + char *d = (char*) P2; + short *e = (short*) P2; + int *f = (int*) P2; + + const char *g = (const char*) P2; + const short *h = (const short*) P2; + const int *i = (const int*) P2; + + const volatile char *j = (const volatile char*) P2; + const volatile short *k = (const volatile short*) P2; + const volatile int *l = (const volatile int*) P2; +} + +// Aligned struct. +__attribute__((align(16))) struct A { + char buffer[16]; +}; +void test2(char *P) { + struct A *a = (struct A*) P; // expected-warning {{cast from 'char *' to 'struct A *' increases required alignment from 1 to 16}} +} + +// Incomplete type. +void test3(char *P) { + struct B *b = (struct B*) P; +} diff --git a/clang/test/SemaCXX/warn-cast-align.cpp b/clang/test/SemaCXX/warn-cast-align.cpp new file mode 100644 index 00000000000..d2144d279eb --- /dev/null +++ b/clang/test/SemaCXX/warn-cast-align.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -Wcast-align -verify %s + +// Simple casts. +void test0(char *P) { + char *a; short *b; int *c; + + a = (char*) P; + a = static_cast<char*>(P); + a = reinterpret_cast<char*>(P); + typedef char *CharPtr; + a = CharPtr(P); + + b = (short*) P; // expected-warning {{cast from 'char *' to 'short *' increases required alignment from 1 to 2}} + b = reinterpret_cast<short*>(P); // expected-warning {{cast from 'char *' to 'short *' increases required alignment from 1 to 2}} + typedef short *ShortPtr; + b = ShortPtr(P); // expected-warning {{cast from 'char *' to 'ShortPtr' (aka 'short *') increases required alignment from 1 to 2}} + + c = (int*) P; // expected-warning {{cast from 'char *' to 'int *' increases required alignment from 1 to 4}} + c = reinterpret_cast<int*>(P); // expected-warning {{cast from 'char *' to 'int *' increases required alignment from 1 to 4}} + typedef int *IntPtr; + c = IntPtr(P); // expected-warning {{cast from 'char *' to 'IntPtr' (aka 'int *') increases required alignment from 1 to 4}} +} + +// Casts from void* are a special case. +void test1(void *P) { + char *a; short *b; int *c; + + a = (char*) P; + a = static_cast<char*>(P); + a = reinterpret_cast<char*>(P); + typedef char *CharPtr; + a = CharPtr(P); + + b = (short*) P; + b = static_cast<short*>(P); + b = reinterpret_cast<short*>(P); + typedef short *ShortPtr; + b = ShortPtr(P); + + c = (int*) P; + c = static_cast<int*>(P); + c = reinterpret_cast<int*>(P); + typedef int *IntPtr; + c = IntPtr(P); +} |

