On Wed, 12 Mar 2025 at 07:38, Tomasz Kaminski <tkami...@redhat.com> wrote:
>
>
>
> 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.

Yes, the new test expects a -Wreturn-local-addr warning for <= C++23
and an error for C++26, but I think having the static_assert
consistently is good.

Especially because the C++26 error can be disabled by -Wno-return-local-addr
With the static_assert, unique_ptr::operator* will still be ill-formed
even if the required compiler diagnostic has been disabled.

>>
>>
>>  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
>>

Reply via email to