[Sema] Adds the pointer-to-int-cast diagnostic

Converting a pointer to an integer whose result cannot represented in the
integer type is undefined behavior is C and prohibited in C++. C++ already
has a diagnostic when casting. This adds a diagnostic for C.

Since this diagnostic uses the range of the conversion it also modifies
int-to-pointer-cast diagnostic to use a range.

Fixes PR8718: No warning on casting between pointer and non-pointer-sized int

Differential Revision: https://reviews.llvm.org/D72231
This commit is contained in:
Mark de Wever
2020-02-16 15:01:25 +01:00
parent 1b04866a3d
commit 9658d895c8
23 changed files with 78 additions and 41 deletions

View File

@@ -51,7 +51,8 @@ Major New Features
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ...
- -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
-------------------------------------------------

View File

@@ -836,6 +836,9 @@ def IncompatibleExceptionSpec : DiagGroup<"incompatible-exception-spec">;
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,

View File

@@ -3658,6 +3658,15 @@ def warn_int_to_pointer_cast : Warning<
def warn_int_to_void_pointer_cast : Warning<
"cast to %1 from smaller integer type %0">,
InGroup<IntToVoidPointerCast>;
def warn_pointer_to_int_cast : Warning<
"cast to smaller integer type %1 from %0">,
InGroup<PointerToIntCast>;
def warn_void_pointer_to_int_cast : Warning<
"cast to smaller integer type %1 from %0">,
InGroup<VoidPointerToIntCast>;
def ext_ms_pointer_to_int_cast : ExtWarn<
"cast to smaller integer type %1 from %0 is a Microsoft extension">,
InGroup<MicrosoftCast>;
def warn_attribute_ignored_for_field_of_type : Warning<
"%0 attribute ignored for field of type %1">,

View File

@@ -1961,7 +1961,7 @@ static void DiagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr,
<< 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 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
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 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
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
@@ -2752,8 +2751,8 @@ void CastOperation::CheckCStyleCast() {
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()) {
@@ -2763,6 +2762,21 @@ void CastOperation::CheckCStyleCast() {
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 = Self.getLangOpts().MicrosoftExt
? diag::ext_ms_pointer_to_int_cast
: 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 &&

View File

@@ -523,6 +523,6 @@ struct S {
};
void nocrash_on_locint_offset(void *addr, void* from, struct S s) {
int iAdd = (int) addr;
size_t iAdd = (size_t) addr;
memcpy(((void *) &(s.f)), from, iAdd);
}

View File

@@ -1,7 +1,7 @@
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -analyzer-config eagerly-assume=false %s
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -analyzer-config eagerly-assume=false %s
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -DEAGERLY_ASSUME=1 -w %s
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -DEAGERLY_ASSUME=1 -DBIT32=1 -w %s
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -Wno-pointer-to-int-cast -verify -analyzer-config eagerly-assume=false %s
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -Wno-pointer-to-int-cast -verify -analyzer-config eagerly-assume=false %s
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -Wno-pointer-to-int-cast -verify -DEAGERLY_ASSUME=1 -w %s
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -Wno-pointer-to-int-cast -verify -DEAGERLY_ASSUME=1 -DBIT32=1 -w %s
extern void clang_analyzer_eval(_Bool);

View File

@@ -1,4 +1,4 @@
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -disable-free -analyzer-checker=core,deadcode,debug.ExprInspection -verify %s
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -disable-free -analyzer-checker=core,deadcode,debug.ExprInspection -Wno-pointer-to-int-cast -verify %s
void clang_analyzer_eval(int);

View File

@@ -1,6 +1,6 @@
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-store=region -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-store=region -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-store=region -Wno-pointer-to-int-cast -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-store=region -Wno-pointer-to-int-cast -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
#ifndef __clang_analyzer__
#error __clang_analyzer__ not defined

View File

@@ -1,5 +1,5 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple x86_64-apple-darwin9 -Wno-tautological-pointer-compare -analyzer-config eagerly-assume=false %s
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple i686-apple-darwin9 -Wno-tautological-pointer-compare -analyzer-config eagerly-assume=false %s
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -Wno-pointer-to-int-cast -verify -triple x86_64-apple-darwin9 -Wno-tautological-pointer-compare -analyzer-config eagerly-assume=false %s
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -Wno-pointer-to-int-cast -verify -triple i686-apple-darwin9 -Wno-tautological-pointer-compare -analyzer-config eagerly-assume=false %s
void clang_analyzer_eval(int);

View File

@@ -1,4 +1,4 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -Wno-pointer-to-int-cast -verify %s
// expected-no-diagnostics
// Testing core functionality of the SValBuilder.

View File

@@ -1,4 +1,4 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -Wno-pointer-to-int-cast -verify %s
void clang_analyzer_eval(int);
void clang_analyzer_warnOnDeadSymbol(int);

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -ffreestanding -verify -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -ffreestanding -Wno-pointer-to-int-cast -verify -emit-llvm -o - %s | FileCheck %s
#include <stdint.h>

View File

@@ -92,18 +92,16 @@ enum : long long { // expected-warning{{enumeration types with a fixed underlyi
SomeValue = 0x100000000
};
void pointer_to_integral_type_conv(char* ptr) {
char ch = (char)ptr;
short sh = (short)ptr;
ch = (char)ptr;
sh = (short)ptr;
char ch = (char)ptr; // expected-warning{{cast to smaller integer type 'char' from 'char *' is a Microsoft extension}}
short sh = (short)ptr; // expected-warning{{cast to smaller integer type 'short' from 'char *' is a Microsoft extension}}
ch = (char)ptr; // expected-warning{{cast to smaller integer type 'char' from 'char *' is a Microsoft extension}}
sh = (short)ptr; // expected-warning{{cast to smaller integer type 'short' from 'char *' is a Microsoft extension}}
// This is valid ISO C.
_Bool b = (_Bool)ptr;
_Bool b = (_Bool)ptr; // expected-warning{{cast to smaller integer type '_Bool' from 'char *' is a Microsoft extension}}
}
typedef struct {
UNKNOWN u; // expected-error {{unknown type name 'UNKNOWN'}}
} AA;

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -Wno-int-to-pointer-cast -pedantic -fsyntax-only %s -verify -fblocks
// RUN: %clang_cc1 -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -pedantic -fsyntax-only %s -verify -fblocks
typedef void (^CL)(void);

View File

@@ -151,19 +151,31 @@ void testCDouble(CDouble v) {
}
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;

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s -Wno-tautological-pointer-compare
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast
#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
int x;

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only -ffreestanding
// RUN: %clang_cc1 %s -Wno-pointer-to-int-cast -verify -fsyntax-only -ffreestanding
#include <stddef.h>
#include <stdint.h>

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -Wno-pointer-to-int-cast -fsyntax-only -verify %s
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-bool-conversion %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-pointer-to-int-cast -Wno-bool-conversion %s
typedef __typeof((int*) 0 - (int*) 0) intptr_t;

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -Wno-pointer-to-int-cast -fsyntax-only -verify %s
// PR3459
struct bar {
char n[1];

View File

@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
// RUN: not %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -Wno-objc-root-class -fdiagnostics-parseable-fixits %s 2>&1
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify -Wno-pointer-to-int-cast -Wno-objc-root-class %s
// RUN: not %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -Wno-pointer-to-int-cast -Wno-objc-root-class -fdiagnostics-parseable-fixits %s 2>&1
typedef unsigned long NSUInteger;
typedef const void * CFTypeRef;

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -verify -fms-extensions -Wno-objc-root-class %s
// RUN: %clang_cc1 -verify -Wno-pointer-to-int-cast -Wno-objc-root-class %s
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
typedef struct _NSRange { } NSRange;

View File

@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-pointer-to-int-cast -Wno-objc-root-class %s
// rdar://5986251
@protocol SomeProtocol