[libcxx-commits] [libcxx] df55542 - [libc++][memory] LWG4148: `unique_ptr::operator*` should not allow dangling references (#214971)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Aug 10 00:06:57 PDT 2026


Author: Hristo Hristov
Date: 2026-08-10T10:06:52+03:00
New Revision: df555425e7023fb1783525a6feee57f82d82b0fb

URL: https://github.com/llvm/llvm-project/commit/df555425e7023fb1783525a6feee57f82d82b0fb
DIFF: https://github.com/llvm/llvm-project/commit/df555425e7023fb1783525a6feee57f82d82b0fb.diff

LOG: [libc++][memory] LWG4148: `unique_ptr::operator*` should not allow dangling references (#214971)

Implements https://wg21.link/LWG4148

Closes #118362

---------

Co-authored-by: Mohamed Atef <mohamedatef1698 at gmail.com>
Co-authored-by: Hristo Hristov <zingam at outlook.com>
Co-authored-by: A. Jiang <de34 at live.cn>

Added: 
    

Modified: 
    libcxx/docs/Status/Cxx26Issues.csv
    libcxx/include/__memory/unique_ptr.h
    libcxx/include/__type_traits/reference_converts_from_temporary.h
    libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/dereference.verify.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx26Issues.csv b/libcxx/docs/Status/Cxx26Issues.csv
index 6b3b5f61727c7..46242eace0c97 100644
--- a/libcxx/docs/Status/Cxx26Issues.csv
+++ b/libcxx/docs/Status/Cxx26Issues.csv
@@ -103,7 +103,7 @@
 "`LWG4142 <https://wg21.link/LWG4142>`__","``format_parse_context::check_dynamic_spec`` should require at least one type","2024-11 (Wrocław)","","","`#118358 <https://github.com/llvm/llvm-project/issues/118358>`__",""
 "`LWG4144 <https://wg21.link/LWG4144>`__","Disallow ``unique_ptr<T&, D>``","2024-11 (Wrocław)","|Complete|","23","`#118359 <https://github.com/llvm/llvm-project/issues/118359>`__",""
 "`LWG4147 <https://wg21.link/LWG4147>`__","Precondition on ``inplace_vector::emplace``","2024-11 (Wrocław)","","","`#118361 <https://github.com/llvm/llvm-project/issues/118361>`__",""
-"`LWG4148 <https://wg21.link/LWG4148>`__","``unique_ptr::operator*`` should not allow dangling references","2024-11 (Wrocław)","","","`#118362 <https://github.com/llvm/llvm-project/issues/118362>`__",""
+"`LWG4148 <https://wg21.link/LWG4148>`__","``unique_ptr::operator*`` should not allow dangling references","2024-11 (Wrocław)","|Complete|","24","`#118362 <https://github.com/llvm/llvm-project/issues/118362>`__",""
 "`LWG4153 <https://wg21.link/LWG4153>`__","Fix extra ""-1"" for ``philox_engine::max()``","2024-11 (Wrocław)","","","`#118363 <https://github.com/llvm/llvm-project/issues/118363>`__",""
 "`LWG4154 <https://wg21.link/LWG4154>`__","The Mandates for ``std::packaged_task``'s constructor from a callable entity should consider decaying","2024-11 (Wrocław)","","","`#118364 <https://github.com/llvm/llvm-project/issues/118364>`__",""
 "`LWG4157 <https://wg21.link/LWG4157>`__","The resolution of LWG3465 was damaged by P2167R3","2024-11 (Wrocław)","|Complete|","20","`#118365 <https://github.com/llvm/llvm-project/issues/118365>`__",""

diff  --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index fcae9d84eb991..c8392d35c352f 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -42,6 +42,7 @@
 #include <__type_traits/is_trivially_relocatable.h>
 #include <__type_traits/is_void.h>
 #include <__type_traits/nat.h>
+#include <__type_traits/reference_converts_from_temporary.h>
 #include <__type_traits/remove_extent.h>
 #include <__type_traits/remove_reference.h>
 #include <__type_traits/void_t.h>
@@ -237,6 +238,9 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr {
   template <class _Ptr = pointer, __enable_if_t<__can_dereference<_Ptr>, int> = 0>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const
       _NOEXCEPT_(_NOEXCEPT_(*std::declval<pointer>())) {
+    static_assert(
+        !__reference_converts_from_temporary_v<__add_lvalue_reference_t<_Tp>, decltype(*std::declval<pointer>())>,
+        "The returned reference must not bind to a temporary object.");
     return *__ptr_;
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer operator->() const _NOEXCEPT { return __ptr_; }

diff  --git a/libcxx/include/__type_traits/reference_converts_from_temporary.h b/libcxx/include/__type_traits/reference_converts_from_temporary.h
index 31479e43ee2c4..8d879e436cab8 100644
--- a/libcxx/include/__type_traits/reference_converts_from_temporary.h
+++ b/libcxx/include/__type_traits/reference_converts_from_temporary.h
@@ -16,10 +16,13 @@
 #  pragma GCC system_header
 #endif
 
-#if _LIBCPP_STD_VER >= 23
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+template <class _Tp, class _Up>
+inline const bool __reference_converts_from_temporary_v = __reference_converts_from_temporary(_Tp, _Up);
+
+#if _LIBCPP_STD_VER >= 23
+
 template <class _Tp, class _Up>
 struct _LIBCPP_NO_SPECIALIZATIONS reference_converts_from_temporary
     : public bool_constant<__reference_converts_from_temporary(_Tp, _Up)> {};
@@ -28,8 +31,8 @@ template <class _Tp, class _Up>
 _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_converts_from_temporary_v =
     __reference_converts_from_temporary(_Tp, _Up);
 
-_LIBCPP_END_NAMESPACE_STD
-
 #endif //  _LIBCPP_STD_VER >= 23
 
+_LIBCPP_END_NAMESPACE_STD
+
 #endif // _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARY_H

diff  --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/dereference.verify.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/dereference.verify.cpp
index 46506e5622622..f17db6e0afba1 100644
--- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/dereference.verify.cpp
+++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/dereference.verify.cpp
@@ -12,13 +12,31 @@
 
 // test op*()
 
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
 #include <memory>
 
 #include "test_macros.h"
 
-void f() {
+void test() {
   std::unique_ptr<int[]> p(new int(3));
   const std::unique_ptr<int[]>& cp = p;
   TEST_IGNORE_NODISCARD(*p);  // expected-error-re {{indirection requires pointer operand ('std::unique_ptr<int{{[ ]*}}[]>' invalid)}}
   TEST_IGNORE_NODISCARD(*cp); // expected-error-re {{indirection requires pointer operand ('const std::unique_ptr<int{{[ ]*}}[]>' invalid)}}
 }
+
+void test_lwg4196() {
+  struct Deleter {
+    using pointer = long*;
+
+    void operator()(pointer) const {}
+  };
+
+  std::unique_ptr<const int, Deleter> p;
+
+  // expected-error-re@*:* {{static assertion failed due to requirement {{.+}}The returned reference must not bind to a temporary object.}}
+#if TEST_STD_VER >= 26
+  // expected-error@*:* {{returning reference to local temporary object}}
+#endif
+  (void)*p;
+}


        


More information about the libcxx-commits mailing list