Skip to content

[libc++] Add missing noexcept on shared_ptr assignment - #219533

Open
ldionne wants to merge 1 commit into
llvm:mainfrom
ldionne:review/shared-ptr-noexcept
Open

[libc++] Add missing noexcept on shared_ptr assignment#219533
ldionne wants to merge 1 commit into
llvm:mainfrom
ldionne:review/shared-ptr-noexcept

Conversation

@ldionne

@ldionne ldionne commented Aug 28, 2026

Copy link
Copy Markdown
Member

The Standard declares it as noexcept in [util.smartptr.shared.assign]. Also add a couple of missing tests.

The Standard declares it as noexcept in [util.smartptr.shared.assign].
Also add a couple of missing tests.
@ldionne
ldionne requested a review from a team as a code owner August 28, 2026 17:04
@llvmorg-github-actions llvmorg-github-actions Bot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Aug 28, 2026
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

The Standard declares it as noexcept in [util.smartptr.shared.assign]. Also add a couple of missing tests.


Full diff: https://github.com/llvm/llvm-project/pull/219533.diff

6 Files Affected:

  • (modified) libcxx/include/__memory/shared_ptr.h (+1-1)
  • (modified) libcxx/include/memory (+1-1)
  • (modified) libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp (+3-1)
  • (modified) libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp (+3-1)
  • (modified) libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp (+3-1)
  • (modified) libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp (+3-1)
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 7d8a0d27739a0..5386eb29e58a2 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -474,7 +474,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI shared_ptr {
   }
 
   template <class _Yp, __enable_if_t<__compatible_with_v<_Yp, _Tp>, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp>& operator=(shared_ptr<_Yp>&& __r) {
+  _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp>& operator=(shared_ptr<_Yp>&& __r) _NOEXCEPT {
     shared_ptr(std::move(__r)).swap(*this);
     return *this;
   }
diff --git a/libcxx/include/memory b/libcxx/include/memory
index e1e2e801a07ab..f1529a1c0f884 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -613,7 +613,7 @@ public:
     shared_ptr& operator=(const shared_ptr& r) noexcept;
     template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
     shared_ptr& operator=(shared_ptr&& r) noexcept;
-    template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r);
+    template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r) noexcept;
     template<class Y> shared_ptr& operator=(auto_ptr<Y>&& r); // removed in C++17
     template <class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r);
 
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp
index 7bf1501d1bcd2..79126748fac52 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp
@@ -10,7 +10,7 @@
 
 // shared_ptr
 
-// shared_ptr& operator=(const shared_ptr& r);
+// shared_ptr& operator=(const shared_ptr& r) noexcept;
 
 // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
 
@@ -45,6 +45,8 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    static_assert(std::is_nothrow_assignable<std::shared_ptr<A>&, const std::shared_ptr<A>&>::value, "");
+
     {
         const std::shared_ptr<A> pA(new A);
         A* ptrA = pA.get();
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp
index 9b7e43ff65af4..1a09f364cb2aa 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp
@@ -10,7 +10,7 @@
 
 // shared_ptr
 
-// template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r);
+// template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
 
 #include <memory>
 #include <type_traits>
@@ -43,6 +43,8 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    static_assert(std::is_nothrow_assignable<std::shared_ptr<B>&, const std::shared_ptr<A>&>::value, "");
+
     {
         const std::shared_ptr<A> pA(new A);
         A* ptrA = pA.get();
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp
index 2a0a523592487..3cf084f667a93 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp
@@ -12,7 +12,7 @@
 
 // shared_ptr
 
-// template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r);
+// template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r) noexcept;
 
 #include <memory>
 #include <type_traits>
@@ -46,6 +46,8 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    static_assert(std::is_nothrow_assignable<std::shared_ptr<B>&, std::shared_ptr<A>&&>::value, "");
+
     {
         std::shared_ptr<A> pA(new A);
         A* ptrA = pA.get();
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp
index f48fe75447eed..7a952f6138bd5 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp
@@ -12,7 +12,7 @@
 
 // shared_ptr
 
-// shared_ptr& operator=(shared_ptr&& r);
+// shared_ptr& operator=(shared_ptr&& r) noexcept;
 
 #include <memory>
 #include <type_traits>
@@ -46,6 +46,8 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    static_assert(std::is_nothrow_assignable<std::shared_ptr<A>&, std::shared_ptr<A>&&>::value, "");
+
     {
         std::shared_ptr<A> pA(new A);
         A* ptrA = pA.get();

@github-actions

Copy link
Copy Markdown

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions ,cpp,h -- libcxx/include/__memory/shared_ptr.h libcxx/include/memory libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp
index 79126748f..04ad53901 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr.pass.cpp
@@ -45,25 +45,25 @@ int A::count = 0;
 
 int main(int, char**)
 {
-    static_assert(std::is_nothrow_assignable<std::shared_ptr<A>&, const std::shared_ptr<A>&>::value, "");
+  static_assert(std::is_nothrow_assignable<std::shared_ptr<A>&, const std::shared_ptr<A>&>::value, "");
 
+  {
+    const std::shared_ptr<A> pA(new A);
+    A* ptrA = pA.get();
     {
-        const std::shared_ptr<A> pA(new A);
-        A* ptrA = pA.get();
-        {
-            std::shared_ptr<A> pB(new A);
-            pB = pA;
-            assert(B::count == 1);
-            assert(A::count == 1);
-            assert(pB.use_count() == 2);
-            assert(pA.use_count() == 2);
-            assert(pA.get() == pB.get());
-            assert(pB.get() == ptrA);
-        }
-        assert(pA.use_count() == 1);
-        assert(B::count == 1);
-        assert(A::count == 1);
+      std::shared_ptr<A> pB(new A);
+      pB = pA;
+      assert(B::count == 1);
+      assert(A::count == 1);
+      assert(pB.use_count() == 2);
+      assert(pA.use_count() == 2);
+      assert(pA.get() == pB.get());
+      assert(pB.get() == ptrA);
     }
+    assert(pA.use_count() == 1);
+    assert(B::count == 1);
+    assert(A::count == 1);
+  }
     assert(B::count == 0);
     assert(A::count == 0);
     {
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp
index 1a09f364c..2e2d82bd5 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y.pass.cpp
@@ -43,25 +43,25 @@ int A::count = 0;
 
 int main(int, char**)
 {
-    static_assert(std::is_nothrow_assignable<std::shared_ptr<B>&, const std::shared_ptr<A>&>::value, "");
+  static_assert(std::is_nothrow_assignable<std::shared_ptr<B>&, const std::shared_ptr<A>&>::value, "");
 
+  {
+    const std::shared_ptr<A> pA(new A);
+    A* ptrA = pA.get();
     {
-        const std::shared_ptr<A> pA(new A);
-        A* ptrA = pA.get();
-        {
-            std::shared_ptr<B> pB(new B);
-            pB = pA;
-            assert(B::count == 1);
-            assert(A::count == 1);
-            assert(pB.use_count() == 2);
-            assert(pA.use_count() == 2);
-            assert(pA.get() == pB.get());
-            assert(pB.get() == ptrA);
-        }
-        assert(pA.use_count() == 1);
-        assert(B::count == 1);
-        assert(A::count == 1);
+      std::shared_ptr<B> pB(new B);
+      pB = pA;
+      assert(B::count == 1);
+      assert(A::count == 1);
+      assert(pB.use_count() == 2);
+      assert(pA.use_count() == 2);
+      assert(pA.get() == pB.get());
+      assert(pB.get() == ptrA);
     }
+    assert(pA.use_count() == 1);
+    assert(B::count == 1);
+    assert(A::count == 1);
+  }
     assert(B::count == 0);
     assert(A::count == 0);
     {
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp
index 3cf084f66..9c58f13e3 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_Y_rv.pass.cpp
@@ -46,25 +46,25 @@ int A::count = 0;
 
 int main(int, char**)
 {
-    static_assert(std::is_nothrow_assignable<std::shared_ptr<B>&, std::shared_ptr<A>&&>::value, "");
+  static_assert(std::is_nothrow_assignable<std::shared_ptr<B>&, std::shared_ptr<A>&&>::value, "");
 
+  {
+    std::shared_ptr<A> pA(new A);
+    A* ptrA = pA.get();
     {
-        std::shared_ptr<A> pA(new A);
-        A* ptrA = pA.get();
-        {
-            std::shared_ptr<B> pB(new B);
-            pB = std::move(pA);
-            assert(B::count == 1);
-            assert(A::count == 1);
-            assert(pB.use_count() == 1);
-            assert(pA.use_count() == 0);
-            assert(pA.get() == 0);
-            assert(pB.get() == ptrA);
-        }
-        assert(pA.use_count() == 0);
-        assert(B::count == 0);
-        assert(A::count == 0);
+      std::shared_ptr<B> pB(new B);
+      pB = std::move(pA);
+      assert(B::count == 1);
+      assert(A::count == 1);
+      assert(pB.use_count() == 1);
+      assert(pA.use_count() == 0);
+      assert(pA.get() == 0);
+      assert(pB.get() == ptrA);
     }
+    assert(pA.use_count() == 0);
+    assert(B::count == 0);
+    assert(A::count == 0);
+  }
     assert(B::count == 0);
     assert(A::count == 0);
     {
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp
index 7a952f613..c2f6e5aad 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/shared_ptr_rv.pass.cpp
@@ -46,25 +46,25 @@ int A::count = 0;
 
 int main(int, char**)
 {
-    static_assert(std::is_nothrow_assignable<std::shared_ptr<A>&, std::shared_ptr<A>&&>::value, "");
+  static_assert(std::is_nothrow_assignable<std::shared_ptr<A>&, std::shared_ptr<A>&&>::value, "");
 
+  {
+    std::shared_ptr<A> pA(new A);
+    A* ptrA = pA.get();
     {
-        std::shared_ptr<A> pA(new A);
-        A* ptrA = pA.get();
-        {
-            std::shared_ptr<A> pB(new A);
-            pB = std::move(pA);
-            assert(B::count == 1);
-            assert(A::count == 1);
-            assert(pB.use_count() == 1);
-            assert(pA.use_count() == 0);
-            assert(pA.get() == 0);
-            assert(pB.get() == ptrA);
-        }
-        assert(pA.use_count() == 0);
-        assert(B::count == 0);
-        assert(A::count == 0);
+      std::shared_ptr<A> pB(new A);
+      pB = std::move(pA);
+      assert(B::count == 1);
+      assert(A::count == 1);
+      assert(pB.use_count() == 1);
+      assert(pA.use_count() == 0);
+      assert(pA.get() == 0);
+      assert(pB.get() == ptrA);
     }
+    assert(pA.use_count() == 0);
+    assert(B::count == 0);
+    assert(A::count == 0);
+  }
     assert(B::count == 0);
     assert(A::count == 0);
     {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant