diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 90ecc4a87a2..30a4abb98b3 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -3798,7 +3798,7 @@ changequote([,])dnl
fi
# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:29:0
+libtool_VERSION=6:30:0
# Everything parsed; figure out what files and settings to use.
case $enable_symvers in
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 5323c7f0604..727afd2d488 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1705,8 +1705,9 @@ GLIBCXX_3.4.21 {
# std::ctype_base::blank
_ZNSt10ctype_base5blankE;
- # std::_Sp_locker::*
- _ZNSt10_Sp_locker[CD]*;
+ # std::_Sp_locker:: constructors and destructors
+ _ZNSt10_Sp_lockerC*[^b];
+ _ZNSt10_Sp_lockerD*;
# std::notify_all_at_thread_exit
_ZSt25notify_all_at_thread_exitRSt18condition_variableSt11unique_lockISt5mutexE;
@@ -2397,6 +2398,13 @@ GLIBCXX_3.4.29 {
} GLIBCXX_3.4.28;
+GLIBCXX_3.4.30 {
+ # std::_Sp_locker:: wait/notify support
+ _ZNSt10_Sp_lockerC*[b];
+ _ZNSt10_Sp_locker7_M_waitEv;
+ _ZNSt10_Sp_locker9_M_notifyEv;
+} GLIBCXX_3.4.29;
+
# Symbols in the support library (libsupc++) have their own tag.
CXXABI_1.3 {
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index 13d52eb0c0e..67ee6db1bea 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -74684,7 +74684,7 @@ $as_echo "$as_me: WARNING: === Symbol versioning will be disabled." >&2;}
fi
# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:29:0
+libtool_VERSION=6:30:0
# Everything parsed; figure out what files and settings to use.
case $enable_symvers in
diff --git a/libstdc++-v3/doc/xml/manual/abi.xml b/libstdc++-v3/doc/xml/manual/abi.xml
index c2c0c028a8b..10bef12c768 100644
--- a/libstdc++-v3/doc/xml/manual/abi.xml
+++ b/libstdc++-v3/doc/xml/manual/abi.xml
@@ -348,6 +348,7 @@ compatible.
GCC 9.3.0: GLIBCXX_3.4.28, CXXABI_1.3.12
GCC 10.1.0: GLIBCXX_3.4.28, CXXABI_1.3.12
GCC 11.1.0: GLIBCXX_3.4.29, CXXABI_1.3.13
+ GCC 12.1.0: GLIBCXX_3.4.30, CXXABI_1.3.13
diff --git a/libstdc++-v3/include/bits/shared_ptr_atomic.h b/libstdc++-v3/include/bits/shared_ptr_atomic.h
index 6e94d83c46d..2aec3adac7c 100644
--- a/libstdc++-v3/include/bits/shared_ptr_atomic.h
+++ b/libstdc++-v3/include/bits/shared_ptr_atomic.h
@@ -32,6 +32,10 @@
#include
+#if __cplusplus > 201703L
+# define __cpp_lib_atomic_shared_ptr 201711L
+#endif
+
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -55,6 +59,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Sp_locker(const void*, const void*) noexcept;
~_Sp_locker();
+#if __cpp_lib_atomic_shared_ptr
+ // called only by notifiers, does not acquire a lock
+ _Sp_locker(const void*, bool) noexcept;
+
+ void
+ _M_wait() noexcept;
+
+ void
+ _M_notify() noexcept;
+#endif
+
private:
unsigned char _M_key1;
unsigned char _M_key2;
@@ -327,6 +342,300 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
/// @}
+#if __cpp_lib_atomic_shared_ptr
+ template
+ struct _Sp_impl
+ {
+ using value_type = _Tp;
+
+ static constexpr bool
+ _M_is_always_lock_free = false;
+
+ static bool
+ _M_is_lock_free() noexcept
+ { return false; }
+
+ constexpr _Sp_impl() noexcept = default;
+ _Sp_impl(value_type __r) noexcept
+ : _M_p(move(__r))
+ { }
+
+ _Sp_impl(const _Sp_impl&) = delete;
+ void operator=(const _Sp_impl&) = delete;
+
+ value_type
+ _M_load(memory_order) const noexcept
+ {
+ _Sp_locker __lock{&_M_p};
+ return _M_p;
+ }
+
+ void
+ _M_store(value_type __r, memory_order) noexcept
+ {
+ _Sp_locker __lock{&_M_p};
+ _M_p.swap(__r); // use swap so that *__p not destroyed while lock held
+ }
+
+ value_type
+ _M_exchange(value_type __r, memory_order) noexcept
+ {
+ _Sp_locker __lock{&_M_p};
+ _M_p.swap(__r);
+ return __r;
+ }
+
+ template
+ bool
+ _M_compare_exchange_strong(value_type& __v, value_type __w,
+ _Pred __pred,
+ memory_order, memory_order) noexcept
+ {
+ value_type __x; // goes out of scope after __lock
+ _Sp_locker __lock{&_M_p, &__v};
+ if (__pred(_M_p, __v))
+ {
+ __x = move(_M_p);
+ _M_p = move(__w);
+ return true;
+ }
+ __x = move(__v);
+ __v = _M_p;
+ return false;
+ }
+
+ template
+ void
+ _M_wait(value_type __old,
+ _Pred __pred, memory_order) const noexcept
+ {
+ _Sp_locker __lock(&_M_p);
+ while (__pred(_M_p, __old))
+ __lock._M_wait();
+ }
+
+ void
+ _M_notify() noexcept
+ {
+ _Sp_locker __lock(&_M_p, true);
+ __lock._M_notify();
+ }
+
+ private:
+ value_type _M_p;
+ };
+
+ template
+ class atomic>
+ {
+ using __impl_t = _Sp_impl>;
+
+ public:
+ using value_type = __impl_t::value_type;
+
+ static constexpr bool
+ is_always_lock_free = __impl_t::_M_is_always_lock_free;
+
+ bool
+ is_lock_free() const noexcept
+ { return __impl_t::_M_is_lock_free(); }
+
+ constexpr atomic() noexcept = default;
+ atomic(value_type __r) noexcept
+ : _M_impl(move(__r))
+ { }
+
+ atomic(const atomic&) = delete;
+ void operator=(const atomic&) = delete;
+
+ value_type
+ load(memory_order __o = memory_order_seq_cst) const noexcept
+ { return _M_impl._M_load(__o); }
+
+ operator shared_ptr<_Tp>() const noexcept
+ { return load(); }
+
+ void
+ store(value_type __r, memory_order __o = memory_order_seq_cst) noexcept
+ { _M_impl._M_store(move(__r), __o); }
+
+ void operator=(value_type __r) noexcept
+ { store(move(__r)); }
+
+ value_type
+ exchange(value_type __r, memory_order __o = memory_order_seq_cst) noexcept
+ { return _M_impl._M_exchange(move(__r), __o); }
+
+ bool
+ compare_exchange_strong(value_type& __v, value_type __w,
+ memory_order, memory_order) noexcept
+ {
+ return _M_impl._M_compare_exchange_strong(__v, move(__w),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ memory_order_seq_cst, memory_order_seq_cst);
+ }
+
+ bool
+ compare_exchange_strong(value_type& __v, value_type __w,
+ memory_order __o = memory_order_seq_cst) noexcept
+ {
+ return _M_impl._M_compare_exchange_strong(__v, move(__w),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ __o, __o);
+ }
+
+ bool
+ compare_exchange_weak(value_type& __v, value_type __w,
+ memory_order, memory_order) noexcept
+ {
+ return _M_impl._M_compare_exchange_strong(__v, move(__w),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ memory_order_seq_cst, memory_order_seq_cst);
+ }
+
+ bool
+ compare_exchange_weak(value_type& __v, value_type __w,
+ memory_order __o = memory_order_seq_cst) noexcept
+ {
+ return _M_impl._M_compare_exchange_strong(__v, move(__w),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ __o, __o);
+ }
+
+ void
+ wait(value_type __old, memory_order __o = memory_order_seq_cst) const noexcept
+ {
+ _M_impl._M_wait(move(__old),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ __o);
+ }
+
+ void
+ notify_one() noexcept
+ { _M_impl._M_notify(); }
+
+ void
+ notify_all() noexcept
+ { _M_impl._M_notify(); }
+
+ private:
+ __impl_t _M_impl;
+
+ static bool
+ _S_compare(const value_type& __a, const value_type& __b) noexcept
+ {
+ owner_less __less;
+ return __a == __b && !__less(__a, __b) && !__less(__b, __a);
+ }
+ };
+
+ template
+ class atomic>
+ {
+ using __impl_t = _Sp_impl>;
+
+ public:
+ using value_type = __impl_t::value_type;
+
+ static constexpr bool
+ is_always_lock_free = __impl_t::_M_is_always_lock_free;
+
+ bool
+ is_lock_free() const noexcept
+ { return __impl_t::_M_is_lock_free(); }
+
+ constexpr atomic() noexcept = default;
+ atomic(value_type __r) noexcept
+ : _M_impl(move(__r))
+ { }
+
+ atomic(const atomic&) = delete;
+ void operator=(const atomic&) = delete;
+
+ value_type
+ load(memory_order __o = memory_order_seq_cst) const noexcept
+ { return _M_impl._M_load(__o); }
+
+ operator weak_ptr<_Tp>() const noexcept
+ { return load(); }
+
+ void
+ store(value_type __r, memory_order __o = memory_order_seq_cst) noexcept
+ { _M_impl._M_store(move(__r), __o); }
+
+ void operator=(value_type __r) noexcept
+ { store(move(__r)); }
+
+ value_type
+ exchange(value_type __r, memory_order __o = memory_order_seq_cst) noexcept
+ { return _M_impl._M_exchange(move(__r), __o); }
+
+ bool
+ compare_exchange_strong(value_type& __v, value_type __w,
+ memory_order, memory_order) noexcept
+ {
+ return _M_impl._M_compare_exchange_strong(__v, move(__w),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ memory_order_seq_cst, memory_order_seq_cst);
+ }
+
+ bool
+ compare_exchange_strong(value_type& __v, value_type __w,
+ memory_order __o = memory_order_seq_cst) noexcept
+ {
+ return _M_impl._M_compare_exchange_strong(__v, move(__w),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ __o, __o);
+ }
+
+ bool
+ compare_exchange_weak(value_type& __v, value_type __w,
+ memory_order, memory_order) noexcept
+ {
+ return _M_impl._M_compare_exchange_strong(__v, move(__w),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ memory_order_seq_cst, memory_order_seq_cst);
+ }
+
+ bool
+ compare_exchange_weak(value_type& __v, value_type __w,
+ memory_order __o = memory_order_seq_cst) noexcept
+ {
+ return _M_impl._M_compare_exchange_strong(__v, move(__w),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ __o, __o);
+ }
+
+ void
+ wait(value_type __old, memory_order __o = memory_order_seq_cst) const noexcept
+ {
+ _M_impl._M_wait(move(__old),
+ [](const auto& __a, const auto& __b) { return _S_compare(__a, __b); },
+ __o);
+ }
+
+ void
+ notify_one() noexcept
+ { _M_impl._M_notify(); }
+
+ void
+ notify_all() noexcept
+ { _M_impl._M_notify(); }
+
+ private:
+ __impl_t _M_impl;
+
+ static bool
+ _S_compare(const value_type& __a, const value_type& __b) noexcept
+ {
+ owner_less __less;
+ const auto& __sa = __a.lock();
+ const auto& __sb = __b.lock();
+ return __sa == __sb && !__less(__a, __b) && !__less(__b, __a);
+ }
+ };
+#endif // __cpp_lib_atomic_shared_ptr
+
/// @} relates shared_ptr
/// @} group pointer_abstractions
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index f41004b5911..37e5f0e5175 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -179,6 +179,7 @@
#define __cpp_lib_atomic_flag_test 201907L
#define __cpp_lib_atomic_float 201711L
#define __cpp_lib_atomic_ref 201806L
+#define __cpp_lib_atomic_shared_ptr 201711L
#define __cpp_lib_atomic_value_initialization 201911L
#define __cpp_lib_bitops 201907L
#define __cpp_lib_bounded_array_traits 201902L
diff --git a/libstdc++-v3/src/c++11/Makefile.am b/libstdc++-v3/src/c++11/Makefile.am
index a26903db6bc..72ab7ac22fe 100644
--- a/libstdc++-v3/src/c++11/Makefile.am
+++ b/libstdc++-v3/src/c++11/Makefile.am
@@ -136,6 +136,12 @@ limits.lo: limits.cc
limits.o: limits.cc
$(CXXCOMPILE) -fchar8_t -c $<
+# Use -std=gnu++20 for shared_ptr.cc
+shared_ptr.lo: shared_ptr.cc
+ $(LTCXXCOMPILE) -std=gnu++20 -c $<
+shared_ptr.o: shared_ptr.cc
+ $(CXXCOMPILE) -std=gnu++20 -c $<
+
if ENABLE_DUAL_ABI
# Rewrite the type info for __ios_failure.
rewrite_ios_failure_typeinfo = sed -e '/^_*_ZTISt13__ios_failure:/,/_ZTVN10__cxxabiv120__si_class_type_infoE/s/_ZTVN10__cxxabiv120__si_class_type_infoE/_ZTVSt19__iosfail_type_info/'
diff --git a/libstdc++-v3/src/c++11/shared_ptr.cc b/libstdc++-v3/src/c++11/shared_ptr.cc
index 4678fbeffe2..144273e6cea 100644
--- a/libstdc++-v3/src/c++11/shared_ptr.cc
+++ b/libstdc++-v3/src/c++11/shared_ptr.cc
@@ -22,12 +22,56 @@
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// .
+#include
#include
#include "mutex_pool.h"
namespace __gnu_internal _GLIBCXX_VISIBILITY(hidden)
{
+ struct __condvar
+ {
+ __condvar() noexcept
+ {
+#ifndef __GTHREAD_COND_INIT
+ __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
+#endif
+ }
+
+ ~__condvar()
+ {
+ int __e __attribute__((__unused__)) = __gthread_cond_destroy(&_M_cond);
+ __glibcxx_assert(__e != EBUSY); // threads are still blocked
+ }
+
+ __condvar(const __condvar&) = delete;
+ __condvar& operator=(const __condvar&) = delete;
+
+ void
+ _M_wait(__gnu_cxx::__mutex& __m) noexcept
+ {
+ int __e __attribute__((__unused__))
+ = __gthread_cond_wait(&_M_cond, __m.gthread_mutex());
+ __glibcxx_assert(__e == 0);
+ }
+
+ void
+ _M_notify() noexcept
+ {
+ // we do a broadcast here because multiple threads may multiplex a wait
+ // against the same __condvar
+ int __e __attribute__((__unused__)) = __gthread_cond_broadcast(&_M_cond);
+ __glibcxx_assert(__e == 0);
+ }
+
+ private:
+#ifdef __GTHREAD_COND_INIT
+ __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
+#else
+ __gthread_cond_t _M_cond;
+#endif
+ };
+
/* Returns different instances of __mutex depending on the passed index
* in order to limit contention.
*/
@@ -39,6 +83,18 @@ namespace __gnu_internal _GLIBCXX_VISIBILITY(hidden)
static M m[mask + 1];
return m[i];
}
+
+ /* Returns different instances of __condvar depending on the passed index
+ * in order to limit contention
+ */
+ __condvar&
+ get_condvar(unsigned char i)
+ {
+ // increase alignment to put each condvar on a separate cache line
+ struct alignas(64) CV : __condvar { };
+ static CV cv[mask + 1];
+ return cv[i];
+ }
}
namespace std _GLIBCXX_VISIBILITY(default)
@@ -90,10 +146,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (_M_key1 != __gnu_internal::invalid)
{
__gnu_internal::get_mutex(_M_key1).unlock();
- if (_M_key2 != _M_key1)
+#if __cpp_lib_atomic_shared_ptr
+ if ((_M_key2 != _M_key1) && (_M_key2 != __gnu_internal::invalid))
+#else
+ if ((_M_key2 != _M_key1))
+#endif
__gnu_internal::get_mutex(_M_key2).unlock();
}
}
+
+#if __cpp_lib_atomic_shared_ptr
+ _Sp_locker::_Sp_locker(const void* p, bool) noexcept
+ {
+ _M_key1 = key(p);
+ _M_key2 = __gnu_internal::invalid;
+ }
+
+ void
+ _Sp_locker::_M_wait() noexcept
+ {
+ __glibcxx_assert(_M_key1 == _M_key2); // can't hold two locks
+ __gnu_cxx::__mutex& m = __gnu_internal::get_mutex(_M_key1);
+ __gnu_internal::get_condvar(_M_key1)._M_wait(m);
+ }
+
+ void
+ _Sp_locker::_M_notify() noexcept
+ {
+ __glibcxx_assert(_M_key2 == __gnu_internal::invalid); // can't hold a lock
+ __gnu_internal::get_condvar(_M_key1)._M_notify();
+ }
+#endif
+
#endif
bool
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/4.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/4.cc
new file mode 100644
index 00000000000..aa9fce9e235
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/4.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2021 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
+// .
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target gthreads }
+
+#include
+
+#ifndef __cpp_lib_atomic_shared_ptr
+# error "Feature-test macro for atomic> missing in "
+#elif __cpp_lib_atomic_shared_ptr != 201711L
+# error "Feature-test macro for atomic> has wrong value in "
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/5.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/5.cc
new file mode 100644
index 00000000000..5f8791f78b5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/5.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2021 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
+// .
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+// { dg-require-effective-target gthreads }
+
+#include
+
+#ifndef __cpp_lib_atomic_shared_ptr
+# error "Feature-test macro for atomic> missing in "
+#elif __cpp_lib_atomic_shared_ptr != 201711L
+# error "Feature-test macro for atomic> has wrong value in "
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/atomic_shared_ptr.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/atomic_shared_ptr.cc
new file mode 100644
index 00000000000..7a34148a974
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/atomic_shared_ptr.cc
@@ -0,0 +1,159 @@
+// Copyright (C) 2020-2021 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
+// .
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+
+#include
+#include
+
+#include
+
+template
+ void
+ test_is_lock_free()
+ {
+ using test_type = std::atomic;
+ VERIFY( test_type::is_always_lock_free == false );
+
+ test_type p;
+ VERIFY( p.is_lock_free() == false );
+ }
+
+struct A { int a; int b; };
+
+template
+ void
+ test_wait_notify(Tp& p, const Ta& a, const Ta& b)
+ {
+ p.store(a);
+ p.wait(b);
+ std::thread t([&]
+ {
+ p.store(b);
+ p.notify_one();
+ });
+ p.wait(a);
+ t.join();
+ }
+
+void
+test_atomic_shared_ptr()
+{
+ test_is_lock_free>();
+ auto a = std::make_shared( 0, 42 );
+ using ptr_t = std::shared_ptr;
+ {
+ std::atomic p{ };
+ VERIFY( p.load().get() == nullptr );
+ }
+
+ std::atomic p{ a };
+ VERIFY( p.load().get() == a.get() );
+ auto b = std::make_shared( 42, 0 );
+ p.store(b);
+ VERIFY( p.load().get() != a.get() );
+ VERIFY( p.load().get() == b.get() );
+ p.exchange(a);
+ VERIFY( p.load().get() != b.get() );
+ VERIFY( p.load().get() == a.get() );
+
+ {
+ ptr_t aa{ a };
+ VERIFY( p.compare_exchange_strong(aa, b,
+ std::memory_order_seq_cst,
+ std::memory_order_seq_cst) == true );
+ ptr_t bb{ a };
+ VERIFY( p.compare_exchange_strong(bb, b,
+ std::memory_order_seq_cst,
+ std::memory_order_seq_cst) == false );
+ VERIFY( bb.get() == b.get() );
+ }
+
+ {
+ ptr_t bb{ b };
+ VERIFY( p.compare_exchange_weak(bb, a,
+ std::memory_order_seq_cst,
+ std::memory_order_seq_cst) == true );
+ ptr_t aa{ b };
+ VERIFY( p.compare_exchange_weak(aa, a,
+ std::memory_order_seq_cst,
+ std::memory_order_seq_cst) == false );
+ VERIFY( aa.get() == a.get() );
+ }
+ test_wait_notify(p, a, b);
+}
+
+void
+test_atomic_weak_ptr()
+{
+ test_is_lock_free>();
+ auto a = std::make_shared( 0, 42 );
+ using ptr_t = std::weak_ptr;
+ ptr_t wa{ a };
+ {
+ std::atomic p{ };
+ VERIFY( p.load().lock().get() == nullptr );
+ }
+
+ std::atomic p{ wa };
+ VERIFY( p.load().lock().get() == a.get() );
+
+ auto b = std::make_shared( 42, 0 );
+ ptr_t wb{ b };
+ p.store(wb);
+ VERIFY( p.load().lock().get() != a.get() );
+ VERIFY( p.load().lock().get() == b.get() );
+ p.exchange(wa);
+ VERIFY( p.load().lock().get() != b.get() );
+ VERIFY( p.load().lock().get() == a.get() );
+
+ {
+ ptr_t aa{ a };
+ VERIFY( p.compare_exchange_strong(aa, b,
+ std::memory_order_seq_cst,
+ std::memory_order_seq_cst) == true );
+ ptr_t bb{ a };
+ VERIFY( p.compare_exchange_strong(bb, b,
+ std::memory_order_seq_cst,
+ std::memory_order_seq_cst) == false );
+ VERIFY( bb.lock().get() == b.get() );
+ }
+
+ {
+ ptr_t bb{ b };
+ VERIFY( p.compare_exchange_weak(bb, a,
+ std::memory_order_seq_cst,
+ std::memory_order_seq_cst) == true );
+ ptr_t aa{ b };
+ VERIFY( p.compare_exchange_weak(aa, a,
+ std::memory_order_seq_cst,
+ std::memory_order_seq_cst) == false );
+ VERIFY( aa.lock().get() == a.get() );
+ }
+ test_wait_notify(p, wa, wb);
+}
+
+int
+main()
+{
+ test_atomic_shared_ptr();
+ test_atomic_weak_ptr();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc
index 3af5dc593c2..1ca7da4fcd0 100644
--- a/libstdc++-v3/testsuite/util/testsuite_abi.cc
+++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc
@@ -210,6 +210,7 @@ check_version(symbol& test, bool added)
known_versions.push_back("GLIBCXX_3.4.27");
known_versions.push_back("GLIBCXX_3.4.28");
known_versions.push_back("GLIBCXX_3.4.29");
+ known_versions.push_back("GLIBCXX_3.4.30");
known_versions.push_back("GLIBCXX_LDBL_3.4.29");
known_versions.push_back("GLIBCXX_IEEE128_3.4.29");
known_versions.push_back("CXXABI_1.3");
@@ -245,7 +246,7 @@ check_version(symbol& test, bool added)
test.version_status = symbol::incompatible;
// Check that added symbols are added in the latest pre-release version.
- bool latestp = (test.version_name == "GLIBCXX_3.4.29"
+ bool latestp = (test.version_name == "GLIBCXX_3.4.30"
// XXX remove next 3 lines when baselines have been regenerated
// to include {IEEE128,LDBL} symbols:
|| test.version_name == "GLIBCXX_LDBL_3.4.29"