https://github.com/drodriguez updated 
https://github.com/llvm/llvm-project/pull/126694

From 6dd960c6cf0550763b986f1909373a5b7e3a069d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Rodri=CC=81guez=20Troitin=CC=83o?=
 <[email protected]>
Date: Mon, 10 Feb 2025 23:23:58 -0800
Subject: [PATCH] [Sema] -Wformat: warn about C23 %b %B when not in C23
 language mode

The validation of %b and %B was done without taking into account the
current language mode, which means that %b and %B could have been used
in format strings before they were supported.

Change the code to check for the language mode being C23 or after,
modify some tests that use %b and %B to specify C23 language mode and
add a new test that checks the different behaviour depending on the
current language mode.
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 ++
 clang/lib/AST/PrintfFormatString.cpp          |  4 ++-
 clang/lib/Sema/SemaChecking.cpp               | 12 +++++++
 clang/test/Sema/format-strings-c23-binary.c   | 32 +++++++++++++++++++
 clang/test/Sema/format-strings-fixit.c        |  6 ++--
 clang/test/Sema/format-strings.c              |  8 ++---
 6 files changed, 57 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/Sema/format-strings-c23-binary.c

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ef0e29af0f224..d3e42c4e5596b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10631,6 +10631,9 @@ def warn_printf_data_arg_not_used : Warning<
   "data argument not used by format string">, InGroup<FormatExtraArgs>;
 def warn_format_invalid_conversion : Warning<
   "invalid conversion specifier '%0'">, InGroup<FormatInvalidSpecifier>;
+def warn_format_conversion_specifier_requires_c23 : Warning<
+  "conversion specifier '%0' requires a C standard library compatible with "
+  "C23; data argument may not be used by format">, InGroup<Format>;
 def warn_printf_incomplete_specifier : Warning<
   "incomplete format specifier">, InGroup<Format>;
 def warn_missing_format_string : Warning<
diff --git a/clang/lib/AST/PrintfFormatString.cpp 
b/clang/lib/AST/PrintfFormatString.cpp
index 855550475721a..2e0adddb70369 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -333,7 +333,9 @@ static PrintfSpecifierResult 
ParsePrintfSpecifier(FormatStringHandler &H,
       else
         k = ConversionSpecifier::bArg;
       break;
-    case 'B': k = ConversionSpecifier::BArg; break;
+    case 'B':
+      k = ConversionSpecifier::BArg;
+      break;
     // POSIX specific.
     case 'C': k = ConversionSpecifier::CArg; break;
     case 'S': k = ConversionSpecifier::SArg; break;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index a49e3883a35a5..a09bf79cfb8ed 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8863,6 +8863,18 @@ bool CheckPrintfHandler::HandlePrintfSpecifier(
   if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
     HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
 
+  // Warn about C23 %b/%B format specifiers when not in C23 mode.
+  if ((CS.getKind() == ConversionSpecifier::bArg ||
+       CS.getKind() == ConversionSpecifier::BArg) &&
+      !LangStandard::getLangStandardForKind(S.getLangOpts().LangStd).isC23()) {
+    EmitFormatDiagnostic(
+        S.PDiag(diag::warn_format_conversion_specifier_requires_c23)
+            << CS.toString(),
+        getLocationOfByte(CS.getStart()), /*IsStringLocation*/ true,
+        getSpecifierRange(startSpecifier, specifierLen));
+    return true;
+  }
+
   // The remaining checks depend on the data arguments.
   if (!HasFormatArguments())
     return true;
diff --git a/clang/test/Sema/format-strings-c23-binary.c 
b/clang/test/Sema/format-strings-c23-binary.c
new file mode 100644
index 0000000000000..a023df82c9a05
--- /dev/null
+++ b/clang/test/Sema/format-strings-c23-binary.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c17 -fsyntax-only -verify=c17 -isystem %S/Inputs %s
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify=c23 -isystem %S/Inputs %s
+
+#include <stdarg.h>
+#include <stddef.h>
+
+int printf(const char *restrict, ...);
+
+void test(unsigned char x) {
+  printf("%lb %lB", (long) 10, (long) 10); // c17-warning{{conversion 
specifier 'b' requires a C standard library compatible with C23; data argument 
may not be used by format}}
+                                           // c17-warning@-1{{conversion 
specifier 'B' requires a C standard library compatible with C23; data argument 
may not be used by format}}
+
+  printf("%llb %llB", (long long) 10, (long long) 10); // 
c17-warning{{conversion specifier 'b' requires a C standard library compatible 
with C23; data argument may not be used by format}}
+                                                       // 
c17-warning@-1{{conversion specifier 'B' requires a C standard library 
compatible with C23; data argument may not be used by format}}
+
+  printf("%0b%0B", -1u, -1u); // c17-warning{{conversion specifier 'b' 
requires a C standard library compatible with C23; data argument may not be 
used by format}}
+                              // c17-warning@-1{{conversion specifier 'B' 
requires a C standard library compatible with C23; data argument may not be 
used by format}}
+
+  printf("%#b %#15.8B\n", 10, 10u); // c17-warning{{conversion specifier 'b' 
requires a C standard library compatible with C23; data argument may not be 
used by format}}
+                                    // c17-warning@-1{{conversion specifier 
'B' requires a C standard library compatible with C23; data argument may not be 
used by format}}
+
+  printf("%'b\n", 123456789); // c17-warning{{conversion specifier 'b' 
requires a C standard library compatible with C23; data argument may not be 
used by format}}
+                              // c17-warning@-1{{results in undefined behavior 
with 'b' conversion specifier}}
+                              // c23-warning@-2{{results in undefined behavior 
with 'b' conversion specifier}}
+
+  printf("%'B\n", 123456789); // c17-warning{{conversion specifier 'B' 
requires a C standard library compatible with C23; data argument may not be 
used by format}}
+                              // c17-warning@-1{{results in undefined behavior 
with 'B' conversion specifier}}
+                              // c23-warning@-2{{results in undefined behavior 
with 'B' conversion specifier}}
+
+  printf("%hhb %hhB", x, x); // c17-warning{{conversion specifier 'b' requires 
a C standard library compatible with C23; data argument may not be used by 
format}}
+                             // c17-warning@-1{{conversion specifier 'B' 
requires a C standard library compatible with C23; data argument may not be 
used by format}}
+}
diff --git a/clang/test/Sema/format-strings-fixit.c 
b/clang/test/Sema/format-strings-fixit.c
index 5e37ec76fed21..6fb191e57bcf2 100644
--- a/clang/test/Sema/format-strings-fixit.c
+++ b/clang/test/Sema/format-strings-fixit.c
@@ -1,7 +1,7 @@
 // RUN: cp %s %t
-// RUN: %clang_cc1 -pedantic -Wall -fixit %t
-// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror %t
-// RUN: %clang_cc1 -E -o - %t | FileCheck %s
+// RUN: %clang_cc1 -std=c23 -pedantic -Wall -fixit %t
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -pedantic -Wall -Werror %t
+// RUN: %clang_cc1 -std=c23 -E -o - %t | FileCheck %s
 
 /* This is a test of the various code modification hints that are
    provided as part of warning or extension diagnostics. All of the
diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c
index bdb4466dc6ae8..956a4dd27255b 100644
--- a/clang/test/Sema/format-strings.c
+++ b/clang/test/Sema/format-strings.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem 
%S/Inputs %s
-// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem 
%S/Inputs -fno-signed-char %s
-// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem 
%S/Inputs -triple=x86_64-unknown-fuchsia %s
-// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem 
%S/Inputs -triple=x86_64-linux-android %s
+// RUN: %clang_cc1 -std=c23 -fblocks -fsyntax-only -verify -Wformat-nonliteral 
-isystem %S/Inputs %s
+// RUN: %clang_cc1 -std=c23 -fblocks -fsyntax-only -verify -Wformat-nonliteral 
-isystem %S/Inputs -fno-signed-char %s
+// RUN: %clang_cc1 -std=c23 -fblocks -fsyntax-only -verify -Wformat-nonliteral 
-isystem %S/Inputs -triple=x86_64-unknown-fuchsia %s
+// RUN: %clang_cc1 -std=c23 -fblocks -fsyntax-only -verify -Wformat-nonliteral 
-isystem %S/Inputs -triple=x86_64-linux-android %s
 
 #include <stdarg.h>
 #include <stddef.h>

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to