summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Analysis/Analyses/FormatString.h22
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--clang/lib/Analysis/PrintfFormatString.cpp4
-rw-r--r--clang/lib/Sema/SemaChecking.cpp66
-rw-r--r--clang/test/FixIt/fixit-format-ios-nopedantic.m21
-rw-r--r--clang/test/FixIt/fixit-format-ios.m2
-rw-r--r--clang/test/SemaObjC/format-size-spec-nsinteger.m30
7 files changed, 109 insertions, 40 deletions
diff --git a/clang/include/clang/Analysis/Analyses/FormatString.h b/clang/include/clang/Analysis/Analyses/FormatString.h
index a23aaae7662..6d76718048b 100644
--- a/clang/include/clang/Analysis/Analyses/FormatString.h
+++ b/clang/include/clang/Analysis/Analyses/FormatString.h
@@ -256,18 +256,19 @@ public:
private:
const Kind K;
QualType T;
- const char *Name;
- bool Ptr;
+ const char *Name = nullptr;
+ bool Ptr = false, IsSizeT = false;
+
public:
- ArgType(Kind k = UnknownTy, const char *n = nullptr)
- : K(k), Name(n), Ptr(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) {}
+ ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
+ ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
+ ArgType(CanQualType T) : K(SpecificTy), T(T) {}
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");
@@ -276,6 +277,13 @@ public:
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;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b7ede8518ee..f08cd00c62e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7719,6 +7719,10 @@ def warn_format_argument_needs_cast : Warning<
"%select{values of type|enum values with underlying type}2 '%0' should not "
"be used as format arguments; add an explicit cast to %1 instead">,
InGroup<Format>;
+def warn_format_argument_needs_cast_pedantic : Warning<
+ "%select{values of type|enum values with underlying type}2 '%0' should not "
+ "be used as format arguments; add an explicit cast to %1 instead">,
+ InGroup<FormatPedantic>, DefaultIgnore;
def warn_printf_positional_arg_exceeds_data_args : Warning <
"data argument position '%0' exceeds the number of data arguments (%1)">,
InGroup<Format>;
diff --git a/clang/lib/Analysis/PrintfFormatString.cpp b/clang/lib/Analysis/PrintfFormatString.cpp
index 3b64508b5a6..93d64f03ead 100644
--- a/clang/lib/Analysis/PrintfFormatString.cpp
+++ b/clang/lib/Analysis/PrintfFormatString.cpp
@@ -466,7 +466,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
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 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
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")
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 53be0f6d9ff..12a599b4f13 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6805,11 +6805,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
ExprTy = TET->getUnderlyingExpr()->getType();
}
- analyze_printf::ArgType::MatchKind match = AT.matchesType(S.Context, ExprTy);
-
- if (match == analyze_printf::ArgType::Match) {
+ const analyze_printf::ArgType::MatchKind Match =
+ AT.matchesType(S.Context, ExprTy);
+ bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic;
+ if (Match == analyze_printf::ArgType::Match)
return true;
- }
// Look through argument promotions for our error message's reported type.
// This includes the integral and floating promotions, but excludes array
@@ -6885,6 +6885,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
+ // (long in ASTContext). Only complain to pedants.
+ if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
+ AT.isSizeT() && AT.matchesType(S.Context, CastTy))
+ Pedantic = true;
IntendedTy = CastTy;
ShouldNotPrintDirectly = true;
}
@@ -6892,10 +6897,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// We may be able to offer a FixItHint if it is a supported type.
PrintfSpecifier fixedFS = FS;
- bool success =
+ bool Success =
fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext());
- if (success) {
+ if (Success) {
// Get the fix string from the fixed format specifier
SmallString<16> buf;
llvm::raw_svector_ostream os(buf);
@@ -6904,13 +6909,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) {
- unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
- if (match == analyze_format_string::ArgType::NoMatchPedantic) {
- diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
- }
+ unsigned Diag =
+ Pedantic
+ ? diag::warn_format_conversion_argument_type_mismatch_pedantic
+ : diag::warn_format_conversion_argument_type_mismatch;
// In this case, the specifier is wrong and should be changed to match
// the argument.
- EmitFormatDiagnostic(S.PDiag(diag)
+ EmitFormatDiagnostic(S.PDiag(Diag)
<< AT.getRepresentativeTypeName(S.Context)
<< IntendedTy << IsEnum << E->getSourceRange(),
E->getLocStart(),
@@ -6963,9 +6968,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
Name = TypedefTy->getDecl()->getName();
else
Name = CastTyName;
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
- << Name << IntendedTy << IsEnum
- << E->getSourceRange(),
+ unsigned Diag = Pedantic
+ ? diag::warn_format_argument_needs_cast_pedantic
+ : diag::warn_format_argument_needs_cast;
+ EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum
+ << E->getSourceRange(),
E->getLocStart(), /*IsStringLocation=*/false,
SpecRange, Hints);
} else {
@@ -6989,13 +6996,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
switch (S.isValidVarArgType(ExprTy)) {
case Sema::VAK_Valid:
case Sema::VAK_ValidInCXX11: {
- unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
- if (match == analyze_printf::ArgType::NoMatchPedantic) {
- diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
- }
+ unsigned Diag =
+ Pedantic
+ ? diag::warn_format_conversion_argument_type_mismatch_pedantic
+ : diag::warn_format_conversion_argument_type_mismatch;
EmitFormatDiagnostic(
- S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
+ S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
<< IsEnum << CSR << E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/ false, CSR);
break;
@@ -7178,29 +7185,28 @@ bool CheckScanfHandler::HandleScanfSpecifier(
return true;
}
- analyze_format_string::ArgType::MatchKind match =
+ analyze_format_string::ArgType::MatchKind Match =
AT.matchesType(S.Context, Ex->getType());
- if (match == analyze_format_string::ArgType::Match) {
+ bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic;
+ if (Match == analyze_format_string::ArgType::Match)
return true;
- }
ScanfSpecifier fixedFS = FS;
- bool success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(),
+ bool Success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(),
S.getLangOpts(), S.Context);
- unsigned diag = diag::warn_format_conversion_argument_type_mismatch;
- if (match == analyze_format_string::ArgType::NoMatchPedantic) {
- diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
- }
+ unsigned Diag =
+ Pedantic ? diag::warn_format_conversion_argument_type_mismatch_pedantic
+ : diag::warn_format_conversion_argument_type_mismatch;
- if (success) {
+ if (Success) {
// Get the fix string from the fixed format specifier.
SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
fixedFS.toString(os);
EmitFormatDiagnostic(
- S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context)
+ S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context)
<< Ex->getType() << false << Ex->getSourceRange(),
Ex->getLocStart(),
/*IsStringLocation*/ false,
@@ -7208,7 +7214,7 @@ bool CheckScanfHandler::HandleScanfSpecifier(
FixItHint::CreateReplacement(
getSpecifierRange(startSpecifier, specifierLen), os.str()));
} else {
- EmitFormatDiagnostic(S.PDiag(diag)
+ EmitFormatDiagnostic(S.PDiag(Diag)
<< AT.getRepresentativeTypeName(S.Context)
<< Ex->getType() << false << Ex->getSourceRange(),
Ex->getLocStart(),
diff --git a/clang/test/FixIt/fixit-format-ios-nopedantic.m b/clang/test/FixIt/fixit-format-ios-nopedantic.m
new file mode 100644
index 00000000000..0b332376c06
--- /dev/null
+++ b/clang/test/FixIt/fixit-format-ios-nopedantic.m
@@ -0,0 +1,21 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -fsyntax-only -Wformat -Werror -fixit %t
+
+int printf(const char *restrict, ...);
+typedef unsigned int NSUInteger;
+typedef int NSInteger;
+NSUInteger getNSUInteger();
+NSInteger getNSInteger();
+
+void test() {
+ // For thumbv7-apple-ios8.0.0 the underlying type of ssize_t is long
+ // and the underlying type of size_t is unsigned long.
+
+ printf("test 1: %zu", getNSUInteger());
+
+ printf("test 2: %zu %zu", getNSUInteger(), getNSUInteger());
+
+ printf("test 3: %zd", getNSInteger());
+
+ printf("test 4: %zd %zd", getNSInteger(), getNSInteger());
+}
diff --git a/clang/test/FixIt/fixit-format-ios.m b/clang/test/FixIt/fixit-format-ios.m
index ef664307786..9c3670d0c84 100644
--- a/clang/test/FixIt/fixit-format-ios.m
+++ b/clang/test/FixIt/fixit-format-ios.m
@@ -1,5 +1,5 @@
// RUN: cp %s %t
-// RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -fsyntax-only -Wformat -fixit %t
+// RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -fsyntax-only -Wformat-pedantic -fixit %t
// RUN: grep -v CHECK %t | FileCheck %s
int printf(const char * restrict, ...);
diff --git a/clang/test/SemaObjC/format-size-spec-nsinteger.m b/clang/test/SemaObjC/format-size-spec-nsinteger.m
new file mode 100644
index 00000000000..9eb954ec512
--- /dev/null
+++ b/clang/test/SemaObjC/format-size-spec-nsinteger.m
@@ -0,0 +1,30 @@
+// 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
+
+#if !defined(PEDANTIC)
+// expected-no-diagnostics
+#endif
+
+#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);
+
+#if defined(PEDANTIC)
+ // expected-warning@-4 {{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ // expected-warning@-4 {{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+#endif
+}
OpenPOWER on IntegriCloud