diff options
-rw-r--r-- | clang/include/clang/Analysis/Analyses/FormatString.h | 21 | ||||
-rw-r--r-- | clang/lib/Analysis/PrintfFormatString.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 5 | ||||
-rw-r--r-- | clang/test/SemaObjC/format-size-spec-nsinteger.m | 22 |
4 files changed, 47 insertions, 7 deletions
diff --git a/clang/include/clang/Analysis/Analyses/FormatString.h b/clang/include/clang/Analysis/Analyses/FormatString.h index 6d76718048b..6f8bb9b4095 100644 --- a/clang/include/clang/Analysis/Analyses/FormatString.h +++ b/clang/include/clang/Analysis/Analyses/FormatString.h @@ -257,7 +257,12 @@ private: const Kind K; QualType T; const char *Name = nullptr; - bool Ptr = false, IsSizeT = false; + bool Ptr = false; + + /// The TypeKind identifies certain well-known types like size_t and + /// ptrdiff_t. + enum class TypeKind { DontCare, SizeT, PtrdiffT }; + TypeKind TK = TypeKind::DontCare; public: ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {} @@ -267,7 +272,9 @@ public: static ArgType Invalid() { return ArgType(InvalidTy); } bool isValid() const { return K != InvalidTy; } - bool isSizeT() const { return IsSizeT; } + bool isSizeT() const { return TK == TypeKind::SizeT; } + + bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; } /// Create an ArgType which corresponds to the type pointer to A. static ArgType PtrTo(const ArgType& A) { @@ -280,7 +287,15 @@ public: /// Create an ArgType which corresponds to the size_t/ssize_t type. static ArgType makeSizeT(const ArgType &A) { ArgType Res = A; - Res.IsSizeT = true; + Res.TK = TypeKind::SizeT; + return Res; + } + + /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t + /// type. + static ArgType makePtrdiffT(const ArgType &A) { + ArgType Res = A; + Res.TK = TypeKind::PtrdiffT; return Res; } diff --git a/clang/lib/Analysis/PrintfFormatString.cpp b/clang/lib/Analysis/PrintfFormatString.cpp index 93d64f03ead..688b2031a3f 100644 --- a/clang/lib/Analysis/PrintfFormatString.cpp +++ b/clang/lib/Analysis/PrintfFormatString.cpp @@ -472,7 +472,8 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, ? ArgType(Ctx.LongLongTy, "__int64") : ArgType(Ctx.IntTy, "__int32"); case LengthModifier::AsPtrDiff: - return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"); + return ArgType::makePtrdiffT( + ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: case LengthModifier::AsWide: @@ -505,7 +506,8 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); case LengthModifier::AsPtrDiff: - return ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"); + return ArgType::makePtrdiffT( + ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: case LengthModifier::AsWide: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 98aeb61fa75..cd2aabb8948 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6894,10 +6894,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, QualType CastTy; std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E); if (!CastTy.isNull()) { - // %zi/%zu are OK to use for NSInteger/NSUInteger of type int + // %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int // (long in ASTContext). Only complain to pedants. if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") && - AT.isSizeT() && AT.matchesType(S.Context, CastTy)) + (AT.isSizeT() || AT.isPtrdiffT()) && + AT.matchesType(S.Context, CastTy)) Pedantic = true; IntendedTy = CastTy; ShouldNotPrintDirectly = true; diff --git a/clang/test/SemaObjC/format-size-spec-nsinteger.m b/clang/test/SemaObjC/format-size-spec-nsinteger.m index 9eb954ec512..e7c0a0dd101 100644 --- a/clang/test/SemaObjC/format-size-spec-nsinteger.m +++ b/clang/test/SemaObjC/format-size-spec-nsinteger.m @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple thumbv7-apple-ios -Wno-objc-root-class -fsyntax-only -verify -Wformat %s // RUN: %clang_cc1 -triple thumbv7-apple-ios -Wno-objc-root-class -fsyntax-only -verify -Wformat-pedantic -DPEDANTIC %s +// RUN: %clang_cc1 -triple thumbv7k-apple-watchos2.0.0 -fsyntax-only -fblocks -verify %s +// RUN: %clang_cc1 -triple thumbv7k-apple-watchos2.0.0 -fsyntax-only -fblocks -verify -Wformat-pedantic -DPEDANTIC %s #if !defined(PEDANTIC) // expected-no-diagnostics @@ -8,9 +10,16 @@ #if __LP64__ typedef unsigned long NSUInteger; typedef long NSInteger; +typedef long ptrdiff_t; #else typedef unsigned int NSUInteger; typedef int NSInteger; +#if __is_target_os(watchos) + // Watch ABI uses long for ptrdiff_t. + typedef long ptrdiff_t; +#else + typedef int ptrdiff_t; +#endif #endif @class NSString; @@ -28,3 +37,16 @@ void testSizeSpecifier() { // expected-warning@-4 {{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}} #endif } + +void testPtrdiffSpecifier(ptrdiff_t x) { + NSInteger i = 0; + NSUInteger j = 0; + + NSLog(@"ptrdiff_t NSUinteger: %tu", j); + NSLog(@"ptrdiff_t NSInteger: %td", i); + NSLog(@"ptrdiff_t %tu, %td", x, x); +#if __is_target_os(watchos) && defined(PEDANTIC) + // expected-warning@-4 {{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}} + // expected-warning@-4 {{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}} +#endif +} |