arphaman created this revision. arphaman added reviewers: ahatanak, vsapsai. Herald added subscribers: jkorous-apple, kristof.beyls, aemerson.
The -Wformat recently started warning for the following code because of the added support for analysis for the '%zi' specifier. NSInteger i = NSIntegerMax; NSLog(@"max NSInteger = %zi", i); The problem is that on armv7 %zi is 'long', and NSInteger is typedefed to 'int' in Foundation. We should avoid this warning as it's inconvenient to our users: it's target specific (happens only on armv7 and not arm64), and breaks their existing code. We should also silence the warning for the '%zu' specifier to ensure consistency. rdar://36874921 Repository: rC Clang https://reviews.llvm.org/D42933 Files: include/clang/Analysis/Analyses/FormatString.h lib/Analysis/PrintfFormatString.cpp lib/Sema/SemaChecking.cpp test/SemaObjC/format-size-spec-nsinteger.m
Index: test/SemaObjC/format-size-spec-nsinteger.m =================================================================== --- /dev/null +++ test/SemaObjC/format-size-spec-nsinteger.m @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple thumbv7-apple-ios -Wformat -fsyntax-only -fblocks -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -triple arm64-apple-ios -Wformat -fsyntax-only -fblocks -verify -Wno-objc-root-class %s +// expected-no-diagnostics + +#if __LP64__ +typedef unsigned long NSUInteger; +typedef long NSInteger; +#else +typedef unsigned int NSUInteger; +typedef int NSInteger; +#endif + +@class NSString; + +extern void NSLog(NSString *format, ...); + +void testSizeSpecifier() { + NSInteger i = 0; + NSUInteger j = 0; + NSLog(@"max NSInteger = %zi", i); + NSLog(@"max NSUinteger = %zu", j); +} Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -6374,6 +6374,11 @@ 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 + // (long in ASTContext). + if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") && + AT.isSizeT() && AT.matchesType(S.Context, CastTy)) + return true; IntendedTy = CastTy; ShouldNotPrintDirectly = true; } Index: lib/Analysis/PrintfFormatString.cpp =================================================================== --- lib/Analysis/PrintfFormatString.cpp +++ lib/Analysis/PrintfFormatString.cpp @@ -466,7 +466,7 @@ case LengthModifier::AsIntMax: return ArgType(Ctx.getIntMaxType(), "intmax_t"); case LengthModifier::AsSizeT: - return ArgType(Ctx.getSignedSizeType(), "ssize_t"); + return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t")); case LengthModifier::AsInt3264: return Ctx.getTargetInfo().getTriple().isArch64Bit() ? ArgType(Ctx.LongLongTy, "__int64") @@ -499,7 +499,7 @@ case LengthModifier::AsIntMax: return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); case LengthModifier::AsSizeT: - return ArgType(Ctx.getSizeType(), "size_t"); + return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t")); case LengthModifier::AsInt3264: return Ctx.getTargetInfo().getTriple().isArch64Bit() ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") Index: include/clang/Analysis/Analyses/FormatString.h =================================================================== --- include/clang/Analysis/Analyses/FormatString.h +++ include/clang/Analysis/Analyses/FormatString.h @@ -257,25 +257,36 @@ const Kind K; QualType T; const char *Name; - bool Ptr; + bool Ptr, IsSizeT; + public: ArgType(Kind k = UnknownTy, const char *n = nullptr) - : K(k), Name(n), Ptr(false) {} + : K(k), Name(n), Ptr(false), IsSizeT(false) {} ArgType(QualType t, const char *n = nullptr) - : K(SpecificTy), T(t), Name(n), Ptr(false) {} - ArgType(CanQualType t) : K(SpecificTy), T(t), Name(nullptr), Ptr(false) {} + : K(SpecificTy), T(t), Name(n), Ptr(false), IsSizeT(false) {} + ArgType(CanQualType t) + : K(SpecificTy), T(t), Name(nullptr), Ptr(false), IsSizeT(false) {} static ArgType Invalid() { return ArgType(InvalidTy); } bool isValid() const { return K != InvalidTy; } + bool isSizeT() const { return IsSizeT; } + /// Create an ArgType which corresponds to the type pointer to A. static ArgType PtrTo(const ArgType& A) { assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); ArgType Res = A; Res.Ptr = true; return Res; } + /// Create an ArgType which corresponds to the size_t/ssize_t type. + static ArgType makeSizeT(const ArgType &A) { + ArgType Res = A; + Res.IsSizeT = true; + return Res; + } + MatchKind matchesType(ASTContext &C, QualType argTy) const; QualType getRepresentativeType(ASTContext &C) const;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits