From 7a6d9c12018b01e8d97ccb88367f24d7f38351cc Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Wed, 18 Sep 2019 19:05:14 +0000 Subject: [PATCH] [Sema] Suppress -Wformat diagnostics for bool types when printed using %hhd Also, add a diagnostic under -Wformat for printing a boolean value as a character. rdar://54579473 Differential revision: https://reviews.llvm.org/D66856 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@372247 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 3 ++ lib/AST/FormatString.cpp | 2 + lib/Sema/SemaChecking.cpp | 16 ++++++++ test/Sema/format-bool.c | 46 ++++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 test/Sema/format-bool.c diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b89bd36757..8dd72d27e3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -8145,6 +8145,9 @@ def warn_printf_invalid_objc_flag: Warning< def warn_scanf_scanlist_incomplete : Warning< "no closing ']' for '%%[' in scanf format string">, InGroup; +def warn_format_bool_as_character : Warning< + "using '%0' format specifier, but argument has boolean value">, + InGroup; def note_format_string_defined : Note<"format string is defined here">; def note_format_fix_specifier : Note<"did you mean to use '%0'?">; def note_printf_c_str: Note<"did you mean to call the %0 method?">; diff --git a/lib/AST/FormatString.cpp b/lib/AST/FormatString.cpp index ff439f9921..3c96c80e4c 100644 --- a/lib/AST/FormatString.cpp +++ b/lib/AST/FormatString.cpp @@ -359,6 +359,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Char_U: + case BuiltinType::Bool: return Match; } return NoMatch; @@ -386,6 +387,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::SChar: case BuiltinType::Char_U: case BuiltinType::UChar: + case BuiltinType::Bool: if (T == C.UnsignedShortTy || T == C.ShortTy) return NoMatchPedantic; return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index c7639b4a40..af69c231f1 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -8109,6 +8109,22 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ExprTy = TET->getUnderlyingExpr()->getType(); } + // Diagnose attempts to print a boolean value as a character. Unlike other + // -Wformat diagnostics, this is fine from a type perspective, but it still + // doesn't make sense. + if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::cArg && + E->isKnownToHaveBooleanValue()) { + const CharSourceRange &CSR = + getSpecifierRange(StartSpecifier, SpecifierLen); + SmallString<4> FSString; + llvm::raw_svector_ostream os(FSString); + FS.toString(os); + EmitFormatDiagnostic(S.PDiag(diag::warn_format_bool_as_character) + << FSString, + E->getExprLoc(), false, CSR); + return true; + } + const analyze_printf::ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic; diff --git a/test/Sema/format-bool.c b/test/Sema/format-bool.c new file mode 100644 index 0000000000..53c2c7fd12 --- /dev/null +++ b/test/Sema/format-bool.c @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -xc %s -verify -DBOOL=_Bool +// RUN: %clang_cc1 -xc++ %s -verify -DBOOL=bool +// RUN: %clang_cc1 -xobjective-c %s -verify -DBOOL=_Bool +// RUN: %clang_cc1 -xc %s -verify -DBOOL=_Bool -Wformat-pedantic -DPEDANTIC +// RUN: %clang_cc1 -xc++ %s -verify -DBOOL=bool -Wformat-pedantic -DPEDANTIC + +__attribute__((format(__printf__, 1, 2))) +int p(const char *fmt, ...); + +BOOL b; + +#ifdef __OBJC__ +@interface NSString ++(NSString *)stringWithFormat:(NSString *)fmt, ... + __attribute__((format(__NSString__, 1, 2))); +@end + +#define YES __objc_yes +#define NO __objc_no +#endif + +int main() { + p("%d", b); + p("%hd", b); +#ifdef PEDANTIC + // expected-warning@-2 {{format specifies type 'short' but the argument has type}} +#endif + p("%hhd", b); + p("%u", b); + p("%hu", b); +#ifdef PEDANTIC + // expected-warning@-2 {{format specifies type 'unsigned short' but the argument has type}} +#endif + p("%hhu", b); + p("%c", b); // expected-warning {{using '%c' format specifier, but argument has boolean value}} + p("%lc", b); // expected-warning {{using '%lc' format specifier, but argument has boolean value}} + p("%c", 1 == 1); // expected-warning {{using '%c' format specifier, but argument has boolean value}} + p("%f", b); // expected-warning{{format specifies type 'double' but the argument has type}} + p("%ld", b); // expected-warning{{format specifies type 'long' but the argument has type}} + p("%lld", b); // expected-warning{{format specifies type 'long long' but the argument has type}} + +#ifdef __OBJC__ + [NSString stringWithFormat: @"%c", 0]; // probably fine? + [NSString stringWithFormat: @"%c", NO]; // expected-warning {{using '%c' format specifier, but argument has boolean value}} +#endif +} -- 2.40.0