diff --git a/stl/inc/tuple b/stl/inc/tuple index cbb51e5ce56..83e3717fb11 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -126,23 +126,26 @@ struct _Tuple_perfect_val, _Uty0, _Uty1, _Uty2> template struct _Tuple_val { // stores each value in a tuple + // Use of remove_cv_t corresponds to N5008 [allocator.uses.construction]/5. + using _Dty = remove_cv_t<_Ty>; + constexpr _Tuple_val() : _Val() {} template constexpr _Tuple_val(_Other&& _Arg) : _Val(_STD forward<_Other>(_Arg)) {} - template , int> = 0> + template , int> = 0> constexpr _Tuple_val(const _Alloc&, allocator_arg_t, _Other&&... _Arg) : _Val(_STD forward<_Other>(_Arg)...) {} template , + enable_if_t, _STD is_constructible<_Ty, _STD allocator_arg_t, const _Alloc&, _Other...>>, int> = 0> constexpr _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg) : _Val(allocator_arg, _Al, _STD forward<_Other>(_Arg)...) {} template , + enable_if_t, _STD negation<_STD is_constructible<_Ty, _STD allocator_arg_t, const _Alloc&, _Other...>>>, int> = 0> constexpr _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg) diff --git a/tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp b/tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp index 7f29c9e1519..0141a239691 100644 --- a/tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp +++ b/tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp @@ -1,9 +1,19 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include #include #include +#include #include +#include + +#if _HAS_CXX20 +#define CONSTEXPR20 constexpr +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#define CONSTEXPR20 inline +#endif // ^^^ !_HAS_CXX20 ^^^ using namespace std; @@ -50,6 +60,111 @@ void takes_tuple(tuple) {} void test_alloc(); +template +class payloaded_allocator { +private: + int payload = 0; + +public: + payloaded_allocator() = default; + + constexpr explicit payloaded_allocator(int n) noexcept : payload{n} {} + + template + constexpr explicit payloaded_allocator(payloaded_allocator a) noexcept : payload{a.get_payload()} {} + + template + friend constexpr bool operator==(payloaded_allocator x, payloaded_allocator y) noexcept { + return x.payload == y.payload; + } + +#if !_HAS_CXX20 + template + friend constexpr bool operator!=(payloaded_allocator x, payloaded_allocator y) noexcept { + return !(x == y); + } +#endif // !_HAS_CXX20 + + using value_type = T; + + CONSTEXPR20 T* allocate(size_t n) { + return allocator{}.allocate(n); + } + + CONSTEXPR20 void deallocate(T* p, size_t n) { + return allocator{}.deallocate(p, n); + } + + constexpr int get_payload() const noexcept { + return payload; + } +}; + +template +class vector_holder { +public: + vector_holder() = default; + template + CONSTEXPR20 explicit vector_holder(Args&&... args, const A& alloc) : vec_(args..., alloc) {} + + CONSTEXPR20 A get_allocator() const noexcept { + return vec_.get_allocator(); + } + +private: + vector vec_; +}; + +template +struct std::uses_allocator, A> : true_type {}; + +class payload_taker { +public: + payload_taker() = default; + + template + constexpr explicit payload_taker(const payloaded_allocator& alloc) noexcept : payload{alloc.get_payload()} {} + + constexpr int get_payload() const noexcept { + return payload; + } + int get_payload() const volatile noexcept { + return payload; + } + +private: + int payload = 0; +}; + +template +struct std::uses_allocator> : true_type {}; + +// LWG-3677 "Is a cv-qualified pair specially handled in uses-allocator construction?" +CONSTEXPR20 bool test_lwg3677() { + using my_allocator = payloaded_allocator; + + tuple t1{allocator_arg, my_allocator{42}}; + assert(get<0>(t1).get_payload() == 42); + tuple t2{allocator_arg, my_allocator{84}}; + assert(get<0>(t2).get_payload() == 84); + + tuple> t3{allocator_arg, my_allocator{126}}; + assert(get<0>(t3).get_allocator().get_payload() == 126); + tuple> t4{allocator_arg, my_allocator{168}}; + assert(get<0>(t4).get_allocator().get_payload() == 168); + + return true; +} + +void test_lwg3677_volatile() { + using my_allocator = payloaded_allocator; + + tuple t5{allocator_arg, my_allocator{210}}; + assert(get<0>(t5).get_payload() == 210); + tuple t6{allocator_arg, my_allocator{252}}; + assert(get<0>(t6).get_payload() == 252); +} + int main() { B* b = nullptr; Y* y = nullptr; @@ -129,6 +244,12 @@ int main() { test_alloc(); + + test_lwg3677(); +#if _HAS_CXX20 + static_assert(test_lwg3677()); +#endif // _HAS_CXX20 + test_lwg3677_volatile(); } struct Meow {