[PATCH] D44865: [libc++] Implement P0608R2 - A sane variant converting constructor

2018-11-03 Thread Zhihao Yuan via Phabricator via cfe-commits
lichray updated this revision to Diff 172514.
lichray added a comment.
Herald added subscribers: libcxx-commits, ldionne.

Updated implementation for https://reviews.llvm.org/source/clang/


Repository:
  rCXX libc++

https://reviews.llvm.org/D44865

Files:
  include/variant
  test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
  test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp

Index: test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
===
--- test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
@@ -20,8 +20,8 @@
 #include 
 #include 
 #include 
+#include 
 
-#include "test_convertible.hpp"
 #include "test_macros.h"
 #include "variant_test_helpers.hpp"
 
@@ -39,6 +39,8 @@
 
 struct AnyConstructible { template  AnyConstructible(T&&) {} };
 struct NoConstructible { NoConstructible() = delete; };
+template 
+struct RValueConvertibleFrom { RValueConvertibleFrom(T&&) {} };
 
 void test_T_ctor_noexcept() {
   {
@@ -53,7 +55,7 @@
 
 void test_T_ctor_sfinae() {
   {
-using V = std::variant;
+using V = std::variant;
 static_assert(!std::is_constructible::value, "ambiguous");
   }
   {
@@ -66,6 +68,32 @@
   "no matching constructor");
   }
   {
+using V = std::variant;
+static_assert(!std::is_constructible::value,
+  "no matching constructor");
+  }
+  {
+using V = std::variant, bool>;
+static_assert(!std::is_constructible>::value,
+  "no explicit bool in constructor");
+struct X {
+  operator void*();
+};
+static_assert(!std::is_constructible::value,
+  "no boolean conversion in constructor");
+static_assert(!std::is_constructible::value,
+  "no converted to bool in constructor");
+  }
+  {
+struct X {};
+struct Y {
+  operator X();
+};
+using V = std::variant;
+static_assert(std::is_constructible::value,
+  "regression on user-defined conversions in constructor");
+  }
+  {
 using V = std::variant;
 static_assert(
 !std::is_constructible>::value,
@@ -99,6 +127,34 @@
 static_assert(v.index() == 1, "");
 static_assert(std::get<1>(v) == 42, "");
   }
+  {
+constexpr std::variant v(42);
+static_assert(v.index() == 1, "");
+static_assert(std::get<1>(v) == 42, "");
+  }
+  {
+std::variant v = "foo";
+assert(v.index() == 0);
+assert(std::get<0>(v) == "foo");
+  }
+  {
+std::variant> v = nullptr;
+assert(v.index() == 1);
+assert(std::get<1>(v) == nullptr);
+  }
+  {
+std::variant v = true;
+assert(v.index() == 0);
+assert(std::get<0>(v));
+  }
+  {
+std::variant> v1 = 42;
+assert(v1.index() == 0);
+
+int x = 42;
+std::variant, AnyConstructible> v2 = x;
+assert(v2.index() == 1);
+  }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   {
 using V = std::variant;
Index: test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
===
--- test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "test_macros.h"
 #include "variant_test_helpers.hpp"
@@ -128,7 +129,7 @@
 
 void test_T_assignment_sfinae() {
   {
-using V = std::variant;
+using V = std::variant;
 static_assert(!std::is_assignable::value, "ambiguous");
   }
   {
@@ -139,6 +140,31 @@
 using V = std::variant;
 static_assert(!std::is_assignable::value, "no matching operator=");
   }
+  {
+using V = std::variant;
+static_assert(!std::is_assignable::value, "no matching operator=");
+  }
+  {
+using V = std::variant, bool>;
+static_assert(!std::is_assignable>::value,
+  "no explicit bool in operator=");
+struct X {
+  operator void*();
+};
+static_assert(!std::is_assignable::value,
+  "no boolean conversion in operator=");
+static_assert(!std::is_assignable::value,
+  "no converted to bool in operator=");
+  }
+  {
+struct X {};
+struct Y {
+  operator X();
+};
+using V = std::variant;
+static_assert(std::is_assignable::value,
+  "regression on user-defined conversions in operator=");
+  }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   {
 using V = std::variant;
@@ -167,6 +193,37 @@
 assert(v.index() == 1);
 assert(std::get<1>(v) == 43);
   }
+  {
+std::variant v;
+v = 42;
+assert(v.index() == 1);
+assert(std::get<1>(v) == 42);
+v = 43u;
+assert(v.index() == 0);
+assert(std::get<0>(v) == 43);
+  }
+  {
+std::variant v = true;
+v = "bar";
+assert(v.index() == 0);
+assert(std::get<0>(v) == "bar");

[PATCH] D44865: [libc++] Implement P0608R2 - A sane variant converting constructor

2018-06-04 Thread Zhihao Yuan via Phabricator via cfe-commits
lichray updated this revision to Diff 149825.
lichray added a comment.

Refine coding style


Repository:
  rCXX libc++

https://reviews.llvm.org/D44865

Files:
  include/variant
  test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
  test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp

Index: test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
===
--- test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "test_convertible.hpp"
 #include "test_macros.h"
@@ -39,6 +40,8 @@
 
 struct AnyConstructible { template  AnyConstructible(T&&) {} };
 struct NoConstructible { NoConstructible() = delete; };
+template 
+struct RValueConvertibleFrom { RValueConvertibleFrom(T&&) {} };
 
 void test_T_ctor_noexcept() {
   {
@@ -53,7 +56,7 @@
 
 void test_T_ctor_sfinae() {
   {
-using V = std::variant;
+using V = std::variant;
 static_assert(!std::is_constructible::value, "ambiguous");
   }
   {
@@ -66,6 +69,16 @@
   "no matching constructor");
   }
   {
+using V = std::variant;
+static_assert(!std::is_constructible::value,
+  "no matching constructor");
+  }
+  {
+using V = std::variant, bool>;
+static_assert(!std::is_constructible>::value,
+  "no explicit bool in constructor");
+  }
+  {
 using V = std::variant;
 static_assert(
 !std::is_constructible>::value,
@@ -99,6 +112,34 @@
 static_assert(v.index() == 1, "");
 static_assert(std::get<1>(v) == 42, "");
   }
+  {
+constexpr std::variant v(42);
+static_assert(v.index() == 1, "");
+static_assert(std::get<1>(v) == 42, "");
+  }
+  {
+std::variant v = "foo";
+assert(v.index() == 0);
+assert(std::get<0>(v) == "foo");
+  }
+  {
+std::variant> v = nullptr;
+assert(v.index() == 1);
+assert(std::get<1>(v) == nullptr);
+  }
+  {
+std::variant v = true;
+assert(v.index() == 0);
+assert(std::get<0>(v));
+  }
+  {
+std::variant> v1 = 42;
+assert(v1.index() == 0);
+
+int x = 42;
+std::variant, AnyConstructible> v2 = x;
+assert(v2.index() == 1);
+  }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   {
 using V = std::variant;
Index: test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
===
--- test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "test_macros.h"
 #include "variant_test_helpers.hpp"
@@ -128,7 +129,7 @@
 
 void test_T_assignment_sfinae() {
   {
-using V = std::variant;
+using V = std::variant;
 static_assert(!std::is_assignable::value, "ambiguous");
   }
   {
@@ -139,6 +140,15 @@
 using V = std::variant;
 static_assert(!std::is_assignable::value, "no matching operator=");
   }
+  {
+using V = std::variant;
+static_assert(!std::is_assignable::value, "no matching operator=");
+  }
+  {
+using V = std::variant, bool>;
+static_assert(!std::is_assignable>::value,
+  "no explicit bool in operator=");
+  }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   {
 using V = std::variant;
@@ -167,6 +177,44 @@
 assert(v.index() == 1);
 assert(std::get<1>(v) == 43);
   }
+  {
+std::variant v;
+v = 42;
+assert(v.index() == 1);
+assert(std::get<1>(v) == 42);
+v = 43u;
+assert(v.index() == 0);
+assert(std::get<0>(v) == 43);
+  }
+  {
+std::variant v = true;
+v = std::false_type();
+assert(v.index() == 1);
+assert(std::get<1>(v) == false);
+v = "bar";
+assert(v.index() == 0);
+assert(std::get<0>(v) == "bar");
+  }
+  {
+std::variant> v;
+v = nullptr;
+assert(v.index() == 1);
+assert(std::get<1>(v) == nullptr);
+v = std::true_type();
+assert(v.index() == 0);
+assert(std::get<0>(v));
+  }
+  {
+std::variant v = 42;
+assert(v.index() == 1);
+assert(std::get<1>(v) == 42);
+v = std::false_type();
+assert(v.index() == 0);
+assert(!std::get<0>(v));
+v = true;
+assert(v.index() == 0);
+assert(std::get<0>(v));
+  }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   {
 using V = std::variant;
Index: include/variant
===
--- include/variant
+++ include/variant
@@ -1097,11 +1097,40 @@
 template 
 struct __overload<_Tp, _Types...> : __overload<_Types...> {
   using __overload<_Types...>::operator();
-  __identity<_Tp> operator()(_Tp) const;
+
+  template 
+  auto operator()(_Tp, _Up&& __t) const
+  -> decltype(_Tp{_VSTD::forward<_Up>(__t)}, __identity<_Tp>());
+};
+
+template 
+struct __ov

[PATCH] D44865: [libc++] Implement P0608R2 - A sane variant converting constructor

2018-06-04 Thread Zhihao Yuan via Phabricator via cfe-commits
lichray updated this revision to Diff 149824.
lichray added a comment.

Preserve value category in narrowing test.


Repository:
  rCXX libc++

https://reviews.llvm.org/D44865

Files:
  include/variant
  test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
  test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp

Index: test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
===
--- test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "test_convertible.hpp"
 #include "test_macros.h"
@@ -40,6 +41,11 @@
 struct AnyConstructible { template  AnyConstructible(T&&) {} };
 struct NoConstructible { NoConstructible() = delete; };
 
+template 
+struct RValueConvertibleFrom {
+RValueConvertibleFrom(T&&) {}
+};
+
 void test_T_ctor_noexcept() {
   {
 using V = std::variant;
@@ -53,7 +59,7 @@
 
 void test_T_ctor_sfinae() {
   {
-using V = std::variant;
+using V = std::variant;
 static_assert(!std::is_constructible::value, "ambiguous");
   }
   {
@@ -66,6 +72,16 @@
   "no matching constructor");
   }
   {
+using V = std::variant;
+static_assert(!std::is_constructible::value,
+  "no matching constructor");
+  }
+  {
+using V = std::variant, bool>;
+static_assert(!std::is_constructible>::value,
+  "no explicit bool in constructor");
+  }
+  {
 using V = std::variant;
 static_assert(
 !std::is_constructible>::value,
@@ -99,6 +115,34 @@
 static_assert(v.index() == 1, "");
 static_assert(std::get<1>(v) == 42, "");
   }
+  {
+constexpr std::variant v(42);
+static_assert(v.index() == 1, "");
+static_assert(std::get<1>(v) == 42, "");
+  }
+  {
+std::variant v = "foo";
+assert(v.index() == 0);
+assert(std::get<0>(v) == "foo");
+  }
+  {
+std::variant> v = nullptr;
+assert(v.index() == 1);
+assert(std::get<1>(v) == nullptr);
+  }
+  {
+std::variant v = true;
+assert(v.index() == 0);
+assert(std::get<0>(v));
+  }
+  {
+std::variant> v1 = 42;
+assert(v1.index() == 0);
+
+int x = 42;
+std::variant, AnyConstructible> v2 = x;
+assert(v2.index() == 1);
+  }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   {
 using V = std::variant;
Index: test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
===
--- test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "test_macros.h"
 #include "variant_test_helpers.hpp"
@@ -128,7 +129,7 @@
 
 void test_T_assignment_sfinae() {
   {
-using V = std::variant;
+using V = std::variant;
 static_assert(!std::is_assignable::value, "ambiguous");
   }
   {
@@ -139,6 +140,15 @@
 using V = std::variant;
 static_assert(!std::is_assignable::value, "no matching operator=");
   }
+  {
+using V = std::variant;
+static_assert(!std::is_assignable::value, "no matching operator=");
+  }
+  {
+using V = std::variant, bool>;
+static_assert(!std::is_assignable>::value,
+  "no explicit bool in operator=");
+  }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   {
 using V = std::variant;
@@ -167,6 +177,44 @@
 assert(v.index() == 1);
 assert(std::get<1>(v) == 43);
   }
+  {
+std::variant v;
+v = 42;
+assert(v.index() == 1);
+assert(std::get<1>(v) == 42);
+v = 43u;
+assert(v.index() == 0);
+assert(std::get<0>(v) == 43);
+  }
+  {
+std::variant v = true;
+v = std::false_type();
+assert(v.index() == 1);
+assert(std::get<1>(v) == false);
+v = "bar";
+assert(v.index() == 0);
+assert(std::get<0>(v) == "bar");
+  }
+  {
+std::variant> v;
+v = nullptr;
+assert(v.index() == 1);
+assert(std::get<1>(v) == nullptr);
+v = std::true_type();
+assert(v.index() == 0);
+assert(std::get<0>(v));
+  }
+  {
+std::variant v = 42;
+assert(v.index() == 1);
+assert(std::get<1>(v) == 42);
+v = std::false_type();
+assert(v.index() == 0);
+assert(!std::get<0>(v));
+v = true;
+assert(v.index() == 0);
+assert(std::get<0>(v));
+  }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   {
 using V = std::variant;
Index: include/variant
===
--- include/variant
+++ include/variant
@@ -1097,11 +1097,40 @@
 template 
 struct __overload<_Tp, _Types...> : __overload<_Types...> {
   using __overload<_Types...>::operator();
-  __identity<_Tp> operator()(_Tp) const;
+
+  template 
+  auto operator()(_Tp, _Up&& __t) const
+  -> decltype(_Tp{_VSTD::forward<_U