Skip to content

Commit eb5bc26

Browse files
authored
[libc++][unique_ptr] Implement LWG 4144: Disallow unique_ptr<T&, D> (#209018)
Implement [LWG 4144](https://cplusplus.github.io/LWG/issue4144) by explicitly rejecting `unique_ptr<T, D>` when `T*` is not a valid type. This adds a pointability check and tests reference and abominable function types. Fixes #118359
1 parent 67ebc4b commit eb5bc26

3 files changed

Lines changed: 45 additions & 3 deletions

File tree

libcxx/docs/Status/Cxx26Issues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
"`LWG4140 <https://wg21.link/LWG4140>`__","Useless default constructors for bit reference types","2024-11 (Wrocław)","|Complete|","","`#118356 <https://github.com/llvm/llvm-project/issues/118356>`__",""
102102
"`LWG4141 <https://wg21.link/LWG4141>`__","Improve prohibitions on ""additional storage""","2024-11 (Wrocław)","","","`#118357 <https://github.com/llvm/llvm-project/issues/118357>`__",""
103103
"`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>`__",""
104-
"`LWG4144 <https://wg21.link/LWG4144>`__","Disallow ``unique_ptr<T&, D>``","2024-11 (Wrocław)","","","`#118359 <https://github.com/llvm/llvm-project/issues/118359>`__",""
104+
"`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>`__",""
105105
"`LWG4147 <https://wg21.link/LWG4147>`__","Precondition on ``inplace_vector::emplace``","2024-11 (Wrocław)","","","`#118361 <https://github.com/llvm/llvm-project/issues/118361>`__",""
106106
"`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>`__",""
107107
"`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>`__",""

libcxx/include/__memory/unique_ptr.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <__type_traits/is_void.h>
4444
#include <__type_traits/remove_extent.h>
4545
#include <__type_traits/remove_reference.h>
46+
#include <__type_traits/void_t.h>
4647
#include <__utility/declval.h>
4748
#include <__utility/forward.h>
4849
#include <__utility/move.h>
@@ -100,6 +101,12 @@ inline const bool __can_dereference = false;
100101
template <class _Tp>
101102
inline const bool __can_dereference<_Tp, decltype((void)*std::declval<_Tp>())> = true;
102103

104+
template <class _Tp, class = void>
105+
inline const bool __can_add_pointer = false;
106+
107+
template <class _Tp>
108+
inline const bool __can_add_pointer<_Tp, __void_t<_Tp*> > = true;
109+
103110
#if defined(_LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI)
104111
# define _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI __attribute__((__trivial_abi__))
105112
#else
@@ -108,13 +115,14 @@ inline const bool __can_dereference<_Tp, decltype((void)*std::declval<_Tp>())> =
108115

109116
template <class _Tp, class _Dp = default_delete<_Tp> >
110117
class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr {
118+
static_assert(__can_add_pointer<_Tp>, "unique_ptr<T, D> requires T* to be a valid type");
119+
static_assert(!is_rvalue_reference<_Dp>::value, "the specified deleter type cannot be an rvalue reference");
120+
111121
public:
112122
typedef _Tp element_type;
113123
typedef _Dp deleter_type;
114124
using pointer _LIBCPP_NODEBUG = __pointer<_Tp, deleter_type>;
115125

116-
static_assert(!is_rvalue_reference<deleter_type>::value, "the specified deleter type cannot be an rvalue reference");
117-
118126
// A unique_ptr contains the following members which may be trivially relocatable:
119127
// - pointer : this may be trivially relocatable, so it's checked
120128
// - deleter_type: this may be trivially relocatable, so it's checked
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <memory>
10+
11+
// unique_ptr
12+
13+
// [unique.ptr.single.general]/1 (added by LWG4144)
14+
// A program that instantiates the definition of unique_ptr<T, D> is ill-formed if T* is an invalid type.
15+
16+
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
17+
18+
#include <memory>
19+
20+
struct Deleter {
21+
typedef int* pointer;
22+
23+
void operator()(pointer) const;
24+
};
25+
26+
typedef void AbominableFunction() const;
27+
28+
void test() {
29+
// expected-error-re@*:* {{static assertion failed {{.*}}unique_ptr<T, D> requires T* to be a valid type}}
30+
(void)sizeof(std::unique_ptr<int&, Deleter>);
31+
32+
// expected-error-re@*:* {{static assertion failed {{.*}}unique_ptr<T, D> requires T* to be a valid type}}
33+
(void)sizeof(std::unique_ptr<AbominableFunction, Deleter>);
34+
}

0 commit comments

Comments
 (0)