libstdc++: Fix new <sstream> constructors
[gcc.git] / libstdc++-v3 / testsuite / 27_io / basic_stringbuf / cons / wchar_t / 2.cc
index e05acc42165974968625bd8aebf80e184508b4c1..4fbbbf39ad393daaab0fd5cd51d9ae8237380f0e 100644 (file)
@@ -15,7 +15,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// 27.7.1.1  basic_stringbuf constructors  [lib.stringbuf.cons]
+// C++20 29.8.2.2  basic_stringbuf constructors  [stringbuf.cons]
 
 // { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 #include <testsuite_allocator.h>
 #include <testsuite_hooks.h>
 
+template<typename Alloc, typename C = typename Alloc::value_type>
+  using stringbuf_with_alloc
+    = std::basic_stringbuf<C, std::char_traits<C>, Alloc>;
+
 void
 test01()
 {
+  // Test C++20 constructors taking an allocator but no string.
+
+  static_assert(!std::is_convertible_v<std::allocator<wchar_t>, std::wstringbuf>,
+      "wstringbuf(const allocator<wchar_t>&) is explicit");
+
+  {
+    using alloc_type = __gnu_test::uneq_allocator<wchar_t>;
+    using sbuf_t = stringbuf_with_alloc<alloc_type>;
+
+    static_assert(!std::is_convertible_v<const alloc_type&, sbuf_t>,
+       "basic_stringbuf(const basic_stringbuf::allocator_type&) is explicit");
+
+    alloc_type aa;
+    sbuf_t sbuf1(aa);
+    VERIFY( aa == sbuf1.get_allocator() );
+
+    alloc_type aaa(42);
+    sbuf_t sbuf2(aaa);
+    VERIFY( aaa == sbuf2.get_allocator() );
+
+    VERIFY( sbuf1.get_allocator() != sbuf2.get_allocator() );
+  }
+
   std::wstringbuf::allocator_type a;
   {
     std::wstringbuf sbuf(std::ios_base::in, a);
+    VERIFY( sbuf.str().empty() );
+
+    std::wstringbuf sbuf2 = {std::ios_base::in, a}; // non-explicit ctor
   }
 
   {
     std::wstringbuf sbuf(a);
+    VERIFY( sbuf.str().empty() );
   }
 }
 
-auto const cstr = L"This is a test";
+auto const cstr = L"This is a test string";
 
 void
 test02()
 {
+  // Test C++20 constructor taking an rvalue string
+
+  static_assert(!std::is_convertible_v<std::wstring, std::wstringbuf>,
+      "wstringbuf(wstring&&, ios::openmode) is explicit");
+
   std::wstring s1(cstr);
-  std::wstringbuf sbuf(std::move(s1));
+  std::wstringbuf sbuf1(std::move(s1));
   VERIFY( s1.empty() );
+  VERIFY( sbuf1.str() == cstr );
+  VERIFY( sbuf1.sgetc() == cstr[0] );
 
   std::wstring s2(cstr);
-  VERIFY( sbuf.str() == s2 );
+  std::wstringbuf sbuf2(std::move(s2), std::ios_base::in);
+  VERIFY( s2.empty() );
+  VERIFY( sbuf2.str() == cstr );
+  VERIFY( sbuf2.sgetc() == cstr[0] );
+  VERIFY( sbuf2.sputc(L'X') == std::wstringbuf::traits_type::eof() );
+
+  std::wstring s3(cstr);
+  std::wstringbuf sbuf3(std::move(s3), std::ios_base::out);
+  VERIFY( s3.empty() );
+  VERIFY( sbuf3.str() == cstr );
+  VERIFY( sbuf3.sputc(L'Y') == L'Y' );
+  VERIFY( sbuf3.sgetc() == std::wstringbuf::traits_type::eof() );
 }
 
+// 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) { }
+  };
+
 void
 test03()
 {
+  // Test C++20 constructors taking strings using different allocators
+
   using alloc_type = __gnu_test::tracker_allocator<wchar_t>;
   using str_type = std::basic_string<wchar_t, std::char_traits<wchar_t>, alloc_type>;
 
@@ -62,28 +124,92 @@ test03()
   str_type s1(cstr);
 
   {
+    // basic_stringbuf(const basic_string<wchar_t, traits_type, SAlloc>&,
+    //                 ios_base::openmode,
+    //                 const allocator_type&)
+
     std::wstringbuf::allocator_type a;
-    std::wstringbuf sbuf(s1, mode, a);
+    std::wstringbuf sbuf = {s1, mode, a}; // ={} checks for non-explicit ctor
     std::wstring s2(cstr);
     VERIFY( sbuf.str() == s2 );
+
+    std::wstringbuf sbuf2 = {std::move(s1), std::ios::in, a};
+    VERIFY( sbuf2.str() == s2 );
+    VERIFY( s1 == cstr ); // did not move from std::move(s1)
+    VERIFY( sbuf2.sgetc() == s1[0] );
+    VERIFY( sbuf2.sputc(L'X') == std::wstringbuf::traits_type::eof() );
+
+    std::wstringbuf sbuf3 = {std::move(s1), std::ios::out, a};
+    VERIFY( sbuf3.str() == s2 );
+    VERIFY( s1 == cstr ); // did not move from std::move(s1)
+    VERIFY( sbuf3.sputc(L'X') == L'X' );
+    VERIFY( sbuf3.sgetc() == std::wstringbuf::traits_type::eof() );
   }
 
   {
+    // explicit
+    // basic_stringbuf(const basic_string<wchar_t, traits_type, SAlloc>&,
+    //                 ios_base::openmode)
+
     std::wstringbuf sbuf(s1, mode);
     std::wstring s2(cstr);
     VERIFY( sbuf.str() == s2 );
+
+    std::wstringbuf sbuf2(std::move(s1), std::ios::in);
+    VERIFY( sbuf2.str() == s2 );
+    VERIFY( s1 == cstr ); // did not move from std::move(s1)
+    VERIFY( sbuf2.sgetc() == s1[0] );
+    VERIFY( sbuf2.sputc(L'X') == std::wstringbuf::traits_type::eof() );
+
+    std::wstringbuf sbuf3(std::move(s1), std::ios::out);
+    VERIFY( sbuf3.str() == s2 );
+    VERIFY( s1 == cstr ); // did not move from std::move(s1)
+    VERIFY( sbuf3.sputc(L'X') == L'X' );
+    VERIFY( sbuf3.sgetc() == std::wstringbuf::traits_type::eof() );
   }
 
   {
+    // explicit
+    // basic_stringbuf(const basic_string<wchar_t, traits_type, SAlloc>&,
+    //                 ios_base::openmode = ios_base::in|ios_base::out)
+
+    static_assert( ! std::is_convertible_v<str_type, std::wstringbuf>,
+       "wstringbuf(const basic_string<wchar_t, traits_type, SAlloc>&,"
+                 " openmode) is explicit");
+
     std::wstringbuf sbuf(s1);
     std::wstring s2(cstr);
     VERIFY( sbuf.str() == s2 );
+
+    std::wstringbuf sbuf2(std::move(s1));
+    VERIFY( sbuf2.str() == s2 );
+    VERIFY( s1 == cstr ); // did not move from std::move(s1)
+    VERIFY( sbuf2.sgetc() == s1[0] );
+  }
+
+  {
+    NoDefaultCons<wchar_t> a(1);
+    stringbuf_with_alloc<NoDefaultCons<wchar_t>> sbuf1(s1, a);
+    VERIFY( sbuf1.str() == cstr );
+    VERIFY( sbuf1.sgetc() == s1[0] );
+
+    stringbuf_with_alloc<NoDefaultCons<wchar_t>> sbuf2(s1, std::ios::in, a);
+    VERIFY( sbuf2.str() == cstr );
+    VERIFY( sbuf2.sgetc() == s1[0] );
+    VERIFY( sbuf2.sputc(L'X') == std::wstringbuf::traits_type::eof() );
+
+    stringbuf_with_alloc<NoDefaultCons<wchar_t>> sbuf3(s1, std::ios::out, a);
+    VERIFY( sbuf3.str() == cstr );
+    VERIFY( sbuf3.sputc(L'X') == L'X' );
+    VERIFY( sbuf3.sgetc() == std::wstringbuf::traits_type::eof() );
   }
 }
 
 void
 test04()
 {
+  // Test C++20 allocator-extended move constructor
+
   std::wstringbuf sbuf1(cstr);
 
   std::wstringbuf::allocator_type a;
@@ -101,5 +227,4 @@ main()
   test02();
   test03();
   test04();
-  return 0;
 }