libstdc++: Add c++2a <syncstream>

Message ID 20201102161050.2120502-1-rodgert@appliantology.com
State New
Headers show
Series
  • libstdc++: Add c++2a <syncstream>
Related show

Commit Message

Thomas Rodgers Nov. 2, 2020, 4:10 p.m.
From: Thomas Rodgers <trodgers@redhat.com>


IGNORE the previous patch.

Changes implementation to use a private __mutex type as discussed on
IRC.

libstdc++/ChangeLog:
	libstdc++-v3/doc/doxygen/user.cfg.in (INPUT): Add new header.
	libstdc++-v3/include/Makefile.am (std_headers): Add new header.
	libstdc++-v3/include/Makefile.in: Regenerate.
	libstdc++-v3/include/precompiled/stdc++.h: Include new header.
	(basic_streambuf): Befriend __detail::__streambuf_core_access.
	libstdc++-v3/include/std/syncstream: New header.
	libstdc++-v3/include/std/version: Add __cpp_lib_syncbuf:
	libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc: New test.
	libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc: Likewise.
	libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc:
	Likewise.
	libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc:
	Likewise.
	libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc:
	Likewise.
	libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc: Likewise.
	libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc: Likewise.
	libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc:
	Likewise.
	libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc:
	Likewise.
---
 libstdc++-v3/doc/doxygen/user.cfg.in          |   1 +
 libstdc++-v3/include/Makefile.am              |   1 +
 libstdc++-v3/include/Makefile.in              |   1 +
 libstdc++-v3/include/precompiled/stdc++.h     |   2 +-
 libstdc++-v3/include/std/syncstream           | 333 ++++++++++++++++++
 libstdc++-v3/include/std/version              |   4 +
 .../testsuite/27_io/basic_syncbuf/1.cc        |  28 ++
 .../testsuite/27_io/basic_syncbuf/2.cc        |  28 ++
 .../27_io/basic_syncbuf/basic_ops/1.cc        | 137 +++++++
 .../27_io/basic_syncbuf/requirements/types.cc |  42 +++
 .../27_io/basic_syncbuf/sync_ops/1.cc         | 130 +++++++
 .../testsuite/27_io/basic_syncstream/1.cc     |  28 ++
 .../testsuite/27_io/basic_syncstream/2.cc     |  28 ++
 .../27_io/basic_syncstream/basic_ops/1.cc     | 134 +++++++
 .../basic_syncstream/requirements/types.cc    |  43 +++
 15 files changed, 939 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/include/std/syncstream
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc
 create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc

-- 
2.26.2

Comments

Jeff Law via Gcc-patches Nov. 2, 2020, 5:38 p.m. | #1
On 02/11/20 08:10 -0800, Thomas Rodgers wrote:
>From: Thomas Rodgers <trodgers@redhat.com>

>

>IGNORE the previous patch.

>

>Changes implementation to use a private __mutex type as discussed on

>IRC.

>

>libstdc++/ChangeLog:

>	libstdc++-v3/doc/doxygen/user.cfg.in (INPUT): Add new header.

>	libstdc++-v3/include/Makefile.am (std_headers): Add new header.

>	libstdc++-v3/include/Makefile.in: Regenerate.

>	libstdc++-v3/include/precompiled/stdc++.h: Include new header.

>	(basic_streambuf): Befriend __detail::__streambuf_core_access.

>	libstdc++-v3/include/std/syncstream: New header.

>	libstdc++-v3/include/std/version: Add __cpp_lib_syncbuf:

>	libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc: New test.

>	libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc: Likewise.

>	libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc:

>	Likewise.

>	libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc:

>	Likewise.

>	libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc:

>	Likewise.

>	libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc: Likewise.

>	libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc: Likewise.

>	libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc:

>	Likewise.

>	libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc:

>	Likewise.

>---

> libstdc++-v3/doc/doxygen/user.cfg.in          |   1 +

> libstdc++-v3/include/Makefile.am              |   1 +

> libstdc++-v3/include/Makefile.in              |   1 +

> libstdc++-v3/include/precompiled/stdc++.h     |   2 +-

> libstdc++-v3/include/std/syncstream           | 333 ++++++++++++++++++

> libstdc++-v3/include/std/version              |   4 +

> .../testsuite/27_io/basic_syncbuf/1.cc        |  28 ++

> .../testsuite/27_io/basic_syncbuf/2.cc        |  28 ++

> .../27_io/basic_syncbuf/basic_ops/1.cc        | 137 +++++++

> .../27_io/basic_syncbuf/requirements/types.cc |  42 +++

> .../27_io/basic_syncbuf/sync_ops/1.cc         | 130 +++++++

> .../testsuite/27_io/basic_syncstream/1.cc     |  28 ++

> .../testsuite/27_io/basic_syncstream/2.cc     |  28 ++

> .../27_io/basic_syncstream/basic_ops/1.cc     | 134 +++++++

> .../basic_syncstream/requirements/types.cc    |  43 +++

> 15 files changed, 939 insertions(+), 1 deletion(-)

> create mode 100644 libstdc++-v3/include/std/syncstream

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc

> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc

>

>diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in b/libstdc++-v3/doc/doxygen/user.cfg.in

>index 9b49a15d31b..320f6dea688 100644

>--- a/libstdc++-v3/doc/doxygen/user.cfg.in

>+++ b/libstdc++-v3/doc/doxygen/user.cfg.in

>@@ -897,6 +897,7 @@ INPUT                  = @srcdir@/doc/doxygen/doxygroups.cc \

>                          include/streambuf \

>                          include/string \

>                          include/string_view \

>+                         include/syncstream \

>                          include/system_error \

>                          include/thread \

>                          include/tuple \

>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am

>index c90ac555e15..8652b921274 100644

>--- a/libstdc++-v3/include/Makefile.am

>+++ b/libstdc++-v3/include/Makefile.am

>@@ -73,6 +73,7 @@ std_headers = \

> 	${std_srcdir}/shared_mutex \

> 	${std_srcdir}/span \

> 	${std_srcdir}/sstream \

>+	${std_srcdir}/syncstream \

> 	${std_srcdir}/stack \

> 	${std_srcdir}/stdexcept \

> 	${std_srcdir}/stop_token \

>diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h

>index 7518a98c25a..8899c323a28 100644

>--- a/libstdc++-v3/include/precompiled/stdc++.h

>+++ b/libstdc++-v3/include/precompiled/stdc++.h

>@@ -141,6 +141,6 @@

> #include <ranges>

> #include <span>

> #include <stop_token>

>-// #include <syncstream>

>+#include <syncstream>

> #include <version>

> #endif

>diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream

>new file mode 100644

>index 00000000000..ff96ca6cf59

>--- /dev/null

>+++ b/libstdc++-v3/include/std/syncstream

>@@ -0,0 +1,333 @@

>+// <syncstream> -*- C++ -*-

>+

>+// Copyright (C) 2020 Free Software Foundation, Inc.

>+//

>+// This file is part of the GNU ISO C++ Library.  This library is free

>+// software; you can redistribute it and/or modify it under the

>+// terms of the GNU General Public License as published by the

>+// Free Software Foundation; either version 3, or (at your option)

>+// any later version.

>+

>+// This library is distributed in the hope that it will be useful,

>+// but WITHOUT ANY WARRANTY; without even the implied warranty of

>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

>+// GNU General Public License for more details.

>+

>+// Under Section 7 of GPL version 3, you are granted additional

>+// permissions described in the GCC Runtime Library Exception, version

>+// 3.1, as published by the Free Software Foundation.

>+

>+// You should have received a copy of the GNU General Public License and

>+// a copy of the GCC Runtime Library Exception along with this program;

>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see

>+// <http://www.gnu.org/licenses/>.

>+

>+/** @file include/syncstream

>+ *  This is a Standard C++ Library header.

>+ */

>+

>+#ifndef _GLIBCXX_SYNCSTREAM

>+#define _GLIBCXX_SYNCSTREAM 1

>+

>+#if __cplusplus > 201703L

>+

>+#include <bits/c++config.h>

>+#if _GLIBCXX_USE_CXX11_ABI

>+

>+#define __cpp_lib_syncbuf 201803L

>+

>+#pragma GCC system_header

>+

>+#include <sstream>

>+

>+#include <bits/alloc_traits.h>

>+#include <bits/allocator.h>

>+#include <bits/functexcept.h>

>+#include <bits/functional_hash.h>

>+

>+#if _GLIBCXX_HAS_GTHREADS

>+# include <bits/std_mutex.h>

>+#endif

>+

>+namespace std _GLIBCXX_VISIBILITY(default)

>+{

>+_GLIBCXX_BEGIN_NAMESPACE_VERSION

>+

>+  template<typename _CharT, typename _Traits = char_traits<_CharT>,

>+	    typename _Alloc = allocator<_CharT>>

>+    class basic_syncbuf : public basic_streambuf<_CharT, _Traits>

>+    {

>+    public:

>+      using char_type = _CharT;

>+      using int_type = typename _Traits::int_type;

>+      using pos_type = typename _Traits::pos_type;

>+      using off_type = typename _Traits::off_type;

>+      using traits_type = _Traits;

>+      using allocator_type = _Alloc;

>+      using streambuf_type = basic_streambuf<_CharT, _Traits>;

>+

>+      basic_syncbuf()

>+      : basic_syncbuf(nullptr, allocator_type{})

>+      { }

>+

>+      explicit

>+      basic_syncbuf(streambuf_type* __obuf)

>+	: basic_syncbuf(__obuf, allocator_type{})

>+      { }

>+

>+      basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)

>+	: _M_wrapped(__obuf)

>+	, _M_impl(__alloc)

>+	, _M_mtx(__obuf)

>+      { }

>+

>+      basic_syncbuf(basic_syncbuf&& __other)

>+	: _M_wrapped(__other._M_wrapped)

>+	, _M_impl(std::move(__other._M_impl))

>+	, _M_mtx(std::move(__other._M_mtx))

>+	, _M_emit_on_sync(__other._M_emit_on_sync)

>+	, _M_needs_sync(__other._M_needs_sync)

>+      {

>+	__other._M_wrapped = nullptr;

>+      }

>+

>+      ~basic_syncbuf()

>+      {

>+	__try

>+	  {

>+	    emit();

>+	  }

>+	__catch (...)

>+	  { }

>+      }

>+

>+      basic_syncbuf& operator=(basic_syncbuf&& __other)

>+      {

>+	if (std::__addressof(__other) != this)

>+	  {

>+	    emit();

>+

>+	    _M_impl = std::move(__other._M_impl);

>+	    _M_wrapped = __other._M_wrapped; __other._M_wrapped = nullptr;

>+	    _M_mtx = std::move(__other._M_mtx);

>+	    _M_emit_on_sync = __other._M_emit_on_sync;

>+	    _M_needs_sync = __other._M_needs_sync;

>+	  }

>+	return *this;

>+      }

>+

>+      void

>+      swap(basic_syncbuf& __other)

>+      {

>+	if (std::__addressof(__other) != this)

>+	  {

>+	    std::swap(_M_impl, __other._M_impl);

>+	    std::swap(_M_wrapped, __other._M_wrapped);

>+	    std::swap(_M_mtx, __other._M_mtx);

>+	    std::swap(_M_emit_on_sync, __other._M_emit_on_sync);

>+	    std::swap(_M_needs_sync, __other._M_needs_sync);

>+	  }

>+      }

>+

>+      bool

>+      emit()

>+      {

>+	if (!_M_wrapped)

>+	  return false;

>+

>+	auto __s = _M_impl.view();

>+	if (__s.empty())

>+	  return true;

>+

>+	const lock_guard<__mutex> __l(_M_mtx);

>+	if (_M_wrapped->sputn(__s.data(), __s.size()) != __s.size())

>+	  return false;

>+

>+	if (_M_needs_sync)

>+	  {

>+	    _M_needs_sync = false;

>+	    if (_M_wrapped->pubsync() != 0)

>+	      return false;

>+	  }

>+

>+	_M_impl.str("");

>+	return true;

>+      }

>+

>+      streambuf_type*

>+      get_wrapped() const noexcept

>+      { return _M_wrapped; }

>+

>+      allocator_type get_allocator() const noexcept

>+      { return _M_impl.get_allocator(); }

>+

>+      void

>+      set_emit_on_sync(bool __b) noexcept

>+      { _M_emit_on_sync = __b; }

>+

>+    protected:

>+      int

>+      sync() override

>+      {

>+	auto __res = _M_impl.pubsync();

>+	if (__res == 0)

>+	  {

>+	    _M_needs_sync = true;

>+	    if (_M_emit_on_sync)

>+	      return emit() ? 0 : -1;

>+	  }

>+	return __res;

>+      }

>+

>+      streamsize

>+      xsputn(const char_type* __s, streamsize __n) override

>+      { return _M_impl.sputn(__s, __n); }

>+

>+    private:

>+      streambuf_type* _M_wrapped;

>+

>+      using __impl_type = basic_stringbuf<char_type, traits_type,

>+					  allocator_type>;

>+      __impl_type _M_impl;

>+

>+      struct __mutex

>+      {

>+#if _GLIBCXX_HAS_GTHREADS

>+	mutex* _M_mtx;

>+

>+	__mutex(void* __t)


Make this 'explicit' please.

>+	  : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)

>+	{ }

>+

>+	void

>+	swap(__mutex& __other) noexcept

>+	{ std::swap(_M_mtx, __other._M_mtx); }

>+

>+	void

>+	lock()

>+	{

>+	  if (_M_mtx)

>+	    _M_mtx->lock();

>+	}

>+

>+	void

>+	unlock()

>+	{

>+	  if (_M_mtx)

>+	    _M_mtx->unlock();

>+	}

>+

>+	// FIXME: This should be put in the .so

>+	static mutex&

>+	_S_get_mutex(void* __t)

>+	{

>+	  const unsigned char __mask = 0xf;

>+	  static mutex __m[__mask + 1];

>+

>+	  auto __key = _Hash_impl::hash(__t) & __mask;

>+	  return __m[__key];

>+	}

>+#else

>+	__mutex(void*)


And 'explicit' here too.

>+	{ }

>+

>+	void

>+	swap(__mutex&&) noexcept


This needs to be an lvalue reference, or it won't compile.

>+	{ }

>+

>+	void

>+	lock()

>+	{ }

>+

>+	void

>+	unlock()

>+	{ }


All these completely empty functions can be put on one line:

       void unlock() { }

There's no need for these no-op members take up so many lines.

>+#endif

>+	__mutex(const __mutex&) = delete;

>+	__mutex& operator=(const __mutex&) = delete;


These are redundant (the user-declared moves below cause the copies to
be deleted) but harmless.

>+

>+	__mutex(__mutex&&) = default;

>+	__mutex& operator=(__mutex&&) = default;

>+      };

>+      __mutex _M_mtx;

>+

>+      bool _M_emit_on_sync = false;

>+      bool _M_needs_sync = false;

>+    };



OK for trunk, thanks.
Jeff Law via Gcc-patches Nov. 2, 2020, 6:43 p.m. | #2
Testsed x86_64-pc-linux-gnu, committed to master.

Jonathan Wakely writes:

> On 02/11/20 08:10 -0800, Thomas Rodgers wrote:

>>From: Thomas Rodgers <trodgers@redhat.com>

>>

>>IGNORE the previous patch.

>>

>>Changes implementation to use a private __mutex type as discussed on

>>IRC.

>>

>>libstdc++/ChangeLog:

>>	libstdc++-v3/doc/doxygen/user.cfg.in (INPUT): Add new header.

>>	libstdc++-v3/include/Makefile.am (std_headers): Add new header.

>>	libstdc++-v3/include/Makefile.in: Regenerate.

>>	libstdc++-v3/include/precompiled/stdc++.h: Include new header.

>>	(basic_streambuf): Befriend __detail::__streambuf_core_access.

>>	libstdc++-v3/include/std/syncstream: New header.

>>	libstdc++-v3/include/std/version: Add __cpp_lib_syncbuf:

>>	libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc: New test.

>>	libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc: Likewise.

>>	libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc:

>>	Likewise.

>>	libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc:

>>	Likewise.

>>	libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc:

>>	Likewise.

>>	libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc: Likewise.

>>	libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc: Likewise.

>>	libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc:

>>	Likewise.

>>	libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc:

>>	Likewise.

>>---

>> libstdc++-v3/doc/doxygen/user.cfg.in          |   1 +

>> libstdc++-v3/include/Makefile.am              |   1 +

>> libstdc++-v3/include/Makefile.in              |   1 +

>> libstdc++-v3/include/precompiled/stdc++.h     |   2 +-

>> libstdc++-v3/include/std/syncstream           | 333 ++++++++++++++++++

>> libstdc++-v3/include/std/version              |   4 +

>> .../testsuite/27_io/basic_syncbuf/1.cc        |  28 ++

>> .../testsuite/27_io/basic_syncbuf/2.cc        |  28 ++

>> .../27_io/basic_syncbuf/basic_ops/1.cc        | 137 +++++++

>> .../27_io/basic_syncbuf/requirements/types.cc |  42 +++

>> .../27_io/basic_syncbuf/sync_ops/1.cc         | 130 +++++++

>> .../testsuite/27_io/basic_syncstream/1.cc     |  28 ++

>> .../testsuite/27_io/basic_syncstream/2.cc     |  28 ++

>> .../27_io/basic_syncstream/basic_ops/1.cc     | 134 +++++++

>> .../basic_syncstream/requirements/types.cc    |  43 +++

>> 15 files changed, 939 insertions(+), 1 deletion(-)

>> create mode 100644 libstdc++-v3/include/std/syncstream

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc

>> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc

>>

>>diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in b/libstdc++-v3/doc/doxygen/user.cfg.in

>>index 9b49a15d31b..320f6dea688 100644

>>--- a/libstdc++-v3/doc/doxygen/user.cfg.in

>>+++ b/libstdc++-v3/doc/doxygen/user.cfg.in

>>@@ -897,6 +897,7 @@ INPUT                  = @srcdir@/doc/doxygen/doxygroups.cc \

>>                          include/streambuf \

>>                          include/string \

>>                          include/string_view \

>>+                         include/syncstream \

>>                          include/system_error \

>>                          include/thread \

>>                          include/tuple \

>>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am

>>index c90ac555e15..8652b921274 100644

>>--- a/libstdc++-v3/include/Makefile.am

>>+++ b/libstdc++-v3/include/Makefile.am

>>@@ -73,6 +73,7 @@ std_headers = \

>> 	${std_srcdir}/shared_mutex \

>> 	${std_srcdir}/span \

>> 	${std_srcdir}/sstream \

>>+	${std_srcdir}/syncstream \

>> 	${std_srcdir}/stack \

>> 	${std_srcdir}/stdexcept \

>> 	${std_srcdir}/stop_token \

>>diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h

>>index 7518a98c25a..8899c323a28 100644

>>--- a/libstdc++-v3/include/precompiled/stdc++.h

>>+++ b/libstdc++-v3/include/precompiled/stdc++.h

>>@@ -141,6 +141,6 @@

>> #include <ranges>

>> #include <span>

>> #include <stop_token>

>>-// #include <syncstream>

>>+#include <syncstream>

>> #include <version>

>> #endif

>>diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream

>>new file mode 100644

>>index 00000000000..ff96ca6cf59

>>--- /dev/null

>>+++ b/libstdc++-v3/include/std/syncstream

>>@@ -0,0 +1,333 @@

>>+// <syncstream> -*- C++ -*-

>>+

>>+// Copyright (C) 2020 Free Software Foundation, Inc.

>>+//

>>+// This file is part of the GNU ISO C++ Library.  This library is free

>>+// software; you can redistribute it and/or modify it under the

>>+// terms of the GNU General Public License as published by the

>>+// Free Software Foundation; either version 3, or (at your option)

>>+// any later version.

>>+

>>+// This library is distributed in the hope that it will be useful,

>>+// but WITHOUT ANY WARRANTY; without even the implied warranty of

>>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

>>+// GNU General Public License for more details.

>>+

>>+// Under Section 7 of GPL version 3, you are granted additional

>>+// permissions described in the GCC Runtime Library Exception, version

>>+// 3.1, as published by the Free Software Foundation.

>>+

>>+// You should have received a copy of the GNU General Public License and

>>+// a copy of the GCC Runtime Library Exception along with this program;

>>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see

>>+// <http://www.gnu.org/licenses/>.

>>+

>>+/** @file include/syncstream

>>+ *  This is a Standard C++ Library header.

>>+ */

>>+

>>+#ifndef _GLIBCXX_SYNCSTREAM

>>+#define _GLIBCXX_SYNCSTREAM 1

>>+

>>+#if __cplusplus > 201703L

>>+

>>+#include <bits/c++config.h>

>>+#if _GLIBCXX_USE_CXX11_ABI

>>+

>>+#define __cpp_lib_syncbuf 201803L

>>+

>>+#pragma GCC system_header

>>+

>>+#include <sstream>

>>+

>>+#include <bits/alloc_traits.h>

>>+#include <bits/allocator.h>

>>+#include <bits/functexcept.h>

>>+#include <bits/functional_hash.h>

>>+

>>+#if _GLIBCXX_HAS_GTHREADS

>>+# include <bits/std_mutex.h>

>>+#endif

>>+

>>+namespace std _GLIBCXX_VISIBILITY(default)

>>+{

>>+_GLIBCXX_BEGIN_NAMESPACE_VERSION

>>+

>>+  template<typename _CharT, typename _Traits = char_traits<_CharT>,

>>+	    typename _Alloc = allocator<_CharT>>

>>+    class basic_syncbuf : public basic_streambuf<_CharT, _Traits>

>>+    {

>>+    public:

>>+      using char_type = _CharT;

>>+      using int_type = typename _Traits::int_type;

>>+      using pos_type = typename _Traits::pos_type;

>>+      using off_type = typename _Traits::off_type;

>>+      using traits_type = _Traits;

>>+      using allocator_type = _Alloc;

>>+      using streambuf_type = basic_streambuf<_CharT, _Traits>;

>>+

>>+      basic_syncbuf()

>>+      : basic_syncbuf(nullptr, allocator_type{})

>>+      { }

>>+

>>+      explicit

>>+      basic_syncbuf(streambuf_type* __obuf)

>>+	: basic_syncbuf(__obuf, allocator_type{})

>>+      { }

>>+

>>+      basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)

>>+	: _M_wrapped(__obuf)

>>+	, _M_impl(__alloc)

>>+	, _M_mtx(__obuf)

>>+      { }

>>+

>>+      basic_syncbuf(basic_syncbuf&& __other)

>>+	: _M_wrapped(__other._M_wrapped)

>>+	, _M_impl(std::move(__other._M_impl))

>>+	, _M_mtx(std::move(__other._M_mtx))

>>+	, _M_emit_on_sync(__other._M_emit_on_sync)

>>+	, _M_needs_sync(__other._M_needs_sync)

>>+      {

>>+	__other._M_wrapped = nullptr;

>>+      }

>>+

>>+      ~basic_syncbuf()

>>+      {

>>+	__try

>>+	  {

>>+	    emit();

>>+	  }

>>+	__catch (...)

>>+	  { }

>>+      }

>>+

>>+      basic_syncbuf& operator=(basic_syncbuf&& __other)

>>+      {

>>+	if (std::__addressof(__other) != this)

>>+	  {

>>+	    emit();

>>+

>>+	    _M_impl = std::move(__other._M_impl);

>>+	    _M_wrapped = __other._M_wrapped; __other._M_wrapped = nullptr;

>>+	    _M_mtx = std::move(__other._M_mtx);

>>+	    _M_emit_on_sync = __other._M_emit_on_sync;

>>+	    _M_needs_sync = __other._M_needs_sync;

>>+	  }

>>+	return *this;

>>+      }

>>+

>>+      void

>>+      swap(basic_syncbuf& __other)

>>+      {

>>+	if (std::__addressof(__other) != this)

>>+	  {

>>+	    std::swap(_M_impl, __other._M_impl);

>>+	    std::swap(_M_wrapped, __other._M_wrapped);

>>+	    std::swap(_M_mtx, __other._M_mtx);

>>+	    std::swap(_M_emit_on_sync, __other._M_emit_on_sync);

>>+	    std::swap(_M_needs_sync, __other._M_needs_sync);

>>+	  }

>>+      }

>>+

>>+      bool

>>+      emit()

>>+      {

>>+	if (!_M_wrapped)

>>+	  return false;

>>+

>>+	auto __s = _M_impl.view();

>>+	if (__s.empty())

>>+	  return true;

>>+

>>+	const lock_guard<__mutex> __l(_M_mtx);

>>+	if (_M_wrapped->sputn(__s.data(), __s.size()) != __s.size())

>>+	  return false;

>>+

>>+	if (_M_needs_sync)

>>+	  {

>>+	    _M_needs_sync = false;

>>+	    if (_M_wrapped->pubsync() != 0)

>>+	      return false;

>>+	  }

>>+

>>+	_M_impl.str("");

>>+	return true;

>>+      }

>>+

>>+      streambuf_type*

>>+      get_wrapped() const noexcept

>>+      { return _M_wrapped; }

>>+

>>+      allocator_type get_allocator() const noexcept

>>+      { return _M_impl.get_allocator(); }

>>+

>>+      void

>>+      set_emit_on_sync(bool __b) noexcept

>>+      { _M_emit_on_sync = __b; }

>>+

>>+    protected:

>>+      int

>>+      sync() override

>>+      {

>>+	auto __res = _M_impl.pubsync();

>>+	if (__res == 0)

>>+	  {

>>+	    _M_needs_sync = true;

>>+	    if (_M_emit_on_sync)

>>+	      return emit() ? 0 : -1;

>>+	  }

>>+	return __res;

>>+      }

>>+

>>+      streamsize

>>+      xsputn(const char_type* __s, streamsize __n) override

>>+      { return _M_impl.sputn(__s, __n); }

>>+

>>+    private:

>>+      streambuf_type* _M_wrapped;

>>+

>>+      using __impl_type = basic_stringbuf<char_type, traits_type,

>>+					  allocator_type>;

>>+      __impl_type _M_impl;

>>+

>>+      struct __mutex

>>+      {

>>+#if _GLIBCXX_HAS_GTHREADS

>>+	mutex* _M_mtx;

>>+

>>+	__mutex(void* __t)

>

> Make this 'explicit' please.

>

>>+	  : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)

>>+	{ }

>>+

>>+	void

>>+	swap(__mutex& __other) noexcept

>>+	{ std::swap(_M_mtx, __other._M_mtx); }

>>+

>>+	void

>>+	lock()

>>+	{

>>+	  if (_M_mtx)

>>+	    _M_mtx->lock();

>>+	}

>>+

>>+	void

>>+	unlock()

>>+	{

>>+	  if (_M_mtx)

>>+	    _M_mtx->unlock();

>>+	}

>>+

>>+	// FIXME: This should be put in the .so

>>+	static mutex&

>>+	_S_get_mutex(void* __t)

>>+	{

>>+	  const unsigned char __mask = 0xf;

>>+	  static mutex __m[__mask + 1];

>>+

>>+	  auto __key = _Hash_impl::hash(__t) & __mask;

>>+	  return __m[__key];

>>+	}

>>+#else

>>+	__mutex(void*)

>

> And 'explicit' here too.

>

>>+	{ }

>>+

>>+	void

>>+	swap(__mutex&&) noexcept

>

> This needs to be an lvalue reference, or it won't compile.

>

>>+	{ }

>>+

>>+	void

>>+	lock()

>>+	{ }

>>+

>>+	void

>>+	unlock()

>>+	{ }

>

> All these completely empty functions can be put on one line:

>

>       void unlock() { }

>

> There's no need for these no-op members take up so many lines.

>

>>+#endif

>>+	__mutex(const __mutex&) = delete;

>>+	__mutex& operator=(const __mutex&) = delete;

>

> These are redundant (the user-declared moves below cause the copies to

> be deleted) but harmless.

>

>>+

>>+	__mutex(__mutex&&) = default;

>>+	__mutex& operator=(__mutex&&) = default;

>>+      };

>>+      __mutex _M_mtx;

>>+

>>+      bool _M_emit_on_sync = false;

>>+      bool _M_needs_sync = false;

>>+    };

>

>

> OK for trunk, thanks.
Jeff Law via Gcc-patches Nov. 3, 2020, 9:22 p.m. | #3
On Mon, 2 Nov 2020 at 19:43, Thomas Rodgers via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>

>

> Testsed x86_64-pc-linux-gnu, committed to master.

>


Hi,

I can see the new tests failing on bare-metal targets using newlib
(arm-eabi, aarch64-elf):
    27_io/basic_syncbuf/1.cc (test for excess errors)
    27_io/basic_syncbuf/basic_ops/1.cc (test for excess errors)
    27_io/basic_syncbuf/requirements/types.cc (test for excess errors)
    27_io/basic_syncstream/1.cc (test for excess errors)
    27_io/basic_syncstream/basic_ops/1.cc (test for excess errors)
    27_io/basic_syncstream/requirements/types.cc (test for excess errors)

because:
libstdc++-v3/include/syncstream:142: error: 'lock_guard' does not name a type

Christophe

> Jonathan Wakely writes:

>

> > On 02/11/20 08:10 -0800, Thomas Rodgers wrote:

> >>From: Thomas Rodgers <trodgers@redhat.com>

> >>

> >>IGNORE the previous patch.

> >>

> >>Changes implementation to use a private __mutex type as discussed on

> >>IRC.

> >>

> >>libstdc++/ChangeLog:

> >>      libstdc++-v3/doc/doxygen/user.cfg.in (INPUT): Add new header.

> >>      libstdc++-v3/include/Makefile.am (std_headers): Add new header.

> >>      libstdc++-v3/include/Makefile.in: Regenerate.

> >>      libstdc++-v3/include/precompiled/stdc++.h: Include new header.

> >>      (basic_streambuf): Befriend __detail::__streambuf_core_access.

> >>      libstdc++-v3/include/std/syncstream: New header.

> >>      libstdc++-v3/include/std/version: Add __cpp_lib_syncbuf:

> >>      libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc: New test.

> >>      libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc: Likewise.

> >>      libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc:

> >>      Likewise.

> >>      libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc:

> >>      Likewise.

> >>      libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc:

> >>      Likewise.

> >>      libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc: Likewise.

> >>      libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc: Likewise.

> >>      libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc:

> >>      Likewise.

> >>      libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc:

> >>      Likewise.

> >>---

> >> libstdc++-v3/doc/doxygen/user.cfg.in          |   1 +

> >> libstdc++-v3/include/Makefile.am              |   1 +

> >> libstdc++-v3/include/Makefile.in              |   1 +

> >> libstdc++-v3/include/precompiled/stdc++.h     |   2 +-

> >> libstdc++-v3/include/std/syncstream           | 333 ++++++++++++++++++

> >> libstdc++-v3/include/std/version              |   4 +

> >> .../testsuite/27_io/basic_syncbuf/1.cc        |  28 ++

> >> .../testsuite/27_io/basic_syncbuf/2.cc        |  28 ++

> >> .../27_io/basic_syncbuf/basic_ops/1.cc        | 137 +++++++

> >> .../27_io/basic_syncbuf/requirements/types.cc |  42 +++

> >> .../27_io/basic_syncbuf/sync_ops/1.cc         | 130 +++++++

> >> .../testsuite/27_io/basic_syncstream/1.cc     |  28 ++

> >> .../testsuite/27_io/basic_syncstream/2.cc     |  28 ++

> >> .../27_io/basic_syncstream/basic_ops/1.cc     | 134 +++++++

> >> .../basic_syncstream/requirements/types.cc    |  43 +++

> >> 15 files changed, 939 insertions(+), 1 deletion(-)

> >> create mode 100644 libstdc++-v3/include/std/syncstream

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc

> >> create mode 100644 libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc

> >>

> >>diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in b/libstdc++-v3/doc/doxygen/user.cfg.in

> >>index 9b49a15d31b..320f6dea688 100644

> >>--- a/libstdc++-v3/doc/doxygen/user.cfg.in

> >>+++ b/libstdc++-v3/doc/doxygen/user.cfg.in

> >>@@ -897,6 +897,7 @@ INPUT                  = @srcdir@/doc/doxygen/doxygroups.cc \

> >>                          include/streambuf \

> >>                          include/string \

> >>                          include/string_view \

> >>+                         include/syncstream \

> >>                          include/system_error \

> >>                          include/thread \

> >>                          include/tuple \

> >>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am

> >>index c90ac555e15..8652b921274 100644

> >>--- a/libstdc++-v3/include/Makefile.am

> >>+++ b/libstdc++-v3/include/Makefile.am

> >>@@ -73,6 +73,7 @@ std_headers = \

> >>      ${std_srcdir}/shared_mutex \

> >>      ${std_srcdir}/span \

> >>      ${std_srcdir}/sstream \

> >>+     ${std_srcdir}/syncstream \

> >>      ${std_srcdir}/stack \

> >>      ${std_srcdir}/stdexcept \

> >>      ${std_srcdir}/stop_token \

> >>diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h

> >>index 7518a98c25a..8899c323a28 100644

> >>--- a/libstdc++-v3/include/precompiled/stdc++.h

> >>+++ b/libstdc++-v3/include/precompiled/stdc++.h

> >>@@ -141,6 +141,6 @@

> >> #include <ranges>

> >> #include <span>

> >> #include <stop_token>

> >>-// #include <syncstream>

> >>+#include <syncstream>

> >> #include <version>

> >> #endif

> >>diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream

> >>new file mode 100644

> >>index 00000000000..ff96ca6cf59

> >>--- /dev/null

> >>+++ b/libstdc++-v3/include/std/syncstream

> >>@@ -0,0 +1,333 @@

> >>+// <syncstream> -*- C++ -*-

> >>+

> >>+// Copyright (C) 2020 Free Software Foundation, Inc.

> >>+//

> >>+// This file is part of the GNU ISO C++ Library.  This library is free

> >>+// software; you can redistribute it and/or modify it under the

> >>+// terms of the GNU General Public License as published by the

> >>+// Free Software Foundation; either version 3, or (at your option)

> >>+// any later version.

> >>+

> >>+// This library is distributed in the hope that it will be useful,

> >>+// but WITHOUT ANY WARRANTY; without even the implied warranty of

> >>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

> >>+// GNU General Public License for more details.

> >>+

> >>+// Under Section 7 of GPL version 3, you are granted additional

> >>+// permissions described in the GCC Runtime Library Exception, version

> >>+// 3.1, as published by the Free Software Foundation.

> >>+

> >>+// You should have received a copy of the GNU General Public License and

> >>+// a copy of the GCC Runtime Library Exception along with this program;

> >>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see

> >>+// <http://www.gnu.org/licenses/>.

> >>+

> >>+/** @file include/syncstream

> >>+ *  This is a Standard C++ Library header.

> >>+ */

> >>+

> >>+#ifndef _GLIBCXX_SYNCSTREAM

> >>+#define _GLIBCXX_SYNCSTREAM 1

> >>+

> >>+#if __cplusplus > 201703L

> >>+

> >>+#include <bits/c++config.h>

> >>+#if _GLIBCXX_USE_CXX11_ABI

> >>+

> >>+#define __cpp_lib_syncbuf 201803L

> >>+

> >>+#pragma GCC system_header

> >>+

> >>+#include <sstream>

> >>+

> >>+#include <bits/alloc_traits.h>

> >>+#include <bits/allocator.h>

> >>+#include <bits/functexcept.h>

> >>+#include <bits/functional_hash.h>

> >>+

> >>+#if _GLIBCXX_HAS_GTHREADS

> >>+# include <bits/std_mutex.h>

> >>+#endif

> >>+

> >>+namespace std _GLIBCXX_VISIBILITY(default)

> >>+{

> >>+_GLIBCXX_BEGIN_NAMESPACE_VERSION

> >>+

> >>+  template<typename _CharT, typename _Traits = char_traits<_CharT>,

> >>+         typename _Alloc = allocator<_CharT>>

> >>+    class basic_syncbuf : public basic_streambuf<_CharT, _Traits>

> >>+    {

> >>+    public:

> >>+      using char_type = _CharT;

> >>+      using int_type = typename _Traits::int_type;

> >>+      using pos_type = typename _Traits::pos_type;

> >>+      using off_type = typename _Traits::off_type;

> >>+      using traits_type = _Traits;

> >>+      using allocator_type = _Alloc;

> >>+      using streambuf_type = basic_streambuf<_CharT, _Traits>;

> >>+

> >>+      basic_syncbuf()

> >>+      : basic_syncbuf(nullptr, allocator_type{})

> >>+      { }

> >>+

> >>+      explicit

> >>+      basic_syncbuf(streambuf_type* __obuf)

> >>+     : basic_syncbuf(__obuf, allocator_type{})

> >>+      { }

> >>+

> >>+      basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)

> >>+     : _M_wrapped(__obuf)

> >>+     , _M_impl(__alloc)

> >>+     , _M_mtx(__obuf)

> >>+      { }

> >>+

> >>+      basic_syncbuf(basic_syncbuf&& __other)

> >>+     : _M_wrapped(__other._M_wrapped)

> >>+     , _M_impl(std::move(__other._M_impl))

> >>+     , _M_mtx(std::move(__other._M_mtx))

> >>+     , _M_emit_on_sync(__other._M_emit_on_sync)

> >>+     , _M_needs_sync(__other._M_needs_sync)

> >>+      {

> >>+     __other._M_wrapped = nullptr;

> >>+      }

> >>+

> >>+      ~basic_syncbuf()

> >>+      {

> >>+     __try

> >>+       {

> >>+         emit();

> >>+       }

> >>+     __catch (...)

> >>+       { }

> >>+      }

> >>+

> >>+      basic_syncbuf& operator=(basic_syncbuf&& __other)

> >>+      {

> >>+     if (std::__addressof(__other) != this)

> >>+       {

> >>+         emit();

> >>+

> >>+         _M_impl = std::move(__other._M_impl);

> >>+         _M_wrapped = __other._M_wrapped; __other._M_wrapped = nullptr;

> >>+         _M_mtx = std::move(__other._M_mtx);

> >>+         _M_emit_on_sync = __other._M_emit_on_sync;

> >>+         _M_needs_sync = __other._M_needs_sync;

> >>+       }

> >>+     return *this;

> >>+      }

> >>+

> >>+      void

> >>+      swap(basic_syncbuf& __other)

> >>+      {

> >>+     if (std::__addressof(__other) != this)

> >>+       {

> >>+         std::swap(_M_impl, __other._M_impl);

> >>+         std::swap(_M_wrapped, __other._M_wrapped);

> >>+         std::swap(_M_mtx, __other._M_mtx);

> >>+         std::swap(_M_emit_on_sync, __other._M_emit_on_sync);

> >>+         std::swap(_M_needs_sync, __other._M_needs_sync);

> >>+       }

> >>+      }

> >>+

> >>+      bool

> >>+      emit()

> >>+      {

> >>+     if (!_M_wrapped)

> >>+       return false;

> >>+

> >>+     auto __s = _M_impl.view();

> >>+     if (__s.empty())

> >>+       return true;

> >>+

> >>+     const lock_guard<__mutex> __l(_M_mtx);

> >>+     if (_M_wrapped->sputn(__s.data(), __s.size()) != __s.size())

> >>+       return false;

> >>+

> >>+     if (_M_needs_sync)

> >>+       {

> >>+         _M_needs_sync = false;

> >>+         if (_M_wrapped->pubsync() != 0)

> >>+           return false;

> >>+       }

> >>+

> >>+     _M_impl.str("");

> >>+     return true;

> >>+      }

> >>+

> >>+      streambuf_type*

> >>+      get_wrapped() const noexcept

> >>+      { return _M_wrapped; }

> >>+

> >>+      allocator_type get_allocator() const noexcept

> >>+      { return _M_impl.get_allocator(); }

> >>+

> >>+      void

> >>+      set_emit_on_sync(bool __b) noexcept

> >>+      { _M_emit_on_sync = __b; }

> >>+

> >>+    protected:

> >>+      int

> >>+      sync() override

> >>+      {

> >>+     auto __res = _M_impl.pubsync();

> >>+     if (__res == 0)

> >>+       {

> >>+         _M_needs_sync = true;

> >>+         if (_M_emit_on_sync)

> >>+           return emit() ? 0 : -1;

> >>+       }

> >>+     return __res;

> >>+      }

> >>+

> >>+      streamsize

> >>+      xsputn(const char_type* __s, streamsize __n) override

> >>+      { return _M_impl.sputn(__s, __n); }

> >>+

> >>+    private:

> >>+      streambuf_type* _M_wrapped;

> >>+

> >>+      using __impl_type = basic_stringbuf<char_type, traits_type,

> >>+                                       allocator_type>;

> >>+      __impl_type _M_impl;

> >>+

> >>+      struct __mutex

> >>+      {

> >>+#if _GLIBCXX_HAS_GTHREADS

> >>+     mutex* _M_mtx;

> >>+

> >>+     __mutex(void* __t)

> >

> > Make this 'explicit' please.

> >

> >>+       : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)

> >>+     { }

> >>+

> >>+     void

> >>+     swap(__mutex& __other) noexcept

> >>+     { std::swap(_M_mtx, __other._M_mtx); }

> >>+

> >>+     void

> >>+     lock()

> >>+     {

> >>+       if (_M_mtx)

> >>+         _M_mtx->lock();

> >>+     }

> >>+

> >>+     void

> >>+     unlock()

> >>+     {

> >>+       if (_M_mtx)

> >>+         _M_mtx->unlock();

> >>+     }

> >>+

> >>+     // FIXME: This should be put in the .so

> >>+     static mutex&

> >>+     _S_get_mutex(void* __t)

> >>+     {

> >>+       const unsigned char __mask = 0xf;

> >>+       static mutex __m[__mask + 1];

> >>+

> >>+       auto __key = _Hash_impl::hash(__t) & __mask;

> >>+       return __m[__key];

> >>+     }

> >>+#else

> >>+     __mutex(void*)

> >

> > And 'explicit' here too.

> >

> >>+     { }

> >>+

> >>+     void

> >>+     swap(__mutex&&) noexcept

> >

> > This needs to be an lvalue reference, or it won't compile.

> >

> >>+     { }

> >>+

> >>+     void

> >>+     lock()

> >>+     { }

> >>+

> >>+     void

> >>+     unlock()

> >>+     { }

> >

> > All these completely empty functions can be put on one line:

> >

> >       void unlock() { }

> >

> > There's no need for these no-op members take up so many lines.

> >

> >>+#endif

> >>+     __mutex(const __mutex&) = delete;

> >>+     __mutex& operator=(const __mutex&) = delete;

> >

> > These are redundant (the user-declared moves below cause the copies to

> > be deleted) but harmless.

> >

> >>+

> >>+     __mutex(__mutex&&) = default;

> >>+     __mutex& operator=(__mutex&&) = default;

> >>+      };

> >>+      __mutex _M_mtx;

> >>+

> >>+      bool _M_emit_on_sync = false;

> >>+      bool _M_needs_sync = false;

> >>+    };

> >

> >

> > OK for trunk, thanks.

>
Jeff Law via Gcc-patches Nov. 3, 2020, 10 p.m. | #4
On 03/11/20 22:22 +0100, Christophe Lyon via Libstdc++ wrote:
>On Mon, 2 Nov 2020 at 19:43, Thomas Rodgers via Gcc-patches

><gcc-patches@gcc.gnu.org> wrote:

>>

>>

>> Testsed x86_64-pc-linux-gnu, committed to master.

>>

>

>Hi,

>

>I can see the new tests failing on bare-metal targets using newlib

>(arm-eabi, aarch64-elf):

>    27_io/basic_syncbuf/1.cc (test for excess errors)

>    27_io/basic_syncbuf/basic_ops/1.cc (test for excess errors)

>    27_io/basic_syncbuf/requirements/types.cc (test for excess errors)

>    27_io/basic_syncstream/1.cc (test for excess errors)

>    27_io/basic_syncstream/basic_ops/1.cc (test for excess errors)

>    27_io/basic_syncstream/requirements/types.cc (test for excess errors)

>

>because:

>libstdc++-v3/include/syncstream:142: error: 'lock_guard' does not name a type


Fixed like so. Tested powerpc64le-linux (--disable-threads) and pushed
to trunk.
commit e1276e334298251d73303999d2adc688abbfc856
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Nov 3 21:56:44 2020

    libstdc++: Ensure std::lock_guard is declared
    
    libstdc++-v3/ChangeLog:
    
            * include/std/syncstream: Include <bits/std_mutex.h>
            unconditionally.

diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream
index 5e0864ec54a8..9d1db0cf286e 100644
--- a/libstdc++-v3/include/std/syncstream
+++ b/libstdc++-v3/include/std/syncstream
@@ -44,10 +44,7 @@
 #include <bits/allocator.h>
 #include <bits/functexcept.h>
 #include <bits/functional_hash.h>
-
-#if _GLIBCXX_HAS_GTHREADS
-# include <bits/std_mutex.h>
-#endif
+#include <bits/std_mutex.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {

Patch

diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in b/libstdc++-v3/doc/doxygen/user.cfg.in
index 9b49a15d31b..320f6dea688 100644
--- a/libstdc++-v3/doc/doxygen/user.cfg.in
+++ b/libstdc++-v3/doc/doxygen/user.cfg.in
@@ -897,6 +897,7 @@  INPUT                  = @srcdir@/doc/doxygen/doxygroups.cc \
                          include/streambuf \
                          include/string \
                          include/string_view \
+                         include/syncstream \
                          include/system_error \
                          include/thread \
                          include/tuple \
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index c90ac555e15..8652b921274 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -73,6 +73,7 @@  std_headers = \
 	${std_srcdir}/shared_mutex \
 	${std_srcdir}/span \
 	${std_srcdir}/sstream \
+	${std_srcdir}/syncstream \
 	${std_srcdir}/stack \
 	${std_srcdir}/stdexcept \
 	${std_srcdir}/stop_token \
diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
index 7518a98c25a..8899c323a28 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -141,6 +141,6 @@ 
 #include <ranges>
 #include <span>
 #include <stop_token>
-// #include <syncstream>
+#include <syncstream>
 #include <version>
 #endif
diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream
new file mode 100644
index 00000000000..ff96ca6cf59
--- /dev/null
+++ b/libstdc++-v3/include/std/syncstream
@@ -0,0 +1,333 @@ 
+// <syncstream> -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/syncstream
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SYNCSTREAM
+#define _GLIBCXX_SYNCSTREAM 1
+
+#if __cplusplus > 201703L 
+
+#include <bits/c++config.h>
+#if _GLIBCXX_USE_CXX11_ABI
+
+#define __cpp_lib_syncbuf 201803L
+
+#pragma GCC system_header
+
+#include <sstream>
+
+#include <bits/alloc_traits.h>
+#include <bits/allocator.h>
+#include <bits/functexcept.h>
+#include <bits/functional_hash.h>
+
+#if _GLIBCXX_HAS_GTHREADS
+# include <bits/std_mutex.h>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _CharT, typename _Traits = char_traits<_CharT>,
+	    typename _Alloc = allocator<_CharT>>
+    class basic_syncbuf : public basic_streambuf<_CharT, _Traits>
+    {
+    public:
+      using char_type = _CharT;
+      using int_type = typename _Traits::int_type;
+      using pos_type = typename _Traits::pos_type;
+      using off_type = typename _Traits::off_type;
+      using traits_type = _Traits;
+      using allocator_type = _Alloc;
+      using streambuf_type = basic_streambuf<_CharT, _Traits>;
+
+      basic_syncbuf()
+      : basic_syncbuf(nullptr, allocator_type{})
+      { }
+
+      explicit
+      basic_syncbuf(streambuf_type* __obuf)
+	: basic_syncbuf(__obuf, allocator_type{})
+      { }
+
+      basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)
+	: _M_wrapped(__obuf)
+	, _M_impl(__alloc)
+	, _M_mtx(__obuf)
+      { }
+
+      basic_syncbuf(basic_syncbuf&& __other)
+	: _M_wrapped(__other._M_wrapped)
+	, _M_impl(std::move(__other._M_impl))
+	, _M_mtx(std::move(__other._M_mtx))
+	, _M_emit_on_sync(__other._M_emit_on_sync)
+	, _M_needs_sync(__other._M_needs_sync)
+      {
+	__other._M_wrapped = nullptr;
+      }
+
+      ~basic_syncbuf()
+      {
+	__try
+	  {
+	    emit();
+	  }
+	__catch (...)
+	  { }
+      }
+
+      basic_syncbuf& operator=(basic_syncbuf&& __other)
+      {
+	if (std::__addressof(__other) != this)
+	  {
+	    emit();
+
+	    _M_impl = std::move(__other._M_impl);
+	    _M_wrapped = __other._M_wrapped; __other._M_wrapped = nullptr;
+	    _M_mtx = std::move(__other._M_mtx);
+	    _M_emit_on_sync = __other._M_emit_on_sync;
+	    _M_needs_sync = __other._M_needs_sync;
+	  }
+	return *this;
+      }
+
+      void
+      swap(basic_syncbuf& __other)
+      {
+	if (std::__addressof(__other) != this)
+	  {
+	    std::swap(_M_impl, __other._M_impl);
+	    std::swap(_M_wrapped, __other._M_wrapped);
+	    std::swap(_M_mtx, __other._M_mtx);
+	    std::swap(_M_emit_on_sync, __other._M_emit_on_sync);
+	    std::swap(_M_needs_sync, __other._M_needs_sync);
+	  }
+      }
+
+      bool
+      emit()
+      {
+	if (!_M_wrapped)
+	  return false;
+
+	auto __s = _M_impl.view();
+	if (__s.empty())
+	  return true;
+
+	const lock_guard<__mutex> __l(_M_mtx);
+	if (_M_wrapped->sputn(__s.data(), __s.size()) != __s.size())
+	  return false;
+
+	if (_M_needs_sync)
+	  {
+	    _M_needs_sync = false;
+	    if (_M_wrapped->pubsync() != 0)
+	      return false;
+	  }
+
+	_M_impl.str("");
+	return true;
+      }
+
+      streambuf_type*
+      get_wrapped() const noexcept
+      { return _M_wrapped; }
+
+      allocator_type get_allocator() const noexcept
+      { return _M_impl.get_allocator(); }
+
+      void
+      set_emit_on_sync(bool __b) noexcept
+      { _M_emit_on_sync = __b; }
+
+    protected:
+      int
+      sync() override
+      {
+	auto __res = _M_impl.pubsync();
+	if (__res == 0)
+	  {
+	    _M_needs_sync = true;
+	    if (_M_emit_on_sync)
+	      return emit() ? 0 : -1;
+	  }
+	return __res;
+      }
+
+      streamsize
+      xsputn(const char_type* __s, streamsize __n) override
+      { return _M_impl.sputn(__s, __n); }
+
+    private:
+      streambuf_type* _M_wrapped;
+
+      using __impl_type = basic_stringbuf<char_type, traits_type,
+					  allocator_type>;
+      __impl_type _M_impl;
+
+      struct __mutex
+      {
+#if _GLIBCXX_HAS_GTHREADS
+	mutex* _M_mtx;
+
+	__mutex(void* __t)
+	  : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)
+	{ }
+
+	void
+	swap(__mutex& __other) noexcept
+	{ std::swap(_M_mtx, __other._M_mtx); }
+
+	void
+	lock()
+	{
+	  if (_M_mtx)
+	    _M_mtx->lock();
+	}
+
+	void
+	unlock()
+	{
+	  if (_M_mtx)
+	    _M_mtx->unlock();
+	}
+
+	// FIXME: This should be put in the .so
+	static mutex&
+	_S_get_mutex(void* __t)
+	{
+	  const unsigned char __mask = 0xf;
+	  static mutex __m[__mask + 1];
+
+	  auto __key = _Hash_impl::hash(__t) & __mask;
+	  return __m[__key];
+	}
+#else
+	__mutex(void*)
+	{ }
+
+	void
+	swap(__mutex&&) noexcept
+	{ }
+
+	void
+	lock()
+	{ }
+
+	void
+	unlock()
+	{ }
+#endif
+	__mutex(const __mutex&) = delete;
+	__mutex& operator=(const __mutex&) = delete;
+
+	__mutex(__mutex&&) = default;
+	__mutex& operator=(__mutex&&) = default;
+      };
+      __mutex _M_mtx;
+
+      bool _M_emit_on_sync = false;
+      bool _M_needs_sync = false;
+    };
+
+  template <typename _CharT, typename _Traits = char_traits<_CharT>,
+	    typename _Alloc = allocator<_CharT>>
+    class basic_osyncstream : public basic_ostream<_CharT, _Traits>
+    {
+      using __ostream_type = basic_ostream<_CharT, _Traits>;
+
+    public:
+      // Types:
+      using char_type = _CharT;
+      using traits_type = _Traits;
+      using allocator_type = _Alloc;
+      using int_type = typename traits_type::int_type;
+      using pos_type = typename traits_type::pos_type;
+      using off_type = typename traits_type::off_type;
+      using syncbuf_type = basic_syncbuf<_CharT, _Traits, _Alloc>;
+      using streambuf_type = typename syncbuf_type::streambuf_type;
+
+    private:
+      syncbuf_type _M_syncbuf;
+
+    public:
+      basic_osyncstream(streambuf_type* __buf, const allocator_type& __a)
+	: _M_syncbuf(__buf, __a)
+      { this->init(std::__addressof(_M_syncbuf)); }
+
+      explicit basic_osyncstream(streambuf_type* __buf)
+	: _M_syncbuf(__buf)
+      { this->init(std::__addressof(_M_syncbuf)); }
+
+      basic_osyncstream(basic_ostream<char_type, traits_type>& __os,
+		        const allocator_type& __a)
+	: basic_osyncstream(__os.rdbuf(), __a)
+      { this->init(std::__addressof(_M_syncbuf)); }
+
+      explicit basic_osyncstream(basic_ostream<char_type, traits_type>& __os)
+	: basic_osyncstream(__os.rdbuf())
+      { this->init(std::__addressof(_M_syncbuf)); }
+
+      basic_osyncstream(basic_osyncstream&& __rhs) noexcept
+	: __ostream_type(std::move(__rhs)),
+	_M_syncbuf(std::move(__rhs._M_syncbuf))
+      { __ostream_type::set_rdbuf(std::__addressof(_M_syncbuf)); }
+
+      ~basic_osyncstream() = default;
+
+      basic_osyncstream& operator=(basic_osyncstream&&) noexcept = default;
+
+      syncbuf_type* rdbuf() const noexcept
+      { return const_cast<syncbuf_type*>(&_M_syncbuf); }
+
+      streambuf_type* get_wrapped() const noexcept
+      { return _M_syncbuf.get_wrapped(); }
+
+      void emit()
+      {
+	if (!_M_syncbuf.emit())
+	  this->setstate(ios_base::failbit);
+      }
+    };
+
+  template <class _CharT, class _Traits, class _Allocator>
+    inline void
+    swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __x,
+	 basic_syncbuf<_CharT, _Traits, _Allocator>& __y) noexcept
+    { __x.swap(__y); }
+
+  using syncbuf = basic_syncbuf<char>;
+  using wsyncbuf = basic_syncbuf<wchar_t>;
+
+  using osyncstream = basic_osyncstream<char>;
+  using wosyncstream = basic_osyncstream<wchar_t>;
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // _GLIBCXX_USE_CXX11_ABI
+#endif // C++2a
+#endif	/* _GLIBCXX_SYNCSTREAM */
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index ebb50a04d24..7f51ef3a6c4 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -229,6 +229,10 @@ 
 #define __cpp_lib_span 202002L
 #define __cpp_lib_ssize 201902L
 #define __cpp_lib_starts_ends_with 201711L
+# if _GLIBCXX_USE_CXX11_ABI
+// Only supported with cx11-abi
+#  define __cpp_lib_syncbuf 201803L
+# endif
 #define __cpp_lib_to_address 201711L
 #define __cpp_lib_to_array 201907L
 #endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc
new file mode 100644
index 00000000000..1b3ae9330bb
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/1.cc
@@ -0,0 +1,28 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+
+#ifndef __cpp_lib_syncbuf
+# error "Feature-test macro for syncbuf missing in <syncstream>"
+#elif __cpp_lib_syncbuf != 201803L
+# error "Feature-test macro for syncbuf has wrong value in <syncstream>"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc
new file mode 100644
index 00000000000..4ffcb0410fd
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/2.cc
@@ -0,0 +1,28 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <version>
+
+#ifndef __cpp_lib_syncbuf
+# error "Feature-test macro for syncbuf missing in <version>"
+#elif __cpp_lib_syncbuf != 201803L
+# error "Feature-test macro for syncbuf has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc
new file mode 100644
index 00000000000..d5062bab70b
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/basic_ops/1.cc
@@ -0,0 +1,137 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <sstream>
+#include <string_view>
+#include <syncstream>
+
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+
+void
+test01() // construction
+{
+  {
+    std::syncbuf s1;
+    VERIFY( s1.get_wrapped() == nullptr );
+
+    std::stringbuf b;
+    std::syncbuf s2(&b);
+    VERIFY( s2.get_wrapped() == &b );
+  }
+
+  {
+    using alloc_type = __gnu_test::uneq_allocator<char>;
+    using sbuf_t = std::basic_syncbuf<char, std::char_traits<char>,
+				      alloc_type>;
+
+    sbuf_t b;
+
+    alloc_type aa;
+    sbuf_t s1(&b, aa);
+    VERIFY( aa == s1.get_allocator() );
+
+    alloc_type aaa(42);
+    sbuf_t s2(&b, aaa);
+    VERIFY( aaa == s2.get_allocator() );
+
+    VERIFY( s1.get_allocator() != s2.get_allocator() );
+  }
+}
+
+void
+test02() // moving
+{
+  {
+    std::stringbuf b;
+    std::syncbuf s1(&b);
+
+    std::syncbuf s2(std::move(s1));
+
+    VERIFY( s1.get_wrapped() == nullptr );
+    VERIFY( s2.get_wrapped() == &b );
+  }
+
+  {
+    std::stringbuf b;
+    std::syncbuf s1(&b);
+
+    std::syncbuf s2;
+    s2 = std::move(s1);
+
+    VERIFY( s1.get_wrapped() == nullptr );
+    VERIFY( s2.get_wrapped() == &b );
+  }
+}
+
+void
+test03() // swaping
+{
+  std::stringbuf b;
+  std::syncbuf s1(&b);
+
+  std::syncbuf s2;
+  std::swap(s1, s2);
+
+  VERIFY( s1.get_wrapped() == nullptr );
+  VERIFY( s2.get_wrapped() == &b );
+}
+
+void
+test04() // emitting
+{
+  {
+    std::stringbuf b;
+    std::syncbuf s(&b);
+
+    const std::string_view txt("This is a test");
+    s.sputn(txt.data(), txt.size());
+
+    VERIFY( b.str() != txt );
+    VERIFY( s.pubsync() == 0 );
+    VERIFY( b.str() != txt );
+
+    VERIFY( s.emit() );
+    VERIFY( b.str() == txt );
+  }
+
+  {
+    std::stringbuf b;
+    std::syncbuf s(&b);
+    s.set_emit_on_sync(true);
+
+    const std::string_view txt("This is a test");
+    s.sputn(txt.data(), txt.size());
+
+    VERIFY( s.pubsync() == 0 );
+    VERIFY( b.str() == txt );
+  }
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc
new file mode 100644
index 00000000000..49266b4abf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/requirements/types.cc
@@ -0,0 +1,42 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+
+template<typename T>
+  struct type_reqs
+  {
+    using test_type = T;
+    using char_type = test_type::char_type;
+    using int_type = test_type::int_type;
+    using pos_type = test_type::pos_type;
+    using off_Type = test_type::off_type;
+    using traits_type = test_type::traits_type;
+    using allocator_type = test_type::allocator_type;
+    using streambuf_type = test_type::streambuf_type;
+  };
+
+void test01()
+{
+  // Check for required typedefs
+  using test_type = type_reqs<std::osyncstream>;
+  using wtest_type = type_reqs<std::wosyncstream>;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc
new file mode 100644
index 00000000000..90d20f1a607
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncbuf/sync_ops/1.cc
@@ -0,0 +1,130 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-effective-target cxx11-abi }
+// { dg-require-gthreads "" }
+
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <syncstream>
+#include <thread>
+#include <vector>
+#include <unordered_map>
+#include <utility>
+
+#include <testsuite_hooks.h>
+
+int
+main()
+{
+  using namespace std::chrono_literals;
+
+  std::stringbuf b;
+  std::atomic<unsigned> running(0);
+
+  auto const cstr = "This is a test";
+
+  constexpr int ct = 1000;
+  auto const body = [&]{
+    ++running;
+    auto tid = std::this_thread::get_id();
+    std::syncbuf s(&b);
+    for (auto i = 0; i < ct; ++i)
+    {
+      std::stringstream stm;
+      stm << tid << ' ' << cstr << ' ' << i << std::endl;
+      auto sv = stm.view();
+      s.sputn(sv.data(), sv.size());
+      VERIFY( s.emit() );
+    }
+  };
+
+  const auto tct = 8;
+  std::vector<std::thread> ts;
+  ts.reserve(tct);
+
+  for (auto i = 0; i < tct; ++i)
+    ts.emplace_back(std::thread(body));
+
+  do
+  {
+    std::this_thread::sleep_for(100ms);
+  }
+  while (running.load() < tct);
+
+  std::unordered_map<std::string, int> tids;
+  for (auto&& t : ts)
+  {
+    std::stringstream stm;
+    stm << t.get_id();
+    tids.emplace(std::make_pair(stm.str(), 0));
+  };
+
+  for (auto&& t : ts)
+     t.join();
+
+  std::vector<std::string_view> lines;
+  const auto lct = ct * ts.size();
+  lines.reserve(lct);
+
+  std::size_t last = 0;
+  auto sv = b.view();
+  auto p = sv.find('\n');
+  while (p != std::string_view::npos)
+  {
+    lines.emplace_back(sv.substr(last, p - last));
+    last = p+1;
+    p = sv.find('\n', last);
+  }
+  VERIFY( lines.size() == lct );
+
+  auto sep = "";
+  auto i = 0;
+  sv = std::string_view(cstr);
+
+  for (auto&& l : lines)
+  {
+    auto p = l.find(' ');
+    VERIFY( p != std::string_view::npos );
+    std::string tid(l.substr(0, p));
+    ++p;
+
+    VERIFY( l.substr(p, sv.size()) == sv );
+    std::string s(l.substr(++p + sv.size()));
+    std::stringstream stm(s);
+    int n;
+    stm >> n;
+    VERIFY( stm.eof() );
+    VERIFY( n >= 0 && n < ct );
+    auto it = tids.find(tid);
+    VERIFY( it != std::end(tids) );
+    ++(it->second);
+  }
+
+  for (auto const& t : tids)
+  {
+    VERIFY( t.second == ct );
+  }
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc
new file mode 100644
index 00000000000..1b3ae9330bb
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncstream/1.cc
@@ -0,0 +1,28 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+
+#ifndef __cpp_lib_syncbuf
+# error "Feature-test macro for syncbuf missing in <syncstream>"
+#elif __cpp_lib_syncbuf != 201803L
+# error "Feature-test macro for syncbuf has wrong value in <syncstream>"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc b/libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc
new file mode 100644
index 00000000000..4ffcb0410fd
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncstream/2.cc
@@ -0,0 +1,28 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <version>
+
+#ifndef __cpp_lib_syncbuf
+# error "Feature-test macro for syncbuf missing in <version>"
+#elif __cpp_lib_syncbuf != 201803L
+# error "Feature-test macro for syncbuf has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc b/libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc
new file mode 100644
index 00000000000..a40cd162fbd
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncstream/basic_ops/1.cc
@@ -0,0 +1,134 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <sstream>
+#include <string_view>
+#include <syncstream>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+
+void
+test01() // construction
+{
+  {
+    std::stringbuf b;
+    std::osyncstream s(&b);
+    VERIFY( s.rdbuf() != nullptr );
+    VERIFY( s.get_wrapped() == &b );
+  }
+
+  {
+    std::ostringstream stm;
+    std::osyncstream s(stm);
+    VERIFY( s.get_wrapped() == stm.rdbuf() );
+  }
+
+  {
+    using alloc_type = __gnu_test::uneq_allocator<char>;
+    using sbuf_t = std::basic_syncbuf<char, std::char_traits<char>,
+				      alloc_type>;
+    using stream_t = std::basic_osyncstream<char, std::char_traits<char>,
+					    alloc_type>;
+    using str_t = std::basic_ostringstream<char, std::char_traits<char>,
+                                      alloc_type>;
+    sbuf_t b;
+
+    alloc_type aa;
+    stream_t s1(&b, aa);
+    VERIFY( aa == s1.rdbuf()->get_allocator() );
+
+    alloc_type aaa(42);
+    stream_t s2(&b, aaa);
+    VERIFY( aaa == s2.rdbuf()->get_allocator() );
+
+    VERIFY( s1.rdbuf()->get_allocator() != s2.rdbuf()->get_allocator() );
+
+    str_t stm;
+    stream_t s3(stm, aa);
+    VERIFY( s3.get_wrapped() == stm.rdbuf() );
+    VERIFY( aa == s1.rdbuf()->get_allocator() );
+  }
+}
+
+void
+test02() // moving
+{
+  {
+    std::stringbuf b;
+    std::osyncstream s1(&b);
+
+    std::osyncstream s2(std::move(s1));
+
+    VERIFY( s1.get_wrapped() == nullptr );
+    VERIFY( s2.get_wrapped() == &b );
+  }
+
+  {
+    std::stringbuf b1;
+    std::osyncstream s1(&b1);
+
+    std::stringbuf b2;
+    std::osyncstream s2(&b2);
+    s2 = std::move(s1);
+
+    VERIFY( s1.get_wrapped() == nullptr );
+    VERIFY( s2.get_wrapped() == &b1 );
+  }
+}
+
+void
+test03() // swaping
+{
+  std::stringbuf b1;
+  std::osyncstream s1(&b1);
+
+  std::stringbuf b2;
+  std::osyncstream s2(&b2);
+
+  std::swap(s1, s2);
+
+  VERIFY( s1.get_wrapped() == &b2 );
+  VERIFY( s2.get_wrapped() == &b1 );
+}
+
+void
+test04() // emitting
+{
+  {
+    std::stringbuf b;
+    std::osyncstream s(&b);
+
+    const std::string_view txt("This is a test");
+    s << txt;
+
+    s.emit();
+    VERIFY( b.str() == txt );
+  }
+}
+int main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc b/libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc
new file mode 100644
index 00000000000..dfc0b72efcd
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_syncstream/requirements/types.cc
@@ -0,0 +1,43 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+
+template<typename T>
+  struct type_reqs
+  {
+    using test_type = T;
+    using char_type = test_type::char_type;
+    using int_type = test_type::int_type;
+    using pos_type = test_type::pos_type;
+    using off_Type = test_type::off_type;
+    using traits_type = test_type::traits_type;
+    using allocator_type = test_type::allocator_type;
+    using streambuf_type = test_type::streambuf_type;
+    using syncbuf_type = test_type::syncbuf_type;
+  };
+
+void test01()
+{
+  // Check for required typedefs
+  using test_type = type_reqs<std::osyncstream>;
+  using wtest_type = type_reqs<std::wosyncstream>;
+}