From 8066e804e63cee92a8216b662c5243dc69ca31b6 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 31 Jul 2022 01:10:54 +0800 Subject: [PATCH 01/15] Test __cpp_lib_forward_like --- .../test.compile.pass.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 cba8cf27342..d3db0812408 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 @@ -786,6 +786,20 @@ STATIC_ASSERT(__cpp_lib_format == 202110L); #endif #endif +#if _HAS_CXX23 +#ifndef __cpp_lib_forward_like +#error __cpp_lib_forward_like is not defined +#elif __cpp_lib_forward_like != 202207L +#error __cpp_lib_forward_like is not 202207L +#else +STATIC_ASSERT(__cpp_lib_forward_like == 202207L); +#endif +#else +#ifdef __cpp_lib_forward_like +#error __cpp_lib_forward_like is defined +#endif +#endif + #if _HAS_CXX17 #ifndef __cpp_lib_gcd_lcm #error __cpp_lib_gcd_lcm is not defined From 40639c91a85ea5dc52f3b7ed1e24688f68a285fd Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 31 Jul 2022 01:46:17 +0800 Subject: [PATCH 02/15] Test cases for std::forward_like --- tests/std/tests/P2445R1_forward_like/env.lst | 4 + .../test.compile.pass.cpp | 78 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 tests/std/tests/P2445R1_forward_like/env.lst create mode 100644 tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp diff --git a/tests/std/tests/P2445R1_forward_like/env.lst b/tests/std/tests/P2445R1_forward_like/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P2445R1_forward_like/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp new file mode 100644 index 00000000000..5ea86c8308d --- /dev/null +++ b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +using namespace std; + +struct owner_type { + inline static constinit int imut = 0; + static constexpr int iconst = 0; + + int m_mutobj = 0; + int& m_mutlref = imut; + int&& m_mutrref = move(imut); + + const int m_cobj = 0; + const int& m_clref = iconst; + const int&& m_crref = move(iconst); +}; + +constinit owner_type owner{}; +constexpr owner_type& owner_lref = owner; +constexpr owner_type&& owner_rref = move(owner); + +constexpr owner_type owner_c{}; +constexpr const owner_type& owner_clref = owner_c; +constexpr const owner_type&& owner_crref = move(owner_c); + +static_assert(is_same_v(owner.m_mutobj)), int&&>); +static_assert(is_same_v(owner.m_mutlref)), int&&>); +static_assert(is_same_v(owner.m_mutrref)), int&&>); + +static_assert(is_same_v(owner.m_cobj)), const int&&>); +static_assert(is_same_v(owner.m_clref)), const int&&>); +static_assert(is_same_v(owner.m_crref)), const int&&>); + +static_assert(is_same_v(owner_lref.m_mutobj)), int&>); +static_assert(is_same_v(owner_lref.m_mutlref)), int&>); +static_assert(is_same_v(owner_lref.m_mutrref)), int&>); + +static_assert(is_same_v(owner_lref.m_cobj)), const int&>); +static_assert(is_same_v(owner_lref.m_clref)), const int&>); +static_assert(is_same_v(owner_lref.m_crref)), const int&>); + +static_assert(is_same_v(owner_rref.m_mutobj)), int&&>); +static_assert(is_same_v(owner_rref.m_mutlref)), int&&>); +static_assert(is_same_v(owner_rref.m_mutrref)), int&&>); + +static_assert(is_same_v(owner_rref.m_cobj)), const int&&>); +static_assert(is_same_v(owner_rref.m_clref)), const int&&>); +static_assert(is_same_v(owner_rref.m_crref)), const int&&>); + +static_assert(is_same_v(owner_c.m_mutobj)), const int&&>); +static_assert(is_same_v(owner_c.m_mutlref)), const int&&>); +static_assert(is_same_v(owner_c.m_mutrref)), const int&&>); + +static_assert(is_same_v(owner_c.m_cobj)), const int&&>); +static_assert(is_same_v(owner_c.m_clref)), const int&&>); +static_assert(is_same_v(owner_c.m_crref)), const int&&>); + +static_assert(is_same_v(owner_clref.m_mutobj)), const int&>); +static_assert(is_same_v(owner_clref.m_mutlref)), const int&>); +static_assert(is_same_v(owner_clref.m_mutrref)), const int&>); + +static_assert(is_same_v(owner_clref.m_cobj)), const int&>); +static_assert(is_same_v(owner_clref.m_clref)), const int&>); +static_assert(is_same_v(owner_clref.m_crref)), const int&>); + +static_assert(is_same_v(owner_crref.m_mutobj)), const int&&>); +static_assert(is_same_v(owner_crref.m_mutlref)), const int&&>); +static_assert(is_same_v(owner_crref.m_mutrref)), const int&&>); + +static_assert(is_same_v(owner_crref.m_cobj)), const int&&>); +static_assert(is_same_v(owner_crref.m_clref)), const int&&>); +static_assert(is_same_v(owner_crref.m_crref)), const int&&>); + +int main() {} // COMPILE-ONLY From 4407f68dcffc357ac6e2d48dfa7a690689c14a77 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 31 Jul 2022 01:47:09 +0800 Subject: [PATCH 03/15] Add P2445R1_forward_like to list --- tests/std/test.lst | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/test.lst b/tests/std/test.lst index 15b0eb8f766..3d90da88ed4 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -500,6 +500,7 @@ tests\P2442R1_views_chunk_death tests\P2442R1_views_slide tests\P2443R1_views_chunk_by tests\P2443R1_views_chunk_by_death +tests\P2445R1_forward_like tests\VSO_0000000_allocator_propagation tests\VSO_0000000_any_calling_conventions tests\VSO_0000000_c_math_functions From a5927c85580f698a55921396e80f936c6f8638be Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 31 Jul 2022 02:05:07 +0800 Subject: [PATCH 04/15] Implement P2445R1 forward_like --- stl/inc/utility | 37 +++++++++++++++++++++++++++++++++++++ stl/inc/yvals_core.h | 2 ++ 2 files changed, 39 insertions(+) diff --git a/stl/inc/utility b/stl/inc/utility index 38633cd38a2..8b31de78394 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -788,6 +788,22 @@ _NODISCARD constexpr bool in_range(const _Ty _Value) noexcept { return true; } + +#ifdef __cpp_lib_concepts +template +using _With_reference = _Ty&; + +template +concept _Can_reference = requires { + typename _With_reference<_Ty>; +}; +#else +template +inline constexpr bool _Can_reference = false; + +template +inline constexpr bool _Can_reference<_Ty, void_t<_Ty&>> = true; +#endif // __cpp_lib_concepts #endif // _HAS_CXX20 #if _HAS_CXX23 @@ -802,6 +818,27 @@ _NODISCARD constexpr underlying_type_t<_Ty> to_underlying(_Ty _Value) noexcept { _CSTD abort(); // likely to be called in debug mode, but can't be relied upon - already entered the UB territory #endif // _DEBUG } + +template +constexpr auto&& forward_like(_Uty&& _Ux) noexcept { + static_assert(_Can_reference<_Ty>, + "The first template parameter of std::forward_like must be a referenceable type."); + + if constexpr (is_lvalue_reference_v<_Ty>) { + if constexpr (is_const_v>) { + return static_cast(_Ux); + } else { + return static_cast<_Uty&>(_Ux); + } + } else { + using _UnrefU = remove_reference_t<_Uty>; + if constexpr (is_const_v>) { + return static_cast(_Ux); + } else { + return static_cast<_UnrefU&&>(_Ux); + } + } +} #endif // _HAS_CXX23 #if _HAS_TR1_NAMESPACE diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 789c661abc5..975f546fbad 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -316,6 +316,7 @@ // P2441R2 views::join_with // P2442R1 Windowing Range Adaptors: views::chunk, views::slide // P2443R1 views::chunk_by +// P2445R1 forward_like() // P2499R0 string_view Range Constructor Should Be explicit // P2549R0 unexpected::error() @@ -1462,6 +1463,7 @@ #define __cpp_lib_expected 202202L #endif // __cpp_lib_concepts +#define __cpp_lib_forward_like 202207L #define __cpp_lib_invoke_r 202106L #define __cpp_lib_is_scoped_enum 202011L #define __cpp_lib_move_only_function 202110L From 52e206c7b4f5dac8ba192e7cd144f6b1ad775fc9 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 31 Jul 2022 02:08:21 +0800 Subject: [PATCH 05/15] Move _Can_reference to --- stl/inc/__msvc_iter_core.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/stl/inc/__msvc_iter_core.hpp b/stl/inc/__msvc_iter_core.hpp index 697da4cf280..f552728d36a 100644 --- a/stl/inc/__msvc_iter_core.hpp +++ b/stl/inc/__msvc_iter_core.hpp @@ -32,14 +32,6 @@ struct random_access_iterator_tag : bidirectional_iterator_tag {}; #ifdef __cpp_lib_concepts struct contiguous_iterator_tag : random_access_iterator_tag {}; -template -using _With_reference = _Ty&; - -template -concept _Can_reference = requires { - typename _With_reference<_Ty>; -}; - template concept _Dereferenceable = requires(_Ty& __t) { { *__t } -> _Can_reference; From c0cadc983f683c50ac141c585853081e127befa3 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 31 Jul 2022 02:17:35 +0800 Subject: [PATCH 06/15] Fix misreading --- stl/inc/utility | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/utility b/stl/inc/utility index 8b31de78394..9c5b4069ac3 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -824,14 +824,14 @@ constexpr auto&& forward_like(_Uty&& _Ux) noexcept { static_assert(_Can_reference<_Ty>, "The first template parameter of std::forward_like must be a referenceable type."); + using _UnrefU = remove_reference_t<_Uty>; if constexpr (is_lvalue_reference_v<_Ty>) { if constexpr (is_const_v>) { - return static_cast(_Ux); + return static_cast(_Ux); } else { - return static_cast<_Uty&>(_Ux); + return static_cast<_UnrefU&>(_Ux); } } else { - using _UnrefU = remove_reference_t<_Uty>; if constexpr (is_const_v>) { return static_cast(_Ux); } else { From 395c76a7d5db59a3401908c460928da722637d0e Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 31 Jul 2022 02:21:38 +0800 Subject: [PATCH 07/15] Clang-format --- stl/inc/utility | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/utility b/stl/inc/utility index 9c5b4069ac3..20ce475a7ef 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -821,8 +821,8 @@ _NODISCARD constexpr underlying_type_t<_Ty> to_underlying(_Ty _Value) noexcept { template constexpr auto&& forward_like(_Uty&& _Ux) noexcept { - static_assert(_Can_reference<_Ty>, - "The first template parameter of std::forward_like must be a referenceable type."); + static_assert( + _Can_reference<_Ty>, "The first template parameter of std::forward_like must be a referenceable type."); using _UnrefU = remove_reference_t<_Uty>; if constexpr (is_lvalue_reference_v<_Ty>) { From caadb2706628ecd4fc3bc35c995f5317cbeaadca Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 31 Jul 2022 02:36:04 +0800 Subject: [PATCH 08/15] Why isn't this constant expression? --- tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp index 5ea86c8308d..4309eb87306 100644 --- a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp +++ b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp @@ -19,7 +19,7 @@ struct owner_type { const int&& m_crref = move(iconst); }; -constinit owner_type owner{}; +owner_type owner{}; constexpr owner_type& owner_lref = owner; constexpr owner_type&& owner_rref = move(owner); From ea051437279a87651fe525de341d15af52a6a559 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 2 Aug 2022 10:11:22 +0800 Subject: [PATCH 09/15] Fixes according to @CaseyCarter's review comments --- stl/inc/utility | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stl/inc/utility b/stl/inc/utility index 20ce475a7ef..7e82b6711a6 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -820,9 +820,8 @@ _NODISCARD constexpr underlying_type_t<_Ty> to_underlying(_Ty _Value) noexcept { } template -constexpr auto&& forward_like(_Uty&& _Ux) noexcept { - static_assert( - _Can_reference<_Ty>, "The first template parameter of std::forward_like must be a referenceable type."); +_NODISCARD constexpr auto&& forward_like(_Uty&& _Ux) noexcept { + static_assert(_Can_reference<_Ty>, "std::forward_like's first template argument must be a referenceable type."); using _UnrefU = remove_reference_t<_Uty>; if constexpr (is_lvalue_reference_v<_Ty>) { From 0b6ddb655a72f4c83f55ffe55d1f4c5f87e45215 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 2 Aug 2022 10:53:34 +0800 Subject: [PATCH 10/15] Address @CaseyCarter's review comments and avoid nested decltype --- .../test.compile.pass.cpp | 136 ++++++++++++------ 1 file changed, 89 insertions(+), 47 deletions(-) diff --git a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp index 4309eb87306..20bf6ecdad2 100644 --- a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp +++ b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp @@ -27,52 +27,94 @@ constexpr owner_type owner_c{}; constexpr const owner_type& owner_clref = owner_c; constexpr const owner_type&& owner_crref = move(owner_c); -static_assert(is_same_v(owner.m_mutobj)), int&&>); -static_assert(is_same_v(owner.m_mutlref)), int&&>); -static_assert(is_same_v(owner.m_mutrref)), int&&>); - -static_assert(is_same_v(owner.m_cobj)), const int&&>); -static_assert(is_same_v(owner.m_clref)), const int&&>); -static_assert(is_same_v(owner.m_crref)), const int&&>); - -static_assert(is_same_v(owner_lref.m_mutobj)), int&>); -static_assert(is_same_v(owner_lref.m_mutlref)), int&>); -static_assert(is_same_v(owner_lref.m_mutrref)), int&>); - -static_assert(is_same_v(owner_lref.m_cobj)), const int&>); -static_assert(is_same_v(owner_lref.m_clref)), const int&>); -static_assert(is_same_v(owner_lref.m_crref)), const int&>); - -static_assert(is_same_v(owner_rref.m_mutobj)), int&&>); -static_assert(is_same_v(owner_rref.m_mutlref)), int&&>); -static_assert(is_same_v(owner_rref.m_mutrref)), int&&>); - -static_assert(is_same_v(owner_rref.m_cobj)), const int&&>); -static_assert(is_same_v(owner_rref.m_clref)), const int&&>); -static_assert(is_same_v(owner_rref.m_crref)), const int&&>); - -static_assert(is_same_v(owner_c.m_mutobj)), const int&&>); -static_assert(is_same_v(owner_c.m_mutlref)), const int&&>); -static_assert(is_same_v(owner_c.m_mutrref)), const int&&>); - -static_assert(is_same_v(owner_c.m_cobj)), const int&&>); -static_assert(is_same_v(owner_c.m_clref)), const int&&>); -static_assert(is_same_v(owner_c.m_crref)), const int&&>); - -static_assert(is_same_v(owner_clref.m_mutobj)), const int&>); -static_assert(is_same_v(owner_clref.m_mutlref)), const int&>); -static_assert(is_same_v(owner_clref.m_mutrref)), const int&>); - -static_assert(is_same_v(owner_clref.m_cobj)), const int&>); -static_assert(is_same_v(owner_clref.m_clref)), const int&>); -static_assert(is_same_v(owner_clref.m_crref)), const int&>); - -static_assert(is_same_v(owner_crref.m_mutobj)), const int&&>); -static_assert(is_same_v(owner_crref.m_mutlref)), const int&&>); -static_assert(is_same_v(owner_crref.m_mutrref)), const int&&>); - -static_assert(is_same_v(owner_crref.m_cobj)), const int&&>); -static_assert(is_same_v(owner_crref.m_clref)), const int&&>); -static_assert(is_same_v(owner_crref.m_crref)), const int&&>); +using owner_t = decltype(owner); +using mutobj_from_owner_t = decltype(forward_like(owner.m_mutobj)); +using mutlref_from_owner_t = decltype(forward_like(owner.m_mutlref)); +using mutrref_from_owner_t = decltype(forward_like(owner.m_mutrref)); +using cobj_from_owner_t = decltype(forward_like(owner.m_cobj)); +using clref_from_owner_t = decltype(forward_like(owner.m_clref)); +using crref_from_owner_t = decltype(forward_like(owner.m_crref)); + +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); + +using owner_lref_t = decltype(owner_lref); +using mutobj_from_owner_lref_t = decltype(forward_like(owner_lref.m_mutobj)); +using mutlref_from_owner_lref_t = decltype(forward_like(owner_lref.m_mutlref)); +using mutrref_from_owner_lref_t = decltype(forward_like(owner_lref.m_mutrref)); +using cobj_from_owner_lref_t = decltype(forward_like(owner_lref.m_cobj)); +using clref_from_owner_lref_t = decltype(forward_like(owner_lref.m_clref)); +using crref_from_owner_lref_t = decltype(forward_like(owner_lref.m_crref)); + +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); + +using owner_rref_t = decltype(owner_rref); +using mutobj_from_owner_rref_t = decltype(forward_like(owner_rref.m_mutobj)); +using mutlref_from_owner_rref_t = decltype(forward_like(owner_rref.m_mutlref)); +using mutrref_from_owner_rref_t = decltype(forward_like(owner_rref.m_mutrref)); +using cobj_from_owner_rref_t = decltype(forward_like(owner_rref.m_cobj)); +using clref_from_owner_rref_t = decltype(forward_like(owner_rref.m_clref)); +using crref_from_owner_rref_t = decltype(forward_like(owner_rref.m_crref)); + +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); + +using owner_c_t = decltype(owner_c); +using mutobj_from_owner_c_t = decltype(forward_like(owner_c.m_mutobj)); +using mutlref_from_owner_c_t = decltype(forward_like(owner_c.m_mutlref)); +using mutrref_from_owner_c_t = decltype(forward_like(owner_c.m_mutrref)); +using cobj_from_owner_c_t = decltype(forward_like(owner_c.m_cobj)); +using clref_from_owner_c_t = decltype(forward_like(owner_c.m_clref)); +using crref_from_owner_c_t = decltype(forward_like(owner_c.m_crref)); + +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); + +using owner_clref_t = decltype(owner_clref); +using mutobj_from_owner_clref_t = decltype(forward_like(owner_clref.m_mutobj)); +using mutlref_from_owner_clref_t = decltype(forward_like(owner_clref.m_mutlref)); +using mutrref_from_owner_clref_t = decltype(forward_like(owner_clref.m_mutrref)); +using cobj_from_owner_clref_t = decltype(forward_like(owner_clref.m_cobj)); +using clref_from_owner_clref_t = decltype(forward_like(owner_clref.m_clref)); +using crref_from_owner_clref_t = decltype(forward_like(owner_clref.m_crref)); + +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); + +using owner_crref_t = decltype(owner_crref); +using mutobj_from_owner_crref_t = decltype(forward_like(owner_crref.m_mutobj)); +using mutlref_from_owner_crref_t = decltype(forward_like(owner_crref.m_mutlref)); +using mutrref_from_owner_crref_t = decltype(forward_like(owner_crref.m_mutrref)); +using cobj_from_owner_crref_t = decltype(forward_like(owner_crref.m_cobj)); +using clref_from_owner_crref_t = decltype(forward_like(owner_crref.m_clref)); +using crref_from_owner_crref_t = decltype(forward_like(owner_crref.m_crref)); + +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); int main() {} // COMPILE-ONLY From c4a9298fbe7b843f465df50f6d23af0ae21f8ede Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 2 Aug 2022 13:48:10 +0800 Subject: [PATCH 11/15] Adpot @CaseyCarter's test coverage --- .../test.compile.pass.cpp | 159 ++++++------------ 1 file changed, 49 insertions(+), 110 deletions(-) diff --git a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp index 20bf6ecdad2..b83c071f548 100644 --- a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp +++ b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp @@ -6,115 +6,54 @@ using namespace std; -struct owner_type { - inline static constinit int imut = 0; - static constexpr int iconst = 0; - - int m_mutobj = 0; - int& m_mutlref = imut; - int&& m_mutrref = move(imut); - - const int m_cobj = 0; - const int& m_clref = iconst; - const int&& m_crref = move(iconst); -}; - -owner_type owner{}; -constexpr owner_type& owner_lref = owner; -constexpr owner_type&& owner_rref = move(owner); - -constexpr owner_type owner_c{}; -constexpr const owner_type& owner_clref = owner_c; -constexpr const owner_type&& owner_crref = move(owner_c); - -using owner_t = decltype(owner); -using mutobj_from_owner_t = decltype(forward_like(owner.m_mutobj)); -using mutlref_from_owner_t = decltype(forward_like(owner.m_mutlref)); -using mutrref_from_owner_t = decltype(forward_like(owner.m_mutrref)); -using cobj_from_owner_t = decltype(forward_like(owner.m_cobj)); -using clref_from_owner_t = decltype(forward_like(owner.m_clref)); -using crref_from_owner_t = decltype(forward_like(owner.m_crref)); - -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); - -using owner_lref_t = decltype(owner_lref); -using mutobj_from_owner_lref_t = decltype(forward_like(owner_lref.m_mutobj)); -using mutlref_from_owner_lref_t = decltype(forward_like(owner_lref.m_mutlref)); -using mutrref_from_owner_lref_t = decltype(forward_like(owner_lref.m_mutrref)); -using cobj_from_owner_lref_t = decltype(forward_like(owner_lref.m_cobj)); -using clref_from_owner_lref_t = decltype(forward_like(owner_lref.m_clref)); -using crref_from_owner_lref_t = decltype(forward_like(owner_lref.m_crref)); - -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); - -using owner_rref_t = decltype(owner_rref); -using mutobj_from_owner_rref_t = decltype(forward_like(owner_rref.m_mutobj)); -using mutlref_from_owner_rref_t = decltype(forward_like(owner_rref.m_mutlref)); -using mutrref_from_owner_rref_t = decltype(forward_like(owner_rref.m_mutrref)); -using cobj_from_owner_rref_t = decltype(forward_like(owner_rref.m_cobj)); -using clref_from_owner_rref_t = decltype(forward_like(owner_rref.m_clref)); -using crref_from_owner_rref_t = decltype(forward_like(owner_rref.m_crref)); - -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); - -using owner_c_t = decltype(owner_c); -using mutobj_from_owner_c_t = decltype(forward_like(owner_c.m_mutobj)); -using mutlref_from_owner_c_t = decltype(forward_like(owner_c.m_mutlref)); -using mutrref_from_owner_c_t = decltype(forward_like(owner_c.m_mutrref)); -using cobj_from_owner_c_t = decltype(forward_like(owner_c.m_cobj)); -using clref_from_owner_c_t = decltype(forward_like(owner_c.m_clref)); -using crref_from_owner_c_t = decltype(forward_like(owner_c.m_crref)); - -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); - -using owner_clref_t = decltype(owner_clref); -using mutobj_from_owner_clref_t = decltype(forward_like(owner_clref.m_mutobj)); -using mutlref_from_owner_clref_t = decltype(forward_like(owner_clref.m_mutlref)); -using mutrref_from_owner_clref_t = decltype(forward_like(owner_clref.m_mutrref)); -using cobj_from_owner_clref_t = decltype(forward_like(owner_clref.m_cobj)); -using clref_from_owner_clref_t = decltype(forward_like(owner_clref.m_clref)); -using crref_from_owner_clref_t = decltype(forward_like(owner_clref.m_crref)); - -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); - -using owner_crref_t = decltype(owner_crref); -using mutobj_from_owner_crref_t = decltype(forward_like(owner_crref.m_mutobj)); -using mutlref_from_owner_crref_t = decltype(forward_like(owner_crref.m_mutlref)); -using mutrref_from_owner_crref_t = decltype(forward_like(owner_crref.m_mutrref)); -using cobj_from_owner_crref_t = decltype(forward_like(owner_crref.m_cobj)); -using clref_from_owner_crref_t = decltype(forward_like(owner_crref.m_clref)); -using crref_from_owner_crref_t = decltype(forward_like(owner_crref.m_crref)); - -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert(is_same_v); +struct T {}; // class type so const-qualification is not stripped from a prvalue +using CT = const T; +using U = int; +using CU = const U; + +T t{}; +const T& ct = t; + +static_assert(is_same_v(T{})), T&&>); +static_assert(is_same_v(CT{})), CT&&>); +static_assert(is_same_v(t)), T&&>); +static_assert(is_same_v(ct)), CT&&>); +static_assert(is_same_v(move(t))), T&&>); +static_assert(is_same_v(move(ct))), CT&&>); + +static_assert(is_same_v(T{})), CT&&>); +static_assert(is_same_v(CT{})), CT&&>); +static_assert(is_same_v(t)), CT&&>); +static_assert(is_same_v(ct)), CT&&>); +static_assert(is_same_v(move(t))), CT&&>); +static_assert(is_same_v(move(ct))), CT&&>); + +static_assert(is_same_v(T{})), T&>); +static_assert(is_same_v(CT{})), CT&>); +static_assert(is_same_v(t)), T&>); +static_assert(is_same_v(ct)), CT&>); +static_assert(is_same_v(move(t))), T&>); +static_assert(is_same_v(move(ct))), CT&>); + +static_assert(is_same_v(T{})), CT&>); +static_assert(is_same_v(CT{})), CT&>); +static_assert(is_same_v(t)), CT&>); +static_assert(is_same_v(ct)), CT&>); +static_assert(is_same_v(move(t))), CT&>); +static_assert(is_same_v(move(ct))), CT&>); + +static_assert(is_same_v(T{})), T&&>); +static_assert(is_same_v(CT{})), CT&&>); +static_assert(is_same_v(t)), T&&>); +static_assert(is_same_v(ct)), CT&&>); +static_assert(is_same_v(move(t))), T&&>); +static_assert(is_same_v(move(ct))), CT&&>); + +static_assert(is_same_v(T{})), CT&&>); +static_assert(is_same_v(CT{})), CT&&>); +static_assert(is_same_v(t)), CT&&>); +static_assert(is_same_v(ct)), CT&&>); +static_assert(is_same_v(move(t))), CT&&>); +static_assert(is_same_v(move(ct))), CT&&>); int main() {} // COMPILE-ONLY From a0aad9bef97912ffc00508d357355a0f4906e02d Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 4 Aug 2022 10:04:53 +0800 Subject: [PATCH 12/15] Swap type aliases to be consistent with the paper --- .../test.compile.pass.cpp | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp index b83c071f548..250c1207434 100644 --- a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp +++ b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp @@ -6,54 +6,54 @@ using namespace std; -struct T {}; // class type so const-qualification is not stripped from a prvalue -using CT = const T; -using U = int; +struct U {}; // class type so const-qualification is not stripped from a prvalue using CU = const U; +using T = int; +using CT = const T; -T t{}; -const T& ct = t; - -static_assert(is_same_v(T{})), T&&>); -static_assert(is_same_v(CT{})), CT&&>); -static_assert(is_same_v(t)), T&&>); -static_assert(is_same_v(ct)), CT&&>); -static_assert(is_same_v(move(t))), T&&>); -static_assert(is_same_v(move(ct))), CT&&>); - -static_assert(is_same_v(T{})), CT&&>); -static_assert(is_same_v(CT{})), CT&&>); -static_assert(is_same_v(t)), CT&&>); -static_assert(is_same_v(ct)), CT&&>); -static_assert(is_same_v(move(t))), CT&&>); -static_assert(is_same_v(move(ct))), CT&&>); - -static_assert(is_same_v(T{})), T&>); -static_assert(is_same_v(CT{})), CT&>); -static_assert(is_same_v(t)), T&>); -static_assert(is_same_v(ct)), CT&>); -static_assert(is_same_v(move(t))), T&>); -static_assert(is_same_v(move(ct))), CT&>); - -static_assert(is_same_v(T{})), CT&>); -static_assert(is_same_v(CT{})), CT&>); -static_assert(is_same_v(t)), CT&>); -static_assert(is_same_v(ct)), CT&>); -static_assert(is_same_v(move(t))), CT&>); -static_assert(is_same_v(move(ct))), CT&>); - -static_assert(is_same_v(T{})), T&&>); -static_assert(is_same_v(CT{})), CT&&>); -static_assert(is_same_v(t)), T&&>); -static_assert(is_same_v(ct)), CT&&>); -static_assert(is_same_v(move(t))), T&&>); -static_assert(is_same_v(move(ct))), CT&&>); - -static_assert(is_same_v(T{})), CT&&>); -static_assert(is_same_v(CT{})), CT&&>); -static_assert(is_same_v(t)), CT&&>); -static_assert(is_same_v(ct)), CT&&>); -static_assert(is_same_v(move(t))), CT&&>); -static_assert(is_same_v(move(ct))), CT&&>); +U t{}; +const U& ct = t; + +static_assert(is_same_v(U{})), U&&>); +static_assert(is_same_v(CU{})), CU&&>); +static_assert(is_same_v(t)), U&&>); +static_assert(is_same_v(ct)), CU&&>); +static_assert(is_same_v(move(t))), U&&>); +static_assert(is_same_v(move(ct))), CU&&>); + +static_assert(is_same_v(U{})), CU&&>); +static_assert(is_same_v(CU{})), CU&&>); +static_assert(is_same_v(t)), CU&&>); +static_assert(is_same_v(ct)), CU&&>); +static_assert(is_same_v(move(t))), CU&&>); +static_assert(is_same_v(move(ct))), CU&&>); + +static_assert(is_same_v(U{})), U&>); +static_assert(is_same_v(CU{})), CU&>); +static_assert(is_same_v(t)), U&>); +static_assert(is_same_v(ct)), CU&>); +static_assert(is_same_v(move(t))), U&>); +static_assert(is_same_v(move(ct))), CU&>); + +static_assert(is_same_v(U{})), CU&>); +static_assert(is_same_v(CU{})), CU&>); +static_assert(is_same_v(t)), CU&>); +static_assert(is_same_v(ct)), CU&>); +static_assert(is_same_v(move(t))), CU&>); +static_assert(is_same_v(move(ct))), CU&>); + +static_assert(is_same_v(U{})), U&&>); +static_assert(is_same_v(CU{})), CU&&>); +static_assert(is_same_v(t)), U&&>); +static_assert(is_same_v(ct)), CU&&>); +static_assert(is_same_v(move(t))), U&&>); +static_assert(is_same_v(move(ct))), CU&&>); + +static_assert(is_same_v(U{})), CU&&>); +static_assert(is_same_v(CU{})), CU&&>); +static_assert(is_same_v(t)), CU&&>); +static_assert(is_same_v(ct)), CU&&>); +static_assert(is_same_v(move(t))), CU&&>); +static_assert(is_same_v(move(ct))), CU&&>); int main() {} // COMPILE-ONLY From 1c797218f09cc2053121afd397ad4100a042b457 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 4 Aug 2022 11:08:01 +0800 Subject: [PATCH 13/15] Partially address @strega-nil-ms's review comments --- stl/inc/utility | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/stl/inc/utility b/stl/inc/utility index 7e82b6711a6..500581d676e 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -823,16 +823,17 @@ template _NODISCARD constexpr auto&& forward_like(_Uty&& _Ux) noexcept { static_assert(_Can_reference<_Ty>, "std::forward_like's first template argument must be a referenceable type."); + using _UnrefT = remove_reference_t<_Ty>; using _UnrefU = remove_reference_t<_Uty>; - if constexpr (is_lvalue_reference_v<_Ty>) { - if constexpr (is_const_v>) { + if constexpr (is_const_v<_UnrefT>) { + if constexpr (is_lvalue_reference_v<_Ty>) { return static_cast(_Ux); } else { - return static_cast<_UnrefU&>(_Ux); + return static_cast(_Ux); } } else { - if constexpr (is_const_v>) { - return static_cast(_Ux); + if constexpr (is_lvalue_reference_v<_Ty>) { + return static_cast<_UnrefU&>(_Ux); } else { return static_cast<_UnrefU&&>(_Ux); } From c85fa437469d042f2d1a457794e0797a3384f8bf Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 4 Aug 2022 11:37:04 +0800 Subject: [PATCH 14/15] Complete renaming --- .../test.compile.pass.cpp | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp index 250c1207434..ad44a7a0bba 100644 --- a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp +++ b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp @@ -11,49 +11,49 @@ using CU = const U; using T = int; using CT = const T; -U t{}; -const U& ct = t; +U u{}; +const U& cu = u; static_assert(is_same_v(U{})), U&&>); static_assert(is_same_v(CU{})), CU&&>); -static_assert(is_same_v(t)), U&&>); -static_assert(is_same_v(ct)), CU&&>); -static_assert(is_same_v(move(t))), U&&>); -static_assert(is_same_v(move(ct))), CU&&>); +static_assert(is_same_v(u)), U&&>); +static_assert(is_same_v(cu)), CU&&>); +static_assert(is_same_v(move(u))), U&&>); +static_assert(is_same_v(move(cu))), CU&&>); static_assert(is_same_v(U{})), CU&&>); static_assert(is_same_v(CU{})), CU&&>); -static_assert(is_same_v(t)), CU&&>); -static_assert(is_same_v(ct)), CU&&>); -static_assert(is_same_v(move(t))), CU&&>); -static_assert(is_same_v(move(ct))), CU&&>); +static_assert(is_same_v(u)), CU&&>); +static_assert(is_same_v(cu)), CU&&>); +static_assert(is_same_v(move(u))), CU&&>); +static_assert(is_same_v(move(cu))), CU&&>); static_assert(is_same_v(U{})), U&>); static_assert(is_same_v(CU{})), CU&>); -static_assert(is_same_v(t)), U&>); -static_assert(is_same_v(ct)), CU&>); -static_assert(is_same_v(move(t))), U&>); -static_assert(is_same_v(move(ct))), CU&>); +static_assert(is_same_v(u)), U&>); +static_assert(is_same_v(cu)), CU&>); +static_assert(is_same_v(move(u))), U&>); +static_assert(is_same_v(move(cu))), CU&>); static_assert(is_same_v(U{})), CU&>); static_assert(is_same_v(CU{})), CU&>); -static_assert(is_same_v(t)), CU&>); -static_assert(is_same_v(ct)), CU&>); -static_assert(is_same_v(move(t))), CU&>); -static_assert(is_same_v(move(ct))), CU&>); +static_assert(is_same_v(u)), CU&>); +static_assert(is_same_v(cu)), CU&>); +static_assert(is_same_v(move(u))), CU&>); +static_assert(is_same_v(move(cu))), CU&>); static_assert(is_same_v(U{})), U&&>); static_assert(is_same_v(CU{})), CU&&>); -static_assert(is_same_v(t)), U&&>); -static_assert(is_same_v(ct)), CU&&>); -static_assert(is_same_v(move(t))), U&&>); -static_assert(is_same_v(move(ct))), CU&&>); +static_assert(is_same_v(u)), U&&>); +static_assert(is_same_v(cu)), CU&&>); +static_assert(is_same_v(move(u))), U&&>); +static_assert(is_same_v(move(cu))), CU&&>); static_assert(is_same_v(U{})), CU&&>); static_assert(is_same_v(CU{})), CU&&>); -static_assert(is_same_v(t)), CU&&>); -static_assert(is_same_v(ct)), CU&&>); -static_assert(is_same_v(move(t))), CU&&>); -static_assert(is_same_v(move(ct))), CU&&>); +static_assert(is_same_v(u)), CU&&>); +static_assert(is_same_v(cu)), CU&&>); +static_assert(is_same_v(move(u))), CU&&>); +static_assert(is_same_v(move(cu))), CU&&>); int main() {} // COMPILE-ONLY From 448f6fa3ec8205973f8d8063002e30a7cfc7ae1a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 3 Aug 2022 22:16:53 -0700 Subject: [PATCH 15/15] Add comment, expand test slightly. --- stl/inc/utility | 2 +- .../P2445R1_forward_like/test.compile.pass.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/stl/inc/utility b/stl/inc/utility index 500581d676e..c649a212904 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -797,7 +797,7 @@ template concept _Can_reference = requires { typename _With_reference<_Ty>; }; -#else +#else // __cpp_lib_concepts template inline constexpr bool _Can_reference = false; diff --git a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp index ad44a7a0bba..3787ed8055d 100644 --- a/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp +++ b/tests/std/tests/P2445R1_forward_like/test.compile.pass.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include @@ -56,4 +57,16 @@ static_assert(is_same_v(cu)), CU&&>); static_assert(is_same_v(move(u))), CU&&>); static_assert(is_same_v(move(cu))), CU&&>); +static_assert(noexcept(forward_like(u))); + +constexpr bool test() { + int val = 1729; + auto&& result = forward_like(val); + static_assert(is_same_v); + assert(&result == &val); + return true; +} + +static_assert(test()); + int main() {} // COMPILE-ONLY