Skip to content

Commit 0cb7f5b

Browse files
Implement LWG-4312 Const and value category mismatch for allocator_arg_t/allocator_arg in the description of uses-allocator construction (#5904)
1 parent 1e6d927 commit 0cb7f5b

File tree

5 files changed

+106
-5
lines changed

5 files changed

+106
-5
lines changed

stl/inc/tuple

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ struct _Tuple_val { // stores each value in a tuple
142142
_STD is_constructible<_Ty, _STD allocator_arg_t, const _Alloc&, _Other...>>,
143143
int> = 0>
144144
constexpr _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg)
145-
: _Val(allocator_arg, _Al, _STD forward<_Other>(_Arg)...) {}
145+
: _Val(allocator_arg_t{}, _Al, _STD forward<_Other>(_Arg)...) {}
146146

147147
template <class _Alloc, class... _Other,
148148
enable_if_t<conjunction_v<_STD uses_allocator<_Dty, _Alloc>,

stl/inc/xpolymorphic_allocator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ void _Uses_alloc_construct_non_pair(_Ty* const _Ptr, _Outer_alloc& _Outer, _Inne
2828
if constexpr (uses_allocator_v<remove_cv_t<_Ty>, _Inner_alloc>) {
2929
if constexpr (is_constructible_v<_Ty, allocator_arg_t, _Inner_alloc&, _Types...>) {
3030
allocator_traits<_Outer_alloc>::construct(
31-
_Outer, _Ptr, allocator_arg, _Inner, _STD forward<_Types>(_Args)...);
31+
_Outer, _Ptr, allocator_arg_t{}, _Inner, _STD forward<_Types>(_Args)...);
3232
} else {
3333
static_assert(is_constructible_v<_Ty, _Types..., _Inner_alloc&>,
3434
"N4950 [allocator.uses.trait]/1 requires "

tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,60 @@ void test_lwg3677_volatile() {
165165
assert(get<0>(t6).get_payload() == 252);
166166
}
167167

168+
// LWG-4312 "Const and value category mismatch for allocator_arg_t/allocator_arg in the description of uses-allocator
169+
// construction"
170+
171+
struct allocator_arg_mutable_rvalue_only {
172+
allocator_arg_mutable_rvalue_only() = default;
173+
174+
template <class A>
175+
constexpr allocator_arg_mutable_rvalue_only(allocator_arg_t&&, const A&) {}
176+
template <class A>
177+
constexpr allocator_arg_mutable_rvalue_only(allocator_arg_t&&, const A&, const allocator_arg_mutable_rvalue_only&) {
178+
}
179+
template <class A>
180+
constexpr allocator_arg_mutable_rvalue_only(allocator_arg_t&&, const A&, allocator_arg_mutable_rvalue_only&&) {}
181+
182+
template <class A>
183+
allocator_arg_mutable_rvalue_only(allocator_arg_t&, const A&) = delete;
184+
template <class A>
185+
allocator_arg_mutable_rvalue_only(allocator_arg_t&, const A&, const allocator_arg_mutable_rvalue_only&) = delete;
186+
template <class A>
187+
allocator_arg_mutable_rvalue_only(allocator_arg_t&, const A&, allocator_arg_mutable_rvalue_only&&) = delete;
188+
189+
template <class A>
190+
allocator_arg_mutable_rvalue_only(const allocator_arg_t&, const A&) = delete;
191+
template <class A>
192+
allocator_arg_mutable_rvalue_only(
193+
const allocator_arg_t&, const A&, const allocator_arg_mutable_rvalue_only&) = delete;
194+
template <class A>
195+
allocator_arg_mutable_rvalue_only(const allocator_arg_t&, const A&, allocator_arg_mutable_rvalue_only&&) = delete;
196+
};
197+
198+
template <class A>
199+
struct std::uses_allocator<allocator_arg_mutable_rvalue_only, A> : true_type {};
200+
201+
CONSTEXPR20 bool test_lwg4312() {
202+
tuple<allocator_arg_mutable_rvalue_only> t1{allocator_arg, allocator<int>{}};
203+
tuple<allocator_arg_mutable_rvalue_only> t2{allocator_arg, allocator<int>{}, get<0>(t1)};
204+
tuple<allocator_arg_mutable_rvalue_only> t3{allocator_arg, allocator<int>{}, allocator_arg_mutable_rvalue_only{}};
205+
206+
(void) t1;
207+
(void) t2;
208+
(void) t3;
209+
210+
tuple<allocator_arg_mutable_rvalue_only> t4{allocator_arg, payloaded_allocator<int>{42}};
211+
tuple<allocator_arg_mutable_rvalue_only> t5{allocator_arg, payloaded_allocator<int>{84}, get<0>(t1)};
212+
tuple<allocator_arg_mutable_rvalue_only> t6{
213+
allocator_arg, payloaded_allocator<int>{168}, allocator_arg_mutable_rvalue_only{}};
214+
215+
(void) t4;
216+
(void) t5;
217+
(void) t6;
218+
219+
return true;
220+
}
221+
168222
int main() {
169223
B* b = nullptr;
170224
Y* y = nullptr;
@@ -250,6 +304,11 @@ int main() {
250304
static_assert(test_lwg3677());
251305
#endif // _HAS_CXX20
252306
test_lwg3677_volatile();
307+
308+
test_lwg4312();
309+
#if _HAS_CXX20
310+
static_assert(test_lwg4312());
311+
#endif // _HAS_CXX20
253312
}
254313

255314
struct Meow {

tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ namespace {
137137

138138
int i_ = 0;
139139

140-
uses_allocator_thing(std::allocator_arg_t, Alloc const& a, int i = 0) : Alloc(a), i_{i} {}
140+
// Such overload set is used for testing LWG-4312.
141+
uses_allocator_thing(std::allocator_arg_t&&, Alloc const& a, int i = 0) : Alloc(a), i_{i} {}
142+
uses_allocator_thing(std::allocator_arg_t&, Alloc const&, int = 0) = delete;
143+
uses_allocator_thing(const std::allocator_arg_t&, Alloc const&, int = 0) = delete;
144+
141145
Alloc get_allocator() const {
142146
return *this;
143147
}
@@ -151,8 +155,8 @@ namespace {
151155
};
152156
template <class Alloc>
153157
struct uses_allocator_thing<Alloc, false> : uses_allocator_thing<Alloc, true> {
154-
uses_allocator_thing(int i, Alloc const& a) : uses_allocator_thing<Alloc, true>{std::allocator_arg, a, i} {}
155-
uses_allocator_thing(Alloc const& a) : uses_allocator_thing<Alloc, true>{std::allocator_arg, a} {}
158+
uses_allocator_thing(int i, Alloc const& a) : uses_allocator_thing<Alloc, true>{std::allocator_arg_t{}, a, i} {}
159+
uses_allocator_thing(Alloc const& a) : uses_allocator_thing<Alloc, true>{std::allocator_arg_t{}, a} {}
156160
};
157161

158162
struct malloc_resource final : std::pmr::memory_resource {
@@ -691,6 +695,25 @@ namespace {
691695
}
692696
} // namespace construct
693697

698+
699+
// Also test LWG-4312 "Const and value category mismatch for allocator_arg_t/allocator_arg in the
700+
// description of uses-allocator construction"
701+
namespace uses_allocator_construct {
702+
void test() {
703+
malloc_resource mr;
704+
std::pmr::polymorphic_allocator<not_constructible> alloc = &mr;
705+
706+
using T = uses_allocator_thing<std::pmr::polymorphic_allocator<int>, true>;
707+
708+
alignas(T) unsigned char space[sizeof(T)];
709+
const auto rawptr = reinterpret_cast<T*>(space);
710+
alloc.construct(rawptr);
711+
placement_ptr<T> ptr{rawptr};
712+
713+
CHECK(ptr->get_allocator().resource() == &mr);
714+
}
715+
} // namespace uses_allocator_construct
716+
694717
namespace piecewise_construct {
695718
void test() {
696719
malloc_resource mr;
@@ -1573,6 +1596,7 @@ int main() {
15731596
polymorphic_allocator::ctor::rebind::test();
15741597
polymorphic_allocator::mem::allocate_deallocate::test();
15751598
polymorphic_allocator::mem::construct::test();
1599+
polymorphic_allocator::mem::uses_allocator_construct::test();
15761600
polymorphic_allocator::mem::piecewise_construct::test();
15771601
polymorphic_allocator::mem::construct_pair::test();
15781602
polymorphic_allocator::mem::construct_pair_U_V::test();

tests/std/tests/VSO_0224478_scoped_allocator/test.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,23 @@ void test_case_LWG_2586() {
119119
sa.deallocate(ptr, 1);
120120
}
121121

122+
struct lwg_4312 {
123+
using allocator_type = allocator<lwg_4312>;
124+
lwg_4312(allocator_arg_t&&, const allocator_type&) {}
125+
lwg_4312(allocator_arg_t&, const allocator_type&) = delete;
126+
lwg_4312(const allocator_arg_t&, const allocator_type&) = delete;
127+
};
128+
129+
void test_case_LWG_4312() {
130+
// LWG-4312 "Const and value category mismatch for allocator_arg_t/allocator_arg in the description of
131+
// uses-allocator construction"
132+
scoped_allocator_adaptor<allocator<lwg_4312>> sa;
133+
const auto ptr = sa.allocate(1);
134+
sa.construct(ptr);
135+
sa.destroy(ptr);
136+
sa.deallocate(ptr, 1);
137+
}
138+
122139
void test_case_move_rebind_one_alloc() {
123140
scoped_allocator_adaptor<allocator<int>> sa;
124141
scoped_allocator_adaptor<allocator<double>> target(move(sa));
@@ -159,5 +176,6 @@ int main() {
159176
test_case_VSO_224478_allow_stacking();
160177
test_case_VSO_224478_piecewise_construct_calls_allocator_construct();
161178
test_case_LWG_2586();
179+
test_case_LWG_4312();
162180
test_case_move_rebind_one_alloc();
163181
}

0 commit comments

Comments
 (0)