https://gcc.gnu.org/g:8ff7ff1a0691b7b409aa31c8f6dfcefec3e4720b

commit r15-7990-g8ff7ff1a0691b7b409aa31c8f6dfcefec3e4720b
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Mar 11 17:29:01 2025 +0000

    libstdc++: Prevent dangling references in std::unique_ptr::operator*
    
    LWG 4148 (approved in Wrocław, November 2024) makes it ill-formed to
    dereference a std::unique_ptr if that would return a dangling reference.
    
    That can happen with a custom pointer type and a const-qualified
    element_type, such that std::add_lvalue_reference_t<element_type> is a
    reference-to-const that could bind to a short-lived temporary.
    
    In C++26 the compiler diagnoses this as an error anyway:
    bits/unique_ptr.h:457:16: error: returning reference to temporary 
[-Wreturn-local-addr]
    But that can be disabled with -Wno-return-local-addr so the
    static_assert ensures it is enforced consistently.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/unique_ptr.h (unique_ptr::operator*): Add
            static_assert to check for dangling reference, as per LWG 4148.
            * testsuite/20_util/unique_ptr/lwg4148.cc: New test.
    
    Reviewed-by: Tomasz Kamiński <tkami...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/unique_ptr.h             |  8 ++++++
 .../testsuite/20_util/unique_ptr/lwg4148.cc        | 31 ++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/libstdc++-v3/include/bits/unique_ptr.h 
b/libstdc++-v3/include/bits/unique_ptr.h
index 746989dfe47e..6ae46a93800c 100644
--- a/libstdc++-v3/include/bits/unique_ptr.h
+++ b/libstdc++-v3/include/bits/unique_ptr.h
@@ -445,6 +445,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typename add_lvalue_reference<element_type>::type
       operator*() const noexcept(noexcept(*std::declval<pointer>()))
       {
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__reference_converts_from_temporary)
+       // _GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 4148. unique_ptr::operator* should not allow dangling references
+       using _ResT = typename add_lvalue_reference<element_type>::type;
+       using _DerefT = decltype(*get());
+       static_assert(!__reference_converts_from_temporary(_ResT, _DerefT),
+                     "operator* must not return a dangling reference");
+#endif
        __glibcxx_assert(get() != pointer());
        return *get();
       }
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc 
b/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc
new file mode 100644
index 000000000000..c70d7a60631b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+// LWG 4148. unique_ptr::operator* should not allow dangling references
+
+#include <memory>
+
+struct pointer
+{
+  pointer() { }
+  pointer(std::nullptr_t) { }
+  int operator*() const { return 0; }
+  bool operator==(pointer) const { return true; }
+  bool operator==(std::nullptr_t) const { return false; }
+#ifndef __cpp_lib_three_way_comparison
+  bool operator!=(pointer) const { return false; }
+  bool operator!=(std::nullptr_t) const { return true; }
+#endif
+};
+
+struct Deleter
+{
+  using pointer = ::pointer;
+  void operator()(pointer) const { }
+};
+
+std::unique_ptr<const int, Deleter> up;
+int i = *up; // { dg-error "here" }
+// { dg-error "dangling reference" "" { target *-*-* } 0 }
+
+// { dg-warning "returning reference to temporary" "" { target c++23_down } 0 }
+// { dg-error "returning reference to temporary" "" { target c++26 } 0 }

Reply via email to