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.

Right. When there's no bugzilla I'll sometimes put the paper number in
parens, e.g. in https://gcc.gnu.org/g:91f4550e1700 which has this
summary:
libstdc++: Move std::monostate to <utility> for C++26 (P0472R2)

But the paper number should not be in square brackets, that should be
reserved for a bugzilla PR number if there is one (and for this
feature, we do have a bugzilla PR).


>
>> 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.
>>
>>         * 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.

More importantly, it has a "convertible to string_view" constructor,
which matches the constraint on _Tp here. So it does look like we can
just construct _M_string directly from __t and __a.

>>
>> +       {
>> +         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?

P2495R3 adds this to basic_istringstream with this note:

[DRAFTING NOTE: Drive-by fix, this adds a missing constraint present
in stringstream and ostringstream.]

The constraints were added elsewhere by P0408 so I missed adding those
constraints in https://gcc.gnu.org/g:95cb0fc8c51841
Nathan, could you please add that same !is_same_v constraint to the
basic_stringbuf, basic_ostringstream and basic_stringstream
constructors as part of this patch?





>
>>         : 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