[PATCH v2] libstdc++: Support limited escaped formatting for non-Unicode literals.
Jonathan Wakely
jwakely@redhat.com
Mon Jun 1 17:31:13 GMT 2026
On Mon, 1 Jun 2026 at 18:30, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On Mon, 1 Jun 2026 at 17:02, Tomasz Kamiński <tkaminsk@redhat.com> wrote:
> >
> > 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.
> > ---
> > v2:
> > - changes error message and commit description
> >
> > OK for trunk?
> >
> > libstdc++-v3/include/std/format | 23 ++++++++++++++++++-
> > libstdc++-v3/testsuite/std/format/debug.cc | 18 +++++++++++++--
> > .../std/format/debug_nonunicode_neg.cc | 19 +++++++++++++++
> > 3 files changed, 57 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..adcd3090b0b 100644
> > --- a/libstdc++-v3/include/std/format
> > +++ b/libstdc++-v3/include/std/format
> > @@ -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"
> > + " expression");
>
> "expressions" plural
>
> > +#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..39aecca91f0
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/std/format/debug_nonunicode_neg.cc
> > @@ -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 "debug ouput for non-unicode literal encoding supports only" }
>
> Does this dg-prune-output need to be adjusted for the new
> __builtin_constexpr_diag string?
OK for trunk with the "epxressions" change, and adjusted prune pattern
if needed.
More information about the Libstdc++
mailing list