forked from OSchip/llvm-project
[clang] Add getUnsignedPointerDiffType method
C11 standard refers to the unsigned counterpart of the type ptrdiff_t in the paragraph 7.21.6.1p7 where it defines the format specifier %tu. In Clang (in PrintfFormatString.cpp, lines 508-510) there is a FIXME for this case, in particular, Clang didn't diagnose %tu issues at all, i.e. it didn't emit any warnings on the code printf("%tu", 3.14). In this diff we add a method getUnsignedPointerDiffType for getting the corresponding type similarly to how it's already done in the other analogous cases (size_t, ssize_t, ptrdiff_t etc) and fix -Wformat diagnostics for %tu plus the emitted fix-it as well. Test plan: make check-all Differential revision: https://reviews.llvm.org/D38270 llvm-svn: 314470
This commit is contained in:
parent
ef29a84d48
commit
195b25cf3c
|
@ -1489,6 +1489,11 @@ public:
|
|||
/// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
|
||||
QualType getPointerDiffType() const;
|
||||
|
||||
/// \brief Return the unique unsigned counterpart of "ptrdiff_t"
|
||||
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
|
||||
/// in the definition of %tu format specifier.
|
||||
QualType getUnsignedPointerDiffType() const;
|
||||
|
||||
/// \brief Return the unique type for "pid_t" defined in
|
||||
/// <sys/types.h>. We need this to compute the correct type for vfork().
|
||||
QualType getProcessIDType() const;
|
||||
|
|
|
@ -248,6 +248,9 @@ public:
|
|||
IntType getPtrDiffType(unsigned AddrSpace) const {
|
||||
return AddrSpace == 0 ? PtrDiffType : getPtrDiffTypeV(AddrSpace);
|
||||
}
|
||||
IntType getUnsignedPtrDiffType(unsigned AddrSpace) const {
|
||||
return getCorrespondingUnsignedType(getPtrDiffType(AddrSpace));
|
||||
}
|
||||
IntType getIntPtrType() const { return IntPtrType; }
|
||||
IntType getUIntPtrType() const {
|
||||
return getCorrespondingUnsignedType(IntPtrType);
|
||||
|
|
|
@ -4571,6 +4571,13 @@ QualType ASTContext::getPointerDiffType() const {
|
|||
return getFromTargetType(Target->getPtrDiffType(0));
|
||||
}
|
||||
|
||||
/// \brief Return the unique unsigned counterpart of "ptrdiff_t"
|
||||
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
|
||||
/// in the definition of %tu format specifier.
|
||||
QualType ASTContext::getUnsignedPointerDiffType() const {
|
||||
return getFromTargetType(Target->getUnsignedPtrDiffType(0));
|
||||
}
|
||||
|
||||
/// \brief Return the unique type for "pid_t" defined in
|
||||
/// <sys/types.h>. We need this to compute the correct type for vfork().
|
||||
QualType ASTContext::getProcessIDType() const {
|
||||
|
|
|
@ -505,9 +505,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
|
|||
? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
|
||||
: ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
|
||||
case LengthModifier::AsPtrDiff:
|
||||
// FIXME: How to get the corresponding unsigned
|
||||
// version of ptrdiff_t?
|
||||
return ArgType();
|
||||
return ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t");
|
||||
case LengthModifier::AsAllocate:
|
||||
case LengthModifier::AsMAllocate:
|
||||
case LengthModifier::AsWide:
|
||||
|
|
|
@ -291,8 +291,8 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
case LengthModifier::AsSizeT:
|
||||
return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
|
||||
case LengthModifier::AsPtrDiff:
|
||||
// FIXME: Unsigned version of ptrdiff_t?
|
||||
return ArgType();
|
||||
return ArgType::PtrTo(
|
||||
ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
|
||||
case LengthModifier::AsLongDouble:
|
||||
// GNU extension.
|
||||
return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
|
||||
|
|
|
@ -242,6 +242,37 @@ void testSizeTypes() {
|
|||
// see the comment in PrintfSpecifier::fixType in PrintfFormatString.cpp.
|
||||
}
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
#define __UNSIGNED_PTRDIFF_TYPE__ \
|
||||
__typeof__(_Generic((__PTRDIFF_TYPE__)0, \
|
||||
long long int : (unsigned long long int)0, \
|
||||
long int : (unsigned long int)0, \
|
||||
int : (unsigned int)0, \
|
||||
short : (unsigned short)0, \
|
||||
signed char : (unsigned char)0))
|
||||
|
||||
void testPtrDiffTypes() {
|
||||
__UNSIGNED_PTRDIFF_TYPE__ p1 = 0;
|
||||
printf("%tu", p1); // No warning.
|
||||
|
||||
printf("%tu", 0.f); // expected-warning-re{{format specifies type 'unsigned ptrdiff_t' (aka '{{.+}}') but the argument has type 'float'}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%f"
|
||||
|
||||
ptrdiff_t p2 = 0;
|
||||
printf("%td", p2); // No warning.
|
||||
|
||||
printf("%td", 0.f); // expected-warning-re{{format specifies type 'ptrdiff_t' (aka '{{.+}}') but the argument has type 'float'}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%f"
|
||||
|
||||
ptrdiff_t p3 = 0;
|
||||
printf("%tn", &p3); // No warning.
|
||||
|
||||
short x;
|
||||
printf("%tn", &x); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'short *'}}
|
||||
// PrintfSpecifier::fixType doesn't handle %n, so a fix-it is not emitted,
|
||||
// see the comment in PrintfSpecifier::fixType in PrintfFormatString.cpp.
|
||||
}
|
||||
|
||||
void testEnum() {
|
||||
typedef enum {
|
||||
ImplicitA = 1,
|
||||
|
|
|
@ -13,6 +13,16 @@ typedef __SIZE_TYPE__ size_t;
|
|||
unsigned short : (short)0, \
|
||||
unsigned char : (signed char)0))
|
||||
typedef __SSIZE_TYPE__ ssize_t;
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
#define __UNSIGNED_PTRDIFF_TYPE__ \
|
||||
__typeof__(_Generic((__PTRDIFF_TYPE__)0, \
|
||||
long long int : (unsigned long long int)0, \
|
||||
long int : (unsigned long int)0, \
|
||||
int : (unsigned int)0, \
|
||||
short : (unsigned short)0, \
|
||||
signed char : (unsigned char)0))
|
||||
|
||||
typedef struct _FILE FILE;
|
||||
typedef __WCHAR_TYPE__ wchar_t;
|
||||
|
||||
|
@ -200,6 +210,26 @@ void test_size_types() {
|
|||
scanf("%zn", &d3); // expected-warning-re{{format specifies type 'ssize_t *' (aka '{{.+}}') but the argument has type 'double *'}}
|
||||
}
|
||||
|
||||
void test_ptrdiff_t_types() {
|
||||
__UNSIGNED_PTRDIFF_TYPE__ p1 = 0;
|
||||
scanf("%tu", &p1); // No warning.
|
||||
|
||||
double d1 = 0.;
|
||||
scanf("%tu", &d1); // expected-warning-re{{format specifies type 'unsigned ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}
|
||||
|
||||
ptrdiff_t p2 = 0;
|
||||
scanf("%td", &p2); // No warning.
|
||||
|
||||
double d2 = 0.;
|
||||
scanf("%td", &d2); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}
|
||||
|
||||
ptrdiff_t p3 = 0;
|
||||
scanf("%tn", &p3); // No warning.
|
||||
|
||||
double d3 = 0.;
|
||||
scanf("%tn", &d3); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}
|
||||
}
|
||||
|
||||
void check_conditional_literal(char *s, int *i) {
|
||||
scanf(0 ? "%s" : "%d", i); // no warning
|
||||
scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char *'}}
|
||||
|
|
Loading…
Reference in New Issue