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.

libstdc++-v3/ChangeLog:

        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.
---
 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.
+
 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)
+       {
+         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
        : 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>;
+  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