On Tue, Mar 11, 2025 at 10:26 PM Jonathan Wakely <jwak...@redhat.com> wrote:
> 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. > > 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. > --- > > Tested x86_64-linux. > LGTM. In C++26 binding reference to temporary in the return is ill-formed per language rules, but it's good QoI to raise these errors in eariel standards. > > libstdc++-v3/include/bits/unique_ptr.h | 8 +++++ > .../testsuite/20_util/unique_ptr/lwg4148.cc | 31 +++++++++++++++++++ > 2 files changed, 39 insertions(+) > create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc > > diff --git a/libstdc++-v3/include/bits/unique_ptr.h > b/libstdc++-v3/include/bits/unique_ptr.h > index 746989dfe47..6ae46a93800 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 00000000000..c70d7a60631 > --- /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 } > -- > 2.48.1 > >