diff --git a/libcxx/docs/Cxx2aStatusIssuesStatus.csv b/libcxx/docs/Cxx2aStatusIssuesStatus.csv --- a/libcxx/docs/Cxx2aStatusIssuesStatus.csv +++ b/libcxx/docs/Cxx2aStatusIssuesStatus.csv @@ -35,7 +35,7 @@ "`2981 `__","Remove redundant deduction guides from standard library","Albuquerque","","" "`2982 `__","Making size_type consistent in associative container deduction guides","Albuquerque","","" "`2988 `__","Clause 32 cleanup missed one typename","Albuquerque","","" -"`2993 `__","reference_wrapper conversion from T&&","Albuquerque","","" +"`2993 `__","reference_wrapper conversion from T&&","Albuquerque","|Complete|","13.0" "`2998 `__","Requirements on function objects passed to {``forward_``,}list-specific algorithms","Albuquerque","|Nothing To Do|","" "`3001 `__","weak_ptr::element_type needs remove_extent_t","Albuquerque","","" "`3024 `__","variant's copies must be deleted instead of disabled via SFINAE","Albuquerque","|Complete|","" diff --git a/libcxx/include/__functional_base b/libcxx/include/__functional_base --- a/libcxx/include/__functional_base +++ b/libcxx/include/__functional_base @@ -380,13 +380,24 @@ private: type* __f_; +#ifndef _LIBCPP_CXX03_LANG + static void __fun(_Tp&) _NOEXCEPT; + static void __fun(_Tp&&) = delete; +#endif + public: // construct/copy/destroy - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 +#ifdef _LIBCPP_CXX03_LANG + _LIBCPP_INLINE_VISIBILITY reference_wrapper(type& __f) _NOEXCEPT : __f_(_VSTD::addressof(__f)) {} -#ifndef _LIBCPP_CXX03_LANG - private: reference_wrapper(type&&); public: // = delete; // do not bind to temps +#else + template ::value, decltype(__fun(_VSTD::declval<_Up>())) >> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + reference_wrapper(_Up&& __u) _NOEXCEPT_(noexcept(__fun(_VSTD::declval<_Up>()))) { + type& __f = static_cast<_Up&&>(__u); + __f_ = _VSTD::addressof(__f); + } #endif // access @@ -511,6 +522,10 @@ #endif // _LIBCPP_CXX03_LANG }; +#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES +template +reference_wrapper(_Tp&) -> reference_wrapper<_Tp>; +#endif template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -42,8 +42,8 @@ typedef see below result_type; // Not always defined // construct/copy/destroy - reference_wrapper(T&) noexcept; - reference_wrapper(T&&) = delete; // do not bind to temps + template + reference_wrapper(U&&); reference_wrapper(const reference_wrapper& x) noexcept; // assignment @@ -59,6 +59,9 @@ operator() (ArgTypes&&...) const; }; +template + reference_wrapper(T&) -> reference_wrapper; + template reference_wrapper ref(T& t) noexcept; template void ref(const T&& t) = delete; template reference_wrapper ref(reference_wrappert) noexcept; diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.assign/copy_assign.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.assign/copy_assign.pass.cpp --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.assign/copy_assign.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.assign/copy_assign.pass.cpp @@ -21,6 +21,12 @@ { }; +struct convertible_to_int_ref { + int val = 0; + operator int&() { return val; } + operator int const&() const { return val; } +}; + template void test(T& t) @@ -56,5 +62,19 @@ const int j = 0; test(j); +#if TEST_STD_VER >= 11 + convertible_to_int_ref convi; + test(convi); + convertible_to_int_ref const convic; + test(convic); + + { + using Ref = std::reference_wrapper; + static_assert((std::is_assignable::value), ""); + static_assert((!std::is_assignable::value), ""); + static_assert((!std::is_assignable::value), ""); + } +#endif + return 0; } diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/deduct.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/deduct.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/deduct.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: libcpp-no-deduction-guides + +// + +// template +// reference_wrapper(T&) -> reference_wrapper; + +#include + +int main() +{ + int i = 0; + std::reference_wrapper ri(i); + static_assert(std::is_same_v>); + std::reference_wrapper ri2(ri); + static_assert(std::is_same_v>); + const int j = 0; + std::reference_wrapper rj(j); + static_assert(std::is_same_v>); + std::reference_wrapper rj2(rj); + static_assert(std::is_same_v>); +} diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +// +// +// reference_wrapper +// +// template +// reference_wrapper(U&&) noexcept(see below); + +#include +#include + +struct convertible_to_int_ref { + int val = 0; + operator int&() { return val; } + operator int const&() const { return val; } +}; + +template +struct nothrow_convertible { + int val = 0; + operator int&() noexcept(IsNothrow) { return val; } +}; + +struct convertible_from_int { + convertible_from_int(int) {} +}; + +void meow(std::reference_wrapper) {} +void meow(convertible_from_int) {} + +int gi; +std::reference_wrapper purr() { return gi; }; + +template +void +test(T& t) +{ + std::reference_wrapper r(t); + assert(&r.get() == &t); +} + +void f() {} + +int main() +{ + convertible_to_int_ref convi; + test(convi); + convertible_to_int_ref const convic; + test(convic); + + { + using Ref = std::reference_wrapper; + static_assert((std::is_nothrow_constructible>::value), ""); + static_assert((!std::is_nothrow_constructible>::value), ""); + } + + { + meow(0); + (true) ? purr() : 0; + } + +#ifdef __cpp_deduction_guides + { + int i = 0; + std::reference_wrapper ri(i); + static_assert((std::is_same>::value), "" ); + const int j = 0; + std::reference_wrapper rj(j); + static_assert((std::is_same>::value), "" ); + } +#endif +} diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor2.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor2.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_conv_ctor2.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +// +// +// reference_wrapper +// +// template +// reference_wrapper(U&&); + +#include +#include + +struct B {} b; + +struct A1 { + operator B& () const { return b; } +}; +struct A2 { + operator B& () const noexcept { return b; } +}; + +int main() +{ + { + std::reference_wrapper b1 = A1(); + assert(&b1.get() == &b); + b1 = A1(); + assert(&b1.get() == &b); + + static_assert(std::is_convertible>::value, ""); + static_assert(!std::is_nothrow_constructible, A1>::value, ""); +#if TEST_STD_VER >= 20 + static_assert(!std::is_nothrow_convertible_v>); +#endif + static_assert(std::is_assignable, A1>::value, ""); + static_assert(!std::is_nothrow_assignable, A1>::value, ""); + } + + { + std::reference_wrapper b2 = A2(); + assert(&b2.get() == &b); + b2 = A2(); + assert(&b2.get() == &b); + + static_assert(std::is_convertible>::value, ""); + static_assert(std::is_nothrow_constructible, A2>::value, ""); +#if TEST_STD_VER >= 20 + static_assert(std::is_nothrow_convertible_v>); +#endif + static_assert(std::is_assignable, A2>::value, ""); + static_assert(std::is_nothrow_assignable, A2>::value, ""); + } +} diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_ctor.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_ctor.pass.cpp --- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_ctor.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.const/type_ctor.pass.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "test_macros.h" @@ -43,5 +44,21 @@ const int j = 0; test(j); + { + using Ref = std::reference_wrapper; + static_assert((std::is_constructible::value), ""); + static_assert((!std::is_constructible::value), ""); + static_assert((!std::is_constructible::value), ""); + } + +#if TEST_STD_VER >= 11 + { + using Ref = std::reference_wrapper; + static_assert((std::is_nothrow_constructible::value), ""); + static_assert((!std::is_nothrow_constructible::value), ""); + static_assert((!std::is_nothrow_constructible::value), ""); + } +#endif + return 0; }