On Wed, Jun 24, 2026 at 8:00 PM Jonathan Wakely <[email protected]> wrote:

> The signature of iconv in SUSv2 and legacy systems used const char** for
> the second parameter. We already have a workaround for this in the
> <ext/codecvt_specializations.h> header, but were not handling this in
> src/c++20/format.cc when using iconv.
>
> Define a concept to check that we can call iconv with a char** and then
> use that to decide which type we cast the input pointer to.
>
> libstdc++-v3/ChangeLog:
>
>         PR libstdc++/125956
>         * src/c++20/format.cc [_GLIBCXX_HAVE_ICONV] (iconv_input): New
>         concept.
>         (__encoding::conv) [_GLIBCXX_HAVE_ICONV]: Use iconv_input to
>         decide which type to cast the input pointer to.
> ---
>
> Tested x86_64-linux.
>
LGTM.

>
>  libstdc++-v3/src/c++20/format.cc | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/libstdc++-v3/src/c++20/format.cc
> b/libstdc++-v3/src/c++20/format.cc
> index 6967d53259da..719d019bc91f 100644
> --- a/libstdc++-v3/src/c++20/format.cc
> +++ b/libstdc++-v3/src/c++20/format.cc
> @@ -58,6 +58,15 @@ struct mutex
>  };
>  #endif
>
> +#ifdef _GLIBCXX_HAVE_ICONV
> +// Detect whether type T* can be used as the second argument to iconv.
> +// SUSv2 used 'const char**', but POSIX.1-2003 uses 'char**'.
> +template<typename T>
> +  concept iconv_input = requires (::iconv_t cd, T in, size_t n, char**
> out) {
> +    ::iconv(cd, &in, &n, out, &n);
> +  };
> +#endif
> +
>  // A non-standard locale::facet that caches the locale's
> std::text_encoding
>  // and an iconv descriptor for converting from that encoding to UTF-8.
>  struct __encoding : locale::facet
> @@ -111,8 +120,9 @@ struct __encoding : locale::facet
>      bool done = false;
>
>      auto overwrite = [&](char* p, size_t n) {
> +      using input_t = __conditional_t<iconv_input<char*>, char*, const
> char*>;
>        auto inbytes
> -       = const_cast<char*>(input.data()) + input.size() - inbytesleft;
> +       = const_cast<input_t>(input.data()) + input.size() - inbytesleft;
>        char* outbytes = p + written;
>        size_t outbytesleft = n - written;
>        size_t res = ::iconv(_M_cd, &inbytes, &inbytesleft,
> --
> 2.54.0
>
>

Reply via email to