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?

Reply via email to