Author: alexshap Date: Thu Sep 28 16:11:31 2017 New Revision: 314470 URL: http://llvm.org/viewvc/llvm-project?rev=314470&view=rev Log: [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 Modified: cfe/trunk/include/clang/AST/ASTContext.h cfe/trunk/include/clang/Basic/TargetInfo.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/Analysis/PrintfFormatString.cpp cfe/trunk/lib/Analysis/ScanfFormatString.cpp cfe/trunk/test/FixIt/format.m cfe/trunk/test/Sema/format-strings-scanf.c Modified: cfe/trunk/include/clang/AST/ASTContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=314470&r1=314469&r2=314470&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h (original) +++ cfe/trunk/include/clang/AST/ASTContext.h Thu Sep 28 16:11:31 2017 @@ -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; Modified: cfe/trunk/include/clang/Basic/TargetInfo.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=314470&r1=314469&r2=314470&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/TargetInfo.h (original) +++ cfe/trunk/include/clang/Basic/TargetInfo.h Thu Sep 28 16:11:31 2017 @@ -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); Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=314470&r1=314469&r2=314470&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Thu Sep 28 16:11:31 2017 @@ -4571,6 +4571,13 @@ QualType ASTContext::getPointerDiffType( 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 { Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=314470&r1=314469&r2=314470&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original) +++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Thu Sep 28 16:11:31 2017 @@ -505,9 +505,7 @@ ArgType PrintfSpecifier::getArgType(ASTC ? 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: Modified: cfe/trunk/lib/Analysis/ScanfFormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=314470&r1=314469&r2=314470&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original) +++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp Thu Sep 28 16:11:31 2017 @@ -291,8 +291,8 @@ ArgType ScanfSpecifier::getArgType(ASTCo 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); Modified: cfe/trunk/test/FixIt/format.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/format.m?rev=314470&r1=314469&r2=314470&view=diff ============================================================================== --- cfe/trunk/test/FixIt/format.m (original) +++ cfe/trunk/test/FixIt/format.m Thu Sep 28 16:11:31 2017 @@ -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, Modified: cfe/trunk/test/Sema/format-strings-scanf.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-scanf.c?rev=314470&r1=314469&r2=314470&view=diff ============================================================================== --- cfe/trunk/test/Sema/format-strings-scanf.c (original) +++ cfe/trunk/test/Sema/format-strings-scanf.c Thu Sep 28 16:11:31 2017 @@ -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 *'}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits