On Mon, 1 Jun 2026 at 18:30, Jonathan Wakely <[email protected]> wrote: > > On Mon, 1 Jun 2026 at 17:02, Tomasz Kamiński <[email protected]> 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.
