Author: ericwf Date: Sat Apr 15 14:32:02 2017 New Revision: 300403 URL: http://llvm.org/viewvc/llvm-project?rev=300403&view=rev Log: Implement LWG 2857 for variant. Tests from Casey Carter @ Microsoft.
Also mark LWG 2857 as complete, since the changes to optional and any were completed by Marshall earlier. Modified: libcxx/trunk/include/variant libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp libcxx/trunk/www/cxx1z_status.html Modified: libcxx/trunk/include/variant URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/variant?rev=300403&r1=300402&r2=300403&view=diff ============================================================================== --- libcxx/trunk/include/variant (original) +++ libcxx/trunk/include/variant Sat Apr 15 14:32:02 2017 @@ -53,16 +53,16 @@ namespace std { // 20.7.2.4, modifiers template <class T, class... Args> - void emplace(Args&&...); + T& emplace(Args&&...); template <class T, class U, class... Args> - void emplace(initializer_list<U>, Args&&...); + T& emplace(initializer_list<U>, Args&&...); template <size_t I, class... Args> - void emplace(Args&&...); + variant_alternative_t<I, variant>& emplace(Args&&...); template <size_t I, class U, class... Args> - void emplace(initializer_list<U>, Args&&...); + variant_alternative_t<I, variant>& emplace(initializer_list<U>, Args&&...); // 20.7.2.5, value status constexpr bool valueless_by_exception() const noexcept; @@ -764,9 +764,10 @@ public: protected: template <size_t _Ip, class _Tp, class... _Args> inline _LIBCPP_INLINE_VISIBILITY - static void __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) { - ::new (_VSTD::addressof(__a)) + static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) { + ::new ((void*)_VSTD::addressof(__a)) __alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...); + return __a.__value; } template <class _Rhs> @@ -876,11 +877,12 @@ public: template <size_t _Ip, class... _Args> inline _LIBCPP_INLINE_VISIBILITY - void __emplace(_Args&&... __args) { + auto& __emplace(_Args&&... __args) { this->__destroy(); - this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), + auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), _VSTD::forward<_Args>(__args)...); this->__index = _Ip; + return __res; } protected: @@ -1218,8 +1220,8 @@ public: class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0> inline _LIBCPP_INLINE_VISIBILITY - void emplace(_Args&&... __args) { - __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); + _Tp& emplace(_Args&&... __args) { + return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); } template < @@ -1231,8 +1233,8 @@ public: enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, int> = 0> inline _LIBCPP_INLINE_VISIBILITY - void emplace(initializer_list<_Up> __il, _Args&&... __args) { - __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); + _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { + return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); } template < @@ -1242,8 +1244,8 @@ public: __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0> inline _LIBCPP_INLINE_VISIBILITY - void emplace(_Args&&... __args) { - __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); + _Tp& emplace(_Args&&... __args) { + return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); } template < @@ -1255,8 +1257,8 @@ public: enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, int> = 0> inline _LIBCPP_INLINE_VISIBILITY - void emplace(initializer_list<_Up> __il, _Args&&... __args) { - __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); + _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { + return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); } inline _LIBCPP_INLINE_VISIBILITY Modified: libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp?rev=300403&r1=300402&r2=300403&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp Sat Apr 15 14:32:02 2017 @@ -14,7 +14,8 @@ // template <class ...Types> class variant; -// template <size_t I, class ...Args> void emplace(Args&&... args); +// template <size_t I, class ...Args> +// variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args); #include <cassert> #include <string> @@ -85,10 +86,14 @@ void test_basic() { { using V = std::variant<int>; V v(42); - v.emplace<0>(); + auto& ref1 = v.emplace<0>(); + static_assert(std::is_same_v<int&, decltype(ref1)>, ""); assert(std::get<0>(v) == 0); - v.emplace<0>(42); + assert(&ref1 == &std::get<0>(v)); + auto& ref2 = v.emplace<0>(42); + static_assert(std::is_same_v<int&, decltype(ref2)>, ""); assert(std::get<0>(v) == 42); + assert(&ref2 == &std::get<0>(v)); } { using V = @@ -96,13 +101,19 @@ void test_basic() { const int x = 100; V v(std::in_place_index<0>, -1); // default emplace a value - v.emplace<1>(); + auto& ref1 = v.emplace<1>(); + static_assert(std::is_same_v<long&, decltype(ref1)>, ""); assert(std::get<1>(v) == 0); - v.emplace<2>(&x); + assert(&ref1 == &std::get<1>(v)); + auto& ref2 = v.emplace<2>(&x); + static_assert(std::is_same_v<const void*&, decltype(ref2)>, ""); assert(std::get<2>(v) == &x); + assert(&ref2 == &std::get<2>(v)); // emplace with multiple args - v.emplace<4>(3, 'a'); + auto& ref3 = v.emplace<4>(3, 'a'); + static_assert(std::is_same_v<std::string&, decltype(ref3)>, ""); assert(std::get<4>(v) == "aaa"); + assert(&ref3 == &std::get<4>(v)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { @@ -113,20 +124,30 @@ void test_basic() { int z = 43; V v(std::in_place_index<0>, -1); // default emplace a value - v.emplace<1>(); + auto& ref1 = v.emplace<1>(); + static_assert(std::is_same_v<long&, decltype(ref1)>, ""); assert(std::get<1>(v) == 0); + assert(&ref1 == &std::get<1>(v)); // emplace a reference - v.emplace<2>(x); + auto& ref2 = v.emplace<2>(x); + static_assert(std::is_same_v<&, decltype(ref)>, ""); assert(&std::get<2>(v) == &x); + assert(&ref2 == &std::get<2>(v)); // emplace an rvalue reference - v.emplace<3>(std::move(y)); + auto& ref3 = v.emplace<3>(std::move(y)); + static_assert(std::is_same_v<&, decltype(ref)>, ""); assert(&std::get<3>(v) == &y); + assert(&ref3 == &std::get<3>(v)); // re-emplace a new reference over the active member - v.emplace<3>(std::move(z)); + auto& ref4 = v.emplace<3>(std::move(z)); + static_assert(std::is_same_v<&, decltype(ref)>, ""); assert(&std::get<3>(v) == &z); + assert(&ref4 == &std::get<3>(v)); // emplace with multiple args - v.emplace<5>(3, 'a'); + auto& ref5 = v.emplace<5>(3, 'a'); + static_assert(std::is_same_v<std::string&, decltype(ref5)>, ""); assert(std::get<5>(v) == "aaa"); + assert(&ref5 == &std::get<5>(v)); } #endif } Modified: libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp?rev=300403&r1=300402&r2=300403&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp Sat Apr 15 14:32:02 2017 @@ -15,7 +15,7 @@ // template <class ...Types> class variant; // template <size_t I, class U, class ...Args> -// void emplace(initializer_list<U> il,Args&&... args); +// variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U> il,Args&&... args); #include <cassert> #include <string> @@ -70,13 +70,19 @@ void test_emplace_sfinae() { void test_basic() { using V = std::variant<int, InitList, InitListArg, TestTypes::NoCtors>; V v; - v.emplace<1>({1, 2, 3}); + auto& ref1 = v.emplace<1>({1, 2, 3}); + static_assert(std::is_same_v<InitList&, decltype(ref1)>, ""); assert(std::get<1>(v).size == 3); - v.emplace<2>({1, 2, 3, 4}, 42); + assert(&ref1 == &std::get<1>(v)); + auto& ref2 = v.emplace<2>({1, 2, 3, 4}, 42); + static_assert(std::is_same_v<InitListArg&, decltype(ref2)>, ""); assert(std::get<2>(v).size == 4); assert(std::get<2>(v).value == 42); - v.emplace<1>({1}); + assert(&ref2 == &std::get<2>(v)); + auto& ref3 = v.emplace<1>({1}); + static_assert(std::is_same_v<InitList&, decltype(ref3)>, ""); assert(std::get<1>(v).size == 1); + assert(&ref3 == &std::get<1>(v)); } int main() { Modified: libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp?rev=300403&r1=300402&r2=300403&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp Sat Apr 15 14:32:02 2017 @@ -14,7 +14,7 @@ // template <class ...Types> class variant; -// template <class T, class ...Args> void emplace(Args&&... args); +// template <class T, class ...Args> T& emplace(Args&&... args); #include <cassert> #include <string> @@ -86,10 +86,14 @@ void test_basic() { { using V = std::variant<int>; V v(42); - v.emplace<int>(); + auto& ref1 = v.emplace<int>(); + static_assert(std::is_same_v<int&, decltype(ref1)>, ""); assert(std::get<0>(v) == 0); - v.emplace<int>(42); + assert(&ref1 == &std::get<0>(v)); + auto& ref2 = v.emplace<int>(42); + static_assert(std::is_same_v<int&, decltype(ref2)>, ""); assert(std::get<0>(v) == 42); + assert(&ref2 == &std::get<0>(v)); } { using V = @@ -97,13 +101,19 @@ void test_basic() { const int x = 100; V v(std::in_place_type<int>, -1); // default emplace a value - v.emplace<long>(); + auto& ref1 = v.emplace<long>(); + static_assert(std::is_same_v<long&, decltype(ref1)>, ""); assert(std::get<1>(v) == 0); - v.emplace<const void *>(&x); + assert(&ref1 == &std::get<1>(v)); + auto& ref2 = v.emplace<const void *>(&x); + static_assert(std::is_same_v<const void *&, decltype(ref2)>, ""); assert(std::get<2>(v) == &x); + assert(&ref2 == &std::get<2>(v)); // emplace with multiple args - v.emplace<std::string>(3, 'a'); + auto& ref3 = v.emplace<std::string>(3, 'a'); + static_assert(std::is_same_v<std::string&, decltype(ref3)>, ""); assert(std::get<4>(v) == "aaa"); + assert(&ref3 == &std::get<4>(v)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { @@ -114,20 +124,30 @@ void test_basic() { int z = 43; V v(std::in_place_index<0>, -1); // default emplace a value - v.emplace<long>(); + auto& ref1 = v.emplace<long>(); + static_assert(std::is_same_v<long&, decltype(ref1)>, ""); assert(std::get<long>(v) == 0); + assert(&ref1 == &std::get<long>(v)); // emplace a reference - v.emplace<const int &>(x); + auto& ref2 = v.emplace<const int &>(x); + static_assert(std::is_same_v<const int&, decltype(ref2)>, ""); assert(&std::get<const int &>(v) == &x); + assert(&ref2 == &std::get<const int &>(v)); // emplace an rvalue reference - v.emplace<int &&>(std::move(y)); + auto& ref3 = v.emplace<int &&>(std::move(y)); + static_assert(std::is_same_v<int &&, decltype(ref3)>, ""); assert(&std::get<int &&>(v) == &y); + assert(&ref3 == &std::get<int &&>(v)); // re-emplace a new reference over the active member - v.emplace<int &&>(std::move(z)); + auto& ref4 = v.emplace<int &&>(std::move(z)); + static_assert(std::is_same_v<int &, decltype(ref4)>, ""); assert(&std::get<int &&>(v) == &z); + assert(&ref4 == &std::get<int &&>(v)); // emplace with multiple args - v.emplace<std::string>(3, 'a'); + auto& ref5 = v.emplace<std::string>(3, 'a'); + static_assert(std::is_same_v<std::string&, decltype(ref5)>, ""); assert(std::get<std::string>(v) == "aaa"); + assert(&ref5 == &std::get<std::string>(v)); } #endif } Modified: libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp?rev=300403&r1=300402&r2=300403&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp Sat Apr 15 14:32:02 2017 @@ -15,7 +15,7 @@ // template <class ...Types> class variant; // template <class T, class U, class ...Args> -// void emplace(initializer_list<U> il,Args&&... args); +// T& emplace(initializer_list<U> il,Args&&... args); #include <cassert> #include <string> @@ -70,13 +70,19 @@ void test_emplace_sfinae() { void test_basic() { using V = std::variant<int, InitList, InitListArg, TestTypes::NoCtors>; V v; - v.emplace<InitList>({1, 2, 3}); + auto& ref1 = v.emplace<InitList>({1, 2, 3}); + static_assert(std::is_same_v<InitList&,decltype(ref1)>, ""); assert(std::get<InitList>(v).size == 3); - v.emplace<InitListArg>({1, 2, 3, 4}, 42); + assert(&ref1 == &std::get<InitList>(v)); + auto& ref2 = v.emplace<InitListArg>({1, 2, 3, 4}, 42); + static_assert(std::is_same_v<InitListArg&,decltype(ref2)>, ""); assert(std::get<InitListArg>(v).size == 4); assert(std::get<InitListArg>(v).value == 42); - v.emplace<InitList>({1}); + assert(&ref2 == &std::get<InitListArg>(v)); + auto& ref3 = v.emplace<InitList>({1}); + static_assert(std::is_same_v<InitList&,decltype(ref3)>, ""); assert(std::get<InitList>(v).size == 1); + assert(&ref3 == &std::get<InitList>(v)); } int main() { Modified: libcxx/trunk/www/cxx1z_status.html URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_status.html?rev=300403&r1=300402&r2=300403&view=diff ============================================================================== --- libcxx/trunk/www/cxx1z_status.html (original) +++ libcxx/trunk/www/cxx1z_status.html Sat Apr 15 14:32:02 2017 @@ -464,7 +464,7 @@ <tr><td><a href="http://wg21.link/LWG2850">2850</a></td><td>std::function move constructor does unnecessary work</td><td>Kona</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2853">2853</a></td><td>Possible inconsistency in specification of erase in [vector.modifiers]</td><td>Kona</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2855">2855</a></td><td>std::throw_with_nested("string_literal")</td><td>Kona</td><td>Complete</td></tr> - <tr><td><a href="http://wg21.link/LWG2857">2857</a></td><td>{variant,optional,any}::emplace should return the constructed value</td><td>Kona</td><td></td></tr> + <tr><td><a href="http://wg21.link/LWG2857">2857</a></td><td>{variant,optional,any}::emplace should return the constructed value</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2861">2861</a></td><td>basic_string should require that charT match traits::char_type</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2866">2866</a></td><td>Incorrect derived classes constraints</td><td>Kona</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2868">2868</a></td><td>Missing specification of bad_any_cast::what()</td><td>Kona</td><td>Complete</td></tr> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits