I want to give full disclosure on AI usage for transparency.

- implementation of hazard pointer: Used AI as a reviewer and debug helper.
- test code: Heavily relied on AI for initial test code generation.
- libstdc++ infrastructure: Used AI to help understanding code infrastructure
- mailinglist: Used AI to write summaries of my patches for the
mailinglist as I did not have any experience with this channel before.
Looking back they seem to verbose and extensive (compared to other
mails).


On Mon, Jun 8, 2026 at 10:41 PM Paul Xi Cao <[email protected]> wrote:
>
> Cover the full C++26 std::hazard_pointer API surface with DejaGnu
> tests under 30_threads/hazard_pointer/.
>
> Functional tests (one file per API / concern):
>     * make_hazard_pointer.cc -- factory, slot accounting, pool growth.
>     * ctor.cc -- default ctor, move ctor, destructor, slot accounting.
>     * empty.cc -- empty() across every state transition.
>     * move_assign.cc -- transfers ownership, releases prior slot, self-
>       assignment is a no-op.
>     * swap.cc -- member swap, free swap, protection follows the slot.
>     * protect.cc -- returns current value, null source, slot ownership,
>       re-protect updates the slot.
>     * try_protect.cc -- success / failure return, ptr output, agreement
>       with protect() on a stable pointer.
>     * reset_protection.cc -- both overloads, idempotence, typed-pointer
>       overload publishes a hazard directly.
>     * retire.cc -- single retire, multiple retires, threshold auto-
>       synchronize fires when retired count exceeds 2 * active slots.
>     * custom_deleter.cc -- functor deleter invoked, default-constructed
>       deleter, deleter suppressed while protected.
>
>   Compile-time property tests:
>     * noexcept.cc -- static_asserts for every noexcept-annotated API.
>     * type_constraints.cc -- _Protectable concept for derived / non-
>       derived types, retire() deleter constraints.
>
>   Multi-threaded tests:
>     * concurrent.cc -- readers + writer, multi-writer multi-reader,
>       high-contention; run under TSan to verify no data races and no
>       use-after-free.
>     * thread_exit.cc -- ~_RetireListNode drains the retire list on
>       thread exit; protected survivors offload to the orphan list.
>
>   Negative compile tests (dg-error + dg-prune-output for cascade
>   diagnostics past the static_assert / -Werror=unused-result):
>     * protect_neg.cc -- protect<int>() and protect<NonHazard>()
>       rejected by the _Protectable concept.
>     * retire_neg.cc -- retire() rejected when hazard_pointer_obj_base
>       is a private base.
>     * retire_virtual_neg.cc -- retire() rejected when
>       hazard_pointer_obj_base is a virtual base; gated on
>       __cpp_lib_is_virtual_base_of.
>     * nodiscard_neg.cc -- discarding the return of
>       make_hazard_pointer(), empty(), protect(), or try_protect()
>       trips -Werror=unused-result.
>
> All tests pass at -std=gnu++26 on x86_64-pc-linux-gnu.
>
> libstdc++-v3/ChangeLog:
>
>         * testsuite/30_threads/hazard_pointer/concurrent.cc: New test.
>         * testsuite/30_threads/hazard_pointer/ctor.cc: New test.
>         * testsuite/30_threads/hazard_pointer/custom_deleter.cc: New test.
>         * testsuite/30_threads/hazard_pointer/empty.cc: New test.
>         * testsuite/30_threads/hazard_pointer/make_hazard_pointer.cc: New 
> test.
>         * testsuite/30_threads/hazard_pointer/move_assign.cc: New test.
>         * testsuite/30_threads/hazard_pointer/nodiscard_neg.cc: New test.
>         * testsuite/30_threads/hazard_pointer/noexcept.cc: New test.
>         * testsuite/30_threads/hazard_pointer/protect.cc: New test.
>         * testsuite/30_threads/hazard_pointer/protect_neg.cc: New test.
>         * testsuite/30_threads/hazard_pointer/reset_protection.cc: New test.
>         * testsuite/30_threads/hazard_pointer/retire.cc: New test.
>         * testsuite/30_threads/hazard_pointer/retire_neg.cc: New test.
>         * testsuite/30_threads/hazard_pointer/retire_virtual_neg.cc: New test.
>         * testsuite/30_threads/hazard_pointer/swap.cc: New test.
>         * testsuite/30_threads/hazard_pointer/thread_exit.cc: New test.
>         * testsuite/30_threads/hazard_pointer/try_protect.cc: New test.
>         * testsuite/30_threads/hazard_pointer/type_constraints.cc: New test.
> ---
>  .../30_threads/hazard_pointer/concurrent.cc   | 226 ++++++++++++++++++
>  .../30_threads/hazard_pointer/ctor.cc         | 102 ++++++++
>  .../hazard_pointer/custom_deleter.cc          | 126 ++++++++++
>  .../30_threads/hazard_pointer/empty.cc        | 105 ++++++++
>  .../hazard_pointer/make_hazard_pointer.cc     |  84 +++++++
>  .../30_threads/hazard_pointer/move_assign.cc  |  91 +++++++
>  .../hazard_pointer/nodiscard_neg.cc           |  58 +++++
>  .../30_threads/hazard_pointer/noexcept.cc     |  56 +++++
>  .../30_threads/hazard_pointer/protect.cc      |  96 ++++++++
>  .../30_threads/hazard_pointer/protect_neg.cc  |  43 ++++
>  .../hazard_pointer/reset_protection.cc        | 116 +++++++++
>  .../30_threads/hazard_pointer/retire.cc       | 119 +++++++++
>  .../30_threads/hazard_pointer/retire_neg.cc   |  39 +++
>  .../hazard_pointer/retire_virtual_neg.cc      |  40 ++++
>  .../30_threads/hazard_pointer/swap.cc         | 133 +++++++++++
>  .../30_threads/hazard_pointer/thread_exit.cc  |  98 ++++++++
>  .../30_threads/hazard_pointer/try_protect.cc  | 132 ++++++++++
>  .../hazard_pointer/type_constraints.cc        |  56 +++++
>  18 files changed, 1720 insertions(+)
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/concurrent.cc
>  create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/ctor.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/custom_deleter.cc
>  create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/empty.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/make_hazard_pointer.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/move_assign.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/nodiscard_neg.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/noexcept.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/protect.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/protect_neg.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/reset_protection.cc
>  create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/retire.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_neg.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_virtual_neg.cc
>  create mode 100644 libstdc++-v3/testsuite/30_threads/hazard_pointer/swap.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/thread_exit.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/try_protect.cc
>  create mode 100644 
> libstdc++-v3/testsuite/30_threads/hazard_pointer/type_constraints.cc
>
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/concurrent.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/concurrent.cc
> new file mode 100644
> index 00000000000..097866eea7e
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/concurrent.cc
> @@ -0,0 +1,226 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <chrono>
> +#include <functional>
> +#include <thread>
> +#include <vector>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +namespace
> +{
> +  struct Node : std::hazard_pointer_obj_base<Node>
> +  {
> +    int value;
> +    explicit Node(int v) : value(v) {}
> +  };
> +
> +  void reader_fn(std::atomic<Node*>& shared, std::atomic<bool>& stop,
> +                 std::atomic<int>& errors)
> +  {
> +    auto hp = std::make_hazard_pointer();
> +    while (!stop.load(std::memory_order_acquire))
> +    {
> +      const Node* const p = hp.protect(shared);
> +      if (p && p->value < 0)
> +        errors.fetch_add(1, std::memory_order_relaxed);
> +      hp.reset_protection();
> +    }
> +  }
> +
> +  void writer_fn(std::atomic<Node*>& shared, std::atomic<bool>& stop)
> +  {
> +    int counter = 0;
> +    while (!stop.load(std::memory_order_acquire))
> +    {
> +      Node* next = new Node(++counter);
> +      Node* const old = shared.exchange(next, std::memory_order_seq_cst);
> +      if (old)
> +        old->retire();
> +    }
> +    Node* final_ = shared.exchange(nullptr, std::memory_order_seq_cst);
> +    if (final_)
> +      final_->retire();
> +  }
> +}
> +
> +// Readers and one writer: no data race, no error from reading freed memory.
> +void test01()
> +{
> +  std::atomic<Node*> shared{new Node(1)};
> +  std::atomic<bool> stop{false};
> +  std::atomic<int> errors{0};
> +
> +  constexpr int kReaders = 4;
> +  std::vector<std::thread> threads;
> +  threads.reserve(kReaders + 1);
> +
> +  for (int i = 0; i < kReaders; ++i)
> +    threads.emplace_back(reader_fn, std::ref(shared), std::ref(stop),
> +                         std::ref(errors));
> +  threads.emplace_back(writer_fn, std::ref(shared), std::ref(stop));
> +
> +  std::this_thread::sleep_for(std::chrono::milliseconds(200));
> +  stop.store(true, std::memory_order_release);
> +  for (auto& t : threads)
> +    t.join();
> +
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( errors.load() == 0 );
> +}
> +
> +// protect() sees the latest value across stores.
> +void test02()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node a{10}, b{20};
> +  std::atomic<Node*> src{&a};
> +
> +  const Node* const p1 = hp.protect(src);
> +  VERIFY( p1 == &a );
> +
> +  src.store(&b, std::memory_order_release);
> +  const Node* const p2 = hp.protect(src);
> +  VERIFY( p2 == &b );
> +}
> +
> +// Multiple writers, multiple readers: no data race.
> +void test03()
> +{
> +  constexpr int kReaders = 4;
> +  constexpr int kWriters = 4;
> +
> +  std::vector<std::atomic<Node*>> srcs(kWriters);
> +  for (auto& s : srcs)
> +    s.store(new Node(1), std::memory_order_relaxed);
> +
> +  std::atomic<bool> stop{false};
> +  std::atomic<int> errors{0};
> +
> +  auto multi_reader = [&] {
> +    std::vector<std::hazard_pointer> hps;
> +    hps.reserve(kWriters);
> +    for (int i = 0; i < kWriters; ++i)
> +      hps.emplace_back(std::make_hazard_pointer());
> +    while (!stop.load(std::memory_order_acquire))
> +      for (int i = 0; i < kWriters; ++i)
> +      {
> +        const Node* const p = hps[i].protect(srcs[i]);
> +        if (p && p->value < 0)
> +          errors.fetch_add(1, std::memory_order_relaxed);
> +        hps[i].reset_protection();
> +      }
> +  };
> +
> +  auto single_writer = [&](int idx) {
> +    int counter = 1;
> +    while (!stop.load(std::memory_order_acquire))
> +    {
> +      Node* next = new Node(++counter);
> +      Node* old = srcs[idx].exchange(next, std::memory_order_seq_cst);
> +      if (old)
> +        old->retire();
> +    }
> +    Node* final_ = srcs[idx].exchange(nullptr, std::memory_order_seq_cst);
> +    if (final_)
> +      final_->retire();
> +  };
> +
> +  std::vector<std::thread> threads;
> +  threads.reserve(kReaders + kWriters);
> +  for (int i = 0; i < kReaders; ++i)
> +    threads.emplace_back(multi_reader);
> +  for (int i = 0; i < kWriters; ++i)
> +    threads.emplace_back(single_writer, i);
> +
> +  std::this_thread::sleep_for(std::chrono::milliseconds(200));
> +  stop.store(true, std::memory_order_release);
> +  for (auto& t : threads)
> +    t.join();
> +
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( errors.load() == 0 );
> +}
> +
> +// Retire from many threads: all reclaimed by thread-exit drain.
> +void test04()
> +{
> +  constexpr int kThreads = 8;
> +  constexpr int kObjectsPerThread = 10;
> +  std::atomic<int> total_deleted{0};
> +
> +  struct CountedNode : std::hazard_pointer_obj_base<CountedNode>
> +  {
> +    std::atomic<int>& counter;
> +    explicit CountedNode(std::atomic<int>& c) : counter(c) {}
> +    ~CountedNode() { counter.fetch_add(1, std::memory_order_relaxed); }
> +  };
> +
> +  std::vector<std::thread> threads;
> +  threads.reserve(kThreads);
> +  for (int i = 0; i < kThreads; ++i)
> +    threads.emplace_back([&] {
> +      for (int j = 0; j < kObjectsPerThread; ++j)
> +        (new CountedNode(total_deleted))->retire();
> +    });
> +  for (auto& t : threads)
> +    t.join();
> +
> +  VERIFY( total_deleted.load() == kThreads * kObjectsPerThread );
> +}
> +
> +// High contention: readers + writer over longer duration.
> +void test05()
> +{
> +  constexpr int kReaders = 6;
> +  std::atomic<Node*> shared{new Node(42)};
> +  std::atomic<bool> stop{false};
> +  std::atomic<int> errors{0};
> +
> +  std::vector<std::thread> threads;
> +  threads.reserve(kReaders + 1);
> +
> +  for (int i = 0; i < kReaders; ++i)
> +    threads.emplace_back(reader_fn, std::ref(shared), std::ref(stop),
> +                         std::ref(errors));
> +  threads.emplace_back(writer_fn, std::ref(shared), std::ref(stop));
> +
> +  std::this_thread::sleep_for(std::chrono::milliseconds(300));
> +  stop.store(true, std::memory_order_release);
> +  for (auto& t : threads)
> +    t.join();
> +
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( errors.load() == 0 );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +}
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/ctor.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/ctor.cc
> new file mode 100644
> index 00000000000..791b3cdbadc
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/ctor.cc
> @@ -0,0 +1,102 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <utility>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +// Default-constructed handle is empty.
> +void test01()
> +{
> +  const std::hazard_pointer hp;
> +  VERIFY( hp.empty() );
> +}
> +
> +// Default-constructed handle does not increment active slot count.
> +void test02()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  const std::hazard_pointer hp;
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before );
> +}
> +
> +// Move ctor transfers slot ownership: count unchanged.
> +void test03()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto a = std::make_hazard_pointer();
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 1 );
> +  const std::hazard_pointer b = std::move(a);
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 1 );
> +}
> +
> +// Move ctor: source becomes empty.
> +void test04()
> +{
> +  auto a = std::make_hazard_pointer();
> +  const std::hazard_pointer b = std::move(a);
> +  VERIFY( a.empty() );
> +  VERIFY( !b.empty() );
> +}
> +
> +// Destructor releases slot.
> +void test05()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  {
> +    auto hp = std::make_hazard_pointer();
> +    VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 1 );
> +  }
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before );
> +}
> +
> +// Destructor on default-constructed handle is a no-op.
> +void test06()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  {
> +    const std::hazard_pointer hp;
> +  }
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before );
> +}
> +
> +// Multiple hazard_pointers are distinct slots.
> +void test07()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto a = std::make_hazard_pointer();
> +  auto b = std::make_hazard_pointer();
> +  auto c = std::make_hazard_pointer();
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 3 );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +  test06();
> +  test07();
> +}
> diff --git 
> a/libstdc++-v3/testsuite/30_threads/hazard_pointer/custom_deleter.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/custom_deleter.cc
> new file mode 100644
> index 00000000000..36d143945a6
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/custom_deleter.cc
> @@ -0,0 +1,126 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +namespace
> +{
> +  struct LoggingNode;
> +
> +  struct LoggingDeleter
> +  {
> +    int* delete_count = nullptr;
> +    LoggingDeleter() = default;
> +    explicit LoggingDeleter(int* c) : delete_count(c) {}
> +    void operator()(LoggingNode* p) const;
> +  };
> +
> +  struct LoggingNode : std::hazard_pointer_obj_base<LoggingNode, 
> LoggingDeleter> {};
> +
> +  inline void LoggingDeleter::operator()(LoggingNode* p) const
> +  {
> +    if (delete_count)
> +      ++(*delete_count);
> +    delete p;
> +  }
> +
> +  struct TrackedNode : std::hazard_pointer_obj_base<TrackedNode>
> +  {
> +    explicit TrackedNode(int& c) : counter(c) {}
> +    ~TrackedNode() { ++counter; }
> +    int& counter;
> +  };
> +}
> +
> +// Default deleter calls delete.
> +void test01()
> +{
> +  int dtor_count = 0;
> +  auto* node = new TrackedNode(dtor_count);
> +  node->retire();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 1 );
> +}
> +
> +// Functor deleter is invoked.
> +void test02()
> +{
> +  int delete_count = 0;
> +  auto* node = new LoggingNode();
> +  node->retire(LoggingDeleter{&delete_count});
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( delete_count == 1 );
> +}
> +
> +// Functor deleter not called while protected.
> +void test03()
> +{
> +  int delete_count = 0;
> +  auto* node = new LoggingNode();
> +  const std::atomic<LoggingNode*> src{node};
> +
> +  auto hp = std::make_hazard_pointer();
> +  (void)hp.protect(src);
> +  node->retire(LoggingDeleter{&delete_count});
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( delete_count == 0 );
> +
> +  hp.reset_protection();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( delete_count == 1 );
> +}
> +
> +// retire() with no arg uses default-constructed D.
> +void test04()
> +{
> +  int dtor_count = 0;
> +  auto* node = new TrackedNode(dtor_count);
> +  node->retire();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 1 );
> +}
> +
> +// Multiple nodes with custom deleter all invoked.
> +void test05()
> +{
> +  constexpr int kCount = 5;
> +  int delete_count = 0;
> +  for (int i = 0; i < kCount; ++i)
> +  {
> +    auto* node = new LoggingNode();
> +    node->retire(LoggingDeleter{&delete_count});
> +  }
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( delete_count == kCount );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +}
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/empty.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/empty.cc
> new file mode 100644
> index 00000000000..afd53c8bd8a
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/empty.cc
> @@ -0,0 +1,105 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <utility>
> +#include <testsuite_hooks.h>
> +
> +namespace
> +{
> +  struct Node : std::hazard_pointer_obj_base<Node> {};
> +}
> +
> +void test01()
> +{
> +  const std::hazard_pointer hp;
> +  VERIFY( hp.empty() );
> +}
> +
> +void test02()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  VERIFY( !hp.empty() );
> +}
> +
> +// After move ctor: source empty, dest non-empty.
> +void test03()
> +{
> +  auto a = std::make_hazard_pointer();
> +  const std::hazard_pointer b = std::move(a);
> +  VERIFY( a.empty() );
> +  VERIFY( !b.empty() );
> +}
> +
> +// After move-assign: source empty.
> +void test04()
> +{
> +  auto a = std::make_hazard_pointer();
> +  std::hazard_pointer b;
> +  b = std::move(a);
> +  VERIFY( a.empty() );
> +  VERIFY( !b.empty() );
> +}
> +
> +// After protect(): still owns slot.
> +void test05()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +  (void)hp.protect(src);
> +  VERIFY( !hp.empty() );
> +}
> +
> +// After reset_protection(): hazard cleared, slot kept.
> +void test06()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +  (void)hp.protect(src);
> +  hp.reset_protection();
> +  VERIFY( !hp.empty() );
> +}
> +
> +// After swap: ownership exchanged.
> +void test07()
> +{
> +  auto a = std::make_hazard_pointer();
> +  std::hazard_pointer b;
> +  VERIFY( !a.empty() );
> +  VERIFY( b.empty() );
> +  a.swap(b);
> +  VERIFY( a.empty() );
> +  VERIFY( !b.empty() );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +  test06();
> +  test07();
> +}
> diff --git 
> a/libstdc++-v3/testsuite/30_threads/hazard_pointer/make_hazard_pointer.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/make_hazard_pointer.cc
> new file mode 100644
> index 00000000000..a726480dc63
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/make_hazard_pointer.cc
> @@ -0,0 +1,84 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <cstddef>
> +#include <vector>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +// Returns non-empty handle.
> +void test01()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  VERIFY( !hp.empty() );
> +}
> +
> +// Increments active slot count by 1.
> +void test02()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto hp = std::make_hazard_pointer();
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 1 );
> +}
> +
> +// Multiple calls return distinct slots.
> +void test03()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto a = std::make_hazard_pointer();
> +  auto b = std::make_hazard_pointer();
> +  auto c = std::make_hazard_pointer();
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 3 );
> +}
> +
> +// Slot reused after handle destruction.
> +void test04()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  {
> +    auto hp = std::make_hazard_pointer();
> +  }
> +  auto hp2 = std::make_hazard_pointer();
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 1 );
> +}
> +
> +// Pool grows beyond initial capacity (_S_initial_slots == 8).
> +void test05()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  constexpr std::size_t kExtra = 8 + 4;
> +  std::vector<std::hazard_pointer> hps;
> +  hps.reserve(kExtra);
> +  for (std::size_t i = 0; i < kExtra; ++i)
> +    hps.emplace_back(std::make_hazard_pointer());
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + kExtra );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +}
> \ No newline at end of file
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/move_assign.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/move_assign.cc
> new file mode 100644
> index 00000000000..7f4e40c1cda
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/move_assign.cc
> @@ -0,0 +1,91 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <utility>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +// Transfers slot ownership.
> +void test01()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto a = std::make_hazard_pointer();
> +  std::hazard_pointer b;
> +  VERIFY( !a.empty() );
> +  VERIFY( b.empty() );
> +  b = std::move(a);
> +  VERIFY( a.empty() );
> +  VERIFY( !b.empty() );
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 1 );
> +}
> +
> +// Source becomes empty after move-assign.
> +void test02()
> +{
> +  auto a = std::make_hazard_pointer();
> +  std::hazard_pointer b;
> +  b = std::move(a);
> +  VERIFY( a.empty() );
> +}
> +
> +// Destination releases prior slot.
> +void test03()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto a = std::make_hazard_pointer();
> +  auto b = std::make_hazard_pointer();
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 2 );
> +  b = std::move(a);
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 1 );
> +}
> +
> +// Self-assignment is a no-op.
> +void test04()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto& alias = hp;
> +  hp = std::move(alias);
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before );
> +  VERIFY( !hp.empty() );
> +}
> +
> +// Move-assign empty to empty: both stay empty, no slot change.
> +void test05()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  std::hazard_pointer a;
> +  std::hazard_pointer b;
> +  b = std::move(a);
> +  VERIFY( b.empty() );
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +}
> diff --git 
> a/libstdc++-v3/testsuite/30_threads/hazard_pointer/nodiscard_neg.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/nodiscard_neg.cc
> new file mode 100644
> index 00000000000..eb725da6790
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/nodiscard_neg.cc
> @@ -0,0 +1,58 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-pthread -Werror=unused-result" { target pthread 
> } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +// Negative tests: each [[nodiscard]] return discard must trip
> +// -Werror=unused-result.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +
> +struct Node : std::hazard_pointer_obj_base<Node> {};
> +
> +void test_make_hazard_pointer()
> +{
> +  std::make_hazard_pointer(); // { dg-error "ignoring return value" }
> +}
> +
> +void test_empty()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  hp.empty(); // { dg-error "ignoring return value" }
> +}
> +
> +void test_protect()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  std::atomic<Node*> src{&x};
> +  hp.protect(src); // { dg-error "ignoring return value" }
> +}
> +
> +void test_try_protect()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  std::atomic<Node*> src{&x};
> +  Node* ptr = &x;
> +  hp.try_protect(ptr, src); // { dg-error "ignoring return value" }
> +}
> +
> +// { dg-prune-output "some warnings being treated as errors" }
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/noexcept.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/noexcept.cc
> new file mode 100644
> index 00000000000..cc19bc309cd
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/noexcept.cc
> @@ -0,0 +1,56 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <type_traits>
> +#include <utility>
> +
> +namespace
> +{
> +  struct Node : std::hazard_pointer_obj_base<Node> {};
> +  using HP = std::hazard_pointer;
> +
> +  static_assert(std::is_nothrow_default_constructible_v<HP>);
> +  static_assert(std::is_nothrow_move_constructible_v<HP>);
> +  static_assert(std::is_nothrow_move_assignable_v<HP>);
> +
> +  static_assert(noexcept(std::declval<const HP&>().empty()));
> +
> +  static_assert(noexcept(std::declval<HP&>().protect(
> +      std::declval<std::atomic<Node*>&>())));
> +
> +  static_assert(noexcept(std::declval<HP&>().try_protect(
> +      std::declval<Node*&>(),
> +      std::declval<const std::atomic<Node*>&>())));
> +
> +  static_assert(noexcept(std::declval<HP&>().reset_protection()));
> +  static_assert(noexcept(std::declval<HP&>().reset_protection(nullptr)));
> +
> +  static_assert(noexcept(std::declval<HP&>().reset_protection(
> +      std::declval<const Node*>())));
> +
> +  static_assert(noexcept(std::declval<HP&>().swap(std::declval<HP&>())));
> +
> +  static_assert(noexcept(std::swap(std::declval<HP&>(), 
> std::declval<HP&>())));
> +
> +  static_assert(noexcept(std::declval<Node&>().retire()));
> +}
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/protect.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/protect.cc
> new file mode 100644
> index 00000000000..19f38292263
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/protect.cc
> @@ -0,0 +1,96 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <testsuite_hooks.h>
> +
> +namespace
> +{
> +  struct Node : std::hazard_pointer_obj_base<Node>
> +  {
> +    int value = 0;
> +  };
> +}
> +
> +// Returns current value of the atomic.
> +void test01()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  x.value = 42;
> +  const std::atomic<Node*> src{&x};
> +  const Node* const p = hp.protect(src);
> +  VERIFY( p == &x );
> +  VERIFY( p->value == 42 );
> +}
> +
> +// Returns nullptr for null atomic.
> +void test02()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  const std::atomic<Node*> src{nullptr};
> +  VERIFY( hp.protect(src) == nullptr );
> +}
> +
> +// Slot not empty after protect.
> +void test03()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +  (void)hp.protect(src);
> +  VERIFY( !hp.empty() );
> +}
> +
> +// protect() matches atomic load.
> +void test04()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node vals[3];
> +  vals[0].value = 1;
> +  vals[1].value = 2;
> +  vals[2].value = 3;
> +  const std::atomic<Node*> src{&vals[0]};
> +  const Node* const p = hp.protect(src);
> +  VERIFY( p == src.load() );
> +}
> +
> +// Re-protect on the same handle updates the slot.
> +void test05()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node a, b;
> +  std::atomic<Node*> src{&a};
> +  (void)hp.protect(src);
> +  src.store(&b, std::memory_order_relaxed);
> +  const Node* const p = hp.protect(src);
> +  VERIFY( p == &b );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +}
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/protect_neg.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/protect_neg.cc
> new file mode 100644
> index 00000000000..07cd3f66d6b
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/protect_neg.cc
> @@ -0,0 +1,43 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +// Negative tests: protect<T>() must be rejected when T is not _Protectable.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +
> +struct Plain {};
> +
> +void test_int()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  std::atomic<int*> src{nullptr};
> +  (void)hp.protect(src); // int is not _Protectable
> +}
> +
> +void test_nonhazard_class()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  std::atomic<Plain*> src{nullptr};
> +  (void)hp.protect(src); // Plain has no _Obj_base_tag base
> +}
> +
> +// { dg-error "hazard-protectable type" "" { target *-*-* } 0 }
> diff --git 
> a/libstdc++-v3/testsuite/30_threads/hazard_pointer/reset_protection.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/reset_protection.cc
> new file mode 100644
> index 00000000000..5dddef71611
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/reset_protection.cc
> @@ -0,0 +1,116 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +namespace
> +{
> +  struct Node : std::hazard_pointer_obj_base<Node> {};
> +
> +  struct Tracked : std::hazard_pointer_obj_base<Tracked>
> +  {
> +    explicit Tracked(int& c) : counter(c) {}
> +    ~Tracked() { ++counter; }
> +    int& counter;
> +  };
> +}
> +
> +// reset_protection clears hazard, slot still owned.
> +void test01()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +  (void)hp.protect(src);
> +  hp.reset_protection();
> +  VERIFY( !hp.empty() );
> +}
> +
> +// nullptr overload clears hazard.
> +void test02()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +  (void)hp.protect(src);
> +  hp.reset_protection(nullptr);
> +  VERIFY( !hp.empty() );
> +}
> +
> +// After reset, object can be reclaimed.
> +void test03()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  int dtor_count = 0;
> +  auto* obj = new Tracked(dtor_count);
> +  const std::atomic<Tracked*> src{obj};
> +  (void)hp.protect(src);
> +
> +  obj->retire();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 0 );
> +
> +  hp.reset_protection();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 1 );
> +}
> +
> +// Typed-pointer overload publishes a hazard.
> +void test04()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  int dtor = 0;
> +  auto* obj = new Tracked(dtor);
> +  hp.reset_protection(obj);
> +
> +  obj->retire();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor == 0 );
> +
> +  hp.reset_protection();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor == 1 );
> +}
> +
> +// Double reset is safe (idempotent).
> +void test05()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +  (void)hp.protect(src);
> +  hp.reset_protection();
> +  hp.reset_protection();
> +  VERIFY( !hp.empty() );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +}
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire.cc
> new file mode 100644
> index 00000000000..afcc97f2ca2
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire.cc
> @@ -0,0 +1,119 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +namespace
> +{
> +  struct Tracked : std::hazard_pointer_obj_base<Tracked>
> +  {
> +    explicit Tracked(int& counter) : counter_(counter) {}
> +    ~Tracked() { ++counter_; }
> +    int& counter_;
> +  };
> +}
> +
> +// Retired object deleted after synchronize.
> +void test01()
> +{
> +  // Hold one active slot so the auto-sync threshold (2 * active_count) >= 2,
> +  // ensuring the single retire below does NOT auto-sync.
> +  auto hp = std::make_hazard_pointer();
> +  int dtor_count = 0;
> +  (new Tracked(dtor_count))->retire();
> +  VERIFY( dtor_count == 0 );
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 1 );
> +}
> +
> +// Multiple retired objects all deleted on synchronize.
> +void test02()
> +{
> +  int dtor_count = 0;
> +  for (int i = 0; i < 5; ++i)
> +    (new Tracked(dtor_count))->retire();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 5 );
> +}
> +
> +// Protected object survives synchronize.
> +void test03()
> +{
> +  int dtor_count = 0;
> +  auto* obj = new Tracked(dtor_count);
> +  const std::atomic<Tracked*> src{obj};
> +
> +  auto hp = std::make_hazard_pointer();
> +  const Tracked* const protected_obj = hp.protect(src);
> +  VERIFY( protected_obj == obj );
> +
> +  obj->retire();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 0 );
> +
> +  hp.reset_protection();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 1 );
> +}
> +
> +// Retire list grows before synchronize.
> +void test04()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  const auto before = hpd::_S_default_domain()._M_retire_list_size();
> +  int dtor_count = 0;
> +  (new Tracked(dtor_count))->retire();
> +  (new Tracked(dtor_count))->retire();
> +  VERIFY( hpd::_S_default_domain()._M_retire_list_size() == before + 2 );
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( hpd::_S_default_domain()._M_retire_list_size() == 0u );
> +  VERIFY( dtor_count == 2 );
> +}
> +
> +// Threshold auto-triggers synchronize: 1 active slot -> threshold 2 -> 3 
> retires trip it.
> +void test05()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  int dummy = 0;
> +  Tracked x{dummy};
> +  const std::atomic<Tracked*> src{&x};
> +  const Tracked* const protected_x = hp.protect(src);
> +  VERIFY( protected_x == &x );
> +
> +  int dtor_count = 0;
> +  for (int i = 0; i < 3; ++i)
> +    (new Tracked(dtor_count))->retire();
> +
> +  VERIFY( dtor_count > 0 );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +}
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_neg.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_neg.cc
> new file mode 100644
> index 00000000000..9b1c952f3af
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_neg.cc
> @@ -0,0 +1,39 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +// Negative test: retire() must be rejected when hazard_pointer_obj_base
> +// is a private base of T (is_convertible_v<T*, base*> fails).
> +
> +#include <hazard_pointer>
> +
> +struct Node : private std::hazard_pointer_obj_base<Node>
> +{
> +  using hazard_pointer_obj_base::retire;
> +};
> +
> +void test()
> +{
> +  auto* p = new Node();
> +  p->retire();
> +}
> +
> +// { dg-error "must be a public base of T" "" { target *-*-* } 0 }
> +// { dg-prune-output "inaccessible base of" }
> diff --git 
> a/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_virtual_neg.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_virtual_neg.cc
> new file mode 100644
> index 00000000000..7275a7b3f10
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/retire_virtual_neg.cc
> @@ -0,0 +1,40 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +// Negative test: retire() must be rejected when hazard_pointer_obj_base
> +// is a virtual base of T.  Requires C++26 std::is_virtual_base_of.
> +
> +#include <hazard_pointer>
> +
> +#ifndef __cpp_lib_is_virtual_base_of
> +# error "Requires __cpp_lib_is_virtual_base_of for this negative check"
> +#endif
> +
> +struct Node : virtual std::hazard_pointer_obj_base<Node> {};
> +
> +void test()
> +{
> +  auto* p = new Node();
> +  p->retire();
> +}
> +
> +// { dg-error "must be a non-virtual base" "" { target *-*-* } 0 }
> +// { dg-prune-output "cannot convert from pointer to base class" }
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/swap.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/swap.cc
> new file mode 100644
> index 00000000000..2d516d0bfc7
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/swap.cc
> @@ -0,0 +1,133 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +namespace
> +{
> +  struct Tracked : std::hazard_pointer_obj_base<Tracked>
> +  {
> +    explicit Tracked(int& c) : counter(c) {}
> +    ~Tracked() { ++counter; }
> +    int& counter;
> +  };
> +}
> +
> +// Member swap exchanges non-empty and empty.
> +void test01()
> +{
> +  auto a = std::make_hazard_pointer();
> +  std::hazard_pointer b;
> +  VERIFY( !a.empty() );
> +  VERIFY( b.empty() );
> +  a.swap(b);
> +  VERIFY( a.empty() );
> +  VERIFY( !b.empty() );
> +}
> +
> +// Member swap both non-empty: slot count unchanged.
> +void test02()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto a = std::make_hazard_pointer();
> +  auto b = std::make_hazard_pointer();
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 2 );
> +  a.swap(b);
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 2 );
> +}
> +
> +// After swap, the protecting slot moves to the other handle.
> +void test03()
> +{
> +  auto hp1 = std::make_hazard_pointer();
> +  auto hp2 = std::make_hazard_pointer();
> +
> +  int dtor = 0;
> +  auto* obj = new Tracked(dtor);
> +  const std::atomic<Tracked*> src{obj};
> +  (void)hp1.protect(src);
> +
> +  hp1.swap(hp2);
> +
> +  obj->retire();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor == 0 );
> +
> +  hp2.reset_protection();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor == 1 );
> +}
> +
> +// Free swap exchanges slots.
> +void test04()
> +{
> +  auto a = std::make_hazard_pointer();
> +  std::hazard_pointer b;
> +  VERIFY( !a.empty() );
> +  VERIFY( b.empty() );
> +  std::swap(a, b);
> +  VERIFY( a.empty() );
> +  VERIFY( !b.empty() );
> +}
> +
> +// Free swap both non-empty: count unchanged.
> +void test05()
> +{
> +  const auto before = hpd::_S_default_domain()._M_active_slots();
> +  auto a = std::make_hazard_pointer();
> +  auto b = std::make_hazard_pointer();
> +  std::swap(a, b);
> +  VERIFY( hpd::_S_default_domain()._M_active_slots() == before + 2 );
> +}
> +
> +// Member self-swap is a no-op.
> +void test06()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  VERIFY( !hp.empty() );
> +  hp.swap(hp);
> +  VERIFY( !hp.empty() );
> +}
> +
> +// Free swap both empty: remains empty.
> +void test07()
> +{
> +  std::hazard_pointer a;
> +  std::hazard_pointer b;
> +  std::swap(a, b);
> +  VERIFY( a.empty() );
> +  VERIFY( b.empty() );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +  test06();
> +  test07();
> +}
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/thread_exit.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/thread_exit.cc
> new file mode 100644
> index 00000000000..cabf95eaeef
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/thread_exit.cc
> @@ -0,0 +1,98 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <thread>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +namespace
> +{
> +  struct Tracked : std::hazard_pointer_obj_base<Tracked>
> +  {
> +    explicit Tracked(int& c) : counter(c) {}
> +    ~Tracked() { ++counter; }
> +    int& counter;
> +  };
> +}
> +
> +// Retired objects in a worker thread reclaimed on thread exit.
> +void test01()
> +{
> +  int dtor_count = 0;
> +  std::thread t([&] {
> +    for (int i = 0; i < 3; ++i)
> +      (new Tracked(dtor_count))->retire();
> +  });
> +  t.join();
> +  VERIFY( dtor_count == 3 );
> +}
> +
> +// Protected survivors offloaded to orphan list, reclaimed by later 
> synchronize.
> +void test02()
> +{
> +  int dtor_count = 0;
> +  auto* obj = new Tracked(dtor_count);
> +  const std::atomic<Tracked*> src{obj};
> +
> +  auto hp = std::make_hazard_pointer();
> +  (void)hp.protect(src);
> +
> +  std::thread t([&] {
> +    obj->retire();
> +  });
> +  t.join();
> +
> +  VERIFY( dtor_count == 0 );
> +
> +  hp.reset_protection();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 1 );
> +}
> +
> +// Many threads each drain own retire list on exit.
> +void test03()
> +{
> +  constexpr int kThreads = 4;
> +  constexpr int kObjectsPerThread = 5;
> +  int dtor_counts[kThreads] = {};
> +
> +  std::thread threads[kThreads];
> +  for (int i = 0; i < kThreads; ++i)
> +    threads[i] = std::thread([&dtor_counts, i] {
> +      for (int j = 0; j < kObjectsPerThread; ++j)
> +        (new Tracked(dtor_counts[i]))->retire();
> +    });
> +  for (auto& t : threads)
> +    t.join();
> +
> +  for (int i = 0; i < kThreads; ++i)
> +    VERIFY( dtor_counts[i] == kObjectsPerThread );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +}
> diff --git a/libstdc++-v3/testsuite/30_threads/hazard_pointer/try_protect.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/try_protect.cc
> new file mode 100644
> index 00000000000..4af3192a2ad
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/try_protect.cc
> @@ -0,0 +1,132 @@
> +// { dg-do run { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <atomic>
> +#include <testsuite_hooks.h>
> +
> +namespace hpd = std::__hazard_pointer;
> +
> +namespace
> +{
> +  struct Node : std::hazard_pointer_obj_base<Node>
> +  {
> +    int value = 0;
> +  };
> +
> +  struct Tracked : std::hazard_pointer_obj_base<Tracked>
> +  {
> +    explicit Tracked(int& c) : counter(c) {}
> +    ~Tracked() { ++counter; }
> +    int& counter;
> +  };
> +}
> +
> +// Returns true when pointer is stable.
> +void test01()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +  Node* ptr = src.load(std::memory_order::relaxed);
> +  VERIFY( hp.try_protect(ptr, src) );
> +}
> +
> +// Sets ptr on success.
> +void test02()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  x.value = 7;
> +  const std::atomic<Node*> src{&x};
> +  Node* ptr = src.load(std::memory_order::relaxed);
> +  const bool ok = hp.try_protect(ptr, src);
> +  VERIFY( ok );
> +  VERIFY( ptr == &x );
> +}
> +
> +// Returns true for null source.
> +void test03()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  const std::atomic<Node*> src{nullptr};
> +  Node* ptr = nullptr;
> +  VERIFY( hp.try_protect(ptr, src) );
> +  VERIFY( ptr == nullptr );
> +}
> +
> +// Slot still owned after success.
> +void test04()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +  Node* ptr = &x;
> +  (void)hp.try_protect(ptr, src);
> +  VERIFY( !hp.empty() );
> +}
> +
> +// Protected object not reclaimed after success.
> +void test05()
> +{
> +  auto hp = std::make_hazard_pointer();
> +  int dtor_count = 0;
> +  auto* obj = new Tracked(dtor_count);
> +  const std::atomic<Tracked*> src{obj};
> +  Tracked* ptr = src.load(std::memory_order::relaxed);
> +  VERIFY( hp.try_protect(ptr, src) );
> +
> +  obj->retire();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 0 );
> +
> +  hp.reset_protection();
> +  hpd::_S_default_domain()._M_synchronize();
> +  VERIFY( dtor_count == 1 );
> +}
> +
> +// try_protect and protect agree on a stable pointer.
> +void test06()
> +{
> +  Node x;
> +  const std::atomic<Node*> src{&x};
> +
> +  auto hp1 = std::make_hazard_pointer();
> +  auto hp2 = std::make_hazard_pointer();
> +
> +  Node* ptr = src.load(std::memory_order::relaxed);
> +  const bool ok = hp1.try_protect(ptr, src);
> +  const Node* const via_protect = hp2.protect(src);
> +
> +  VERIFY( ok );
> +  VERIFY( ptr == via_protect );
> +  VERIFY( ptr == &x );
> +}
> +
> +int main()
> +{
> +  test01();
> +  test02();
> +  test03();
> +  test04();
> +  test05();
> +  test06();
> +}
> diff --git 
> a/libstdc++-v3/testsuite/30_threads/hazard_pointer/type_constraints.cc 
> b/libstdc++-v3/testsuite/30_threads/hazard_pointer/type_constraints.cc
> new file mode 100644
> index 00000000000..60040bc3c71
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/30_threads/hazard_pointer/type_constraints.cc
> @@ -0,0 +1,56 @@
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-pthread" { target pthread } }
> +// { dg-require-gthreads "" }
> +
> +// Copyright (C) 2026 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/>.
> +
> +#include <hazard_pointer>
> +#include <memory>
> +#include <string>
> +#include <type_traits>
> +
> +namespace
> +{
> +  struct SimpleNode : std::hazard_pointer_obj_base<SimpleNode> {};
> +  struct CustomDelNode
> +      : std::hazard_pointer_obj_base<CustomDelNode,
> +                                     std::default_delete<CustomDelNode>> {};
> +
> +  // Indirect derivation must still satisfy _Protectable.
> +  struct FurtherDerived : SimpleNode {};
> +
> +  // Not hazard-protectable.
> +  struct PlainClass {};
> +}
> +
> +// _Protectable concept (libstdc++ internal name for HazardProtectable).
> +static_assert(std::__hazard_pointer::_Protectable<SimpleNode>);
> +static_assert(std::__hazard_pointer::_Protectable<CustomDelNode>);
> +static_assert(std::__hazard_pointer::_Protectable<FurtherDerived>);
> +
> +static_assert(!std::__hazard_pointer::_Protectable<int>);
> +static_assert(!std::__hazard_pointer::_Protectable<void>);
> +static_assert(!std::__hazard_pointer::_Protectable<int*>);
> +
> +static_assert(!std::__hazard_pointer::_Protectable<PlainClass>);
> +static_assert(!std::__hazard_pointer::_Protectable<std::string>);
> +
> +// retire() deleter constraints.
> +static_assert(std::is_invocable_v<std::default_delete<SimpleNode>, 
> SimpleNode*>);
> +static_assert(std::is_default_constructible_v<std::default_delete<SimpleNode>>);
> +static_assert(std::is_move_assignable_v<std::default_delete<SimpleNode>>);
> --
> 2.54.0
>

Reply via email to