]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Support limited escaped formatting for non-Unicode literals.
authorTomasz Kamiński <tkaminsk@redhat.com>
Fri, 15 May 2026 09:07:03 +0000 (11:07 +0200)
committerTomasz Kamiński <tkaminsk@redhat.com>
Tue, 2 Jun 2026 07:28:19 +0000 (09:28 +0200)
This restores limited support debug (escaped) output for string when literal
encoding is non-Unicode, by allowing strings that contains only printable
ASCII characters and standard defined escapes (expanded with nul (\0)).
This covers common use-cases, while still preserving flexibility to provide
proper handling for escaping of encoding-specific characters.

libstdc++-v3/ChangeLog:

* include/std/format (__format::__write_escaped_ascii): Mark as
_GLIBCXX_CONSTEXPR_FORMAT and at compile time, reject strings
containing characters other than printable ASCII and standard
escapes.
* testsuite/std/format/debug.cc: Test basic_escapes and \0
at compile-time.
* testsuite/std/format/debug_nonunicode_neg.cc: New test.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
libstdc++-v3/include/std/format
libstdc++-v3/testsuite/std/format/debug.cc
libstdc++-v3/testsuite/std/format/debug_nonunicode_neg.cc [new file with mode: 0644]

index fe0f611b83394d5069bec99654133f1e56296794..4a517b70889c4f38b4dd08ecee6e73636f18247a 100644 (file)
@@ -1116,12 +1116,33 @@ namespace __format
     }
 
   template<typename _CharT, typename _Out>
-    _Out
+    _GLIBCXX_CONSTEXPR_FORMAT _Out
     __write_escaped_ascii(_Out __out,
                          basic_string_view<_CharT> __str,
                          _Term_char __term)
     {
       using _Str_view = basic_string_view<_CharT>;
+      if consteval {
+       // As set of the escaped characters depends on the encoding, for
+       // compile time allow only printable ASCII and standard escapes.
+       constexpr _Str_view __supported(_GLIBCXX_WIDEN(
+           "ABCDEFGHIJKLMNOPQRSTUWXYZ"
+           "abdeefghijklmnopqrstuwzyz"
+           " !#$%&'()*+-./:;<=>?[]^_{|}~"
+           "0123456789" "\t\n\r\\\"\'\0"
+         ), 95);
+       if (__str.find_first_not_of(__supported) != _Str_view::npos)
+#if __has_builtin(__builtin_constexpr_diag)
+         __builtin_constexpr_diag (2, "",
+                                   "for non-Unicode literal encodings, only"
+                                   " printable ASCII characters and standard"
+                                   " escape sequencess can be escaped in constant"
+                                   " expressions");
+#else
+         __asm__("");
+#endif
+      }
+
       auto __first = __str.begin();
       auto const __last = __str.end();
       while (__first != __last)
index 01bb9074ba7a42beb9791c4aa3de10cfda57015b..959822b2182848be7565ab1bb1bffc2db20a0586 100644 (file)
@@ -75,6 +75,13 @@ test_basic_escapes()
   VERIFY( res == WIDEN(R"("'")") );
   res = fdebug(apos[0]);
   VERIFY( res == WIDEN(R"('\'')") );
+
+  // This is not standard escape, but still supported at compile time.
+  const std::basic_string<CharT> null(WIDEN("\0"), 1);
+  res = fdebug(null);
+  VERIFY( res == WIDEN(R"("\u{0}")") );
+  res = fdebug(null[0]);
+  VERIFY( res == WIDEN(R"('\u{0}')") );
 }
 
 template<typename CharT>
@@ -831,6 +838,14 @@ test_all()
 {
   test_basic_escapes<char>();
   test_basic_escapes<wchar_t>();
+
+#ifndef UNICODE_ENC
+  // For non-unicode literal encoding debug output only supports
+  // printable ASCII and standard escapes at compile time
+  if (std::is_constant_evaluated())
+    return true;
+#endif
+
   test_ascii_escapes<char>();
   test_ascii_escapes<wchar_t>();
   test_extended_ascii<char>();
@@ -857,8 +872,7 @@ test_all()
   return true;
 }
 
-#if defined(__glibcxx_constexpr_format) && defined(UNICODE_ENC)
-// Deboug ouput is supported only for unicode literal encoding
+#ifdef __glibcxx_constexpr_format
 static_assert(test_all());
 #endif
 
diff --git a/libstdc++-v3/testsuite/std/format/debug_nonunicode_neg.cc b/libstdc++-v3/testsuite/std/format/debug_nonunicode_neg.cc
new file mode 100644 (file)
index 0000000..cc2b11e
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-options "-fexec-charset=ISO-8859-1" }
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target cxx11_abi }
+// { dg-require-iconv "ISO-8859-1" }
+
+#include <format>
+
+constexpr bool
+test_format(std::string_view str)
+{
+  (void)std::format("{:?}", str);
+  return true;
+}
+
+static_assert(test_format("\x10")); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_format("Åëÿ")); // { dg-error "in 'constexpr' expansion of" }
+
+// { dg-prune-output "for non-Unicode literal encodings, only printable ASCII characters and standard" }
+