On Tue, 20 May 2025 at 09:10, Tomasz Kaminski <tkami...@redhat.com> wrote:
>
>
>
> On Mon, May 19, 2025 at 11:28 PM Nathan Myers <n...@cantrip.org> wrote:
> In the title, we usually put link to bugzilla PR119741 in your case, not the 
> paper.
> Then link the paper in commit descritpion.
>
>> Add constructors to stringbuf, stringstream, istringstream,
>> and ostringstream, and a matching overload of str(sv) in each,
>> that take anything convertible to a string_view where the
>> existing functions take a string.
>
>
> After you put bugzilla number, git gcc-verify will suggest you to add 
> following node:
> <tab>PR libstdc++/119741
>
>>
>>
>> libstdc++-v3/ChangeLog:
>>
>>         P2495R3 stringstream to init from string_view-ish
>
> We usually put only the change files here. Did git gcc-verify accepted it.

The GNU ChangeLog style does allow a description of the change here,
but that's not useful now that we use Git because the free text
description should be in the Git commit message, not squeezed into the
GNU ChangeLog part.


>>
>>         * include/std/sstream: full implementation, really just
>>         decls, requires clause and plumbing.
>>         * include/std/bits/version.def, .h: new preprocessor symbol
>>         __cpp_lib_sstream_from_string_view.
>>         * testsuite/27_io/basic_stringbuf/cons/char/3.cc: New tests.
>>         * testsuite/27_io/basic_istringstream/cons/char/2.cc: New tests.
>>         * testsuite/27_io/basic_ostringstream/cons/char/4.cc: New tests.
>>         * testsuite/27_io/basic_stringstream/cons/char/2.cc: New tests.
>> ---
>>  libstdc++-v3/ChangeLog                        |  11 +
>>  libstdc++-v3/include/bits/version.def         |  11 +-
>>  libstdc++-v3/include/bits/version.h           |  10 +
>>  libstdc++-v3/include/std/sstream              | 181 +++++++++++++--
>>  .../27_io/basic_istringstream/cons/char/2.cc  | 193 ++++++++++++++++
>>  .../27_io/basic_ostringstream/cons/char/4.cc  | 193 ++++++++++++++++
>>  .../27_io/basic_stringbuf/cons/char/3.cc      | 216 ++++++++++++++++++
>>  .../27_io/basic_stringstream/cons/char/2.cc   | 194 ++++++++++++++++
>>  8 files changed, 990 insertions(+), 19 deletions(-)
>>  create mode 100644 
>> libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc
>>  create mode 100644 
>> libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc
>>  create mode 100644 
>> libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc
>>  create mode 100644 
>> libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc
>>
>> diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
>> index b45f8c2c7a5..ac0ff4a386f 100644
>> --- a/libstdc++-v3/ChangeLog
>> +++ b/libstdc++-v3/ChangeLog
>> @@ -41,6 +41,17 @@
>>         PR libstdc++/119246
>>         * include/std/format: Updated check for _GLIBCXX_FORMAT_F128.
>>
>> +2025-05-14  Nathan Myers  <nmy...@redhat.com>
>> +       P2495R3 stringstream to init from string_view-ish
>> +       * include/std/sstream: full implementation, really just
>> +       decls, requires clause and plumbing.
>> +       * include/std/bits/version.def, .h: new preprocessor symbol
>> +       __cpp_lib_sstream_from_string_view.
>> +       * testsuite/27_io/basic_stringbuf/cons/char/3.cc: New tests.
>> +       * testsuite/27_io/basic_istringstream/cons/char/2.cc: New tests.
>> +       * testsuite/27_io/basic_ostringstream/cons/char/4.cc: New tests.
>> +       * testsuite/27_io/basic_stringstream/cons/char/2.cc: New tests.
>> +
>
> Changelogs are now automatically generated from commit messages, so you do not
> need to edit this file.
>>
>>  2025-05-14  Tomasz Kamiński  <tkami...@redhat.com>
>>
>>         PR libstdc++/119125
>> diff --git a/libstdc++-v3/include/bits/version.def 
>> b/libstdc++-v3/include/bits/version.def
>> index 6ca148f0488..567c56b4117 100644
>> --- a/libstdc++-v3/include/bits/version.def
>> +++ b/libstdc++-v3/include/bits/version.def
>> @@ -649,7 +649,7 @@ ftms = {
>>    };
>>    values = {
>>      v = 1;
>> -    /* For when there's no gthread.  */
>> +    // For when there is no gthread.
>>      cxxmin = 17;
>>      hosted = yes;
>>      gthread = no;
>> @@ -1961,6 +1961,15 @@ ftms = {
>>    };
>>  };
>>
>> +ftms = {
>> +  name = sstream_from_string_view;
>> +  values = {
>> +    v = 202302;
>> +    cxxmin = 26;
>> +    hosted = yes;
>> +  };
>> +};
>> +
>>  // Standard test specifications.
>>  stds[97] = ">= 199711L";
>>  stds[03] = ">= 199711L";
>> diff --git a/libstdc++-v3/include/bits/version.h 
>> b/libstdc++-v3/include/bits/version.h
>> index 48a090c14a3..5d1beb83a25 100644
>> --- a/libstdc++-v3/include/bits/version.h
>> +++ b/libstdc++-v3/include/bits/version.h
>> @@ -2193,4 +2193,14 @@
>>  #endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */
>>  #undef __glibcxx_want_modules
>>
>> +#if !defined(__cpp_lib_sstream_from_string_view)
>> +# if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
>> +#  define __glibcxx_sstream_from_string_view 202302L
>> +#  if defined(__glibcxx_want_all) || 
>> defined(__glibcxx_want_sstream_from_string_view)
>> +#   define __cpp_lib_sstream_from_string_view 202302L
>> +#  endif
>> +# endif
>> +#endif /* !defined(__cpp_lib_sstream_from_string_view) && 
>> defined(__glibcxx_want_sstream_from_string_view) */
>> +#undef __glibcxx_want_sstream_from_string_view
>> +
>>  #undef __glibcxx_want_all
>> diff --git a/libstdc++-v3/include/std/sstream 
>> b/libstdc++-v3/include/std/sstream
>> index ad0c16a91e8..9b2b0eb53fc 100644
>> --- a/libstdc++-v3/include/std/sstream
>> +++ b/libstdc++-v3/include/std/sstream
>> @@ -38,9 +38,14 @@
>>  #endif
>>
>>  #include <bits/requires_hosted.h> // iostream
>> +#include <bits/version.h>
>>
>>  #include <istream>
>>  #include <ostream>
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +# include <type_traits>  // is_convertible_v
>> +#endif
>> +
>>  #include <bits/alloc_traits.h> // allocator_traits, __allocator_like
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>> @@ -52,8 +57,6 @@
>>  # define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]]
>>  #endif
>>
>> -
>> -
>>  namespace std _GLIBCXX_VISIBILITY(default)
>>  {
>>  _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> @@ -159,6 +162,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 
>> 0); }
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>> +       // P0408 Efficient access to basic_stringbuf buffer
>>        explicit
>>        basic_stringbuf(const allocator_type& __a)
>>        : basic_stringbuf(ios_base::in | std::ios_base::out, __a)
>> @@ -197,7 +201,35 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>                                                     | ios_base::out)
>>         : basic_stringbuf(__s, __mode, allocator_type{})
>>         { }
>> +#endif
>> +
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +      template<typename _Tp>
>> +       explicit
>> +       basic_stringbuf(const _Tp& __t, ios_base::openmode __mode = 
>> ios_base::in | ios_base::out)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_stringbuf(__t, __mode, allocator_type{})
>> +       { }
>> +
>> +      template<typename _Tp>
>> +       basic_stringbuf(const _Tp& __t, const allocator_type& __a)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_stringbuf(__t, ios_base::in | ios_base::out, __a)
>> +       { }
>>
>> +      template<typename _Tp>
>> +       basic_stringbuf(const _Tp& __t, ios_base::openmode __mode, const 
>> allocator_type& __a)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_stringbuf(__mode, __a)
>
> Any reason for not initializing _M_string(t, __a) directly here, string has 
> string_view constructor.
>>
>> +       {
>> +         basic_string_view<_CharT, _Traits> __sv{__t};
>> +         _M_string = __sv;
>> +         _M_stringbuf_init(__mode);
>> +       }
>> +#endif // C++26
>> +
>> +#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>> +       // P0408 Efficient access to basic_stringbuf buffer
>>        basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a)
>>        : basic_stringbuf(std::move(__rhs), __a, __xfer_bufptrs(__rhs, this))
>>        { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 
>> 0); }
>> @@ -262,6 +294,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>  #if __cplusplus > 201703L
>>  #if _GLIBCXX_USE_CXX11_ABI
>>  #if __cpp_concepts
>> +       // P0407 Allocator-aware basic_streambuf
>>        template<__allocator_like _SAlloc>
>>         _GLIBCXX_NODISCARD
>>         basic_string<_CharT, _Traits, _SAlloc>
>> @@ -317,6 +350,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>>  #if __cpp_concepts
>> +       // P0407 Allocator-aware basic_streambuf
>>        template<__allocator_like _SAlloc>
>>         requires (!is_same_v<_SAlloc, _Alloc>)
>>         void
>> @@ -335,6 +369,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        }
>>  #endif
>>
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +      template <typename _Tp>
>> +       void
>> +       str(const _Tp& __t)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       {
>> +         basic_string_view<_CharT, _Traits> __sv{__t};
>> +         _M_string = __sv;
>> +         _M_stringbuf_init(_M_mode);
>> +       }
>> +#endif // C++26
>> +
>>      protected:
>>        // Common initialization code goes here.
>>        void
>> @@ -521,6 +567,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        { }
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>> +       // P0408 Efficient access to basic_stringbuf buffer
>> +
>>        // The move constructor initializes an __xfer_bufptrs temporary then
>>        // delegates to this constructor to performs moves during its 
>> lifetime.
>>        basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a,
>> @@ -584,7 +632,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        */
>>        basic_istringstream()
>>        : __istream_type(), _M_stringbuf(ios_base::in)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Starts with an empty string buffer.
>> @@ -601,7 +649,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        explicit
>>        basic_istringstream(ios_base::openmode __mode)
>>        : __istream_type(), _M_stringbuf(__mode | ios_base::in)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Starts with an existing string buffer.
>> @@ -620,7 +668,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        basic_istringstream(const __string_type& __str,
>>                           ios_base::openmode __mode = ios_base::in)
>>        : __istream_type(), _M_stringbuf(__str, __mode | ios_base::in)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  The destructor does nothing.
>> @@ -637,9 +685,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        basic_istringstream(basic_istringstream&& __rhs)
>>        : __istream_type(std::move(__rhs)),
>>        _M_stringbuf(std::move(__rhs._M_stringbuf))
>> -      { __istream_type::set_rdbuf(&_M_stringbuf); }
>> +      { __istream_type::set_rdbuf(std::__addressof(_M_stringbuf)); }
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>> +       // P0408 Efficient access to basic_stringbuf buffer
>>        basic_istringstream(ios_base::openmode __mode, const allocator_type& 
>> __a)
>>        : __istream_type(), _M_stringbuf(__mode | ios_base::in, __a)
>>        { this->init(std::__addressof(_M_stringbuf)); }
>> @@ -667,10 +716,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>         explicit
>>         basic_istringstream(const basic_string<_CharT, _Traits, _SAlloc>& 
>> __str,
>>                             ios_base::openmode __mode = ios_base::in)
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +         requires (!is_same_v<_SAlloc, allocator_type>)
>> +#endif // C++26
>
> Standard have same constraint of ostringstream 
> (https://eel.is/c++draft/string.streams#ostringstream.cons-6):
> Constraints: is_same_v<SAlloc,Allocator> is false.
> Do we miss some library issue?
>
>>         : basic_istringstream(__str, __mode, allocator_type())
>>         { }
>>  #endif // C++20
>>
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +      template <typename _Tp>
>> +       explicit basic_istringstream(const _Tp& __t, ios_base::openmode 
>> __mode = ios_base::in)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_istringstream(__t, __mode, allocator_type{})
>> +       { }
>> +
>> +      template <typename _Tp>
>> +       basic_istringstream(const _Tp& __t, const allocator_type& __a)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_istringstream(__t, ios_base::in, __a)
>> +       { }
>> +
>> +      template <typename _Tp>
>> +       basic_istringstream(const _Tp& __t, ios_base::openmode __mode, const 
>> allocator_type& __a)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +         : __istream_type(), _M_stringbuf(__t, __mode | ios_base::in, __a)
>> +       { this->init(std::__addressof(_M_stringbuf)); }
>> +#endif // C++26
>> +
>>        // 27.8.3.2 Assign and swap:
>>
>>        basic_istringstream&
>> @@ -702,7 +774,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        _GLIBCXX_NODISCARD
>>        __stringbuf_type*
>>        rdbuf() const
>> -      { return const_cast<__stringbuf_type*>(&_M_stringbuf); }
>> +      { return 
>> const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Copying out the string buffer.
>> @@ -716,6 +788,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>  #if __cplusplus > 201703L
>>  #if _GLIBCXX_USE_CXX11_ABI
>>  #if __cpp_concepts
>> +       // P0407 Allocator-aware basic_streambuf
>>        template<__allocator_like _SAlloc>
>>         _GLIBCXX_NODISCARD
>>         basic_string<_CharT, _Traits, _SAlloc>
>> @@ -747,6 +820,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>>  #if __cpp_concepts
>> +       // P0407 Allocator-aware basic_streambuf
>>        template<__allocator_like _SAlloc>
>>         requires (!is_same_v<_SAlloc, _Alloc>)
>>         void
>> @@ -758,6 +832,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        str(__string_type&& __s)
>>        { _M_stringbuf.str(std::move(__s)); }
>>  #endif
>> +
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +      template<typename _Tp>
>> +       void
>> +       str(const _Tp& __t)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       { _M_stringbuf.str(__t); }
>> +#endif // C++26
>>      };
>>
>>
>> @@ -812,7 +894,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        */
>>        basic_ostringstream()
>>        : __ostream_type(), _M_stringbuf(ios_base::out)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Starts with an empty string buffer.
>> @@ -829,7 +911,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        explicit
>>        basic_ostringstream(ios_base::openmode __mode)
>>        : __ostream_type(), _M_stringbuf(__mode | ios_base::out)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Starts with an existing string buffer.
>> @@ -848,7 +930,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        basic_ostringstream(const __string_type& __str,
>>                           ios_base::openmode __mode = ios_base::out)
>>        : __ostream_type(), _M_stringbuf(__str, __mode | ios_base::out)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  The destructor does nothing.
>> @@ -865,9 +947,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        basic_ostringstream(basic_ostringstream&& __rhs)
>>        : __ostream_type(std::move(__rhs)),
>>        _M_stringbuf(std::move(__rhs._M_stringbuf))
>> -      { __ostream_type::set_rdbuf(&_M_stringbuf); }
>> +      { __ostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); }
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>> +       // P0408 Efficient access to basic_stringbuf buffer
>>        basic_ostringstream(ios_base::openmode __mode, const allocator_type& 
>> __a)
>>        : __ostream_type(), _M_stringbuf(__mode | ios_base::out, __a)
>>        { this->init(std::__addressof(_M_stringbuf)); }
>> @@ -899,6 +982,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>         { }
>>  #endif // C++20
>>
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +      template <typename _Tp>
>> +       explicit basic_ostringstream(const _Tp& __t, ios_base::openmode 
>> __mode = ios_base::out)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_ostringstream(__t, __mode, allocator_type{})
>> +       { }
>> +
>> +      template <typename _Tp>
>> +       basic_ostringstream(const _Tp& __t, const allocator_type& __a)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_ostringstream(__t, ios_base::out, __a)
>> +       { }
>> +
>> +      template <typename _Tp>
>> +       basic_ostringstream(const _Tp& __t, ios_base::openmode __mode, const 
>> allocator_type& __a)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : __ostream_type(), _M_stringbuf(__t, __mode | ios_base::out, __a)
>> +       { this->init(std::__addressof(_M_stringbuf)); }
>> +#endif // C++26
>> +
>>        // 27.8.3.2 Assign and swap:
>>
>>        basic_ostringstream&
>> @@ -930,7 +1033,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        _GLIBCXX_NODISCARD
>>        __stringbuf_type*
>>        rdbuf() const
>> -      { return const_cast<__stringbuf_type*>(&_M_stringbuf); }
>> +      { return 
>> const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Copying out the string buffer.
>> @@ -944,6 +1047,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>  #if __cplusplus > 201703L
>>  #if _GLIBCXX_USE_CXX11_ABI
>>  #if __cpp_concepts
>> +       // P0407 Allocator-aware basic_streambuf
>>        template<__allocator_like _SAlloc>
>>         _GLIBCXX_NODISCARD
>>         basic_string<_CharT, _Traits, _SAlloc>
>> @@ -975,6 +1079,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>>  #if __cpp_concepts
>> +       // P0407 Allocator-aware basic_streambuf
>>        template<__allocator_like _SAlloc>
>>         requires (!is_same_v<_SAlloc, _Alloc>)
>>         void
>> @@ -986,6 +1091,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        str(__string_type&& __s)
>>        { _M_stringbuf.str(std::move(__s)); }
>>  #endif
>> +
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +      template<typename _Tp>
>> +       void
>> +       str(const _Tp& __t)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       { _M_stringbuf.str(__t); }
>> +#endif // C++26
>>      };
>>
>>
>> @@ -1040,7 +1153,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        */
>>        basic_stringstream()
>>        : __iostream_type(), _M_stringbuf(ios_base::out | ios_base::in)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Starts with an empty string buffer.
>> @@ -1055,7 +1168,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        explicit
>>        basic_stringstream(ios_base::openmode __m)
>>        : __iostream_type(), _M_stringbuf(__m)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Starts with an existing string buffer.
>> @@ -1072,7 +1185,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        basic_stringstream(const __string_type& __str,
>>                          ios_base::openmode __m = ios_base::out | 
>> ios_base::in)
>>        : __iostream_type(), _M_stringbuf(__str, __m)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  The destructor does nothing.
>> @@ -1089,12 +1202,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        basic_stringstream(basic_stringstream&& __rhs)
>>        : __iostream_type(std::move(__rhs)),
>>        _M_stringbuf(std::move(__rhs._M_stringbuf))
>> -      { __iostream_type::set_rdbuf(&_M_stringbuf); }
>> +      { __iostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); }
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>> +       // P0408 Efficient access to basic_stringbuf buffer
>>        basic_stringstream(ios_base::openmode __mode, const allocator_type& 
>> __a)
>>        : __iostream_type(), _M_stringbuf(__mode, __a)
>> -      { this->init(&_M_stringbuf); }
>> +      { this->init(std::__addressof(_M_stringbuf)); }
>>
>>        explicit
>>        basic_stringstream(__string_type&& __str,
>> @@ -1125,6 +1239,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>         { }
>>  #endif // C++20
>>
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +      template <typename _Tp>
>> +       explicit basic_stringstream(const _Tp& __t,
>> +                                   ios_base::openmode __mode = ios_base::in 
>> | ios_base::out)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_stringstream(__t, __mode, allocator_type{})
>> +       { }
>> +
>> +      template <typename _Tp>
>> +       basic_stringstream(const _Tp& __t, const allocator_type& __a)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : basic_stringstream(__t, ios_base::in | ios_base::out, __a)
>> +       { }
>> +
>> +      template <typename _Tp>
>> +       basic_stringstream(const _Tp& __t, ios_base::openmode __mode, const 
>> allocator_type& __a)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       : __iostream_type(), _M_stringbuf(__t, __mode, __a)
>> +       { this->init(std::__addressof(_M_stringbuf)); }
>> +#endif // C++26
>> +
>>        // 27.8.3.2 Assign and swap:
>>
>>        basic_stringstream&
>> @@ -1156,7 +1291,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        _GLIBCXX_NODISCARD
>>        __stringbuf_type*
>>        rdbuf() const
>> -      { return const_cast<__stringbuf_type*>(&_M_stringbuf); }
>> +      { return 
>> const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); }
>>
>>        /**
>>         *  @brief  Copying out the string buffer.
>> @@ -1170,6 +1305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>  #if __cplusplus > 201703L
>>  #if _GLIBCXX_USE_CXX11_ABI
>>  #if __cpp_concepts
>> +       // P0407 Allocator-aware basic_streambuf
>>        template<__allocator_like _SAlloc>
>>         _GLIBCXX_NODISCARD
>>         basic_string<_CharT, _Traits, _SAlloc>
>> @@ -1201,6 +1337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>
>>  #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
>>  #if __cpp_concepts
>> +       // P0407 Allocator-aware basic_streambuf
>>        template<__allocator_like _SAlloc>
>>         requires (!is_same_v<_SAlloc, _Alloc>)
>>         void
>> @@ -1212,6 +1349,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>>        str(__string_type&& __s)
>>        { _M_stringbuf.str(std::move(__s)); }
>>  #endif
>> +
>> +#ifdef __cpp_lib_sstream_from_string_view
>> +      template<typename _Tp>
>> +       void
>> +       str(const _Tp& __t)
>> +         requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, 
>> _Traits>>)
>> +       { _M_stringbuf.str(__t); }
>> +#endif // C++26
>>      };
>>
>>  #if __cplusplus >= 201103L
>> diff --git a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc 
>> b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc
>> new file mode 100644
>> index 00000000000..4c27ad2ea07
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/2.cc
>> @@ -0,0 +1,193 @@
>> +// C++26 [istringstream.general]
>> +
>> +// { dg-do run { target c++26 } }
>> +// { dg-require-effective-target cxx11_abi }
>> +
>> +#include <sstream>
>> +#include <string>
>> +#include <string_view>
>> +#include <testsuite_allocator.h>
>> +#include <testsuite_hooks.h>
>> +
>> +// Check C++26 P2495 istringstream ctors and members str(s) that accept a
>> +// string_view, or anything convertible to a string_view, in place of a
>> +// string object. Mostly just verify plumbing.
>> +
>> +struct convertible_to_string_view {
>> +  std::string s;
>> +  operator std::string_view() const { return s; }
>> +};
>> +
>> +const std::string str("This is a test string");
>> +convertible_to_string_view cstr{str};  // a copy
>> +const convertible_to_string_view ccstr{str};  // another copy
>> +
>> +template <typename istringstream = std::basic_istringstream<char>>
>> +void
>> +test01()
>> +{
>> +  // Test C++26 constructor and str(s) taking a generalized string_view
>> +
>> +  static_assert(! requires { istringstream(1); },
>> +      "istringstream ctor should reject what cannot be converted to a 
>> string_view");
>> +  static_assert(! requires { istringstream().str(1); },
>> +      "istringstream::str(s) should reject what cannot be converted to a 
>> string_view");
>> +
>> +  static_assert(!std::is_convertible_v<std::string_view, 
>> std::istringstream>,
>> +      "istringstream(string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<const std::string_view, 
>> std::istringstream>,
>> +      "istringstream(string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<convertible_to_string_view, 
>> std::istringstream>,
>> +      "istringstream(convertible_to_string_view, ios::openmode) is 
>> explicit");
>> +  static_assert(!std::is_convertible_v<const convertible_to_string_view, 
>> std::istringstream>,
>> +      "istringstream(convertible_to_string_view, ios::openmode) is 
>> explicit");
>> +
>> +  {
>> +    std::istringstream istr(cstr);
>> +    VERIFY( istr.str() == cstr.s );
>> +    VERIFY( istr.get() == cstr.s[0] );
>> +  }
>> +  {
>> +    std::istringstream istr(ccstr);
>> +    VERIFY( istr.str() == ccstr.s );
>> +    VERIFY( istr.get() == ccstr.s[0] );
>> +  }
>> +  {
>> +    std::istringstream istr(cstr, std::ios_base::in);
>> +    VERIFY( istr.str() == cstr.s );
>> +    VERIFY( istr.get() == cstr.s[0] );
>> +    VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>> +  }
>> +  {
>> +    std::istringstream istr(cstr, std::ios_base::out);
>> +    VERIFY( istr.str() == cstr.s );
>> +    VERIFY( istr.get() == cstr.s[0] );
>> +    VERIFY( istr.rdbuf()->sputc('X') == 'X' );
>> +  }
>> +}
>> +
>> +void
>> +test02()
>> +{
>> +  // Test C++26 constructors taking string views using different allocators
>> +
>> +  using alloc_type = __gnu_test::tracker_allocator<char>;
>
> I would use __gnu_test::uneq_allocator<>, as it have state (int), that is 
> checked in equality in VERIFY.
>
>>
>> +  using str_type = std::basic_string<char, std::char_traits<char>, 
>> alloc_type>;
>> +
>> +  auto const mode = std::ios_base::in | std::ios_base::out;
>> +
>> +  {
>> +    // template <typename T>
>> +    // basic_istringstream(const T&, ios_base::openmode, const 
>> allocator_type&)
>> +
>> +    std::istringstream::allocator_type a;
>> +    {
>> +      std::istringstream istr(cstr, mode, a); // ={} checks for 
>> non-explicit ctor
>> +      VERIFY( istr.str() == cstr.s );
>> +    }
>> +    {
>> +      std::istringstream istr(cstr, std::ios::in, a);
>> +      VERIFY( istr.str() == cstr.s );
>> +      VERIFY( istr.get() == cstr.s[0] );
>> +      VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>> +    }
>> +    {
>> +      std::istringstream istr(cstr, std::ios::out, a);
>> +      VERIFY( istr.str() == cstr.s );
>> +      VERIFY( istr.get() == cstr.s[0] );
>> +      VERIFY( istr.rdbuf()->sputc('X') == 'X' );
>> +    }
>> +  }
>> +
>> +  {
>> +    // template <typename T>
>> +    // basic_istringstream(const T&, ios_base::openmode)
>> +    {
>> +      std::istringstream istr(cstr, mode);
>> +      VERIFY( istr.str() == cstr.s );
>> +      VERIFY( istr.get() == cstr.s[0] );
>> +      VERIFY( istr.rdbuf()->sputc('X') == 'X' );
>> +    }
>> +    {
>> +      std::istringstream istr(cstr, std::ios::in);
>> +      VERIFY( istr.str() == cstr.s );
>> +      VERIFY( istr.get() == cstr.s[0] );
>> +      VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>> +    }
>> +    {
>> +      std::istringstream istr(cstr, std::ios::out);
>> +      VERIFY( istr.str() == cstr.s );
>> +      VERIFY( istr.get() == cstr.s[0] );
>> +      VERIFY( istr.rdbuf()->sputc('X') == 'X' );
>> +    }
>> +  }
>> +
>> +  {
>> +    // template <typename T>
>> +    // explicit
>> +    // basic_istringstream(const T&, ios_base::openmode = ios_base::in)
>> +
>> +    std::istringstream istr(cstr);
>> +    VERIFY( istr.str() == cstr.s );
>> +    VERIFY( istr.get() == cstr.s[0] );
>> +    VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>> +  }
>> +}
>> +
>> +// A minimal allocator with no default constructor
>> +template<typename T>
>> +  struct NoDefaultCons : __gnu_test::SimpleAllocator<T>
>> +  {
>> +    using __gnu_test::SimpleAllocator<T>::SimpleAllocator;
>> +    NoDefaultCons() = delete;
>> +    NoDefaultCons(int) { }
>> +  };
>> +
>> +template<typename Alloc, typename C = typename Alloc::value_type>
>> +  using istringstream_with_alloc
>> +    = std::basic_istringstream<C, std::char_traits<C>, Alloc>;
>> +
>> +void test03()
>> +{
>> +  NoDefaultCons<char> a{1};
>> +  {
>> +    istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, a);
>> +    VERIFY( std::string_view{istr.str()} == cstr );
>> +    VERIFY( istr.get() == cstr.s[0] );
>> +  }
>> +  {
>> +    istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, std::ios::in, 
>> a);
>> +    VERIFY( std::string_view{istr.str()} == cstr );
>> +    VERIFY( istr.get() == cstr.s[0] );
>> +    VERIFY( istr.rdbuf()->sputc('X') != 'X' );
>> +  }
>> +  {
>> +    istringstream_with_alloc<NoDefaultCons<char>> istr(cstr, std::ios::out, 
>> a);
>> +    VERIFY( std::string_view{istr.str()} == cstr );
>> +    VERIFY( istr.get() == cstr.s[0] );
>> +    VERIFY( istr.rdbuf()->sputc('X') == 'X' );
>> +  }
>> +}
>> +
>> +void test04()
>> +{
>> +  {
>> +    std::istringstream istr;
>> +    istr.str( cstr );
>> +    VERIFY( istr.str() == cstr.s );
>> +  }
>> +  {
>> +    std::istringstream istr;
>> +    istr.str( ccstr );
>> +    VERIFY( istr.str() == ccstr.s );
>> +  }
>> +}
>> +
>> +int
>> +main()
>> +{
>> +  test01();
>> +  test02();
>> +  test03();
>> +  test04();
>> +}
>> diff --git a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc 
>> b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc
>> new file mode 100644
>> index 00000000000..1ca27dfbfa5
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/4.cc
>> @@ -0,0 +1,193 @@
>> +// C++26 [ostringstream.general]
>> +
>> +// { dg-do run { target c++26 } }
>> +// { dg-require-effective-target cxx11_abi }
>> +
>> +#include <sstream>
>> +#include <string>
>> +#include <string_view>
>> +#include <testsuite_allocator.h>
>> +#include <testsuite_hooks.h>
>> +
>> +// Check C++26 P2495 ostringstream ctors and members str(s) that accept a
>> +// string_view, or anything convertible to a string_view, in place of a
>> +// string object. Mostly just verify plumbing.
>> +
>> +struct convertible_to_string_view {
>> +  std::string s;
>> +  operator std::string_view() const { return s; }
>> +};
>> +
>> +const std::string str("This is a test string");
>> +convertible_to_string_view cstr{str};  // a copy
>> +const convertible_to_string_view ccstr{str};  // another copy
>> +
>> +template <typename ostringstream = std::basic_ostringstream<char>>
>> +void
>> +test01()
>> +{
>> +  // Test C++26 constructor and str(s) taking a generalized string_view
>> +
>> +  static_assert(! requires { ostringstream(1); },
>> +      "ostringstream ctor should reject what cannot be converted to a 
>> string_view");
>> +  static_assert(! requires { ostringstream().str(1); },
>> +      "ostringstream::str(s) should reject what cannot be converted to a 
>> string_view");
>> +
>> +  static_assert(!std::is_convertible_v<std::string_view, 
>> std::ostringstream>,
>> +      "ostringstream(string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<const std::string_view, 
>> std::ostringstream>,
>> +      "ostringstream(string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<convertible_to_string_view, 
>> std::ostringstream>,
>> +      "ostringstream(convertible_to_string_view, ios::openmode) is 
>> explicit");
>> +  static_assert(!std::is_convertible_v<const convertible_to_string_view, 
>> std::ostringstream>,
>> +      "ostringstream(convertible_to_string_view, ios::openmode) is 
>> explicit");
>> +
>> +  {
>> +    std::ostringstream ostrstr(cstr);
>> +    VERIFY( ostrstr.str() == cstr.s );
>> +    VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() 
>> );
>> +  }
>> +  {
>> +    std::ostringstream ostrstr(ccstr);
>> +    VERIFY( ostrstr.str() == ccstr.s );
>> +    VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() 
>> );
>> +  }
>> +  {
>> +    std::ostringstream ostrstr(cstr, std::ios_base::in);
>> +    VERIFY( ostrstr.str() == cstr.s );
>> +    VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
>> +    VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>> +  }
>> +  {
>> +    std::ostringstream ostrstr(cstr, std::ios_base::out);
>> +    VERIFY( ostrstr.str() == cstr.s );
>> +    VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() 
>> );
>> +    VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>> +  }
>> +}
>> +
>> +void
>> +test02()
>> +{
>> +  // Test C++26 constructors taking string views using different allocators
>> +
>> +  using alloc_type = __gnu_test::tracker_allocator<char>;
>> +  using str_type = std::basic_string<char, std::char_traits<char>, 
>> alloc_type>;
>> +
>> +  auto const mode = std::ios_base::in | std::ios_base::out;
>> +
>> +  {
>> +    std::ostringstream::allocator_type a;
>> +    // template <typename T>
>> +    // basic_ostringstream(const T&, ios_base::openmode, const 
>> allocator_type&)
>> +    {
>> +      std::ostringstream ostrstr(cstr, mode, a); // ={} checks for 
>> non-explicit ctor
>> +      VERIFY( ostrstr.str() == cstr.s );
>> +    }
>> +    {
>> +      std::ostringstream ostrstr(cstr, std::ios::in, a);
>> +      VERIFY( ostrstr.str() == cstr.s );
>> +      VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
>> +      VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>> +    }
>> +    {
>> +      std::ostringstream ostrstr(cstr, std::ios::out, a);
>> +      VERIFY( ostrstr.str() == cstr.s );
>> +      VERIFY( ostrstr.rdbuf()->sgetc() == 
>> std::stringbuf::traits_type::eof() );
>> +      VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>> +    }
>> +  }
>> +
>> +  {
>> +    // template <typename T>
>> +    // basic_ostringstream(const T&, ios_base::openmode)
>> +    {
>> +      std::ostringstream ostrstr(cstr, mode);
>> +      VERIFY( ostrstr.str() == cstr.s );
>> +      VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
>> +      VERIFY( ostrstr.put('Y').good() );
>> +    }
>> +    {
>> +      std::ostringstream ostrstr(cstr, std::ios::in);
>> +      VERIFY( ostrstr.str() == cstr.s );
>> +      VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
>> +      VERIFY( ostrstr.put('X').good() );
>> +    }
>> +    {
>> +      std::ostringstream ostrstr(cstr, std::ios::out);
>> +      VERIFY( ostrstr.str() == cstr.s );
>> +      VERIFY( ostrstr.rdbuf()->sgetc() == 
>> std::stringbuf::traits_type::eof() );
>> +      VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>> +    }
>> +  }
>> +
>> +  {
>> +    // template <typename T>
>> +    // explicit
>> +    // basic_ostringstream(const T&, ios_base::openmode = ios_base::out)
>> +
>> +    std::ostringstream ostrstr(cstr);
>> +    VERIFY( ostrstr.str() == cstr.s );
>> +    VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() 
>> );
>> +    VERIFY( ostrstr.put('Y').good() );
>> +  }
>> +}
>> +
>> +// A minimal allocator with no default constructor
>> +template<typename T>
>> +  struct NoDefaultCons : __gnu_test::SimpleAllocator<T>
>> +  {
>> +    using __gnu_test::SimpleAllocator<T>::SimpleAllocator;
>> +    NoDefaultCons() = delete;
>> +    NoDefaultCons(int) { }
>> +  };
>> +
>> +template<typename Alloc, typename C = typename Alloc::value_type>
>> +  using ostringstream_with_alloc
>> +    = std::basic_ostringstream<C, std::char_traits<C>, Alloc>;
>> +
>> +void test03()
>> +{
>> +  NoDefaultCons<char> a{1};
>> +  {
>> +    ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, a);
>> +    VERIFY( std::string_view{ostrstr.str()} == cstr );
>> +    VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() 
>> );
>> +    VERIFY( ostrstr.put('X').good() );
>> +  }
>> +  {
>> +    ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, 
>> std::ios::in, a);
>> +    VERIFY( std::string_view{ostrstr.str()} == cstr );
>> +    VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
>> +    VERIFY( ostrstr.put('X').good() );
>> +  }
>> +  {
>> +    ostringstream_with_alloc<NoDefaultCons<char>> ostrstr(cstr, 
>> std::ios::out, a);
>> +    VERIFY( std::string_view{ostrstr.str()} == cstr );
>> +    VERIFY( ostrstr.rdbuf()->sgetc() == std::stringbuf::traits_type::eof() 
>> );
>> +    VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
>> +  }
>> +}
>> +
>> +void test04()
>> +{
>> +  {
>> +    std::ostringstream ostrstr;
>> +    ostrstr.str(cstr);
>> +    VERIFY( ostrstr.str() == cstr.s );
>> +  }
>> +  {
>> +    std::ostringstream ostrstr;
>> +    ostrstr.str(ccstr);
>> +    VERIFY( ostrstr.str() == ccstr.s );
>> +  }
>> +}
>> +
>> +int
>> +main()
>> +{
>> +  test01();
>> +  test02();
>> +  test03();
>> +  test04();
>> +}
>> diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc 
>> b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc
>> new file mode 100644
>> index 00000000000..35f544c1201
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/3.cc
>> @@ -0,0 +1,216 @@
>> +// C++26 31.8.2.1 [stringbuf.general]
>> +
>> +// { dg-do run { target c++26 } }
>> +// { dg-require-effective-target cxx11_abi }
>> +
>> +#include <sstream>
>> +#include <string>
>> +#include <string_view>
>> +#include <testsuite_allocator.h>
>> +#include <testsuite_hooks.h>
>> +
>> +// Check C++26 P2495 stringbuf ctors and members str(s) that accept a
>> +// string_view, or anything convertible to a string_view, in place of a
>> +// string object.
>> +
>> +struct convertible_to_string_view {
>> +  std::string s;
>> +  operator std::string_view() const { return s; }
>> +};
>> +
>> +struct convertible_to_both {
>> +  std::string s;
>> +  operator std::string_view() const { return s; }
>> +  operator std::string() const { return s; }
>> +};
>> +
>> +const std::string str("This is a test string");
>> +convertible_to_string_view cstr{str};  // a copy
>> +const convertible_to_string_view ccstr{str};  // another copy
>> +convertible_to_both bcstr{str};
>> +
>> +template <typename stringbuf = std::basic_stringbuf<char>>
>> +void
>> +test01()
>> +{
>> +  // Test C++26 constructor and str(s) taking a generalized string_view
>> +
>> +  static_assert(! requires { stringbuf(1); },
>> +      "stringbuf ctor should reject what cannot be converted to a 
>> string_view");
>> +  static_assert(! requires { stringbuf().str(1); },
>> +      "stringbuf::str(s) should reject what cannot be converted to a 
>> string_view");
>> +
>> +  static_assert(!std::is_convertible_v<std::string_view, std::stringbuf>,
>> +      "stringbuf(string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<const std::string_view, 
>> std::stringbuf>,
>> +      "stringbuf(string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<convertible_to_string_view, 
>> std::stringbuf>,
>> +      "stringbuf(convertible_to_string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<const convertible_to_string_view, 
>> std::stringbuf>,
>> +      "stringbuf(convertible_to_string_view, ios::openmode) is explicit");
>> +
>> +  {
>> +    std::stringbuf sbuf(cstr);
>> +    VERIFY( sbuf.str() == cstr.s );
>> +    VERIFY( sbuf.sgetc() == cstr.s[0] );
>> +  }
>> +  { // check from a const source object
>> +    std::stringbuf sbuf(ccstr);
>> +    VERIFY( sbuf.str() == ccstr.s );
>> +    VERIFY( sbuf.sgetc() == ccstr.s[0] );
>> +  }
>> +  { // check from a type that has conversions to both std::string
>> +    // and std::string_view
>> +    std::stringbuf sbuf(bcstr);
>> +    VERIFY( sbuf.str() == bcstr.s );
>> +    VERIFY( sbuf.sgetc() == ccstr.s[0] );
>> +  }
>> +  {
>> +    std::stringbuf sbuf(cstr, std::ios_base::in);
>> +    VERIFY( sbuf.str() == cstr.s );
>> +    VERIFY( sbuf.sgetc() == cstr.s[0] );
>> +    VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() );
>> +  }
>> +  {
>> +    std::stringbuf sbuf(ccstr, std::ios_base::in);
>> +    VERIFY( sbuf.str() == ccstr.s );
>> +    VERIFY( sbuf.sgetc() == ccstr.s[0] );
>> +    VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() );
>> +  }
>> +  {
>> +    std::stringbuf sbuf(cstr, std::ios_base::out);
>> +    VERIFY( sbuf.str() == cstr.s );
>> +    VERIFY( sbuf.sputc('Y') == 'Y' );
>> +    VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() );
>> +  }
>> +  {
>> +    std::stringbuf sbuf(ccstr, std::ios_base::out);
>> +    VERIFY( sbuf.str() == ccstr.s );
>> +    VERIFY( sbuf.sputc('Y') == 'Y' );
>> +    VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() );
>> +  }
>> +}
>> +
>> +void
>> +test02()
>> +{
>> +  // Test C++26 constructors taking string views using different allocators
>> +
>> +  using alloc_type = __gnu_test::tracker_allocator<char>;
>> +  using str_type = std::basic_string<char, std::char_traits<char>, 
>> alloc_type>;
>> +
>> +  auto const mode = std::ios_base::in | std::ios_base::out;
>> +
>> +  {
>> +    // template <typename T>
>> +    // basic_stringbuf(const T&, ios_base::openmode, const allocator_type&)
>> +
>> +    std::stringbuf::allocator_type a;
>> +    {
>> +      std::stringbuf sbuf(cstr, mode, a); // ={} checks for non-explicit 
>> ctor
>> +      VERIFY( sbuf.str() == cstr.s );
>> +    }
>> +    {
>> +      std::stringbuf sbuf(cstr, std::ios::in, a);
>> +      VERIFY( sbuf.str() == cstr.s );
>> +      VERIFY( sbuf.sgetc() == cstr.s[0] );
>> +      VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() );
>> +    }
>> +
>> +    {
>> +      std::stringbuf sbuf(cstr, std::ios::out, a);
>> +      VERIFY( sbuf.str() == cstr.s );
>> +      VERIFY( sbuf.sputc('X') == 'X' );
>> +      VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() );
>> +    }
>> +  }
>> +
>> +  {
>> +    // template <typename T>
>> +    // basic_stringbuf(const T&, ios_base::openmode)
>> +    {
>> +      std::stringbuf sbuf(cstr, mode);
>> +      VERIFY( sbuf.str() == cstr.s );
>> +    }
>> +    {
>> +      std::stringbuf sbuf(cstr, std::ios::in);
>> +      VERIFY( sbuf.str() == cstr.s );
>> +      VERIFY( sbuf.sgetc() == cstr.s[0] );
>> +      VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() );
>> +    }
>> +    {
>> +      std::stringbuf sbuf(cstr, std::ios::out);
>> +      VERIFY( sbuf.str() == cstr.s );
>> +      VERIFY( sbuf.sputc('X') == 'X' );
>> +      VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() );
>> +    }
>> +  }
>> +
>> +  {
>> +    // template <typename T>
>> +    // explicit
>> +    // basic_stringbuf(const T&, ios_base::openmode = 
>> ios_base::in|ios_base::out)
>> +
>> +    std::stringbuf sbuf(cstr);
>> +    VERIFY( sbuf.str() == cstr.s );
>> +    VERIFY( sbuf.sgetc() == cstr.s[0] );
>> +  }
>> +}
>> +
>> +// A minimal allocator with no default constructor
>> +template<typename T>
>> +  struct NoDefaultCons : __gnu_test::SimpleAllocator<T>
>> +  {
>> +    using __gnu_test::SimpleAllocator<T>::SimpleAllocator;
>> +    NoDefaultCons() = delete;
>> +    NoDefaultCons(int) { }
>> +  };
>> +
>> +template<typename Alloc, typename C = typename Alloc::value_type>
>> +  using stringbuf_with_alloc
>> +    = std::basic_stringbuf<C, std::char_traits<C>, Alloc>;
>> +
>> +void test03()
>> +{
>> +  NoDefaultCons<char> a{1};
>> +  {
>> +    stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, a);
>> +    VERIFY( std::string_view{sbuf.str()} == cstr );
>> +    VERIFY( sbuf.sgetc() == cstr.s[0] );
>> +  }
>> +  {
>> +    stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, std::ios::in, a);
>> +    VERIFY( std::string_view{sbuf.str()} == cstr );
>> +    VERIFY( sbuf.sgetc() == cstr.s[0] );
>> +    VERIFY( sbuf.sputc('X') == std::stringbuf::traits_type::eof() );
>> +  }
>> +  {
>> +    stringbuf_with_alloc<NoDefaultCons<char>> sbuf(cstr, std::ios::out, a);
>> +    VERIFY( std::string_view{sbuf.str()} == cstr );
>> +    VERIFY( sbuf.sputc('X') == 'X' );
>> +    VERIFY( sbuf.sgetc() == std::stringbuf::traits_type::eof() );
>> +  }
>> +}
>> +
>> +void test04()
>> +{
>> +  {
>> +    std::stringbuf sbuf;
>> +    sbuf.str(cstr);
>> +    VERIFY( sbuf.str() == cstr.s );
>> +  }
>> +  {
>> +    std::stringbuf sbuf;
>> +    sbuf.str(ccstr);
>> +    VERIFY( sbuf.str() == ccstr.s );
>> +  }
>> +}
>> +
>> +int
>> +main()
>> +{
>> +  test01();
>> +  test02();
>> +  test03();
>> +  test04();
>> +}
>> diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc 
>> b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc
>> new file mode 100644
>> index 00000000000..06fab33a382
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/2.cc
>> @@ -0,0 +1,194 @@
>> +// C++26 31.8.2.1 [stringstream.general]
>> +
>> +// { dg-do run { target c++26 } }
>> +// { dg-require-effective-target cxx11_abi }
>> +
>> +#include <sstream>
>> +#include <string>
>> +#include <string_view>
>> +#include <testsuite_allocator.h>
>> +#include <testsuite_hooks.h>
>> +
>> +// Check C++26 P2495 stringstream ctors and members str(s) that accept a
>> +// string_view, or anything convertible to a string_view, in place of a
>> +// string object. Mostly just verify plumbing.
>> +
>> +struct convertible_to_string_view {
>> +  std::string s;
>> +  operator std::string_view() const { return s; }
>> +};
>> +
>> +const std::string str("This is a test string");
>> +convertible_to_string_view cstr{str};  // a copy
>> +const convertible_to_string_view ccstr{str};  // another copy
>> +
>> +template <typename stringstream = std::basic_stringstream<char>>
>> +void
>> +test01()
>> +{
>> +  // Test C++26 constructor and str(s) taking a generalized string_view
>> +
>> +  static_assert(! requires { stringstream(1); },
>> +      "stringstream ctor should reject what cannot be converted to a 
>> string_view");
>> +  static_assert(! requires { stringstream().str(1); },
>> +      "stringstream::str(s) should reject what cannot be converted to a 
>> string_view");
>> +
>> +  static_assert(!std::is_convertible_v<std::string_view, std::stringstream>,
>> +      "stringstream(string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<const std::string_view, 
>> std::stringstream>,
>> +      "stringstream(string_view, ios::openmode) is explicit");
>> +  static_assert(!std::is_convertible_v<convertible_to_string_view, 
>> std::stringstream>,
>> +      "stringstream(convertible_to_string_view, ios::openmode) is 
>> explicit");
>> +  static_assert(!std::is_convertible_v<const convertible_to_string_view, 
>> std::stringstream>,
>> +      "stringstream(convertible_to_string_view, ios::openmode) is 
>> explicit");
>> +
>> +  {
>> +    std::stringstream strstr(cstr);
>> +    VERIFY( strstr.str() == cstr.s );
>> +    VERIFY( strstr.get() == cstr.s[0] );
>> +  }
>> +  {
>> +    std::stringstream strstr(ccstr);
>> +    VERIFY( strstr.str() == ccstr.s );
>> +    VERIFY( strstr.get() == ccstr.s[0] );
>> +  }
>> +  {
>> +    std::stringstream strstr(cstr, std::ios_base::in);
>> +    VERIFY( strstr.str() == cstr.s );
>> +    VERIFY( strstr.get() == cstr.s[0] );
>> +    VERIFY( strstr.put('X').rdstate() == strstr.badbit );
>> +  }
>> +  {
>> +    std::stringstream strstr(cstr, std::ios_base::out);
>> +    VERIFY( strstr.str() == cstr.s );
>> +    VERIFY( strstr.put('Y').good() );
>> +    VERIFY( strstr.get() == std::stringbuf::traits_type::eof());
>> +  }
>> +}
>> +
>> +void
>> +test02()
>> +{
>> +  // Test C++26 constructors taking string views using different allocators
>> +
>> +  using alloc_type = __gnu_test::tracker_allocator<char>;
>> +  using str_type = std::basic_string<char, std::char_traits<char>, 
>> alloc_type>;
>> +
>> +  auto const mode = std::ios_base::in | std::ios_base::out;
>> +
>> +  {
>> +    // template <typename T>
>> +    // basic_stringstream(const T&, ios_base::openmode, const 
>> allocator_type&)
>> +
>> +    std::stringstream::allocator_type a;
>> +    {
>> +      std::stringstream strstr(cstr, mode, a); // ={} checks for 
>> non-explicit ctor
>> +      VERIFY( strstr.str() == cstr.s );
>> +    }
>> +    {
>> +      std::stringstream strstr(cstr, std::ios::in, a);
>> +      VERIFY( strstr.str() == cstr.s );
>> +      VERIFY( strstr.get() == cstr.s[0] );
>> +      VERIFY( strstr.put('X').rdstate() == strstr.badbit );
>> +    }
>> +    {
>> +      std::stringstream strstr(cstr, std::ios::out, a);
>> +      VERIFY( strstr.str() == cstr.s );
>> +      VERIFY( strstr.put('X').good() );
>> +      VERIFY( strstr.get() == std::stringbuf::traits_type::eof());
>> +    }
>> +  }
>> +
>> +  {
>> +    // template <typename T>
>> +    // basic_stringstream(const T&, ios_base::openmode)
>> +
>> +    {
>> +      std::stringstream strstr(cstr, mode);
>> +      VERIFY( strstr.str() == cstr.s );
>> +      VERIFY( strstr.get() == cstr.s[0] );
>> +      VERIFY( strstr.put('X').good() );
>> +    }
>> +    {
>> +      std::stringstream strstr(cstr, std::ios::in);
>> +      VERIFY( strstr.str() == cstr.s );
>> +      VERIFY( strstr.get() == cstr.s[0] );
>> +      VERIFY( strstr.put('X').rdstate() == strstr.badbit );
>> +    }
>> +    {
>> +      std::stringstream strstr(cstr, std::ios::out);
>> +      VERIFY( strstr.str() == cstr.s );
>> +      VERIFY( strstr.put('X').good() );
>> +      VERIFY( strstr.get() == std::stringbuf::traits_type::eof());
>> +    }
>> +  }
>> +
>> +  {
>> +    // template <typename T>
>> +    // explicit
>> +    // basic_stringstream(const T&, ios_base::openmode = 
>> ios_base::in|ios_base::out)
>> +
>> +    std::stringstream strstr(cstr);
>> +    VERIFY( strstr.str() == cstr.s );
>> +    VERIFY( strstr.get() == cstr.s[0] );
>> +    VERIFY( strstr.put('X').good() );
>> +  }
>> +}
>> +
>> +// A minimal allocator with no default constructor
>> +template<typename T>
>> +  struct NoDefaultCons : __gnu_test::SimpleAllocator<T>
>> +  {
>> +    using __gnu_test::SimpleAllocator<T>::SimpleAllocator;
>> +    NoDefaultCons() = delete;
>> +    NoDefaultCons(int) { }
>> +  };
>> +
>> +template<typename Alloc, typename C = typename Alloc::value_type>
>> +  using stringstream_with_alloc
>> +    = std::basic_stringstream<C, std::char_traits<C>, Alloc>;
>> +
>> +void test03()
>> +{
>> +  NoDefaultCons<char> a{1};
>> +  {
>> +    stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, a);
>> +    VERIFY( std::string_view{strstr.str()} == cstr );
>> +    VERIFY( strstr.get() == cstr.s[0] );
>> +  }
>> +  {
>> +    stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, std::ios::in, 
>> a);
>> +    VERIFY( std::string_view{strstr.str()} == cstr );
>> +    VERIFY( strstr.get() == cstr.s[0] );
>> +    VERIFY( strstr.put('X').rdstate() == strstr.badbit );
>> +  }
>> +  {
>> +    stringstream_with_alloc<NoDefaultCons<char>> strstr(cstr, 
>> std::ios::out, a);
>> +    VERIFY( std::string_view{strstr.str()} == cstr );
>> +    VERIFY( strstr.put('X').good() );
>> +    VERIFY( strstr.get() == std::stringbuf::traits_type::eof());
>> +  }
>> +}
>> +
>> +void test04()
>> +{
>> +  {
>> +    std::stringstream strstr;
>> +    strstr.str( cstr );
>> +    VERIFY( strstr.str() == cstr.s );
>> +  }
>> +  {
>> +    std::stringstream strstr;
>> +    strstr.str( ccstr );
>> +    VERIFY( strstr.str() == ccstr.s );
>> +  }
>> +}
>> +
>> +int
>> +main()
>> +{
>> +  test01();
>> +  test02();
>> +  test03();
>> +  test04();
>> +}
>> --
>> 2.49.0
>>

Reply via email to