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.

Reply via email to