Make tuple's constructor and std::get<>(tuple) constexpr. Final stage of fixing bug #16599. Thanks to Howard for the review and updates.

llvm-svn: 186834
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp
index 37d58b8..d6fbdae 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp
@@ -19,6 +19,17 @@
 
 #include "../MoveOnly.h"
 
+#if _LIBCPP_STD_VER > 11
+
+struct Empty {};
+struct A
+{
+    int id_;
+    explicit constexpr A(int i) : id_(i) {}
+};
+
+#endif
+
 int main()
 {
     {
@@ -52,4 +63,13 @@
         assert(std::get<1>(t) == MoveOnly());
         assert(std::get<2>(t) == MoveOnly());
     }
+#if _LIBCPP_STD_VER > 11
+    {
+        constexpr std::tuple<Empty> t0{Empty()};
+    }
+    {
+        constexpr std::tuple<A, A> t(3, 2);
+        static_assert(std::get<0>(t).id_ == 3, "");
+    }
+#endif
 }
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
index 188d632..04cb3d5 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
@@ -23,11 +23,28 @@
         std::tuple<int> t(2);
         assert(std::get<0>(t) == 2);
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+        constexpr std::tuple<int> t(2);
+        static_assert(std::get<0>(t) == 2, "");
+    }
+    {
+        constexpr std::tuple<int> t;
+        static_assert(std::get<0>(t) == 0, "");
+    }
+#endif
     {
         std::tuple<int, char*> t(2, 0);
         assert(std::get<0>(t) == 2);
         assert(std::get<1>(t) == nullptr);
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+        constexpr std::tuple<int, char*> t(2, nullptr);
+        static_assert(std::get<0>(t) == 2, "");
+        static_assert(std::get<1>(t) == nullptr, "");
+    }
+#endif
     {
         std::tuple<int, char*> t(2, nullptr);
         assert(std::get<0>(t) == 2);
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp
index 54807f1..d40196b 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp
@@ -27,4 +27,16 @@
         assert(std::get<0>(t1) == 2);
         assert(std::get<1>(t1) == short('a'));
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+        typedef std::pair<double, char> P0;
+        typedef std::tuple<int, short> T1;
+        constexpr P0 p0(2.5, 'a');
+        constexpr T1 t1 = p0;
+        static_assert(std::get<0>(t1) != std::get<0>(p0), "");
+        static_assert(std::get<1>(t1) == std::get<1>(p0), "");
+        static_assert(std::get<0>(t1) == 2, "");
+        static_assert(std::get<1>(t1) == short('a'), "");
+    }
+#endif
 }
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp
index 33aed89..bcdb9d9 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp
@@ -30,6 +30,26 @@
     explicit D(int i) : B(i) {}
 };
 
+#if _LIBCPP_STD_VER > 11 
+
+struct A
+{
+    int id_;
+
+    constexpr A(int i) : id_(i) {}
+    friend constexpr bool operator==(const A& x, const A& y) {return x.id_ == y.id_;}
+};
+
+struct C
+{
+    int id_;
+
+    constexpr explicit C(int i) : id_(i) {}
+    friend constexpr bool operator==(const C& x, const C& y) {return x.id_ == y.id_;}
+};
+
+#endif
+
 int main()
 {
     {
@@ -39,6 +59,22 @@
         T1 t1 = t0;
         assert(std::get<0>(t1) == 2);
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+        typedef std::tuple<double> T0;
+        typedef std::tuple<A> T1;
+        constexpr T0 t0(2.5);
+        constexpr T1 t1 = t0;
+        static_assert(std::get<0>(t1) == 2, "");
+    }
+    {
+        typedef std::tuple<int> T0;
+        typedef std::tuple<C> T1;
+        constexpr T0 t0(2);
+        constexpr T1 t1{t0};
+        static_assert(std::get<0>(t1) == C(2), "");
+    }
+#endif
     {
         typedef std::tuple<double, char> T0;
         typedef std::tuple<int, int> T1;
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/copy.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/copy.pass.cpp
index 7de3ef6..fd953f8 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/copy.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/copy.pass.cpp
@@ -17,6 +17,8 @@
 #include <string>
 #include <cassert>
 
+struct Empty {};
+
 int main()
 {
     {
@@ -45,4 +47,17 @@
         assert(std::get<1>(t) == 'a');
         assert(std::get<2>(t) == "some text");
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+        typedef std::tuple<int> T;
+        constexpr T t0(2);
+        constexpr T t = t0;
+        static_assert(std::get<0>(t) == 2, "");
+    }
+    {
+        typedef std::tuple<Empty> T;
+        constexpr T t0;
+        constexpr T t = t0;
+    }
+#endif
 }
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp
index f3dba38..4b6649a 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp
@@ -38,4 +38,13 @@
         assert(i == 0);
         assert(j == 0);
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+    	constexpr auto t1 = std::make_tuple(0, 1, 3.14);
+        constexpr int i1 = std::get<1>(t1);
+        constexpr double d1 = std::get<2>(t1);
+        static_assert (i1 == 1, "" );
+        static_assert (d1 == 3.14, "" );
+    }
+#endif
 }
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp
index 7cfc736..b47842d 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp
@@ -36,12 +36,38 @@
     {
         std::tuple<> t = std::tuple_cat(std::array<int, 0>());
     }
-
     {
         std::tuple<int> t1(1);
         std::tuple<int> t = std::tuple_cat(t1);
         assert(std::get<0>(t) == 1);
     }
+
+#if _LIBCPP_STD_VER > 11 
+    {
+        constexpr std::tuple<> t = std::tuple_cat();
+    }
+    {
+        constexpr std::tuple<> t1;
+        constexpr std::tuple<> t2 = std::tuple_cat(t1);
+    }
+    {
+        constexpr std::tuple<> t = std::tuple_cat(std::tuple<>());
+    }
+    {
+        constexpr std::tuple<> t = std::tuple_cat(std::array<int, 0>());
+    }
+    {
+        constexpr std::tuple<int> t1(1);
+        constexpr std::tuple<int> t = std::tuple_cat(t1);
+        static_assert(std::get<0>(t) == 1, "");
+    }
+    {
+        constexpr std::tuple<int> t1(1);
+        constexpr std::tuple<int, int> t = std::tuple_cat(t1, t1);
+        static_assert(std::get<0>(t) == 1, "");
+        static_assert(std::get<1>(t) == 1, "");
+    }
+#endif
     {
         std::tuple<int, MoveOnly> t =
                                 std::tuple_cat(std::tuple<int, MoveOnly>(1, 2));
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp
index 03a00ae..0ba898d 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp
@@ -19,6 +19,8 @@
 #include <string>
 #include <cassert>
 
+struct Empty {};
+
 int main()
 {
     {
@@ -32,6 +34,19 @@
         assert(std::get<0>(t) == "high");
         assert(std::get<1>(t) == 5);
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+        typedef std::tuple<double, int> T;
+        constexpr T t(2.718, 5);
+        static_assert(std::get<0>(t) == 2.718, "");
+        static_assert(std::get<1>(t) == 5, "");
+    }
+    {
+        typedef std::tuple<Empty> T;
+        constexpr T t{Empty()};
+        constexpr Empty e = std::get<0>(t);
+    }
+#endif
     {
         typedef std::tuple<double&, std::string, int> T;
         double d = 1.5;
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp
index bcbf10e..3b98b5e 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp
@@ -19,6 +19,20 @@
 #include <string>
 #include <cassert>
 
+#if __cplusplus > 201103L
+
+struct Empty {};
+
+struct S {
+   std::tuple<int, Empty> a;
+   int k;
+   Empty e;
+   constexpr S() : a{1,Empty{}}, k(std::get<0>(a)), e(std::get<1>(a)) {}
+   };
+
+constexpr std::tuple<int, int> getP () { return { 3, 4 }; }
+#endif
+
 int main()
 {
     {
@@ -53,4 +67,15 @@
         assert(std::get<2>(t) == 4);
         assert(d == 2.5);
     }
+#if _LIBCPP_STD_VER > 11 
+    { // get on an rvalue tuple
+        static_assert ( std::get<0> ( std::make_tuple ( 0.0f, 1, 2.0, 3L )) == 0, "" );
+        static_assert ( std::get<1> ( std::make_tuple ( 0.0f, 1, 2.0, 3L )) == 1, "" );
+        static_assert ( std::get<2> ( std::make_tuple ( 0.0f, 1, 2.0, 3L )) == 2, "" );
+        static_assert ( std::get<3> ( std::make_tuple ( 0.0f, 1, 2.0, 3L )) == 3, "" );
+        static_assert(S().k == 1, "");
+        static_assert(std::get<1>(getP()) == 4, "");
+    }
+#endif
+
 }
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp
index 1835a9f..5cc33e1 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp
@@ -33,6 +33,12 @@
     }
     
     {
+    constexpr std::tuple<int, const int, double, double> p5 { 1, 2, 3.4, 5.6 };
+    static_assert ( std::get<int>(p5) == 1, "" );
+    static_assert ( std::get<const int>(p5) == 2, "" );
+    }
+
+    {
     const std::tuple<int, const int, double, double> p5 { 1, 2, 3.4, 5.6 };
     const int &i1 = std::get<int>(p5);
     const int &i2 = std::get<const int>(p5);
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
index fff93f5..e05cd61 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
@@ -141,4 +141,14 @@
         assert(!(t1 == t2));
         assert(t1 != t2);
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+        typedef std::tuple<char, int, double> T1;
+        typedef std::tuple<double, char, int> T2;
+        constexpr T1 t1(1, 2, 3);
+        constexpr T2 t2(1.1, 3, 2);
+        static_assert(!(t1 == t2), "");
+        static_assert(t1 != t2, "");
+    }
+#endif
 }
diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
index dcefa17..f09a105 100644
--- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
+++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
@@ -193,4 +193,16 @@
         assert(!(t1 >  t2));
         assert(!(t1 >= t2));
     }
+#if _LIBCPP_STD_VER > 11 
+    {
+        typedef std::tuple<char, int, double> T1;
+        typedef std::tuple<double, char, int> T2;
+        constexpr T1 t1(1, 2, 3);
+        constexpr T2 t2(1, 2, 4);
+        static_assert( (t1 <  t2), "");
+        static_assert( (t1 <= t2), "");
+        static_assert(!(t1 >  t2), "");
+        static_assert(!(t1 >= t2), "");
+    }
+#endif
 }