Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -64,6 +64,8 @@ - -Wbitwise-conditional-parentheses will warn on operator precedence issues when mixing bitwise-and (&) and bitwise-or (|) operator with the conditional operator (?:). +- -Wpointer-to-int-cast is a new warning group. This group warns about C-style + casts of pointers to a integer type too small to hold all possible values. Non-comprehensive list of changes in this release ------------------------------------------------- Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -832,6 +832,9 @@ def IntToVoidPointerCast : DiagGroup<"int-to-void-pointer-cast">; def IntToPointerCast : DiagGroup<"int-to-pointer-cast", [IntToVoidPointerCast]>; +def VoidPointerToIntCast : DiagGroup<"void-pointer-to-int-cast">; +def PointerToIntCast : DiagGroup<"pointer-to-int-cast", + [VoidPointerToIntCast]>; def Move : DiagGroup<"move", [ PessimizingMove, Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3534,6 +3534,12 @@ def warn_int_to_void_pointer_cast : Warning< "cast to %1 from smaller integer type %0">, InGroup; +def warn_pointer_to_int_cast : Warning< + "cast to smaller integer type %1 from %0">, + InGroup, DefaultIgnore; +def warn_void_pointer_to_int_cast : Warning< + "cast to smaller integer type %1 from %0">, + InGroup, DefaultIgnore; def warn_attribute_ignored_for_field_of_type : Warning< "%0 attribute ignored for field of type %1">, Index: clang/lib/Sema/SemaCast.cpp =================================================================== --- clang/lib/Sema/SemaCast.cpp +++ clang/lib/Sema/SemaCast.cpp @@ -1961,7 +1961,7 @@ << FD << DstCCName << FixItHint::CreateInsertion(NameLoc, CCAttrText); } -static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, +static void checkIntToPointerCast(bool CStyle, const SourceRange &OpRange, const Expr *SrcExpr, QualType DestType, Sema &Self) { QualType SrcType = SrcExpr->getType(); @@ -1983,7 +1983,7 @@ unsigned Diag = DestType->isVoidPointerType() ? diag::warn_int_to_void_pointer_cast : diag::warn_int_to_pointer_cast; - Self.Diag(Loc, Diag) << SrcType << DestType; + Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange; } } @@ -2218,8 +2218,7 @@ if (SrcType->isIntegralOrEnumerationType()) { assert(destIsPtr && "One type must be a pointer"); - checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType, - Self); + checkIntToPointerCast(CStyle, OpRange, SrcExpr.get(), DestType, Self); // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly // converted to a pointer. // C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not @@ -2734,8 +2733,8 @@ SrcExpr = ExprError(); return; } - checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(), - DestType, Self); + checkIntToPointerCast(/* CStyle */ true, OpRange, SrcExpr.get(), DestType, + Self); } else if (!SrcType->isArithmeticType()) { if (!DestType->isIntegralType(Self.Context) && DestType->isArithmeticType()) { @@ -2745,6 +2744,19 @@ SrcExpr = ExprError(); return; } + + if ((Self.Context.getTypeSize(SrcType) > + Self.Context.getTypeSize(DestType))) { + // C 6.3.2.3p6: Any pointer type may be converted to an integer type. + // Except as previously specified, the result is implementation-defined. + // If the result cannot be represented in the integer type, the behavior + // is undefined. The result need not be in the range of values of any + // integer type. + unsigned Diag = SrcType->isVoidPointerType() + ? diag::warn_void_pointer_to_int_cast + : diag::warn_pointer_to_int_cast; + Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange; + } } if (Self.getLangOpts().OpenCL && Index: clang/test/Sema/cast.c =================================================================== --- clang/test/Sema/cast.c +++ clang/test/Sema/cast.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown %s -verify +// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -Wpointer-to-int-cast %s -verify typedef struct { unsigned long bits[(((1) + (64) - 1) / (64))]; } cpumask_t; cpumask_t x; @@ -151,19 +151,31 @@ } void testVoidPtr(VoidPtr v) { - (void) (Bool) v; - (void) (Int) v; + (void) (Bool) v; // expected-warning{{cast to smaller integer type 'Bool' (aka '_Bool') from 'VoidPtr' (aka 'void *')}} + (void) (Int) v; // expected-warning{{cast to smaller integer type 'Int' (aka 'int') from 'VoidPtr' (aka 'void *')}} (void) (Long) v; (void) (VoidPtr) v; (void) (CharPtr) v; + // Test that casts to void* can be controlled separately + // from other -Wpointer-to-int-cast warnings. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvoid-pointer-to-int-cast" + (void) (Bool) v; // no-warning +#pragma clang diagnostic pop } void testCharPtr(CharPtr v) { - (void) (Bool) v; - (void) (Int) v; + (void) (Bool) v; // expected-warning{{cast to smaller integer type 'Bool' (aka '_Bool') from 'CharPtr' (aka 'char *')}} + (void) (Int) v; // expected-warning{{cast to smaller integer type 'Int' (aka 'int') from 'CharPtr' (aka 'char *')}} (void) (Long) v; (void) (VoidPtr) v; (void) (CharPtr) v; + // Test that casts to void* can be controlled separately + // from other -Wpointer-to-int-cast warnings. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvoid-pointer-to-int-cast" + (void) (Bool) v; // expected-warning{{cast to smaller integer type 'Bool' (aka '_Bool') from 'CharPtr' (aka 'char *')}} +#pragma clang diagnostic pop } typedef enum { x_a, x_b } X;