[PATCH] libstdc++: Support limited escaped formatting for non-unicode literals.

Jonathan Wakely jwakely@redhat.com
Mon Jun 1 15:44:50 GMT 2026


On Fri, 15 May 2026 at 11:07 +0200, Tomasz Kamiński wrote:
>This restores limited support debug (esaped) output for string when literal

"escaped"

>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 encodingspecific characters.

"encoding-specific"

>
>libstdc++-v3/ChangeLog:
>
>	* include/std/format (__format::__write_escaped_ascii): Mark as
>	_GLIBCXX_CONSTEXPR_FORMAT and reject at compile time string

"and at compile time, reject strings"

>	containing charcters other than printable ASCII and standard

"characters"

>	escapes.
>	* testsuite/std/format/debug.cc: Test basic_escapes and \0
>	at compile-time.
>	* testsuite/std/format/debug_nonunicode_neg.cc: New test.
>---
>Sending v2 that addresses handling program using non-unicode literal
>encoding linking with libstdc++. I am starting to lean more into
>this solution, in combination with accepting later format-string
>additions as extension being better direction.
>
>Tested on x86_64-linux. OK for trunk?
>
> libstdc++-v3/include/std/format               | 22 ++++++++++++++++++-
> libstdc++-v3/testsuite/std/format/debug.cc    | 18 +++++++++++++--
> .../std/format/debug_nonunicode_neg.cc        | 18 +++++++++++++++
> 3 files changed, 55 insertions(+), 3 deletions(-)
> create mode 100644 libstdc++-v3/testsuite/std/format/debug_nonunicode_neg.cc
>
>diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
>index fe0f611b833..b75aaa6df51 100644
>--- a/libstdc++-v3/include/std/format
>+++ b/libstdc++-v3/include/std/format
>@@ -1116,12 +1116,32 @@ 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, "",
>+				    "debug ouput for non-unicode literal encoding "

"output"

And Unicode should be capitalized.

>+				    "supports only printable ASCII characters and "
>+				    "standard escapes at compile time");

Let's phrase this differently:

"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)
>diff --git a/libstdc++-v3/testsuite/std/format/debug.cc b/libstdc++-v3/testsuite/std/format/debug.cc
>index 01bb9074ba7..959822b2182 100644
>--- a/libstdc++-v3/testsuite/std/format/debug.cc
>+++ b/libstdc++-v3/testsuite/std/format/debug.cc
>@@ -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
>index 00000000000..1d7b8743f31
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/std/format/debug_nonunicode_neg.cc
>@@ -0,0 +1,18 @@
>+// { dg-options "-fexec-charset=ISO8859-1" }
>+// { dg-do compile { target c++26 } }
>+// { dg-require-effective-target cxx11_abi }
>+
>+#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 "debug ouput for non-unicode literal encoding supports only" }
>+
>-- 
>2.54.0
>
>



More information about the Libstdc++ mailing list