[libcxx] r300403 - Implement LWG 2857 for variant. Tests from Casey Carter @ Microsoft.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Sat Apr 15 12:32:02 PDT 2017


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>




More information about the cfe-commits mailing list