On Wed, Jun 4, 2025 at 8:02 PM Jonathan Wakely <jwak...@redhat.com> wrote: > > On Thu, 29 May 2025 at 20:30, Nathan Myers <n...@cantrip.org> wrote: > > > > Change in V4: > > * Rename tests to string_view.cc > > * Adapt tests to cons/wchar_t directories > > * Define symbol __cpp_lib_sstream_from_string_view as 202406 > > * Define symbol __glibcxx_want_sstream_from_string_view before version.h > > * Include version.h after other includes > > * No include type_traits > > * Drive-by comment moved to commit message > > * Each `explicit` on its own line > > * Run tests even when using old COW string > > > > Change in V3: > > * Comment that p2495 specifies a drive-by constraint omitted as redundant > > * Adjust whitespace to fit in 80 columns > > > > Change in V2: > > * Apply all review comments > > * Remove redundant drive-by "requires" on ctor from string allocator arg > > * Check allocators are plumbed through > > Looks great now, thanks for iterating on it. > > Please push to trunk (you'll probably need to rebase first, which will > have a merge conflict in bits/version.h but just regenerating it again > will resolve that).
On Fedora 42/x86-64, I got FAIL: 27_io/basic_istringstream/cons/wchar_t/string_view.cc -std=gnu++17 (test for excess errors) Excess errors: /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39: error: 'requires' only available with '-std=c++20' or '-fconcepts' [-Wtemplate-body] /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39: error: expected ',' before '{' token [-Wtemplate-body] /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39: warning: 'static_assert' with non-string message only available with '-std=c++2c' or '-std=gnu++2c' [-Wc++26-extensions] /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39: error: expected primary-expression before '{' token [-Wtemplate-body] /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:39: error: expected ')' before '{' token [-Wtemplate-body] /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:41: error: 'requires' only available with '-std=c++20' or '-fconcepts' [-Wtemplate-body] /export/gnu/import/git/gitlab/x86-gcc-test/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/../char/string_view.cc:41: error: expected ',' before '{' token [-Wtemplate-body] > > > -- >8 -- > > > > Implement PR libstdc++/119741 (P2495R3). > > 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 in places where the existing ctors and function take a string. > > Note this change omits the constraint applied to the istringstream > > constructor > > from string cited as a "drive-by" in P2495R3, as we have determined it is > > redundant. > > > > libstdc++-v3/ChangeLog: > > > > PR libstdc++/119741 > > * include/std/sstream: full implementation, really just > > decls, requires clause and plumbing. > > * include/bits/version.def, include/bits/version.h: > > new preprocessor symbol > > __cpp_lib_sstream_from_string_view. > > * testsuite/27_io/basic_stringbuf/cons/char/string_view.cc: > > New tests. > > * testsuite/27_io/basic_istringstream/cons/char/string_view.cc: > > New tests. > > * testsuite/27_io/basic_ostringstream/cons/char/string_view.cc: > > New tests. > > * testsuite/27_io/basic_stringstream/cons/char/string_view.cc: > > New tests. > > * testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc: > > New tests. > > * testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc: > > New tests. > > * testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc: > > New tests. > > * testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc: > > New tests. > > --- > > libstdc++-v3/include/bits/version.def | 11 +- > > libstdc++-v3/include/bits/version.h | 10 + > > libstdc++-v3/include/std/sstream | 198 +++++++++++++++-- > > .../cons/char/string_view.cc | 195 +++++++++++++++++ > > .../cons/wchar_t/string_view.cc | 3 + > > .../cons/char/string_view.cc | 194 +++++++++++++++++ > > .../cons/wchar_t/string_view.cc | 3 + > > .../basic_stringbuf/cons/char/string_view.cc | 205 ++++++++++++++++++ > > .../cons/wchar_t/string_view.cc | 3 + > > .../cons/char/string_view.cc | 204 +++++++++++++++++ > > .../cons/wchar_t/string_view.cc | 3 + > > 11 files changed, 1010 insertions(+), 19 deletions(-) > > create mode 100644 > > libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc > > create mode 100644 > > libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc > > create mode 100644 > > libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc > > create mode 100644 > > libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc > > create mode 100644 > > libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc > > create mode 100644 > > libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc > > create mode 100644 > > libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc > > create mode 100644 > > libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc > > > > diff --git a/libstdc++-v3/include/bits/version.def > > b/libstdc++-v3/include/bits/version.def > > index 282667eabda..53bf72d95c2 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; > > @@ -1945,6 +1945,15 @@ ftms = { > > }; > > }; > > > > +ftms = { > > + name = sstream_from_string_view; > > + values = { > > + v = 202306; > > + 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 bb7c0479c72..0b932183e5b 100644 > > --- a/libstdc++-v3/include/bits/version.h > > +++ b/libstdc++-v3/include/bits/version.h > > @@ -2174,4 +2174,14 @@ > > #endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */ > > #undef __glibcxx_want_modules > > > > +#if !defined(__cpp_lib_sstream_from_string_view) > > +# if (__cplusplus >= 202306L) && _GLIBCXX_HOSTED > > +# define __glibcxx_sstream_from_string_view 202306L > > +# if defined(__glibcxx_want_all) || > > defined(__glibcxx_want_sstream_from_string_view) > > +# define __cpp_lib_sstream_from_string_view 202306L > > +# 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..edef599bd6f 100644 > > --- a/libstdc++-v3/include/std/sstream > > +++ b/libstdc++-v3/include/std/sstream > > @@ -41,8 +41,12 @@ > > > > #include <istream> > > #include <ostream> > > + > > #include <bits/alloc_traits.h> // allocator_traits, __allocator_like > > > > +#define __glibcxx_want_sstream_from_string_view > > +#include <bits/version.h> > > + > > #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI > > # define _GLIBCXX_LVAL_REF_QUAL & > > # define _GLIBCXX_SSTREAM_ALWAYS_INLINE > > @@ -52,8 +56,6 @@ > > # define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]] > > #endif > > > > - > > - > > namespace std _GLIBCXX_VISIBILITY(default) > > { > > _GLIBCXX_BEGIN_NAMESPACE_VERSION > > @@ -159,6 +161,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 +200,36 @@ _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>>) > > + : _M_string(__t, __a) > > + { _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,19 @@ _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 +568,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 +633,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 +650,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 +669,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 +686,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)); } > > @@ -671,6 +721,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > > { } > > #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 +778,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 +792,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 +824,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 +836,15 @@ _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 +899,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 +916,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 +935,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 +952,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 +987,32 @@ _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 +1044,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 +1058,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 +1090,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 +1102,15 @@ _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 +1165,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 +1180,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 +1197,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 +1214,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 +1251,31 @@ _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 +1307,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 +1321,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 +1353,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 +1365,15 @@ _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/string_view.cc > > b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc > > new file mode 100644 > > index 00000000000..27f65aa9437 > > --- /dev/null > > +++ > > b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc > > @@ -0,0 +1,195 @@ > > +// C++26 [istringstream.general] > > + > > +// { dg-do run { target c++26 } } > > + > > +#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. > > + > > +#ifndef C > > +# define C char > > +# define L(a) a > > +#endif > > + > > +using string = std::basic_string<C>; > > +using string_view = std::basic_string_view<C>; > > +using istringstream = std::basic_istringstream<C>; > > + > > +struct convertible_to_string_view { > > + string s; > > + operator string_view() const { return s; } > > +}; > > + > > +const string str(L("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<C>> > > +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<string_view, istringstream>, > > + "istringstream(string_view, ios::openmode) is explicit"); > > + static_assert(!std::is_convertible_v<const string_view, istringstream>, > > + "istringstream(string_view, ios::openmode) is explicit"); > > + static_assert(!std::is_convertible_v<convertible_to_string_view, > > istringstream>, > > + "istringstream(convertible_to_string_view, ios::openmode) is > > explicit"); > > + static_assert(!std::is_convertible_v<const convertible_to_string_view, > > istringstream>, > > + "istringstream(convertible_to_string_view, ios::openmode) is > > explicit"); > > + > > + { > > + istringstream istr(cstr); > > + VERIFY( istr.str() == cstr.s ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + } > > + { > > + istringstream istr(ccstr); > > + VERIFY( istr.str() == ccstr.s ); > > + VERIFY( istr.get() == ccstr.s[0] ); > > + } > > + { > > + istringstream istr(cstr, std::ios_base::in); > > + VERIFY( istr.str() == cstr.s ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > > + } > > + { > > + 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 various C++26 constructors taking string views > > + // and mix of other arguments > > + > > + auto const mode = std::ios_base::in | std::ios_base::out; > > + > > + { > > + // template <typename T> > > + // basic_istringstream(const T&, ios_base::openmode, const > > allocator_type&) > > + > > + istringstream::allocator_type a; > > + { > > + istringstream istr(cstr, mode, a); // ={} checks for non-explicit > > ctor > > + VERIFY( istr.str() == cstr.s ); > > + } > > + { > > + istringstream istr(cstr, std::ios::in, a); > > + VERIFY( istr.str() == cstr.s ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > > + } > > + { > > + 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) > > + { > > + istringstream istr(cstr, mode); > > + VERIFY( istr.str() == cstr.s ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); > > + } > > + { > > + istringstream istr(cstr, std::ios::in); > > + VERIFY( istr.str() == cstr.s ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > > + } > > + { > > + 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) > > + > > + istringstream istr(cstr); > > + VERIFY( istr.str() == cstr.s ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > > + } > > +} > > + > > +using alloc_type = __gnu_test::uneq_allocator<C>; > > + > > +template<typename Alloc, typename CC = typename Alloc::value_type> > > + using istringstream_with_alloc > > + = std::basic_istringstream<CC, std::char_traits<CC>, Alloc>; > > + > > +void test03() > > +{ > > + alloc_type a{1}; > > + { > > + istringstream_with_alloc<alloc_type> istr(cstr, a); > > + VERIFY( istr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{istr.str()} == cstr ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + } > > + { > > + istringstream_with_alloc<alloc_type> istr(cstr, std::ios::in, a); > > + VERIFY( istr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{istr.str()} == cstr ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); > > + } > > + { > > + istringstream_with_alloc<alloc_type> istr(cstr, std::ios::out, a); > > + VERIFY( istr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{istr.str()} == cstr ); > > + VERIFY( istr.get() == cstr.s[0] ); > > + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); > > + } > > +} > > + > > +void test04() > > +{ > > + { > > + istringstream istr; > > + istr.str( cstr ); > > + VERIFY( istr.str() == cstr.s ); > > + } > > + { > > + 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_istringstream/cons/wchar_t/string_view.cc > > > > b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc > > new file mode 100644 > > index 00000000000..cfb73c4c510 > > --- /dev/null > > +++ > > b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc > > @@ -0,0 +1,3 @@ > > +#define C wchar_t > > +#define L(a) L##a > > +#include "../char/string_view.cc" > > diff --git > > a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc > > b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc > > new file mode 100644 > > index 00000000000..731e97e4aa2 > > --- /dev/null > > +++ > > b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc > > @@ -0,0 +1,194 @@ > > +// C++26 [ostringstream.general] > > + > > +// { dg-do run { target c++26 } } > > + > > +#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. > > + > > +#ifndef C > > +# define C char > > +# define L(a) a > > +#endif > > + > > +using string = std::basic_string<C>; > > +using string_view = std::basic_string_view<C>; > > +using ostringstream = std::basic_ostringstream<C>; > > + > > +struct convertible_to_string_view { > > + string s; > > + operator string_view() const { return s; } > > +}; > > + > > +const string str(L("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<C>> > > +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<string_view, ostringstream>, > > + "ostringstream(string_view, ios::openmode) is explicit"); > > + static_assert(!std::is_convertible_v<const string_view, ostringstream>, > > + "ostringstream(string_view, ios::openmode) is explicit"); > > + static_assert(!std::is_convertible_v<convertible_to_string_view, > > ostringstream>, > > + "ostringstream(convertible_to_string_view, ios::openmode) is > > explicit"); > > + static_assert(!std::is_convertible_v<const convertible_to_string_view, > > ostringstream>, > > + "ostringstream(convertible_to_string_view, ios::openmode) is > > explicit"); > > + > > + { > > + ostringstream ostrstr(cstr); > > + VERIFY( ostrstr.str() == cstr.s ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() > > ); > > + } > > + { > > + ostringstream ostrstr(ccstr); > > + VERIFY( ostrstr.str() == ccstr.s ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() > > ); > > + } > > + { > > + 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 ); > > + } > > + { > > + ostringstream ostrstr(cstr, std::ios_base::out); > > + VERIFY( ostrstr.str() == cstr.s ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() > > ); > > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > > + } > > +} > > + > > +void > > +test02() > > +{ > > + // Test plumbing of C++26 various constructors taking string views > > + > > + auto const mode = std::ios_base::in | std::ios_base::out; > > + > > + { > > + ostringstream::allocator_type a; > > + // template <typename T> > > + // basic_ostringstream(const T&, ios_base::openmode, const > > allocator_type&) > > + { > > + ostringstream ostrstr(cstr, mode, a); // ={} checks for non-explicit > > ctor > > + VERIFY( ostrstr.str() == cstr.s ); > > + } > > + { > > + 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 ); > > + } > > + { > > + ostringstream ostrstr(cstr, std::ios::out, a); > > + VERIFY( ostrstr.str() == cstr.s ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == > > ostringstream::traits_type::eof() ); > > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > > + } > > + } > > + > > + { > > + // template <typename T> > > + // basic_ostringstream(const T&, ios_base::openmode) > > + { > > + ostringstream ostrstr(cstr, mode); > > + VERIFY( ostrstr.str() == cstr.s ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); > > + VERIFY( ostrstr.put('Y').good() ); > > + } > > + { > > + ostringstream ostrstr(cstr, std::ios::in); > > + VERIFY( ostrstr.str() == cstr.s ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); > > + VERIFY( ostrstr.put('X').good() ); > > + } > > + { > > + ostringstream ostrstr(cstr, std::ios::out); > > + VERIFY( ostrstr.str() == cstr.s ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == > > ostringstream::traits_type::eof() ); > > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > > + } > > + } > > + > > + { > > + // template <typename T> > > + // explicit > > + // basic_ostringstream(const T&, ios_base::openmode = ios_base::out) > > + > > + ostringstream ostrstr(cstr); > > + VERIFY( ostrstr.str() == cstr.s ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() > > ); > > + VERIFY( ostrstr.put('Y').good() ); > > + } > > +} > > + > > +using alloc_type = __gnu_test::uneq_allocator<C>; > > + > > +template<typename Alloc, typename CC = typename Alloc::value_type> > > + using ostringstream_with_alloc > > + = std::basic_ostringstream<CC, std::char_traits<CC>, Alloc>; > > + > > +void test03() > > +{ > > + alloc_type a{1}; > > + { > > + ostringstream_with_alloc<alloc_type> ostrstr(cstr, a); > > + VERIFY( ostrstr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{ostrstr.str()} == cstr ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() > > ); > > + VERIFY( ostrstr.put('X').good() ); > > + } > > + { > > + ostringstream_with_alloc<alloc_type> ostrstr(cstr, std::ios::in, a); > > + VERIFY( ostrstr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{ostrstr.str()} == cstr ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); > > + VERIFY( ostrstr.put('X').good() ); > > + } > > + { > > + ostringstream_with_alloc<alloc_type> ostrstr(cstr, std::ios::out, a); > > + VERIFY( ostrstr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{ostrstr.str()} == cstr ); > > + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() > > ); > > + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); > > + } > > +} > > + > > +void test04() > > +{ > > + { > > + ostringstream ostrstr; > > + ostrstr.str(cstr); > > + VERIFY( ostrstr.str() == cstr.s ); > > + } > > + { > > + 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_ostringstream/cons/wchar_t/string_view.cc > > > > b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc > > new file mode 100644 > > index 00000000000..cfb73c4c510 > > --- /dev/null > > +++ > > b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc > > @@ -0,0 +1,3 @@ > > +#define C wchar_t > > +#define L(a) L##a > > +#include "../char/string_view.cc" > > diff --git > > a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc > > b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc > > new file mode 100644 > > index 00000000000..7843269c48f > > --- /dev/null > > +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc > > @@ -0,0 +1,205 @@ > > +// C++26 31.8.2.1 [stringbuf.general] > > + > > +// { dg-do run { target c++26 } } > > + > > +#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. > > + > > +#ifndef C > > +# define C char > > +# define L(a) a > > +#endif > > + > > +using string = std::basic_string<C>; > > +using string_view = std::basic_string_view<C>; > > +using stringbuf = std::basic_stringbuf<C>; > > + > > +struct convertible_to_string_view { > > + string s; > > + operator string_view() const { return s; } > > +}; > > + > > +const string str(L("This is a test string")); > > +convertible_to_string_view cstr{str}; // a copy > > +const convertible_to_string_view ccstr{str}; // another copy > > + > > +template <typename stringbuf = std::basic_stringbuf<C>> > > +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<string_view, stringbuf>, > > + "stringbuf(string_view, ios::openmode) is explicit"); > > + static_assert(!std::is_convertible_v<const string_view, stringbuf>, > > + "stringbuf(string_view, ios::openmode) is explicit"); > > + static_assert(!std::is_convertible_v<convertible_to_string_view, > > stringbuf>, > > + "stringbuf(convertible_to_string_view, ios::openmode) is explicit"); > > + static_assert( > > + !std::is_convertible_v<const convertible_to_string_view, stringbuf>, > > + "stringbuf(convertible_to_string_view, ios::openmode) is explicit"); > > + > > + { > > + stringbuf sbuf(cstr); > > + VERIFY( sbuf.str() == cstr.s ); > > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > > + } > > + { > > + stringbuf sbuf(ccstr); > > + VERIFY( sbuf.str() == ccstr.s ); > > + VERIFY( sbuf.sgetc() == ccstr.s[0] ); > > + } > > + { > > + stringbuf sbuf(cstr, std::ios_base::in); > > + VERIFY( sbuf.str() == cstr.s ); > > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > > + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); > > + } > > + { > > + stringbuf sbuf(ccstr, std::ios_base::in); > > + VERIFY( sbuf.str() == ccstr.s ); > > + VERIFY( sbuf.sgetc() == ccstr.s[0] ); > > + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); > > + } > > + { > > + stringbuf sbuf(cstr, std::ios_base::out); > > + VERIFY( sbuf.str() == cstr.s ); > > + VERIFY( sbuf.sputc('Y') == 'Y' ); > > + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); > > + } > > + { > > + stringbuf sbuf(ccstr, std::ios_base::out); > > + VERIFY( sbuf.str() == ccstr.s ); > > + VERIFY( sbuf.sputc('Y') == 'Y' ); > > + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); > > + } > > +} > > + > > +void > > +test02() > > +{ > > + // Test C++26 constructors taking string views using different allocators > > + > > + auto const mode = std::ios_base::in | std::ios_base::out; > > + > > + { > > + // template <typename T> > > + // basic_stringbuf(const T&, ios_base::openmode, const allocator_type&) > > + > > + stringbuf::allocator_type a; > > + { > > + stringbuf sbuf(cstr, mode, a); // ={} checks for non-explicit ctor > > + VERIFY( sbuf.str() == cstr.s ); > > + } > > + { > > + stringbuf sbuf(cstr, std::ios::in, a); > > + VERIFY( sbuf.str() == cstr.s ); > > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > > + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); > > + } > > + > > + { > > + stringbuf sbuf(cstr, std::ios::out, a); > > + VERIFY( sbuf.str() == cstr.s ); > > + VERIFY( sbuf.sputc('X') == 'X' ); > > + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); > > + } > > + } > > + > > + { > > + // template <typename T> > > + // basic_stringbuf(const T&, ios_base::openmode) > > + { > > + stringbuf sbuf(cstr, mode); > > + VERIFY( sbuf.str() == cstr.s ); > > + } > > + { > > + stringbuf sbuf(cstr, std::ios::in); > > + VERIFY( sbuf.str() == cstr.s ); > > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > > + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); > > + } > > + { > > + stringbuf sbuf(cstr, std::ios::out); > > + VERIFY( sbuf.str() == cstr.s ); > > + VERIFY( sbuf.sputc('X') == 'X' ); > > + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); > > + } > > + } > > + > > + { > > + // template <typename T> > > + // explicit > > + // basic_stringbuf(const T&, ios_base::openmode = > > ios_base::in|ios_base::out) > > + > > + stringbuf sbuf(cstr); > > + VERIFY( sbuf.str() == cstr.s ); > > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > > + } > > +} > > + > > +using alloc_type = __gnu_test::uneq_allocator<C>; > > + > > +template<typename Alloc, typename CC = typename Alloc::value_type> > > + using stringbuf_with_alloc > > + = std::basic_stringbuf<CC, std::char_traits<CC>, Alloc>; > > + > > +void test03() > > +{ > > + alloc_type a{1}; > > + { > > + stringbuf_with_alloc<alloc_type> sbuf(cstr, a); > > + VERIFY( sbuf.get_allocator() == a ); > > + VERIFY( string_view{sbuf.str()} == cstr ); > > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > > + } > > + { > > + stringbuf_with_alloc<alloc_type> sbuf(cstr, std::ios::in, a); > > + VERIFY( sbuf.get_allocator() == a ); > > + VERIFY( string_view{sbuf.str()} == cstr ); > > + VERIFY( sbuf.sgetc() == cstr.s[0] ); > > + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); > > + } > > + { > > + stringbuf_with_alloc<alloc_type> sbuf(cstr, std::ios::out, a); > > + VERIFY( sbuf.get_allocator() == a ); > > + VERIFY( string_view{sbuf.str()} == cstr ); > > + VERIFY( sbuf.sputc('X') == 'X' ); > > + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); > > + } > > +} > > + > > +void test04() > > +{ > > + { > > + stringbuf sbuf; > > + sbuf.str(cstr); > > + VERIFY( sbuf.str() == cstr.s ); > > + } > > + { > > + 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_stringbuf/cons/wchar_t/string_view.cc > > b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc > > new file mode 100644 > > index 00000000000..cfb73c4c510 > > --- /dev/null > > +++ > > b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc > > @@ -0,0 +1,3 @@ > > +#define C wchar_t > > +#define L(a) L##a > > +#include "../char/string_view.cc" > > diff --git > > a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc > > b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc > > new file mode 100644 > > index 00000000000..72085230442 > > --- /dev/null > > +++ > > b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc > > @@ -0,0 +1,204 @@ > > +// C++26 31.8.2.1 [stringstream.general] > > + > > +// { dg-do run { target c++26 } } > > + > > +#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. > > + > > +#ifndef C > > +# define C char > > +# define L(a) a > > +#endif > > + > > +using string = std::basic_string<C>; > > +using string_view = std::basic_string_view<C>; > > +using stringstream = std::basic_stringstream<C>; > > + > > +struct convertible_to_string_view { > > + string s; > > + operator string_view() const { return s; } > > +}; > > + > > +const string str(L("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<C>> > > +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<string_view, stringstream>, > > + "stringstream(string_view, ios::openmode) is explicit"); > > + static_assert(!std::is_convertible_v<const string_view, stringstream>, > > + "stringstream(string_view, ios::openmode) is explicit"); > > + static_assert(!std::is_convertible_v<convertible_to_string_view, > > stringstream>, > > + "stringstream(convertible_to_string_view, ios::openmode) is > > explicit"); > > + static_assert(!std::is_convertible_v<const convertible_to_string_view, > > stringstream>, > > + "stringstream(convertible_to_string_view, ios::openmode) is > > explicit"); > > + > > + { > > + stringstream strstr(cstr); > > + VERIFY( strstr.str() == cstr.s ); > > + VERIFY( strstr.get() == cstr.s[0] ); > > + } > > + { > > + stringstream strstr(ccstr); > > + VERIFY( strstr.str() == ccstr.s ); > > + VERIFY( strstr.get() == ccstr.s[0] ); > > + } > > + { > > + 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 ); > > + } > > + { > > + stringstream strstr(cstr, std::ios_base::out); > > + VERIFY( strstr.str() == cstr.s ); > > + VERIFY( strstr.put('Y').good() ); > > + VERIFY( strstr.get() == stringstream::traits_type::eof()); > > + } > > +} > > + > > +void > > +test02() > > +{ > > + // Test C++26 various constructors taking string views > > + > > + auto const mode = std::ios_base::in | std::ios_base::out; > > + > > + { > > + // template <typename T> > > + // basic_stringstream(const T&, ios_base::openmode, const > > allocator_type&) > > + > > + stringstream::allocator_type a; > > + { > > + stringstream strstr(cstr, mode, a); // ={} checks for non-explicit > > ctor > > + VERIFY( strstr.str() == cstr.s ); > > + } > > + { > > + 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 ); > > + } > > + { > > + stringstream strstr(cstr, std::ios::out, a); > > + VERIFY( strstr.str() == cstr.s ); > > + VERIFY( strstr.put('X').good() ); > > + VERIFY( strstr.get() == stringstream::traits_type::eof()); > > + } > > + } > > + > > + { > > + // template <typename T> > > + // basic_stringstream(const T&, ios_base::openmode) > > + > > + { > > + stringstream strstr(cstr, mode); > > + VERIFY( strstr.str() == cstr.s ); > > + VERIFY( strstr.get() == cstr.s[0] ); > > + VERIFY( strstr.put('X').good() ); > > + } > > + { > > + stringstream strstr(cstr, std::ios::in); > > + VERIFY( strstr.str() == cstr.s ); > > + VERIFY( strstr.get() == cstr.s[0] ); > > + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); > > + } > > + { > > + stringstream strstr(cstr, std::ios::out); > > + VERIFY( strstr.str() == cstr.s ); > > + VERIFY( strstr.put('X').good() ); > > + VERIFY( strstr.get() == stringstream::traits_type::eof()); > > + } > > + } > > + > > + { > > + // template <typename T> > > + // explicit > > + // basic_stringstream(const T&, ios_base::openmode = > > ios_base::in|ios_base::out) > > + > > + 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) { } > > + }; > > + > > +using alloc_type = __gnu_test::uneq_allocator<C>; > > + > > +template<typename Alloc, typename CC = typename Alloc::value_type> > > + using stringstream_with_alloc > > + = std::basic_stringstream<CC, std::char_traits<CC>, Alloc>; > > + > > +void test03() > > +{ > > + alloc_type a{1}; > > + { > > + stringstream_with_alloc<alloc_type> strstr(cstr, a); > > + VERIFY( strstr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{strstr.str()} == cstr ); > > + VERIFY( strstr.get() == cstr.s[0] ); > > + } > > + { > > + stringstream_with_alloc<alloc_type> strstr(cstr, std::ios::in, a); > > + VERIFY( strstr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{strstr.str()} == cstr ); > > + VERIFY( strstr.get() == cstr.s[0] ); > > + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); > > + } > > + { > > + stringstream_with_alloc<alloc_type> strstr(cstr, std::ios::out, a); > > + VERIFY( strstr.rdbuf()->get_allocator() == a ); > > + VERIFY( string_view{strstr.str()} == cstr ); > > + VERIFY( strstr.put('X').good() ); > > + VERIFY( strstr.get() == stringstream::traits_type::eof()); > > + } > > +} > > + > > +void test04() > > +{ > > + { > > + stringstream strstr; > > + strstr.str( cstr ); > > + VERIFY( strstr.str() == cstr.s ); > > + } > > + { > > + stringstream strstr; > > + strstr.str( ccstr ); > > + VERIFY( strstr.str() == ccstr.s ); > > + } > > +} > > + > > +int > > +main() > > +{ > > + test01(); > > + test02(); > > + test03(); > > + test04(); > > +} > > diff --git > > a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc > > > > b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc > > new file mode 100644 > > index 00000000000..cfb73c4c510 > > --- /dev/null > > +++ > > b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc > > @@ -0,0 +1,3 @@ > > +#define C wchar_t > > +#define L(a) L##a > > +#include "../char/string_view.cc" > > -- > > 2.49.0 > > > -- H.J.