From b35643bed6f61602c60b3c293fbc72c9a2b04541 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 10 Jun 2021 17:46:34 +0200 Subject: [PATCH 1/8] Implement P1132R7 --- stl/inc/memory | 161 ++++++++++++++++++ stl/inc/yvals_core.h | 3 + tests/std/tests/P1132R7_out_ptr/env.lst | 4 + tests/std/tests/P1132R7_out_ptr/test.cpp | 201 +++++++++++++++++++++++ 4 files changed, 369 insertions(+) create mode 100644 tests/std/tests/P1132R7_out_ptr/env.lst create mode 100644 tests/std/tests/P1132R7_out_ptr/test.cpp diff --git a/stl/inc/memory b/stl/inc/memory index 9eca0290ce..ea94763e36 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4094,6 +4094,167 @@ public: }; #endif // _HAS_CXX20 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +template +struct _Pointer_of_helper {}; + +// clang-format off +template + requires requires { typename _Ty::pointer; } +struct _Pointer_of_helper<_Ty> { + using type = typename _Ty::pointer; +}; + +template + requires (!requires { typename _Ty::pointer; } && requires { typename _Ty::element_type; }) +struct _Pointer_of_helper<_Ty> { + using type = typename _Ty::element_type*; +}; + +template + requires (!requires { typename _Ty::element_type; } && !requires { typename _Ty::pointer; } + && requires { typename pointer_traits<_Ty>::element_type; }) +struct _Pointer_of_helper<_Ty> { + using type = typename pointer_traits<_Ty>::element_type*; +}; +// clang-format on + +template +using _Pointer_of = typename _Pointer_of_helper<_Ty>::type; + +template +struct _Pointer_of_or_helper { + using type = _Uty; +}; + +// clang-format off +template + requires requires { typename _Pointer_of<_Ty>; } +struct _Pointer_of_or_helper<_Ty, _Uty> { + using type = _Pointer_of<_Ty>; +}; +// clang-format on + +template +using _Pointer_of_or = typename _Pointer_of_or_helper<_Ty, _Uty>::type; + +template +concept _Resettable_pointer = requires(_SmartPtr& _Smart_ptr, _Pointer _Ptr, _ArgsT&&... _Args) { + _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args)...); +}; + +template +class out_ptr_t { + static_assert(!_Is_specialization_v<_SmartPtr, shared_ptr> || sizeof...(_ArgsT) != 0, + "out_ptr_t with shared_ptr requires a deleter"); + +public: + explicit out_ptr_t(_SmartPtr& _Smart_ptr_, _ArgsT... _Args_) + : _Smart_ptr(_Smart_ptr_), _Args(_STD forward<_ArgsT>(_Args_)...) {} + + out_ptr_t(const out_ptr_t&) = delete; + + ~out_ptr_t() { + if (_Ptr) { + _STD apply( + [&](auto&&... _Args_) { + using _Sp = _Pointer_of_or<_SmartPtr, _Pointer>; + if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { + _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } else { + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } + }, + _STD move(_Args)); + } + } + + operator _Pointer*() const noexcept { + return _STD addressof(const_cast<_Pointer&>(_Ptr)); + } + + operator void**() const noexcept requires(!is_same_v<_Pointer, void*>) { + static_assert(is_pointer_v<_Pointer>, "out_ptr_t's operator void** requires Pointer to be a pointer"); + return reinterpret_cast(_STD addressof(const_cast<_Pointer&>(_Ptr))); + } + +private: + _SmartPtr& _Smart_ptr; + tuple<_ArgsT...> _Args; + _Pointer _Ptr{}; +}; + +template +_NODISCARD auto out_ptr(_SmartPtr& _Smart_ptr, _ArgsT&&... _Args) { + if constexpr (is_void_v<_Pointer>) { + return out_ptr_t<_SmartPtr, _Pointer_of<_SmartPtr>, _ArgsT&&...>(_Smart_ptr, _STD forward<_ArgsT>(_Args)...); + } else { + return out_ptr_t<_SmartPtr, _Pointer, _ArgsT&&...>(_Smart_ptr, _STD forward<_ArgsT>(_Args)...); + } +} + +template +class inout_ptr_t { + static_assert(!_Is_specialization_v<_SmartPtr, shared_ptr>, "inout_ptr_t doesn't work with shared_ptr"); + + static auto _Get_ptr(_SmartPtr& _Smart_ptr) { + if constexpr (is_pointer_v<_SmartPtr>) { + return _Smart_ptr; + } else { + return _Smart_ptr.get(); + } + } + +public: + explicit inout_ptr_t(_SmartPtr& _Smart_ptr_, _ArgsT... _Args_) + : _Smart_ptr(_Smart_ptr_), _Args(_STD forward<_ArgsT>(_Args_)...), _Ptr(_Get_ptr(_Smart_ptr_)) {} + + inout_ptr_t(const inout_ptr_t&) = delete; + + ~inout_ptr_t() { + if (_Ptr) { + _STD apply( + [&](auto&&... _Args_) { + using _Sp = _Pointer_of_or<_SmartPtr, _Pointer>; + if constexpr (is_pointer_v<_SmartPtr>) { + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } else if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { + _Smart_ptr.release(); + _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } else { + _Smart_ptr.release(); + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } + }, + _STD move(_Args)); + } + } + + operator _Pointer*() const noexcept { + return _STD addressof(const_cast<_Pointer&>(_Ptr)); + } + + operator void**() const noexcept requires(!is_same_v<_Pointer, void*>) { + static_assert(is_pointer_v<_Pointer>, "inout_ptr_t's operator void** requires Pointer to be a pointer"); + return reinterpret_cast(_STD addressof(const_cast<_Pointer&>(_Ptr))); + } + +private: + _SmartPtr& _Smart_ptr; + tuple<_ArgsT...> _Args; + _Pointer _Ptr; +}; + +template +_NODISCARD auto inout_ptr(_SmartPtr& _Smart_ptr, _ArgsT&&... _Args) { + if constexpr (is_void_v<_Pointer>) { + return inout_ptr_t<_SmartPtr, _Pointer_of<_SmartPtr>, _ArgsT&&...>(_Smart_ptr, _STD forward<_ArgsT>(_Args)...); + } else { + return inout_ptr_t<_SmartPtr, _Pointer, _ArgsT&&...>(_Smart_ptr, _STD forward<_ArgsT>(_Args)...); + } +} +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + #if _HAS_TR1_NAMESPACE namespace _DEPRECATE_TR1_NAMESPACE tr1 { using _STD allocate_shared; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 3b2c62061b..71e4b0c2fd 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -255,6 +255,9 @@ // P1831R1 Deprecating volatile In The Standard Library // Other C++20 deprecation warnings +// _HAS_CXX23 controls: +// P1132R7 out_ptr(), inout_ptr() + // Parallel Algorithms Notes // C++ allows an implementation to implement parallel algorithms as calls to the serial algorithms. // This implementation parallelizes several common algorithm calls, but not all. diff --git a/tests/std/tests/P1132R7_out_ptr/env.lst b/tests/std/tests/P1132R7_out_ptr/env.lst new file mode 100644 index 0000000000..18e2d7c71e --- /dev/null +++ b/tests/std/tests/P1132R7_out_ptr/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P1132R7_out_ptr/test.cpp b/tests/std/tests/P1132R7_out_ptr/test.cpp new file mode 100644 index 0000000000..3d655f540c --- /dev/null +++ b/tests/std/tests/P1132R7_out_ptr/test.cpp @@ -0,0 +1,201 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +using namespace std; + +void test_raw_ptr() { + int i = 5; + int* int_ptr = &i; + + { + const auto f = [](int** ptr) { + assert(**ptr == 5); + static int i = 7; + *ptr = &i; + }; + + f(inout_ptr(int_ptr)); + + assert(*int_ptr == 7); + } + { + const auto f = [](void** ptr) { + assert(*reinterpret_cast(*ptr) == 7); + static int i = 15; + *ptr = &i; + }; + + f(inout_ptr(int_ptr)); + + assert(*int_ptr == 15); + } +} + +void test_shared_ptr() { + shared_ptr int_ptr = make_shared(5); + + { + const auto f = [](int** ptr) { *ptr = new int(7); }; + + f(out_ptr(int_ptr, default_delete{})); + + assert(*int_ptr == 7); + } + { + const auto f = [](void** ptr) { *ptr = new int(15); }; + + f(out_ptr(int_ptr, default_delete{})); + + assert(*int_ptr == 15); + } + + int count = 0; + const auto deleter = [&count](int* ptr) { + ++count; + delete ptr; + }; + + { + const auto f = [](int** ptr) { *ptr = new int(23); }; + + f(out_ptr(int_ptr, deleter)); + + assert(count == 0); + assert(*int_ptr == 23); + } + { + const auto f = [](void** ptr) { *ptr = new int(32); }; + + f(out_ptr(int_ptr, deleter)); + + assert(count == 1); + assert(*int_ptr == 32); + } + + int_ptr.reset(); + assert(count == 2); +} + +template +void test_smart_ptr(Args&&... args) { + Ptr int_ptr{new int(5)}; + + { + const auto f = [](int** ptr) { + assert(**ptr == 5); + *ptr = new int(7); + }; + + f(inout_ptr(int_ptr, forward(args)...)); + + assert(*int_ptr == 7); + } + { + const auto f = [](int** ptr) { *ptr = new int(12); }; + + f(out_ptr(int_ptr, forward(args)...)); + + assert(*int_ptr == 12); + } + { + const auto f = [](void** ptr) { + assert(*reinterpret_cast(*ptr) == 12); + *ptr = new int(15); + }; + + f(inout_ptr(int_ptr, forward(args)...)); + + assert(*int_ptr == 15); + } + { + const auto f = [](void** ptr) { *ptr = new int(19); }; + + f(out_ptr(int_ptr, forward(args)...)); + + assert(*int_ptr == 19); + } +} + +struct reset_tag {}; + +struct resettable_ptr { + using element_type = int; // test having element_type only + + unique_ptr ptr; + + explicit resettable_ptr(int* p) : ptr(p) {} + + void reset(int* p, reset_tag) { + ptr.reset(p); + } + + auto operator*() const { + return *ptr; + } + + auto get() const { + return ptr.get(); + } + + void release() { + ptr.release(); + } +}; + +struct constructible_ptr { + using pointer = int*; // test having pointer only + + unique_ptr ptr; + + explicit constructible_ptr(int* p) : ptr(p) {} + explicit constructible_ptr(int* p, reset_tag) : ptr(p) {} + + auto operator*() const { + return *ptr; + } + + auto get() const { + return ptr.get(); + } + + void release() { + ptr.release(); + } +}; + +struct resettable_ptr2 : public resettable_ptr { + using resettable_ptr::resettable_ptr; + +private: + using resettable_ptr::element_type; +}; + +template <> +struct pointer_traits { + using element_type = int; // test having only pointer_traits::element_type +}; + +struct constructible_ptr2 : public constructible_ptr { + using constructible_ptr::constructible_ptr; + +private: + using constructible_ptr::pointer; +}; + +template <> +struct pointer_traits { + // test having nothing +}; + +int main() { + test_raw_ptr(); + test_shared_ptr(); + test_smart_ptr>(); + test_smart_ptr(reset_tag{}); + test_smart_ptr(reset_tag{}); + test_smart_ptr(reset_tag{}); + test_smart_ptr(reset_tag{}); +} From 31e8a51f634541cd7cf1f8f08e36121d5742ab50 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 11 Jun 2021 14:36:10 +0200 Subject: [PATCH 2/8] use existing concepts --- stl/inc/memory | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index ea94763e36..5da438637d 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4099,21 +4099,20 @@ template struct _Pointer_of_helper {}; // clang-format off -template - requires requires { typename _Ty::pointer; } +template <_Has_member_pointer _Ty> struct _Pointer_of_helper<_Ty> { using type = typename _Ty::pointer; }; -template - requires (!requires { typename _Ty::pointer; } && requires { typename _Ty::element_type; }) +template <_Has_member_element_type _Ty> + requires (!_Has_member_pointer<_Ty>) struct _Pointer_of_helper<_Ty> { using type = typename _Ty::element_type*; }; template - requires (!requires { typename _Ty::element_type; } && !requires { typename _Ty::pointer; } - && requires { typename pointer_traits<_Ty>::element_type; }) + requires (!_Has_member_element_type<_Ty> && !_Has_member_pointer<_Ty> + && _Has_member_element_type>) struct _Pointer_of_helper<_Ty> { using type = typename pointer_traits<_Ty>::element_type*; }; From a203cf52471307d620bb6261e50b2e5096548631 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 11 Jun 2021 15:02:28 +0200 Subject: [PATCH 3/8] miscco's code review --- stl/inc/memory | 60 ++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 5da438637d..69ad1826c0 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4154,18 +4154,19 @@ public: out_ptr_t(const out_ptr_t&) = delete; ~out_ptr_t() { - if (_Ptr) { - _STD apply( - [&](auto&&... _Args_) { - using _Sp = _Pointer_of_or<_SmartPtr, _Pointer>; - if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { - _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); - } else { - _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); - } - }, - _STD move(_Args)); - } + if (!_Ptr) + return; + + _STD apply( + [this](auto&&... _Args_) { + using _Sp = _Pointer_of_or<_SmartPtr, _Pointer>; + if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { + _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } else { + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } + }, + _STD move(_Args)); } operator _Pointer*() const noexcept { @@ -4196,7 +4197,7 @@ template class inout_ptr_t { static_assert(!_Is_specialization_v<_SmartPtr, shared_ptr>, "inout_ptr_t doesn't work with shared_ptr"); - static auto _Get_ptr(_SmartPtr& _Smart_ptr) { + _NODISCARD static auto _Get_ptr(_SmartPtr& _Smart_ptr) { if constexpr (is_pointer_v<_SmartPtr>) { return _Smart_ptr; } else { @@ -4211,22 +4212,23 @@ public: inout_ptr_t(const inout_ptr_t&) = delete; ~inout_ptr_t() { - if (_Ptr) { - _STD apply( - [&](auto&&... _Args_) { - using _Sp = _Pointer_of_or<_SmartPtr, _Pointer>; - if constexpr (is_pointer_v<_SmartPtr>) { - _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); - } else if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { - _Smart_ptr.release(); - _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); - } else { - _Smart_ptr.release(); - _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); - } - }, - _STD move(_Args)); - } + if (!_Ptr) + return; + + _STD apply( + [this](auto&&... _Args_) { + using _Sp = _Pointer_of_or<_SmartPtr, _Pointer>; + if constexpr (is_pointer_v<_SmartPtr>) { + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } else if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { + _Smart_ptr.release(); + _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } else { + _Smart_ptr.release(); + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + } + }, + _STD move(_Args)); } operator _Pointer*() const noexcept { From 32e322d72496b5fc24c6fb0c0b910b0026d04d0c Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sun, 13 Jun 2021 14:35:22 +0200 Subject: [PATCH 4/8] add test to test.lst --- tests/std/test.lst | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/test.lst b/tests/std/test.lst index cba3615d38..37771d3ac3 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -407,6 +407,7 @@ tests\P1007R3_assume_aligned tests\P1020R1_smart_pointer_for_overwrite tests\P1023R0_constexpr_for_array_comparisons tests\P1032R1_miscellaneous_constexpr +tests\P1132R7_out_ptr tests\P1135R6_atomic_flag_test tests\P1135R6_atomic_wait tests\P1135R6_atomic_wait_vista From 57db1828c5c5b204c2d1d44d6ec8ecc43fa21a4f Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 8 Jul 2021 11:16:13 +0200 Subject: [PATCH 5/8] Code review --- stl/inc/memory | 31 ++++++++++++------- stl/inc/yvals_core.h | 7 ++++- .../test.compile.pass.cpp | 14 +++++++++ 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 32640b463e..ab9e2c405a 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4164,6 +4164,7 @@ struct _Pointer_of_or_helper<_Ty, _Uty> { template using _Pointer_of_or = typename _Pointer_of_or_helper<_Ty, _Uty>::type; +// TRANSITION, requires expression support template concept _Resettable_pointer = requires(_SmartPtr& _Smart_ptr, _Pointer _Ptr, _ArgsT&&... _Args) { _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args)...); @@ -4175,14 +4176,16 @@ class out_ptr_t { "out_ptr_t with shared_ptr requires a deleter"); public: - explicit out_ptr_t(_SmartPtr& _Smart_ptr_, _ArgsT... _Args_) + explicit out_ptr_t(_SmartPtr& _Smart_ptr_, _ArgsT... _Args_) noexcept( + is_nothrow_constructible_v, _ArgsT...>) : _Smart_ptr(_Smart_ptr_), _Args(_STD forward<_ArgsT>(_Args_)...) {} out_ptr_t(const out_ptr_t&) = delete; ~out_ptr_t() { - if (!_Ptr) + if (!_Ptr) { return; + } _STD apply( [this](auto&&... _Args_) { @@ -4201,7 +4204,8 @@ public: } operator void**() const noexcept requires(!is_same_v<_Pointer, void*>) { - static_assert(is_pointer_v<_Pointer>, "out_ptr_t's operator void** requires Pointer to be a pointer"); + static_assert(is_pointer_v<_Pointer>, + "conversion of out_ptr_t to void** requires Pointer to be a raw pointer"); return reinterpret_cast(_STD addressof(const_cast<_Pointer&>(_Ptr))); } @@ -4224,23 +4228,25 @@ template class inout_ptr_t { static_assert(!_Is_specialization_v<_SmartPtr, shared_ptr>, "inout_ptr_t doesn't work with shared_ptr"); - _NODISCARD static auto _Get_ptr(_SmartPtr& _Smart_ptr) { - if constexpr (is_pointer_v<_SmartPtr>) { - return _Smart_ptr; - } else { - return _Smart_ptr.get(); - } + _NODISCARD static auto _Get_ptr(_SmartPtr& _Smart_ptr) noexcept requires is_pointer_v<_SmartPtr> { + return _Smart_ptr; + } + + _NODISCARD static auto _Get_ptr(_SmartPtr& _Smart_ptr) noexcept(noexcept(_Smart_ptr.get())) { + return _Smart_ptr.get(); } public: - explicit inout_ptr_t(_SmartPtr& _Smart_ptr_, _ArgsT... _Args_) + explicit inout_ptr_t(_SmartPtr& _Smart_ptr_, _ArgsT... _Args_) noexcept( + is_nothrow_constructible_v, _ArgsT...>&& noexcept(_Get_ptr(_Smart_ptr_))) : _Smart_ptr(_Smart_ptr_), _Args(_STD forward<_ArgsT>(_Args_)...), _Ptr(_Get_ptr(_Smart_ptr_)) {} inout_ptr_t(const inout_ptr_t&) = delete; ~inout_ptr_t() { - if (!_Ptr) + if (!_Ptr) { return; + } _STD apply( [this](auto&&... _Args_) { @@ -4263,7 +4269,8 @@ public: } operator void**() const noexcept requires(!is_same_v<_Pointer, void*>) { - static_assert(is_pointer_v<_Pointer>, "inout_ptr_t's operator void** requires Pointer to be a pointer"); + static_assert(is_pointer_v<_Pointer>, + "conversion of inout_ptr_t to void** requires Pointer to be a raw pointer"); return reinterpret_cast(_STD addressof(const_cast<_Pointer&>(_Ptr))); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index c78361afa1..759b8913fa 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1360,7 +1360,12 @@ // C++23 #if _HAS_CXX23 -#define __cpp_lib_is_scoped_enum 202011L +#define __cpp_lib_is_scoped_enum 202011L + +#ifdef __cpp_lib_concepts +#define __cpp_lib_out_ptr 202106L +#endif // __cpp_lib_concepts + #define __cpp_lib_string_contains 202011L #define __cpp_lib_to_underlying 202102L #endif // _HAS_CXX23 diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index d518ecc273..734af0fc23 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1185,6 +1185,20 @@ STATIC_ASSERT(__cpp_lib_optional == 201606L); #endif #endif +#if _HAS_CXX23 && !defined(__EDG__) // TRANSITION, EDG concepts support +#ifndef __cpp_lib_out_ptr +#error __cpp_lib_out_ptr is not defined +#elif __cpp_lib_out_ptr != 202106L +#error __cpp_lib_out_ptr is not 202106L +#else +STATIC_ASSERT(__cpp_lib_out_ptr == 202106L); +#endif +#else +#ifdef __cpp_lib_out_ptr +#error __cpp_lib_out_ptr is defined +#endif +#endif + #if _HAS_CXX17 && !defined(_M_CEE) #ifndef __cpp_lib_parallel_algorithm #error __cpp_lib_parallel_algorithm is not defined From 10b2be619c0f92807168a0418523d83b68c85cec Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 8 Jul 2021 17:26:25 +0200 Subject: [PATCH 6/8] static_assert is_constructible --- stl/inc/memory | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stl/inc/memory b/stl/inc/memory index ab9e2c405a..42c8571a5a 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4193,6 +4193,7 @@ public: if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); } else { + static_assert(is_constructible_v<_SmartPtr, _Sp, _ArgsT...>); _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); } }, @@ -4257,6 +4258,7 @@ public: _Smart_ptr.release(); _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); } else { + static_assert(is_constructible_v<_SmartPtr, _Sp, _ArgsT...>); _Smart_ptr.release(); _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); } From 51c3a625516ed398d71fe5f3f80cbcfad87fd7b1 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sun, 11 Jul 2021 12:40:24 +0200 Subject: [PATCH 7/8] Code review --- stl/inc/memory | 82 +++++++++++++++--------- tests/std/tests/P1132R7_out_ptr/test.cpp | 9 +-- 2 files changed, 56 insertions(+), 35 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 42c8571a5a..de33f7f4eb 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4173,17 +4173,18 @@ concept _Resettable_pointer = requires(_SmartPtr& _Smart_ptr, _Pointer _Ptr, _Ar template class out_ptr_t { static_assert(!_Is_specialization_v<_SmartPtr, shared_ptr> || sizeof...(_ArgsT) != 0, - "out_ptr_t with shared_ptr requires a deleter"); + "out_ptr_t with shared_ptr requires a deleter (N4892 [out.ptr.t]/3)"); public: explicit out_ptr_t(_SmartPtr& _Smart_ptr_, _ArgsT... _Args_) noexcept( - is_nothrow_constructible_v, _ArgsT...>) - : _Smart_ptr(_Smart_ptr_), _Args(_STD forward<_ArgsT>(_Args_)...) {} + is_nothrow_constructible_v, _ArgsT...>) /* strengthened */ + : _Smart_ptr(_Smart_ptr_), + _Mypair(_One_then_variadic_args_t{}, tuple<_ArgsT...>{_STD forward<_ArgsT>(_Args_)...}) {} out_ptr_t(const out_ptr_t&) = delete; ~out_ptr_t() { - if (!_Ptr) { + if (!_Get_ptr()) { return; } @@ -4191,29 +4192,36 @@ public: [this](auto&&... _Args_) { using _Sp = _Pointer_of_or<_SmartPtr, _Pointer>; if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { - _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + _Smart_ptr.reset(static_cast<_Sp>(_Get_ptr()), _STD forward<_ArgsT>(_Args_)...); } else { - static_assert(is_constructible_v<_SmartPtr, _Sp, _ArgsT...>); - _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + static_assert(is_constructible_v<_SmartPtr, _Sp, _ArgsT...>, "(N4892 [out.ptr.t]/9.3)"); + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Get_ptr()), _STD forward<_ArgsT>(_Args_)...); } }, - _STD move(_Args)); + _STD move(_Get_args())); } operator _Pointer*() const noexcept { - return _STD addressof(const_cast<_Pointer&>(_Ptr)); + return _STD addressof(_Get_ptr()); } operator void**() const noexcept requires(!is_same_v<_Pointer, void*>) { - static_assert(is_pointer_v<_Pointer>, - "conversion of out_ptr_t to void** requires Pointer to be a raw pointer"); - return reinterpret_cast(_STD addressof(const_cast<_Pointer&>(_Ptr))); + static_assert(is_pointer_v<_Pointer>, "conversion of out_ptr_t to void** requires " + "Pointer to be a raw pointer (N4892 [out.ptr.t]/13)"); + return reinterpret_cast(_STD addressof(_Get_ptr())); } private: + _NODISCARD _Pointer& _Get_ptr() const noexcept { + return const_cast<_Pointer&>(_Mypair._Myval2); + } + + _NODISCARD tuple<_ArgsT...>& _Get_args() noexcept { + return _Mypair._Get_first(); + } + _SmartPtr& _Smart_ptr; - tuple<_ArgsT...> _Args; - _Pointer _Ptr{}; + _Compressed_pair, _Pointer> _Mypair; }; template @@ -4227,25 +4235,30 @@ _NODISCARD auto out_ptr(_SmartPtr& _Smart_ptr, _ArgsT&&... _Args) { template class inout_ptr_t { - static_assert(!_Is_specialization_v<_SmartPtr, shared_ptr>, "inout_ptr_t doesn't work with shared_ptr"); + static_assert(!_Is_specialization_v<_SmartPtr, shared_ptr>, + "inout_ptr_t doesn't work with shared_ptr (N4892 [inout.ptr.t]/3)"); - _NODISCARD static auto _Get_ptr(_SmartPtr& _Smart_ptr) noexcept requires is_pointer_v<_SmartPtr> { +private: + _NODISCARD static auto _Get_ptr_from_smart(_SmartPtr& _Smart_ptr) noexcept requires is_pointer_v<_SmartPtr> { return _Smart_ptr; } - _NODISCARD static auto _Get_ptr(_SmartPtr& _Smart_ptr) noexcept(noexcept(_Smart_ptr.get())) { + _NODISCARD static auto _Get_ptr_from_smart(_SmartPtr& _Smart_ptr) noexcept(noexcept(_Smart_ptr.get())) { return _Smart_ptr.get(); } public: explicit inout_ptr_t(_SmartPtr& _Smart_ptr_, _ArgsT... _Args_) noexcept( - is_nothrow_constructible_v, _ArgsT...>&& noexcept(_Get_ptr(_Smart_ptr_))) - : _Smart_ptr(_Smart_ptr_), _Args(_STD forward<_ArgsT>(_Args_)...), _Ptr(_Get_ptr(_Smart_ptr_)) {} + is_nothrow_constructible_v, _ArgsT...>&& noexcept( + _Get_ptr_from_smart(_Smart_ptr_))) /* strengthened */ + : _Smart_ptr(_Smart_ptr_), + _Mypair(_One_then_variadic_args_t{}, tuple<_ArgsT...>{_STD forward<_ArgsT>(_Args_)...}, + _Get_ptr_from_smart(_Smart_ptr_)) {} inout_ptr_t(const inout_ptr_t&) = delete; ~inout_ptr_t() { - if (!_Ptr) { + if (!_Get_ptr()) { return; } @@ -4253,33 +4266,40 @@ public: [this](auto&&... _Args_) { using _Sp = _Pointer_of_or<_SmartPtr, _Pointer>; if constexpr (is_pointer_v<_SmartPtr>) { - _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Get_ptr()), _STD forward<_ArgsT>(_Args_)...); } else if constexpr (_Resettable_pointer<_SmartPtr, _Sp, _Pointer, _ArgsT...>) { _Smart_ptr.release(); - _Smart_ptr.reset(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + _Smart_ptr.reset(static_cast<_Sp>(_Get_ptr()), _STD forward<_ArgsT>(_Args_)...); } else { - static_assert(is_constructible_v<_SmartPtr, _Sp, _ArgsT...>); + static_assert(is_constructible_v<_SmartPtr, _Sp, _ArgsT...>, "(N4892 [inout.ptr.t]/11.4)"); _Smart_ptr.release(); - _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Ptr), _STD forward<_ArgsT>(_Args_)...); + _Smart_ptr = _SmartPtr(static_cast<_Sp>(_Get_ptr()), _STD forward<_ArgsT>(_Args_)...); } }, - _STD move(_Args)); + _STD move(_Get_args())); } operator _Pointer*() const noexcept { - return _STD addressof(const_cast<_Pointer&>(_Ptr)); + return _STD addressof(_Get_ptr()); } operator void**() const noexcept requires(!is_same_v<_Pointer, void*>) { - static_assert(is_pointer_v<_Pointer>, - "conversion of inout_ptr_t to void** requires Pointer to be a raw pointer"); - return reinterpret_cast(_STD addressof(const_cast<_Pointer&>(_Ptr))); + static_assert(is_pointer_v<_Pointer>, "conversion of inout_ptr_t to void** requires " + "Pointer to be a raw pointer (N4892 [inout.ptr.t]/15)"); + return reinterpret_cast(_STD addressof(_Get_ptr())); } private: + _NODISCARD _Pointer& _Get_ptr() const noexcept { + return const_cast<_Pointer&>(_Mypair._Myval2); + } + + _NODISCARD tuple<_ArgsT...>& _Get_args() noexcept { + return _Mypair._Get_first(); + } + _SmartPtr& _Smart_ptr; - tuple<_ArgsT...> _Args; - _Pointer _Ptr; + _Compressed_pair, _Pointer> _Mypair; }; template diff --git a/tests/std/tests/P1132R7_out_ptr/test.cpp b/tests/std/tests/P1132R7_out_ptr/test.cpp index 3d655f540c..48bb41c96e 100644 --- a/tests/std/tests/P1132R7_out_ptr/test.cpp +++ b/tests/std/tests/P1132R7_out_ptr/test.cpp @@ -3,6 +3,7 @@ #include #include +#include using namespace std; @@ -23,7 +24,7 @@ void test_raw_ptr() { } { const auto f = [](void** ptr) { - assert(*reinterpret_cast(*ptr) == 7); + assert(*static_cast(*ptr) == 7); static int i = 15; *ptr = &i; }; @@ -102,7 +103,7 @@ void test_smart_ptr(Args&&... args) { } { const auto f = [](void** ptr) { - assert(*reinterpret_cast(*ptr) == 12); + assert(*static_cast(*ptr) == 12); *ptr = new int(15); }; @@ -166,7 +167,7 @@ struct constructible_ptr { } }; -struct resettable_ptr2 : public resettable_ptr { +struct resettable_ptr2 : resettable_ptr { using resettable_ptr::resettable_ptr; private: @@ -178,7 +179,7 @@ struct pointer_traits { using element_type = int; // test having only pointer_traits::element_type }; -struct constructible_ptr2 : public constructible_ptr { +struct constructible_ptr2 : constructible_ptr { using constructible_ptr::constructible_ptr; private: From d968d790a4135951c6969b54fca1be9bc67d56da Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 19 Jul 2021 21:06:22 -0700 Subject: [PATCH 8/8] Avoid clang-format 12 damage. --- stl/inc/memory | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stl/inc/memory b/stl/inc/memory index 26ccbb0115..9da84c51c7 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4211,10 +4211,12 @@ public: return reinterpret_cast(_STD addressof(_Get_ptr())); } + // clang-format off private: _NODISCARD _Pointer& _Get_ptr() const noexcept { return const_cast<_Pointer&>(_Mypair._Myval2); } + // clang-format on _NODISCARD tuple<_ArgsT...>& _Get_args() noexcept { return _Mypair._Get_first(); @@ -4289,10 +4291,12 @@ public: return reinterpret_cast(_STD addressof(_Get_ptr())); } + // clang-format off private: _NODISCARD _Pointer& _Get_ptr() const noexcept { return const_cast<_Pointer&>(_Mypair._Myval2); } + // clang-format on _NODISCARD tuple<_ArgsT...>& _Get_args() noexcept { return _Mypair._Get_first();