diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 8c88a42fc2c5..565a01745f11 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -416,7 +416,9 @@ def Format2 : DiagGroup<"format=2", def TypeSafety : DiagGroup<"type-safety">; -def IntToPointerCast : DiagGroup<"int-to-pointer-cast">; +def IntToVoidPointerCast : DiagGroup<"int-to-void-pointer-cast">; +def IntToPointerCast : DiagGroup<"int-to-pointer-cast", + [IntToVoidPointerCast]>; def Extra : DiagGroup<"extra", [ MissingFieldInitializers, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 28ca164ee83a..46351da12f23 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2222,9 +2222,17 @@ def warn_cast_align : Warning< "cast from %0 to %1 increases required alignment from %2 to %3">, InGroup, DefaultIgnore; +// Separate between casts to void* and non-void* pointers. +// Some APIs use (abuse) void* for something like a user context, +// and often that value is an integer even if it isn't a pointer itself. +// Having a separate warning flag allows users to control the warning +// for their workflow. def warn_int_to_pointer_cast : Warning< "cast to %1 from smaller integer type %0">, InGroup; +def warn_int_to_void_pointer_cast : Warning< + "cast to %1 from smaller integer type %0">, + InGroup; def warn_attribute_ignored_for_field_of_type : Warning< "%0 attribute ignored for field of type %1">, diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index eb11a577cb0a..3f0a1a36e46e 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -1614,8 +1614,18 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, && !SrcType->isBooleanType() && !SrcType->isEnumeralType() && !SrcExpr->isIntegerConstantExpr(Self.Context) - && Self.Context.getTypeSize(DestType) > Self.Context.getTypeSize(SrcType)) - Self.Diag(Loc, diag::warn_int_to_pointer_cast) << SrcType << DestType; + && Self.Context.getTypeSize(DestType) > + Self.Context.getTypeSize(SrcType)) { + // Separate between casts to void* and non-void* pointers. + // Some APIs use (abuse) void* for something like a user context, + // and often that value is an integer even if it isn't a pointer itself. + // Having a separate warning flag allows users to control the warning + // for their workflow. + unsigned Diag = DestType->isVoidPointerType() ? + diag::warn_int_to_void_pointer_cast + : diag::warn_int_to_pointer_cast; + Self.Diag(Loc, Diag) << SrcType << DestType; + } } static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, diff --git a/clang/test/Sema/cast.c b/clang/test/Sema/cast.c index 25ef1d03a4fe..7971163c12d0 100644 --- a/clang/test/Sema/cast.c +++ b/clang/test/Sema/cast.c @@ -54,6 +54,14 @@ void testInt(Int v) { (void) (CDouble) v; (void) (VoidPtr) v; // expected-warning{{cast to 'VoidPtr' (aka 'void *') from smaller integer type 'Int' (aka 'int')}} (void) (CharPtr) v; // expected-warning{{cast to 'CharPtr' (aka 'char *') from smaller integer type 'Int' (aka 'int')}} + + // Test that casts to void* can be controlled separately + // from other -Wint-to-pointer-cast warnings. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" + (void) (VoidPtr) v; // no-warning + (void) (CharPtr) v; // expected-warning{{cast to 'CharPtr' (aka 'char *') from smaller integer type 'Int' (aka 'int')}} +#pragma clang diagnostic pop } void testLong(Long v) {