summaryrefslogtreecommitdiff
path: root/test/std/utilities/tuple/tuple.tuple
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:47:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:47:26 +0000
commit51072bd6bf79ef2bc6a922079bff57c31c1effbc (patch)
tree91a2effbc9e6f80bdbbf9eb70e06c51ad0867ea0 /test/std/utilities/tuple/tuple.tuple
parentbb5e33f003797b67974a8893f7f2930fc51b8210 (diff)
Notes
Diffstat (limited to 'test/std/utilities/tuple/tuple.tuple')
-rw-r--r--test/std/utilities/tuple/tuple.tuple/TupleFunction.pass.cpp4
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp275
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp426
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp144
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp214
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_copy.pass.cpp12
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_move.pass.cpp19
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp178
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp96
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp51
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp7
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp28
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp121
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.fail.cpp43
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp22
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.fail.cpp43
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp21
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.fail.cpp36
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp20
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp3
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp3
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.fail.cpp27
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp35
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp2
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp24
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_move.pass.cpp20
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp6
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp102
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.creation/forward_as_tuple.pass.cpp6
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp2
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp2
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp6
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.fail.cpp38
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp1
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp27
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type2.fail.cpp27
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type3.fail.cpp27
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type4.fail.cpp27
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.array.pass.cpp2
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.utility.pass.cpp3
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp34
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp27
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp26
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp43
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp2
-rw-r--r--test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp2
46 files changed, 2096 insertions, 188 deletions
diff --git a/test/std/utilities/tuple/tuple.tuple/TupleFunction.pass.cpp b/test/std/utilities/tuple/tuple.tuple/TupleFunction.pass.cpp
index df5fdff511e35..ce6dcf811e468 100644
--- a/test/std/utilities/tuple/tuple.tuple/TupleFunction.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/TupleFunction.pass.cpp
@@ -9,7 +9,9 @@
// This is for bugs 18853 and 19118
-#if __cplusplus >= 201103L
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 11
#include <tuple>
#include <functional>
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp
new file mode 100644
index 0000000000000..2e821945d09a1
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp
@@ -0,0 +1,275 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <tuple>
+
+// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
+
+// Test with different ref/ptr/cv qualified argument types.
+
+#include <tuple>
+#include <array>
+#include <utility>
+#include <cassert>
+
+#include "test_macros.h"
+#include "type_id.h"
+
+// std::array is explicitly allowed to be initialized with A a = { init-list };.
+// Disable the missing braces warning for this reason.
+#include "disable_missing_braces_warning.h"
+
+
+constexpr int constexpr_sum_fn() { return 0; }
+
+template <class ...Ints>
+constexpr int constexpr_sum_fn(int x1, Ints... rest) { return x1 + constexpr_sum_fn(rest...); }
+
+struct ConstexprSumT {
+ constexpr ConstexprSumT() = default;
+ template <class ...Ints>
+ constexpr int operator()(Ints... values) const {
+ return constexpr_sum_fn(values...);
+ }
+};
+
+
+void test_constexpr_evaluation()
+{
+ constexpr ConstexprSumT sum_obj{};
+ {
+ using Tup = std::tuple<>;
+ using Fn = int(&)();
+ constexpr Tup t;
+ static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 0, "");
+ static_assert(std::apply(sum_obj, t) == 0, "");
+ }
+ {
+ using Tup = std::tuple<int>;
+ using Fn = int(&)(int);
+ constexpr Tup t(42);
+ static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 42, "");
+ static_assert(std::apply(sum_obj, t) == 42, "");
+ }
+ {
+ using Tup = std::tuple<int, long>;
+ using Fn = int(&)(int, int);
+ constexpr Tup t(42, 101);
+ static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, "");
+ static_assert(std::apply(sum_obj, t) == 143, "");
+ }
+ {
+ using Tup = std::pair<int, long>;
+ using Fn = int(&)(int, int);
+ constexpr Tup t(42, 101);
+ static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, "");
+ static_assert(std::apply(sum_obj, t) == 143, "");
+ }
+ {
+ using Tup = std::tuple<int, long, int>;
+ using Fn = int(&)(int, int, int);
+ constexpr Tup t(42, 101, -1);
+ static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, "");
+ static_assert(std::apply(sum_obj, t) == 142, "");
+ }
+ {
+ using Tup = std::array<int, 3>;
+ using Fn = int(&)(int, int, int);
+ constexpr Tup t = {42, 101, -1};
+ static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, "");
+ static_assert(std::apply(sum_obj, t) == 142, "");
+ }
+}
+
+
+enum CallQuals {
+ CQ_None,
+ CQ_LValue,
+ CQ_ConstLValue,
+ CQ_RValue,
+ CQ_ConstRValue
+};
+
+template <class Tuple>
+struct CallInfo {
+ CallQuals quals;
+ TypeID const* arg_types;
+ Tuple args;
+
+ template <class ...Args>
+ CallInfo(CallQuals q, Args&&... xargs)
+ : quals(q), arg_types(&makeArgumentID<Args&&...>()), args(std::forward<Args>(xargs)...)
+ {}
+};
+
+template <class ...Args>
+inline CallInfo<decltype(std::forward_as_tuple(std::declval<Args>()...))>
+makeCallInfo(CallQuals quals, Args&&... args) {
+ return {quals, std::forward<Args>(args)...};
+}
+
+struct TrackedCallable {
+
+ TrackedCallable() = default;
+
+ template <class ...Args> auto operator()(Args&&... xargs) &
+ { return makeCallInfo(CQ_LValue, std::forward<Args>(xargs)...); }
+
+ template <class ...Args> auto operator()(Args&&... xargs) const&
+ { return makeCallInfo(CQ_ConstLValue, std::forward<Args>(xargs)...); }
+
+ template <class ...Args> auto operator()(Args&&... xargs) &&
+ { return makeCallInfo(CQ_RValue, std::forward<Args>(xargs)...); }
+
+ template <class ...Args> auto operator()(Args&&... xargs) const&&
+ { return makeCallInfo(CQ_ConstRValue, std::forward<Args>(xargs)...); }
+};
+
+template <class ...ExpectArgs, class Tuple>
+void check_apply_quals_and_types(Tuple&& t) {
+ TypeID const* const expect_args = &makeArgumentID<ExpectArgs...>();
+ TrackedCallable obj;
+ TrackedCallable const& cobj = obj;
+ {
+ auto ret = std::apply(obj, std::forward<Tuple>(t));
+ assert(ret.quals == CQ_LValue);
+ assert(ret.arg_types == expect_args);
+ assert(ret.args == t);
+ }
+ {
+ auto ret = std::apply(cobj, std::forward<Tuple>(t));
+ assert(ret.quals == CQ_ConstLValue);
+ assert(ret.arg_types == expect_args);
+ assert(ret.args == t);
+ }
+ {
+ auto ret = std::apply(std::move(obj), std::forward<Tuple>(t));
+ assert(ret.quals == CQ_RValue);
+ assert(ret.arg_types == expect_args);
+ assert(ret.args == t);
+ }
+ {
+ auto ret = std::apply(std::move(cobj), std::forward<Tuple>(t));
+ assert(ret.quals == CQ_ConstRValue);
+ assert(ret.arg_types == expect_args);
+ assert(ret.args == t);
+ }
+}
+
+void test_call_quals_and_arg_types()
+{
+ TrackedCallable obj;
+ using Tup = std::tuple<int, int const&, unsigned&&>;
+ const int x = 42;
+ unsigned y = 101;
+ Tup t(-1, x, std::move(y));
+ Tup const& ct = t;
+ check_apply_quals_and_types<int&, int const&, unsigned&>(t);
+ check_apply_quals_and_types<int const&, int const&, unsigned&>(ct);
+ check_apply_quals_and_types<int&&, int const&, unsigned&&>(std::move(t));
+ check_apply_quals_and_types<int const&&, int const&, unsigned&&>(std::move(ct));
+}
+
+
+struct NothrowMoveable {
+ NothrowMoveable() noexcept = default;
+ NothrowMoveable(NothrowMoveable const&) noexcept(false) {}
+ NothrowMoveable(NothrowMoveable&&) noexcept {}
+};
+
+template <bool IsNoexcept>
+struct TestNoexceptCallable {
+ template <class ...Args>
+ NothrowMoveable operator()(Args...) const noexcept(IsNoexcept) { return {}; }
+};
+
+void test_noexcept()
+{
+ TestNoexceptCallable<true> nec;
+ TestNoexceptCallable<false> tc;
+ {
+ // test that the functions noexcept-ness is propagated
+ using Tup = std::tuple<int, const char*, long>;
+ Tup t;
+ ASSERT_NOEXCEPT(std::apply(nec, t));
+ ASSERT_NOT_NOEXCEPT(std::apply(tc, t));
+ }
+ {
+ // test that the noexcept-ness of the argument conversions is checked.
+ using Tup = std::tuple<NothrowMoveable, int>;
+ Tup t;
+ ASSERT_NOT_NOEXCEPT(std::apply(nec, t));
+ ASSERT_NOEXCEPT(std::apply(nec, std::move(t)));
+ }
+}
+
+namespace ReturnTypeTest {
+ static int my_int = 42;
+
+ template <int N> struct index {};
+
+ void f(index<0>) {}
+
+ int f(index<1>) { return 0; }
+
+ int & f(index<2>) { return static_cast<int &>(my_int); }
+ int const & f(index<3>) { return static_cast<int const &>(my_int); }
+ int volatile & f(index<4>) { return static_cast<int volatile &>(my_int); }
+ int const volatile & f(index<5>) { return static_cast<int const volatile &>(my_int); }
+
+ int && f(index<6>) { return static_cast<int &&>(my_int); }
+ int const && f(index<7>) { return static_cast<int const &&>(my_int); }
+ int volatile && f(index<8>) { return static_cast<int volatile &&>(my_int); }
+ int const volatile && f(index<9>) { return static_cast<int const volatile &&>(my_int); }
+
+ int * f(index<10>) { return static_cast<int *>(&my_int); }
+ int const * f(index<11>) { return static_cast<int const *>(&my_int); }
+ int volatile * f(index<12>) { return static_cast<int volatile *>(&my_int); }
+ int const volatile * f(index<13>) { return static_cast<int const volatile *>(&my_int); }
+
+ template <int Func, class Expect>
+ void test()
+ {
+ using RawInvokeResult = decltype(f(index<Func>{}));
+ static_assert(std::is_same<RawInvokeResult, Expect>::value, "");
+ using FnType = RawInvokeResult (*) (index<Func>);
+ FnType fn = f;
+ std::tuple<index<Func>> t; ((void)t);
+ using InvokeResult = decltype(std::apply(fn, t));
+ static_assert(std::is_same<InvokeResult, Expect>::value, "");
+ }
+} // end namespace ReturnTypeTest
+
+void test_return_type()
+{
+ using ReturnTypeTest::test;
+ test<0, void>();
+ test<1, int>();
+ test<2, int &>();
+ test<3, int const &>();
+ test<4, int volatile &>();
+ test<5, int const volatile &>();
+ test<6, int &&>();
+ test<7, int const &&>();
+ test<8, int volatile &&>();
+ test<9, int const volatile &&>();
+ test<10, int *>();
+ test<11, int const *>();
+ test<12, int volatile *>();
+ test<13, int const volatile *>();
+}
+
+int main() {
+ test_constexpr_evaluation();
+ test_call_quals_and_arg_types();
+ test_return_type();
+ test_noexcept();
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp
new file mode 100644
index 0000000000000..02d7fe43e9cdc
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp
@@ -0,0 +1,426 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <tuple>
+
+// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
+
+// Testing extended function types. The extended function types are those
+// named by INVOKE but that are not actual callable objects. These include
+// bullets 1-4 of invoke.
+
+#include <tuple>
+#include <array>
+#include <utility>
+#include <cassert>
+
+// std::array is explicitly allowed to be initialized with A a = { init-list };.
+// Disable the missing braces warning for this reason.
+#include "disable_missing_braces_warning.h"
+
+int count = 0;
+
+struct A_int_0
+{
+ A_int_0() : obj1(0){}
+ A_int_0(int x) : obj1(x) {}
+ int mem1() { return ++count; }
+ int mem2() const { return ++count; }
+ int const obj1;
+};
+
+struct A_int_1
+{
+ A_int_1() {}
+ A_int_1(int) {}
+ int mem1(int x) { return count += x; }
+ int mem2(int x) const { return count += x; }
+};
+
+struct A_int_2
+{
+ A_int_2() {}
+ A_int_2(int) {}
+ int mem1(int x, int y) { return count += (x + y); }
+ int mem2(int x, int y) const { return count += (x + y); }
+};
+
+template <class A>
+struct A_wrap
+{
+ A_wrap() {}
+ A_wrap(int x) : m_a(x) {}
+ A & operator*() { return m_a; }
+ A const & operator*() const { return m_a; }
+ A m_a;
+};
+
+typedef A_wrap<A_int_0> A_wrap_0;
+typedef A_wrap<A_int_1> A_wrap_1;
+typedef A_wrap<A_int_2> A_wrap_2;
+
+
+template <class A>
+struct A_base : public A
+{
+ A_base() : A() {}
+ A_base(int x) : A(x) {}
+};
+
+typedef A_base<A_int_0> A_base_0;
+typedef A_base<A_int_1> A_base_1;
+typedef A_base<A_int_2> A_base_2;
+
+
+template <
+ class Tuple, class ConstTuple
+ , class TuplePtr, class ConstTuplePtr
+ , class TupleWrap, class ConstTupleWrap
+ , class TupleBase, class ConstTupleBase
+ >
+void test_ext_int_0()
+{
+ count = 0;
+ typedef A_int_0 T;
+ typedef A_wrap_0 Wrap;
+ typedef A_base_0 Base;
+
+ typedef int(T::*mem1_t)();
+ mem1_t mem1 = &T::mem1;
+
+ typedef int(T::*mem2_t)() const;
+ mem2_t mem2 = &T::mem2;
+
+ typedef int const T::*obj1_t;
+ obj1_t obj1 = &T::obj1;
+
+ // member function w/ref
+ {
+ T a;
+ Tuple t{a};
+ assert(1 == std::apply(mem1, t));
+ assert(count == 1);
+ }
+ count = 0;
+ // member function w/pointer
+ {
+ T a;
+ TuplePtr t{&a};
+ assert(1 == std::apply(mem1, t));
+ assert(count == 1);
+ }
+ count = 0;
+ // member function w/base
+ {
+ Base a;
+ TupleBase t{a};
+ assert(1 == std::apply(mem1, t));
+ assert(count == 1);
+ }
+ count = 0;
+ // member function w/wrap
+ {
+ Wrap a;
+ TupleWrap t{a};
+ assert(1 == std::apply(mem1, t));
+ assert(count == 1);
+ }
+ count = 0;
+ // const member function w/ref
+ {
+ T const a;
+ ConstTuple t{a};
+ assert(1 == std::apply(mem2, t));
+ assert(count == 1);
+ }
+ count = 0;
+ // const member function w/pointer
+ {
+ T const a;
+ ConstTuplePtr t{&a};
+ assert(1 == std::apply(mem2, t));
+ assert(count == 1);
+ }
+ count = 0;
+ // const member function w/base
+ {
+ Base const a;
+ ConstTupleBase t{a};
+ assert(1 == std::apply(mem2, t));
+ assert(count == 1);
+ }
+ count = 0;
+ // const member function w/wrapper
+ {
+ Wrap const a;
+ ConstTupleWrap t{a};
+ assert(1 == std::apply(mem2, t));
+ assert(1 == count);
+ }
+ // member object w/ref
+ {
+ T a{42};
+ Tuple t{a};
+ assert(42 == std::apply(obj1, t));
+ }
+ // member object w/pointer
+ {
+ T a{42};
+ TuplePtr t{&a};
+ assert(42 == std::apply(obj1, t));
+ }
+ // member object w/base
+ {
+ Base a{42};
+ TupleBase t{a};
+ assert(42 == std::apply(obj1, t));
+ }
+ // member object w/wrapper
+ {
+ Wrap a{42};
+ TupleWrap t{a};
+ assert(42 == std::apply(obj1, t));
+ }
+}
+
+
+template <
+ class Tuple, class ConstTuple
+ , class TuplePtr, class ConstTuplePtr
+ , class TupleWrap, class ConstTupleWrap
+ , class TupleBase, class ConstTupleBase
+ >
+void test_ext_int_1()
+{
+ count = 0;
+ typedef A_int_1 T;
+ typedef A_wrap_1 Wrap;
+ typedef A_base_1 Base;
+
+ typedef int(T::*mem1_t)(int);
+ mem1_t mem1 = &T::mem1;
+
+ typedef int(T::*mem2_t)(int) const;
+ mem2_t mem2 = &T::mem2;
+
+ // member function w/ref
+ {
+ T a;
+ Tuple t{a, 2};
+ assert(2 == std::apply(mem1, t));
+ assert(count == 2);
+ }
+ count = 0;
+ // member function w/pointer
+ {
+ T a;
+ TuplePtr t{&a, 3};
+ assert(3 == std::apply(mem1, t));
+ assert(count == 3);
+ }
+ count = 0;
+ // member function w/base
+ {
+ Base a;
+ TupleBase t{a, 4};
+ assert(4 == std::apply(mem1, t));
+ assert(count == 4);
+ }
+ count = 0;
+ // member function w/wrap
+ {
+ Wrap a;
+ TupleWrap t{a, 5};
+ assert(5 == std::apply(mem1, t));
+ assert(count == 5);
+ }
+ count = 0;
+ // const member function w/ref
+ {
+ T const a;
+ ConstTuple t{a, 6};
+ assert(6 == std::apply(mem2, t));
+ assert(count == 6);
+ }
+ count = 0;
+ // const member function w/pointer
+ {
+ T const a;
+ ConstTuplePtr t{&a, 7};
+ assert(7 == std::apply(mem2, t));
+ assert(count == 7);
+ }
+ count = 0;
+ // const member function w/base
+ {
+ Base const a;
+ ConstTupleBase t{a, 8};
+ assert(8 == std::apply(mem2, t));
+ assert(count == 8);
+ }
+ count = 0;
+ // const member function w/wrapper
+ {
+ Wrap const a;
+ ConstTupleWrap t{a, 9};
+ assert(9 == std::apply(mem2, t));
+ assert(9 == count);
+ }
+}
+
+
+template <
+ class Tuple, class ConstTuple
+ , class TuplePtr, class ConstTuplePtr
+ , class TupleWrap, class ConstTupleWrap
+ , class TupleBase, class ConstTupleBase
+ >
+void test_ext_int_2()
+{
+ count = 0;
+ typedef A_int_2 T;
+ typedef A_wrap_2 Wrap;
+ typedef A_base_2 Base;
+
+ typedef int(T::*mem1_t)(int, int);
+ mem1_t mem1 = &T::mem1;
+
+ typedef int(T::*mem2_t)(int, int) const;
+ mem2_t mem2 = &T::mem2;
+
+ // member function w/ref
+ {
+ T a;
+ Tuple t{a, 1, 1};
+ assert(2 == std::apply(mem1, t));
+ assert(count == 2);
+ }
+ count = 0;
+ // member function w/pointer
+ {
+ T a;
+ TuplePtr t{&a, 1, 2};
+ assert(3 == std::apply(mem1, t));
+ assert(count == 3);
+ }
+ count = 0;
+ // member function w/base
+ {
+ Base a;
+ TupleBase t{a, 2, 2};
+ assert(4 == std::apply(mem1, t));
+ assert(count == 4);
+ }
+ count = 0;
+ // member function w/wrap
+ {
+ Wrap a;
+ TupleWrap t{a, 2, 3};
+ assert(5 == std::apply(mem1, t));
+ assert(count == 5);
+ }
+ count = 0;
+ // const member function w/ref
+ {
+ T const a;
+ ConstTuple t{a, 3, 3};
+ assert(6 == std::apply(mem2, t));
+ assert(count == 6);
+ }
+ count = 0;
+ // const member function w/pointer
+ {
+ T const a;
+ ConstTuplePtr t{&a, 3, 4};
+ assert(7 == std::apply(mem2, t));
+ assert(count == 7);
+ }
+ count = 0;
+ // const member function w/base
+ {
+ Base const a;
+ ConstTupleBase t{a, 4, 4};
+ assert(8 == std::apply(mem2, t));
+ assert(count == 8);
+ }
+ count = 0;
+ // const member function w/wrapper
+ {
+ Wrap const a;
+ ConstTupleWrap t{a, 4, 5};
+ assert(9 == std::apply(mem2, t));
+ assert(9 == count);
+ }
+}
+
+int main()
+{
+ {
+ test_ext_int_0<
+ std::tuple<A_int_0 &>, std::tuple<A_int_0 const &>
+ , std::tuple<A_int_0 *>, std::tuple<A_int_0 const *>
+ , std::tuple<A_wrap_0 &>, std::tuple<A_wrap_0 const &>
+ , std::tuple<A_base_0 &>, std::tuple<A_base_0 const &>
+ >();
+ test_ext_int_0<
+ std::tuple<A_int_0>, std::tuple<A_int_0 const>
+ , std::tuple<A_int_0 *>, std::tuple<A_int_0 const *>
+ , std::tuple<A_wrap_0>, std::tuple<A_wrap_0 const>
+ , std::tuple<A_base_0>, std::tuple<A_base_0 const>
+ >();
+ test_ext_int_0<
+ std::array<A_int_0, 1>, std::array<A_int_0 const, 1>
+ , std::array<A_int_0*, 1>, std::array<A_int_0 const*, 1>
+ , std::array<A_wrap_0, 1>, std::array<A_wrap_0 const, 1>
+ , std::array<A_base_0, 1>, std::array<A_base_0 const, 1>
+ >();
+ }
+ {
+ test_ext_int_1<
+ std::tuple<A_int_1 &, int>, std::tuple<A_int_1 const &, int>
+ , std::tuple<A_int_1 *, int>, std::tuple<A_int_1 const *, int>
+ , std::tuple<A_wrap_1 &, int>, std::tuple<A_wrap_1 const &, int>
+ , std::tuple<A_base_1 &, int>, std::tuple<A_base_1 const &, int>
+ >();
+ test_ext_int_1<
+ std::tuple<A_int_1, int>, std::tuple<A_int_1 const, int>
+ , std::tuple<A_int_1 *, int>, std::tuple<A_int_1 const *, int>
+ , std::tuple<A_wrap_1, int>, std::tuple<A_wrap_1 const, int>
+ , std::tuple<A_base_1, int>, std::tuple<A_base_1 const, int>
+ >();
+ test_ext_int_1<
+ std::pair<A_int_1 &, int>, std::pair<A_int_1 const &, int>
+ , std::pair<A_int_1 *, int>, std::pair<A_int_1 const *, int>
+ , std::pair<A_wrap_1 &, int>, std::pair<A_wrap_1 const &, int>
+ , std::pair<A_base_1 &, int>, std::pair<A_base_1 const &, int>
+ >();
+ test_ext_int_1<
+ std::pair<A_int_1, int>, std::pair<A_int_1 const, int>
+ , std::pair<A_int_1 *, int>, std::pair<A_int_1 const *, int>
+ , std::pair<A_wrap_1, int>, std::pair<A_wrap_1 const, int>
+ , std::pair<A_base_1, int>, std::pair<A_base_1 const, int>
+ >();
+ }
+ {
+ test_ext_int_2<
+ std::tuple<A_int_2 &, int, int>, std::tuple<A_int_2 const &, int, int>
+ , std::tuple<A_int_2 *, int, int>, std::tuple<A_int_2 const *, int, int>
+ , std::tuple<A_wrap_2 &, int, int>, std::tuple<A_wrap_2 const &, int, int>
+ , std::tuple<A_base_2 &, int, int>, std::tuple<A_base_2 const &, int, int>
+ >();
+ test_ext_int_2<
+ std::tuple<A_int_2, int, int>, std::tuple<A_int_2 const, int, int>
+ , std::tuple<A_int_2 *, int, int>, std::tuple<A_int_2 const *, int, int>
+ , std::tuple<A_wrap_2, int, int>, std::tuple<A_wrap_2 const, int, int>
+ , std::tuple<A_base_2, int, int>, std::tuple<A_base_2 const, int, int>
+ >();
+ }
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp
new file mode 100644
index 0000000000000..33c3ef5956e4e
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp
@@ -0,0 +1,144 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <tuple>
+
+// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
+
+// Stress testing large arities with tuple and array.
+
+#include <tuple>
+#include <array>
+#include <utility>
+#include <cassert>
+
+////////////////////////////////////////////////////////////////////////////////
+template <class T, std::size_t Dummy = 0>
+struct always_imp
+{
+ typedef T type;
+};
+
+template <class T, std::size_t Dummy = 0>
+using always_t = typename always_imp<T, Dummy>::type;
+
+////////////////////////////////////////////////////////////////////////////////
+template <class Tuple, class Idx>
+struct make_function;
+
+template <class Tp, std::size_t ...Idx>
+struct make_function<Tp, std::integer_sequence<std::size_t, Idx...>>
+{
+ using type = bool (*)(always_t<Tp, Idx>...);
+};
+
+template <class Tp, std::size_t Size>
+using make_function_t = typename make_function<Tp, std::make_index_sequence<Size>>::type;
+
+////////////////////////////////////////////////////////////////////////////////
+template <class Tp, class Idx>
+struct make_tuple_imp;
+
+////////////////////////////////////////////////////////////////////////////////
+template <class Tp, std::size_t ...Idx>
+struct make_tuple_imp<Tp, std::integer_sequence<std::size_t, Idx...>>
+{
+ using type = std::tuple<always_t<Tp, Idx>...>;
+};
+
+template <class Tp, std::size_t Size>
+using make_tuple_t = typename make_tuple_imp<Tp, std::make_index_sequence<Size>>::type;
+
+template <class ...Types>
+bool test_apply_fn(Types...) { return true; }
+
+
+template <std::size_t Size>
+void test_all()
+{
+
+ using A = std::array<int, Size>;
+ using ConstA = std::array<int const, Size>;
+
+ using Tuple = make_tuple_t<int, Size>;
+ using CTuple = make_tuple_t<const int, Size>;
+
+ using ValFn = make_function_t<int, Size>;
+ ValFn val_fn = &test_apply_fn;
+
+ using RefFn = make_function_t<int &, Size>;
+ RefFn ref_fn = &test_apply_fn;
+
+ using CRefFn = make_function_t<int const &, Size>;
+ CRefFn cref_fn = &test_apply_fn;
+
+ using RRefFn = make_function_t<int &&, Size>;
+ RRefFn rref_fn = &test_apply_fn;
+
+ {
+ A a{};
+ assert(std::apply(val_fn, a));
+ assert(std::apply(ref_fn, a));
+ assert(std::apply(cref_fn, a));
+ assert(std::apply(rref_fn, std::move(a)));
+ }
+ {
+ ConstA a{};
+ assert(std::apply(val_fn, a));
+ assert(std::apply(cref_fn, a));
+ }
+ {
+ Tuple a{};
+ assert(std::apply(val_fn, a));
+ assert(std::apply(ref_fn, a));
+ assert(std::apply(cref_fn, a));
+ assert(std::apply(rref_fn, std::move(a)));
+ }
+ {
+ CTuple a{};
+ assert(std::apply(val_fn, a));
+ assert(std::apply(cref_fn, a));
+ }
+
+}
+
+
+template <std::size_t Size>
+void test_one()
+{
+ using A = std::array<int, Size>;
+ using Tuple = make_tuple_t<int, Size>;
+
+ using ValFn = make_function_t<int, Size>;
+ ValFn val_fn = &test_apply_fn;
+
+ {
+ A a{};
+ assert(std::apply(val_fn, a));
+ }
+ {
+ Tuple a{};
+ assert(std::apply(val_fn, a));
+ }
+}
+
+int main()
+{
+ // Instantiate with 1-5 arguments.
+ test_all<1>();
+ test_all<2>();
+ test_all<3>();
+ test_all<4>();
+ test_all<5>();
+
+ // Stress test with 256
+ test_one<256>();
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
new file mode 100644
index 0000000000000..143ae195e6f44
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
@@ -0,0 +1,214 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <tuple>
+
+// template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&);
+
+#include <tuple>
+#include <array>
+#include <utility>
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+#include "type_id.h"
+
+// std::array is explicitly allowed to be initialized with A a = { init-list };.
+// Disable the missing braces warning for this reason.
+#include "disable_missing_braces_warning.h"
+
+template <class Tuple>
+struct ConstexprConstructibleFromTuple {
+ template <class ...Args>
+ explicit constexpr ConstexprConstructibleFromTuple(Args&&... xargs)
+ : args{std::forward<Args>(xargs)...} {}
+ Tuple args;
+};
+
+template <class TupleLike>
+struct ConstructibleFromTuple;
+
+template <template <class ...> class Tuple, class ...Types>
+struct ConstructibleFromTuple<Tuple<Types...>> {
+ template <class ...Args>
+ explicit ConstructibleFromTuple(Args&&... xargs)
+ : args(xargs...),
+ arg_types(&makeArgumentID<Args&&...>())
+ {}
+ Tuple<std::decay_t<Types>...> args;
+ TypeID const* arg_types;
+};
+
+template <class Tp, size_t N>
+struct ConstructibleFromTuple<std::array<Tp, N>> {
+template <class ...Args>
+ explicit ConstructibleFromTuple(Args&&... xargs)
+ : args{xargs...},
+ arg_types(&makeArgumentID<Args&&...>())
+ {}
+ std::array<Tp, N> args;
+ TypeID const* arg_types;
+};
+
+template <class Tuple>
+constexpr bool do_constexpr_test(Tuple&& tup) {
+ using RawTuple = std::decay_t<Tuple>;
+ using Tp = ConstexprConstructibleFromTuple<RawTuple>;
+ return std::make_from_tuple<Tp>(std::forward<Tuple>(tup)).args == tup;
+}
+
+// Needed by do_forwarding_test() since it compare pairs of different types.
+template <class T1, class T2, class U1, class U2>
+inline bool operator==(const std::pair<T1, T2>& lhs, const std::pair<U1, U2>& rhs) {
+ return lhs.first == rhs.first && lhs.second == rhs.second;
+}
+
+template <class ...ExpectTypes, class Tuple>
+bool do_forwarding_test(Tuple&& tup) {
+ using RawTuple = std::decay_t<Tuple>;
+ using Tp = ConstructibleFromTuple<RawTuple>;
+ const Tp value = std::make_from_tuple<Tp>(std::forward<Tuple>(tup));
+ return value.args == tup
+ && value.arg_types == &makeArgumentID<ExpectTypes...>();
+}
+
+void test_constexpr_construction() {
+ {
+ constexpr std::tuple<> tup;
+ static_assert(do_constexpr_test(tup), "");
+ }
+ {
+ constexpr std::tuple<int> tup(42);
+ static_assert(do_constexpr_test(tup), "");
+ }
+ {
+ constexpr std::tuple<int, long, void*> tup(42, 101, nullptr);
+ static_assert(do_constexpr_test(tup), "");
+ }
+ {
+ constexpr std::pair<int, const char*> p(42, "hello world");
+ static_assert(do_constexpr_test(p), "");
+ }
+ {
+ using Tuple = std::array<int, 3>;
+ using ValueTp = ConstexprConstructibleFromTuple<Tuple>;
+ constexpr Tuple arr = {42, 101, -1};
+ constexpr ValueTp value = std::make_from_tuple<ValueTp>(arr);
+ static_assert(value.args[0] == arr[0] && value.args[1] == arr[1]
+ && value.args[2] == arr[2], "");
+ }
+}
+
+void test_perfect_forwarding() {
+ {
+ using Tup = std::tuple<>;
+ Tup tup;
+ Tup const& ctup = tup;
+ assert(do_forwarding_test<>(tup));
+ assert(do_forwarding_test<>(ctup));
+ }
+ {
+ using Tup = std::tuple<int>;
+ Tup tup(42);
+ Tup const& ctup = tup;
+ assert(do_forwarding_test<int&>(tup));
+ assert(do_forwarding_test<int const&>(ctup));
+ assert(do_forwarding_test<int&&>(std::move(tup)));
+ assert(do_forwarding_test<int const&&>(std::move(ctup)));
+ }
+ {
+ using Tup = std::tuple<int&, const char*, unsigned&&>;
+ int x = 42;
+ unsigned y = 101;
+ Tup tup(x, "hello world", std::move(y));
+ Tup const& ctup = tup;
+ assert((do_forwarding_test<int&, const char*&, unsigned&>(tup)));
+ assert((do_forwarding_test<int&, const char* const&, unsigned &>(ctup)));
+ assert((do_forwarding_test<int&, const char*&&, unsigned&&>(std::move(tup))));
+ assert((do_forwarding_test<int&, const char* const&&, unsigned &&>(std::move(ctup))));
+ }
+ // test with pair<T, U>
+ {
+ using Tup = std::pair<int&, const char*>;
+ int x = 42;
+ Tup tup(x, "hello world");
+ Tup const& ctup = tup;
+ assert((do_forwarding_test<int&, const char*&>(tup)));
+ assert((do_forwarding_test<int&, const char* const&>(ctup)));
+ assert((do_forwarding_test<int&, const char*&&>(std::move(tup))));
+ assert((do_forwarding_test<int&, const char* const&&>(std::move(ctup))));
+ }
+ // test with array<T, I>
+ {
+ using Tup = std::array<int, 3>;
+ Tup tup = {42, 101, -1};
+ Tup const& ctup = tup;
+ assert((do_forwarding_test<int&, int&, int&>(tup)));
+ assert((do_forwarding_test<int const&, int const&, int const&>(ctup)));
+ assert((do_forwarding_test<int&&, int&&, int&&>(std::move(tup))));
+ assert((do_forwarding_test<int const&&, int const&&, int const&&>(std::move(ctup))));
+ }
+}
+
+void test_noexcept() {
+ struct NothrowMoveable {
+ NothrowMoveable() = default;
+ NothrowMoveable(NothrowMoveable const&) {}
+ NothrowMoveable(NothrowMoveable&&) noexcept {}
+ };
+ struct TestType {
+ TestType(int, NothrowMoveable) noexcept {}
+ TestType(int, int, int) noexcept(false) {}
+ TestType(long, long, long) noexcept {}
+ };
+ {
+ using Tuple = std::tuple<int, NothrowMoveable>;
+ Tuple tup; ((void)tup);
+ Tuple const& ctup = tup; ((void)ctup);
+ ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
+ ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
+ }
+ {
+ using Tuple = std::pair<int, NothrowMoveable>;
+ Tuple tup; ((void)tup);
+ Tuple const& ctup = tup; ((void)ctup);
+ ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
+ ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
+ }
+ {
+ using Tuple = std::tuple<int, int, int>;
+ Tuple tup; ((void)tup);
+ ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
+ }
+ {
+ using Tuple = std::tuple<long, long, long>;
+ Tuple tup; ((void)tup);
+ ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
+ }
+ {
+ using Tuple = std::array<int, 3>;
+ Tuple tup; ((void)tup);
+ ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
+ }
+ {
+ using Tuple = std::array<long, 3>;
+ Tuple tup; ((void)tup);
+ ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
+ }
+}
+
+int main()
+{
+ test_constexpr_construction();
+ test_perfect_forwarding();
+ test_noexcept();
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_copy.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_copy.pass.cpp
index 2dde6b5521f2d..91892efaf1393 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_copy.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_copy.pass.cpp
@@ -74,4 +74,16 @@ int main()
assert(std::get<1>(t1) == int('a'));
assert(std::get<2>(t1).id_ == 2);
}
+ {
+ // Test that tuple evaluates correctly applies an lvalue reference
+ // before evaluating is_assignable (ie 'is_assignable<int&, int&>')
+ // instead of evaluating 'is_assignable<int&&, int&>' which is false.
+ int x = 42;
+ int y = 43;
+ std::tuple<int&&> t(std::move(x));
+ std::tuple<int&> t2(y);
+ t = t2;
+ assert(std::get<0>(t) == 43);
+ assert(&std::get<0>(t) == &x);
+ }
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_move.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_move.pass.cpp
index 11bfdd0c94a98..afd3e0fdb8e3d 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_move.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_move.pass.cpp
@@ -37,6 +37,13 @@ struct D
explicit D(int i) : B(i) {}
};
+struct E {
+ E() = default;
+ E& operator=(int val) {
+ return *this;
+ }
+};
+
int main()
{
{
@@ -88,4 +95,16 @@ int main()
assert(std::get<1>(t1) == int('a'));
assert(std::get<2>(t1)->id_ == 3);
}
+ {
+ // Test that tuple evaluates correctly applies an lvalue reference
+ // before evaluating is_assignable (ie 'is_assignable<int&, int&&>')
+ // instead of evaluating 'is_assignable<int&&, int&&>' which is false.
+ int x = 42;
+ int y = 43;
+ std::tuple<int&&, E> t(std::move(x), E{});
+ std::tuple<int&&, int> t2(std::move(y), 44);
+ t = std::move(t2);
+ assert(std::get<0>(t) == 43);
+ assert(&std::get<0>(t) == &x);
+ }
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp
new file mode 100644
index 0000000000000..4ddfb463385c7
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp
@@ -0,0 +1,178 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++98, c++03
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class TupleLike>
+// tuple(TupleLike&&);
+// template <class Alloc, class TupleLike>
+// tuple(std::allocator_arg_t, Alloc const&, TupleLike&&);
+
+// Check that the tuple-like ctors are properly disabled when the UTypes...
+// constructor should be selected. See PR22806.
+
+#include <tuple>
+#include <memory>
+#include <cassert>
+
+template <class Tp>
+using uncvref_t = typename std::remove_cv<typename std::remove_reference<Tp>::type>::type;
+
+template <class Tuple, class = uncvref_t<Tuple>>
+struct IsTuple : std::false_type {};
+
+template <class Tuple, class ...Args>
+struct IsTuple<Tuple, std::tuple<Args...>> : std::true_type {};
+
+struct ConstructibleFromTupleAndInt {
+ enum State { FromTuple, FromInt, Copied, Moved };
+ State state;
+
+ ConstructibleFromTupleAndInt(ConstructibleFromTupleAndInt const&) : state(Copied) {}
+ ConstructibleFromTupleAndInt(ConstructibleFromTupleAndInt &&) : state(Moved) {}
+
+ template <class Tuple, class = typename std::enable_if<IsTuple<Tuple>::value>::type>
+ explicit ConstructibleFromTupleAndInt(Tuple&&) : state(FromTuple) {}
+
+ explicit ConstructibleFromTupleAndInt(int) : state(FromInt) {}
+};
+
+struct ConvertibleFromTupleAndInt {
+ enum State { FromTuple, FromInt, Copied, Moved };
+ State state;
+
+ ConvertibleFromTupleAndInt(ConvertibleFromTupleAndInt const&) : state(Copied) {}
+ ConvertibleFromTupleAndInt(ConvertibleFromTupleAndInt &&) : state(Moved) {}
+
+ template <class Tuple, class = typename std::enable_if<IsTuple<Tuple>::value>::type>
+ ConvertibleFromTupleAndInt(Tuple&&) : state(FromTuple) {}
+
+ ConvertibleFromTupleAndInt(int) : state(FromInt) {}
+};
+
+struct ConstructibleFromInt {
+ enum State { FromInt, Copied, Moved };
+ State state;
+
+ ConstructibleFromInt(ConstructibleFromInt const&) : state(Copied) {}
+ ConstructibleFromInt(ConstructibleFromInt &&) : state(Moved) {}
+
+ explicit ConstructibleFromInt(int) : state(FromInt) {}
+};
+
+struct ConvertibleFromInt {
+ enum State { FromInt, Copied, Moved };
+ State state;
+
+ ConvertibleFromInt(ConvertibleFromInt const&) : state(Copied) {}
+ ConvertibleFromInt(ConvertibleFromInt &&) : state(Moved) {}
+ ConvertibleFromInt(int) : state(FromInt) {}
+};
+
+int main()
+{
+ // Test for the creation of dangling references when a tuple is used to
+ // store a reference to another tuple as its only element.
+ // Ex std::tuple<std::tuple<int>&&>.
+ // In this case the constructors 1) 'tuple(UTypes&&...)'
+ // and 2) 'tuple(TupleLike&&)' need to be manually disambiguated because
+ // when both #1 and #2 participate in partial ordering #2 will always
+ // be chosen over #1.
+ // See PR22806 and LWG issue #2549 for more information.
+ // (https://llvm.org/bugs/show_bug.cgi?id=22806)
+ using T = std::tuple<int>;
+ std::allocator<int> A;
+ { // rvalue reference
+ T t1(42);
+ std::tuple< T&& > t2(std::move(t1));
+ assert(&std::get<0>(t2) == &t1);
+ }
+ { // const lvalue reference
+ T t1(42);
+
+ std::tuple< T const & > t2(t1);
+ assert(&std::get<0>(t2) == &t1);
+
+ std::tuple< T const & > t3(static_cast<T const&>(t1));
+ assert(&std::get<0>(t3) == &t1);
+ }
+ { // lvalue reference
+ T t1(42);
+
+ std::tuple< T & > t2(t1);
+ assert(&std::get<0>(t2) == &t1);
+ }
+ { // const rvalue reference
+ T t1(42);
+
+ std::tuple< T const && > t2(std::move(t1));
+ assert(&std::get<0>(t2) == &t1);
+ }
+ { // rvalue reference via uses-allocator
+ T t1(42);
+ std::tuple< T&& > t2(std::allocator_arg, A, std::move(t1));
+ assert(&std::get<0>(t2) == &t1);
+ }
+ { // const lvalue reference via uses-allocator
+ T t1(42);
+
+ std::tuple< T const & > t2(std::allocator_arg, A, t1);
+ assert(&std::get<0>(t2) == &t1);
+
+ std::tuple< T const & > t3(std::allocator_arg, A, static_cast<T const&>(t1));
+ assert(&std::get<0>(t3) == &t1);
+ }
+ { // lvalue reference via uses-allocator
+ T t1(42);
+
+ std::tuple< T & > t2(std::allocator_arg, A, t1);
+ assert(&std::get<0>(t2) == &t1);
+ }
+ { // const rvalue reference via uses-allocator
+ T const t1(42);
+ std::tuple< T const && > t2(std::allocator_arg, A, std::move(t1));
+ assert(&std::get<0>(t2) == &t1);
+ }
+ // Test constructing a 1-tuple of the form tuple<UDT> from another 1-tuple
+ // 'tuple<T>' where UDT *can* be constructed from 'tuple<T>' In this case
+ // the 'tuple(UTypes...)' ctor should be choosen and 'UDT' constructed frow
+ // 'tuple<T>'.
+ {
+ using VT = ConstructibleFromTupleAndInt;
+ std::tuple<int> t1(42);
+ std::tuple<VT> t2(t1);
+ assert(std::get<0>(t2).state == VT::FromTuple);
+ }
+ {
+ using VT = ConvertibleFromTupleAndInt;
+ std::tuple<int> t1(42);
+ std::tuple<VT> t2 = {t1};
+ assert(std::get<0>(t2).state == VT::FromTuple);
+ }
+ // Test constructing a 1-tuple of the form tuple<UDT> from another 1-tuple
+ // 'tuple<T>' where UDT cannot be constructed from 'tuple<T>' but can
+ // be constructed from 'T'. In this case the tuple-like ctor should be
+ // chosen and 'UDT' constructed from 'T'
+ {
+ using VT = ConstructibleFromInt;
+ std::tuple<int> t1(42);
+ std::tuple<VT> t2(t1);
+ assert(std::get<0>(t2).state == VT::FromInt);
+ }
+ {
+ using VT = ConvertibleFromInt;
+ std::tuple<int> t1(42);
+ std::tuple<VT> t2 = {t1};
+ assert(std::get<0>(t2).state == VT::FromInt);
+ }
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
new file mode 100644
index 0000000000000..ed3cafadbf08d
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
@@ -0,0 +1,96 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++98, c++03
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class ...UTypes>
+// EXPLICIT(...) tuple(UTypes&&...)
+
+// Check that the UTypes... ctor is properly disabled before evaluating any
+// SFINAE when the tuple-like copy/move ctor should *clearly* be selected
+// instead. This happens 'sizeof...(UTypes) == 1' and the first element of
+// 'UTypes...' is an instance of the tuple itself. See PR23256.
+
+#include <tuple>
+#include <memory>
+#include <type_traits>
+
+
+struct UnconstrainedCtor {
+ int value_;
+
+ UnconstrainedCtor() : value_(0) {}
+
+ // Blows up when instantiated for any type other than int. Because the ctor
+ // is constexpr it is instantiated by 'is_constructible' and 'is_convertible'
+ // for Clang based compilers. GCC does not instantiate the ctor body
+ // but it does instantiate the noexcept specifier and it will blow up there.
+ template <typename T>
+ constexpr UnconstrainedCtor(T value) noexcept(noexcept(value_ = value))
+ : value_(static_cast<int>(value))
+ {
+ static_assert(std::is_same<int, T>::value, "");
+ }
+};
+
+struct ExplicitUnconstrainedCtor {
+ int value_;
+
+ ExplicitUnconstrainedCtor() : value_(0) {}
+
+ template <typename T>
+ constexpr explicit ExplicitUnconstrainedCtor(T value)
+ noexcept(noexcept(value_ = value))
+ : value_(static_cast<int>(value))
+ {
+ static_assert(std::is_same<int, T>::value, "");
+ }
+
+};
+
+int main() {
+ typedef UnconstrainedCtor A;
+ typedef ExplicitUnconstrainedCtor ExplicitA;
+ {
+ static_assert(std::is_copy_constructible<std::tuple<A>>::value, "");
+ static_assert(std::is_move_constructible<std::tuple<A>>::value, "");
+ static_assert(std::is_copy_constructible<std::tuple<ExplicitA>>::value, "");
+ static_assert(std::is_move_constructible<std::tuple<ExplicitA>>::value, "");
+ }
+ {
+ static_assert(std::is_constructible<
+ std::tuple<A>,
+ std::allocator_arg_t, std::allocator<void>,
+ std::tuple<A> const&
+ >::value, "");
+ static_assert(std::is_constructible<
+ std::tuple<A>,
+ std::allocator_arg_t, std::allocator<void>,
+ std::tuple<A> &&
+ >::value, "");
+ static_assert(std::is_constructible<
+ std::tuple<ExplicitA>,
+ std::allocator_arg_t, std::allocator<void>,
+ std::tuple<ExplicitA> const&
+ >::value, "");
+ static_assert(std::is_constructible<
+ std::tuple<ExplicitA>,
+ std::allocator_arg_t, std::allocator<void>,
+ std::tuple<ExplicitA> &&
+ >::value, "");
+ }
+ {
+ std::tuple<A&&> t(std::forward_as_tuple(A{}));
+ std::tuple<ExplicitA&&> t2(std::forward_as_tuple(ExplicitA{}));
+ }
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp
new file mode 100644
index 0000000000000..c8b722f836c17
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++98, c++03
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class Alloc> tuple(allocator_arg_t, Alloc const&)
+
+// Libc++ has to deduce the 'allocator_arg_t' parameter for this constructor
+// as 'AllocArgT'. Previously libc++ has tried to support tags derived from
+// 'allocator_arg_t' by using 'is_base_of<AllocArgT, allocator_arg_t>'.
+// However this breaks whenever a 2-tuple contains a reference to an incomplete
+// type as its first parameter. See PR27684.
+
+#include <tuple>
+#include <cassert>
+
+struct IncompleteType;
+extern IncompleteType inc1;
+extern IncompleteType inc2;
+IncompleteType const& cinc1 = inc1;
+IncompleteType const& cinc2 = inc2;
+
+int main() {
+ using IT = IncompleteType;
+ { // try calling tuple(Tp const&...)
+ using Tup = std::tuple<const IT&, const IT&>;
+ Tup t(cinc1, cinc2);
+ assert(&std::get<0>(t) == &inc1);
+ assert(&std::get<1>(t) == &inc2);
+ }
+ { // try calling tuple(Up&&...)
+ using Tup = std::tuple<const IT&, const IT&>;
+ Tup t(inc1, inc2);
+ assert(&std::get<0>(t) == &inc1);
+ assert(&std::get<1>(t) == &inc2);
+ }
+}
+
+struct IncompleteType {};
+IncompleteType inc1;
+IncompleteType inc2;
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp
index 817cc8f109905..6ab303c735bec 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp
@@ -82,6 +82,8 @@ void test_default_constructible_extension_sfinae()
MoveOnly, Tuple, MoveOnly, MoveOnly
>::value, "");
}
+ // testing extensions
+#ifdef _LIBCPP_VERSION
{
typedef std::tuple<MoveOnly, int> Tuple;
typedef std::tuple<MoveOnly, Tuple, MoveOnly, MoveOnly> NestedTuple;
@@ -96,6 +98,7 @@ void test_default_constructible_extension_sfinae()
MoveOnly, Tuple, MoveOnly, MoveOnly
>::value, "");
}
+#endif
}
int main()
@@ -118,6 +121,7 @@ int main()
assert(std::get<2>(t) == 2);
}
// extensions
+#ifdef _LIBCPP_VERSION
{
std::tuple<MoveOnly, MoveOnly, MoveOnly> t(MoveOnly(0),
MoveOnly(1));
@@ -131,7 +135,8 @@ int main()
assert(std::get<1>(t) == MoveOnly());
assert(std::get<2>(t) == MoveOnly());
}
-#if _LIBCPP_STD_VER > 11
+#endif
+#if TEST_STD_VER > 11
{
constexpr std::tuple<Empty> t0{Empty()};
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp
index 39776822cbda4..4da5fc7f83979 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++98, c++03
+
// <tuple>
// template <class... Types> class tuple;
@@ -14,7 +16,9 @@
// template <class Alloc>
// tuple(allocator_arg_t, const Alloc& a);
-// UNSUPPORTED: c++98, c++03
+// NOTE: this constructor does not currently support tags derived from
+// allocator_arg_t because libc++ has to deduce the parameter as a template
+// argument. See PR27684 (https://llvm.org/bugs/show_bug.cgi?id=27684)
#include <tuple>
#include <cassert>
@@ -24,6 +28,18 @@
#include "../alloc_first.h"
#include "../alloc_last.h"
+template <class T = void>
+struct NonDefaultConstructible {
+ constexpr NonDefaultConstructible() {
+ static_assert(!std::is_same<T, T>::value, "Default Ctor instantiated");
+ }
+
+ explicit constexpr NonDefaultConstructible(int) {}
+};
+
+
+struct DerivedFromAllocArgT : std::allocator_arg_t {};
+
int main()
{
{
@@ -78,4 +94,14 @@ int main()
assert(!alloc_last::allocator_constructed);
assert(std::get<2>(t) == alloc_last());
}
+ {
+ // Test that the uses-allocator default constructor does not evaluate
+ // it's SFINAE when it otherwise shouldn't be selected. Do this by
+ // using 'NonDefaultConstructible' which will cause a compile error
+ // if std::is_default_constructible is evaluated on it.
+ using T = NonDefaultConstructible<>;
+ T v(42);
+ std::tuple<T, T> t(v, v);
+ std::tuple<T, T> t2(42, 42);
+ }
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp
index 3929965cd2735..e174e9b321b8d 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp
@@ -24,16 +24,29 @@
#include "../alloc_first.h"
#include "../alloc_last.h"
-struct NoDefault { NoDefault() = delete; };
+template <class T = void>
+struct DefaultCtorBlowsUp {
+ constexpr DefaultCtorBlowsUp() {
+ static_assert(!std::is_same<T, T>::value, "Default Ctor instantiated");
+ }
-// Make sure the _Up... constructor SFINAEs out when the types that
-// are not explicitly initialized are not all default constructible.
-// Otherwise, std::is_constructible would return true but instantiating
-// the constructor would fail.
-void test_default_constructible_extension_sfinae()
+ explicit constexpr DefaultCtorBlowsUp(int x) : value(x) {}
+
+ int value;
+};
+
+
+struct DerivedFromAllocArgT : std::allocator_arg_t {};
+
+
+// Make sure the _Up... constructor SFINAEs out when the number of initializers
+// is less that the number of elements in the tuple. Previously libc++ would
+// offer these constructers as an extension but they broke conforming code.
+void test_uses_allocator_sfinae_evaluation()
{
+ using BadDefault = DefaultCtorBlowsUp<>;
{
- typedef std::tuple<MoveOnly, NoDefault> Tuple;
+ typedef std::tuple<MoveOnly, MoveOnly, BadDefault> Tuple;
static_assert(!std::is_constructible<
Tuple,
@@ -42,11 +55,11 @@ void test_default_constructible_extension_sfinae()
static_assert(std::is_constructible<
Tuple,
- std::allocator_arg_t, A1<int>, MoveOnly, NoDefault
+ std::allocator_arg_t, A1<int>, MoveOnly, MoveOnly, BadDefault
>::value, "");
}
{
- typedef std::tuple<MoveOnly, MoveOnly, NoDefault> Tuple;
+ typedef std::tuple<MoveOnly, MoveOnly, BadDefault, BadDefault> Tuple;
static_assert(!std::is_constructible<
Tuple,
@@ -55,53 +68,44 @@ void test_default_constructible_extension_sfinae()
static_assert(std::is_constructible<
Tuple,
- std::allocator_arg_t, A1<int>, MoveOnly, MoveOnly, NoDefault
- >::value, "");
- }
- {
- // Same idea as above but with a nested tuple
- typedef std::tuple<MoveOnly, NoDefault> Tuple;
- typedef std::tuple<MoveOnly, Tuple, MoveOnly, MoveOnly> NestedTuple;
-
- static_assert(!std::is_constructible<
- NestedTuple,
- std::allocator_arg_t, A1<int>, MoveOnly, MoveOnly, MoveOnly, MoveOnly
- >::value, "");
-
- static_assert(std::is_constructible<
- NestedTuple,
- std::allocator_arg_t, A1<int>, MoveOnly, Tuple, MoveOnly, MoveOnly
- >::value, "");
- }
- {
- typedef std::tuple<MoveOnly, int> Tuple;
- typedef std::tuple<MoveOnly, Tuple, MoveOnly, MoveOnly> NestedTuple;
-
- static_assert(std::is_constructible<
- NestedTuple,
- std::allocator_arg_t, A1<int>, MoveOnly, MoveOnly, MoveOnly, MoveOnly
- >::value, "");
-
- static_assert(std::is_constructible<
- NestedTuple,
- std::allocator_arg_t, A1<int>, MoveOnly, Tuple, MoveOnly, MoveOnly
+ std::allocator_arg_t, A1<int>, MoveOnly, MoveOnly, BadDefault, BadDefault
>::value, "");
}
}
+struct Explicit {
+ int value;
+ explicit Explicit(int x) : value(x) {}
+};
+
int main()
{
{
+ std::tuple<Explicit> t{std::allocator_arg, std::allocator<void>{}, 42};
+ assert(std::get<0>(t).value == 42);
+ }
+ {
std::tuple<MoveOnly> t(std::allocator_arg, A1<int>(), MoveOnly(0));
assert(std::get<0>(t) == 0);
}
{
+ using T = DefaultCtorBlowsUp<>;
+ std::tuple<T> t(std::allocator_arg, A1<int>(), T(42));
+ assert(std::get<0>(t).value == 42);
+ }
+ {
std::tuple<MoveOnly, MoveOnly> t(std::allocator_arg, A1<int>(),
MoveOnly(0), MoveOnly(1));
assert(std::get<0>(t) == 0);
assert(std::get<1>(t) == 1);
}
{
+ using T = DefaultCtorBlowsUp<>;
+ std::tuple<T, T> t(std::allocator_arg, A1<int>(), T(42), T(43));
+ assert(std::get<0>(t).value == 42);
+ assert(std::get<1>(t).value == 43);
+ }
+ {
std::tuple<MoveOnly, MoveOnly, MoveOnly> t(std::allocator_arg, A1<int>(),
MoveOnly(0),
1, 2);
@@ -110,6 +114,13 @@ int main()
assert(std::get<2>(t) == 2);
}
{
+ using T = DefaultCtorBlowsUp<>;
+ std::tuple<T, T, T> t(std::allocator_arg, A1<int>(), T(1), T(2), T(3));
+ assert(std::get<0>(t).value == 1);
+ assert(std::get<1>(t).value == 2);
+ assert(std::get<2>(t).value == 3);
+ }
+ {
alloc_first::allocator_constructed = false;
alloc_last::allocator_constructed = false;
std::tuple<int, alloc_first, alloc_last> t(std::allocator_arg,
@@ -120,22 +131,22 @@ int main()
assert(alloc_last::allocator_constructed);
assert(std::get<2>(t) == alloc_last(3));
}
- // extensions
- {
- std::tuple<MoveOnly, MoveOnly, MoveOnly> t(std::allocator_arg, A1<int>(),
- 0, 1);
- assert(std::get<0>(t) == 0);
- assert(std::get<1>(t) == 1);
- assert(std::get<2>(t) == MoveOnly());
- }
{
- std::tuple<MoveOnly, MoveOnly, MoveOnly> t(std::allocator_arg, A1<int>(),
- 0);
- assert(std::get<0>(t) == 0);
- assert(std::get<1>(t) == MoveOnly());
- assert(std::get<2>(t) == MoveOnly());
+ // Check that uses-allocator construction is still selected when
+ // given a tag type that derives from allocator_arg_t.
+ DerivedFromAllocArgT tag;
+ alloc_first::allocator_constructed = false;
+ alloc_last::allocator_constructed = false;
+ std::tuple<int, alloc_first, alloc_last> t(tag,
+ A1<int>(5), 1, 2, 3);
+ assert(std::get<0>(t) == 1);
+ assert(alloc_first::allocator_constructed);
+ assert(std::get<1>(t) == alloc_first(2));
+ assert(alloc_last::allocator_constructed);
+ assert(std::get<2>(t) == alloc_last(3));
}
- // Check that SFINAE is properly applied with the default reduced arity
- // constructor extensions.
- test_default_constructible_extension_sfinae();
+ // Stress test the SFINAE on the uses-allocator constructors and
+ // ensure that the "reduced-arity-initialization" extension is not offered
+ // for these constructors.
+ test_uses_allocator_sfinae_evaluation();
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.fail.cpp
new file mode 100644
index 0000000000000..b28ad6dab5ab7
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.fail.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class Alloc>
+// EXPLICIT tuple(allocator_arg_t, const Alloc& a, const Types&...);
+
+// UNSUPPORTED: c++98, c++03
+
+#include <tuple>
+#include <memory>
+#include <cassert>
+
+struct ExplicitCopy {
+ explicit ExplicitCopy(ExplicitCopy const&) {}
+ explicit ExplicitCopy(int) {}
+};
+
+std::tuple<ExplicitCopy> const_explicit_copy_test() {
+ const ExplicitCopy e(42);
+ return {std::allocator_arg, std::allocator<void>{}, e};
+ // expected-error@-1 {{chosen constructor is explicit in copy-initialization}}
+}
+
+std::tuple<ExplicitCopy> non_const_explicity_copy_test() {
+ ExplicitCopy e(42);
+ return {std::allocator_arg, std::allocator<void>{}, e};
+ // expected-error@-1 {{chosen constructor is explicit in copy-initialization}}
+}
+int main()
+{
+ const_explicit_copy_test();
+ non_const_explicity_copy_test();
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp
index 0f68926376f24..73d53a4c0e261 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp
@@ -17,15 +17,37 @@
// UNSUPPORTED: c++98, c++03
#include <tuple>
+#include <memory>
#include <cassert>
#include "allocators.h"
#include "../alloc_first.h"
#include "../alloc_last.h"
+struct ImplicitCopy {
+ explicit ImplicitCopy(int) {}
+ ImplicitCopy(ImplicitCopy const&) {}
+};
+
+// Test that tuple(std::allocator_arg, Alloc, Types const&...) allows implicit
+// copy conversions in return value expressions.
+std::tuple<ImplicitCopy> testImplicitCopy1() {
+ ImplicitCopy i(42);
+ return {std::allocator_arg, std::allocator<void>{}, i};
+}
+
+std::tuple<ImplicitCopy> testImplicitCopy2() {
+ const ImplicitCopy i(42);
+ return {std::allocator_arg, std::allocator<void>{}, i};
+}
+
int main()
{
{
+ // check that the literal '0' can implicitly initialize a stored pointer.
+ std::tuple<int*> t = {std::allocator_arg, std::allocator<void>{}, 0};
+ }
+ {
std::tuple<int> t(std::allocator_arg, A1<int>(), 3);
assert(std::get<0>(t) == 3);
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.fail.cpp
new file mode 100644
index 0000000000000..ccf08833b537e
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.fail.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class Alloc, class ...UTypes>
+// tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...> const&);
+
+// UNSUPPORTED: c++98, c++03
+
+#include <tuple>
+#include <memory>
+
+struct ExplicitCopy {
+ explicit ExplicitCopy(int) {}
+ explicit ExplicitCopy(ExplicitCopy const&) {}
+
+};
+
+std::tuple<ExplicitCopy> const_explicit_copy_test() {
+ const std::tuple<int> t1(42);
+ return {std::allocator_arg, std::allocator<void>{}, t1};
+ // expected-error@-1 {{chosen constructor is explicit in copy-initialization}}
+}
+
+std::tuple<ExplicitCopy> non_const_explicit_copy_test() {
+ std::tuple<int> t1(42);
+ return {std::allocator_arg, std::allocator<void>{}, t1};
+ // expected-error@-1 {{chosen constructor is explicit in copy-initialization}}
+}
+
+int main()
+{
+
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp
index 8acfde7a98eb1..36d9f32879cbb 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp
@@ -17,12 +17,23 @@
// UNSUPPORTED: c++98, c++03
#include <tuple>
+#include <memory>
#include <cassert>
#include "allocators.h"
#include "../alloc_first.h"
#include "../alloc_last.h"
+struct Explicit {
+ int value;
+ explicit Explicit(int x) : value(x) {}
+};
+
+struct Implicit {
+ int value;
+ Implicit(int x) : value(x) {}
+};
+
int main()
{
{
@@ -66,4 +77,14 @@ int main()
assert(std::get<1>(t1) == 2);
assert(std::get<2>(t1) == 3);
}
+ {
+ const std::tuple<int> t1(42);
+ std::tuple<Explicit> t2{std::allocator_arg, std::allocator<void>{}, t1};
+ assert(std::get<0>(t2).value == 42);
+ }
+ {
+ const std::tuple<int> t1(42);
+ std::tuple<Implicit> t2 = {std::allocator_arg, std::allocator<void>{}, t1};
+ assert(std::get<0>(t2).value == 42);
+ }
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.fail.cpp
new file mode 100644
index 0000000000000..d3539cebf9500
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.fail.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class Alloc, class ...UTypes>
+// tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
+
+// UNSUPPORTED: c++98, c++03
+
+#include <tuple>
+#include <memory>
+
+struct ExplicitCopy {
+ explicit ExplicitCopy(int) {}
+ explicit ExplicitCopy(ExplicitCopy const&) {}
+};
+
+std::tuple<ExplicitCopy> explicit_move_test() {
+ std::tuple<int> t1(42);
+ return {std::allocator_arg, std::allocator<void>{}, std::move(t1)};
+ // expected-error@-1 {{chosen constructor is explicit in copy-initialization}}
+}
+
+int main()
+{
+
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp
index c862d3b64d56f..d3a6add5da6a8 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp
@@ -40,6 +40,16 @@ struct D
explicit D(int i) : B(i) {}
};
+struct Explicit {
+ int value;
+ explicit Explicit(int x) : value(x) {}
+};
+
+struct Implicit {
+ int value;
+ Implicit(int x) : value(x) {}
+};
+
int main()
{
{
@@ -81,4 +91,14 @@ int main()
assert(std::get<1>(t1) == 2);
assert(std::get<2>(t1)->id_ == 3);
}
+ {
+ std::tuple<int> t1(42);
+ std::tuple<Explicit> t2{std::allocator_arg, std::allocator<void>{}, std::move(t1)};
+ assert(std::get<0>(t2).value == 42);
+ }
+ {
+ std::tuple<int> t1(42);
+ std::tuple<Implicit> t2 = {std::allocator_arg, std::allocator<void>{}, std::move(t1)};
+ assert(std::get<0>(t2).value == 42);
+ }
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp
index 14e127e59ba91..7c9f60cbf901b 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp
@@ -52,6 +52,8 @@ int main()
assert(alloc_last::allocator_constructed);
assert(std::get<0>(t) == 2);
}
+// testing extensions
+#ifdef _LIBCPP_VERSION
{
typedef std::tuple<alloc_first, alloc_last> T;
T t0(2, 3);
@@ -75,4 +77,5 @@ int main()
assert(std::get<1>(t) == 2);
assert(std::get<2>(t) == 3);
}
+#endif
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp
index 54d3f7ee0c079..a3e1a9de61958 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp
@@ -53,6 +53,8 @@ int main()
assert(alloc_last::allocator_constructed);
assert(std::get<0>(t) == 1);
}
+// testing extensions
+#ifdef _LIBCPP_VERSION
{
typedef std::tuple<MoveOnly, alloc_first> T;
T t0(0 ,1);
@@ -74,4 +76,5 @@ int main()
assert(std::get<1>(t) == 2);
assert(std::get<2>(t) == 3);
}
+#endif
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.fail.cpp
index 00e2af265b360..b72f0fc2efec4 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.fail.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.fail.cpp
@@ -19,9 +19,30 @@
#include <string>
#include <cassert>
+struct ExplicitCopy {
+ ExplicitCopy(int) {}
+ explicit ExplicitCopy(ExplicitCopy const&) {}
+};
+
+std::tuple<ExplicitCopy> const_explicit_copy() {
+ const ExplicitCopy e(42);
+ return {e};
+ // expected-error@-1 {{chosen constructor is explicit in copy-initialization}}
+}
+
+
+std::tuple<ExplicitCopy> non_const_explicit_copy() {
+ ExplicitCopy e(42);
+ return {e};
+ // expected-error@-1 {{chosen constructor is explicit in copy-initialization}}
+}
+
+std::tuple<ExplicitCopy> const_explicit_copy_no_brace() {
+ const ExplicitCopy e(42);
+ return e;
+ // expected-error@-1 {{no viable conversion}}
+}
+
int main()
{
- {
- std::tuple<int*> t = 0;
- }
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
index bbadf8de16001..367f19e5d8dd6 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
@@ -53,13 +53,40 @@ struct NoValueCtorEmpty
{ static_assert(never<T>::value, "This should not be instantiated"); }
};
+
+struct ImplicitCopy {
+ explicit ImplicitCopy(int) {}
+ ImplicitCopy(ImplicitCopy const&) {}
+};
+
+// Test that tuple(std::allocator_arg, Alloc, Types const&...) allows implicit
+// copy conversions in return value expressions.
+std::tuple<ImplicitCopy> testImplicitCopy1() {
+ ImplicitCopy i(42);
+ return {i};
+}
+
+std::tuple<ImplicitCopy> testImplicitCopy2() {
+ const ImplicitCopy i(42);
+ return {i};
+}
+
+std::tuple<ImplicitCopy> testImplicitCopy3() {
+ const ImplicitCopy i(42);
+ return i;
+}
+
int main()
{
{
+ // check that the literal '0' can implicitly initialize a stored pointer.
+ std::tuple<int*> t = 0;
+ }
+ {
std::tuple<int> t(2);
assert(std::get<0>(t) == 2);
}
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
{
constexpr std::tuple<int> t(2);
static_assert(std::get<0>(t) == 2, "");
@@ -74,7 +101,7 @@ int main()
assert(std::get<0>(t) == 2);
assert(std::get<1>(t) == nullptr);
}
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
{
constexpr std::tuple<int, char*> t(2, nullptr);
static_assert(std::get<0>(t) == 2, "");
@@ -109,7 +136,8 @@ int main()
assert(std::get<2>(t) == 2);
assert(std::get<3>(t) == 3);
}
- // extensions
+// extensions
+#ifdef _LIBCPP_VERSION
{
std::tuple<int, char*, std::string> t(2);
assert(std::get<0>(t) == 2);
@@ -129,4 +157,5 @@ int main()
assert(std::get<2>(t) == "text");
assert(std::get<3>(t) == 0.0);
}
+#endif
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp
index 740b6589e5114..d6d489fd0ea44 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_pair.pass.cpp
@@ -29,7 +29,7 @@ int main()
assert(std::get<0>(t1) == 2);
assert(std::get<1>(t1) == short('a'));
}
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
{
typedef std::pair<double, char> P0;
typedef std::tuple<int, short> T1;
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp
index 5ad4f9227f481..b7fa2e3a03cc5 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_copy.pass.cpp
@@ -20,6 +20,16 @@
#include <string>
#include <cassert>
+struct Explicit {
+ int value;
+ explicit Explicit(int x) : value(x) {}
+};
+
+struct Implicit {
+ int value;
+ Implicit(int x) : value(x) {}
+};
+
struct B
{
int id_;
@@ -33,7 +43,7 @@ struct D
explicit D(int i) : B(i) {}
};
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
struct A
{
@@ -62,7 +72,7 @@ int main()
T1 t1 = t0;
assert(std::get<0>(t1) == 2);
}
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
{
typedef std::tuple<double> T0;
typedef std::tuple<A> T1;
@@ -115,4 +125,14 @@ int main()
assert(std::get<1>(t1) == int('a'));
assert(std::get<2>(t1).id_ == 3);
}
+ {
+ const std::tuple<int> t1(42);
+ std::tuple<Explicit> t2(t1);
+ assert(std::get<0>(t2).value == 42);
+ }
+ {
+ const std::tuple<int> t1(42);
+ std::tuple<Implicit> t2 = t1;
+ assert(std::get<0>(t2).value == 42);
+ }
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_move.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_move.pass.cpp
index 3a6abd3a95af4..8423f5d0145fc 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_move.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_move.pass.cpp
@@ -20,6 +20,16 @@
#include <memory>
#include <cassert>
+struct Explicit {
+ int value;
+ explicit Explicit(int x) : value(x) {}
+};
+
+struct Implicit {
+ int value;
+ Implicit(int x) : value(x) {}
+};
+
struct B
{
int id_;
@@ -81,4 +91,14 @@ int main()
assert(std::get<1>(t1) == int('a'));
assert(std::get<2>(t1)->id_ == 3);
}
+ {
+ std::tuple<int> t1(42);
+ std::tuple<Explicit> t2(std::move(t1));
+ assert(std::get<0>(t2).value == 42);
+ }
+ {
+ std::tuple<int> t1(42);
+ std::tuple<Implicit> t2 = std::move(t1);
+ assert(std::get<0>(t2).value == 42);
+ }
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
index 0cda96846f717..1bd7d6d4e8a87 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
@@ -29,8 +29,10 @@ struct ConstructsWithTupleLeaf
ConstructsWithTupleLeaf(ConstructsWithTupleLeaf &&) {}
template <class T>
- ConstructsWithTupleLeaf(T t)
- { assert(false); }
+ ConstructsWithTupleLeaf(T t) {
+ static_assert(!std::is_same<T, T>::value,
+ "Constructor instantiated for type other than int");
+ }
};
int main()
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp
new file mode 100644
index 0000000000000..76f7e794a8e81
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// UNSUPPORTED: c++98, c++03
+
+#include <tuple>
+#include <utility>
+#include <cassert>
+
+template <class ConstructFrom>
+struct ConstructibleFromT {
+ ConstructibleFromT() = default;
+ ConstructibleFromT(ConstructFrom v) : value(v) {}
+ ConstructFrom value;
+};
+
+template <class AssertOn>
+struct CtorAssertsT {
+ bool defaulted;
+ CtorAssertsT() : defaulted(true) {}
+ template <class T>
+ constexpr CtorAssertsT(T) : defaulted(false) {
+ static_assert(!std::is_same<T, AssertOn>::value, "");
+ }
+};
+
+template <class AllowT, class AssertT>
+struct AllowAssertT {
+ AllowAssertT() = default;
+ AllowAssertT(AllowT) {}
+ template <class U>
+ constexpr AllowAssertT(U) {
+ static_assert(!std::is_same<U, AssertT>::value, "");
+ }
+};
+
+// Construct a tuple<T1, T2> from pair<int, int> where T1 and T2
+// are not constructible from ints but T1 is constructible from std::pair.
+// This considers the following constructors:
+// (1) tuple(TupleLike) -> checks is_constructible<Tn, int>
+// (2) tuple(UTypes...) -> checks is_constructible<T1, pair<int, int>>
+// and is_default_constructible<T2>
+// The point of this test is to ensure that the consideration of (1)
+// short circuits before evaluating is_constructible<T2, int>, which
+// will cause a static assertion.
+void test_tuple_like_lazy_sfinae() {
+#if defined(_LIBCPP_VERSION)
+ // This test requires libc++'s reduced arity initialization.
+ using T1 = ConstructibleFromT<std::pair<int, int>>;
+ using T2 = CtorAssertsT<int>;
+ std::pair<int, int> p(42, 100);
+ std::tuple<T1, T2> t(p);
+ assert(std::get<0>(t).value == p);
+ assert(std::get<1>(t).defaulted);
+#endif
+}
+
+
+struct NonConstCopyable {
+ NonConstCopyable() = default;
+ explicit NonConstCopyable(int v) : value(v) {}
+ NonConstCopyable(NonConstCopyable&) = default;
+ NonConstCopyable(NonConstCopyable const&) = delete;
+ int value;
+};
+
+template <class T>
+struct BlowsUpOnConstCopy {
+ BlowsUpOnConstCopy() = default;
+ constexpr BlowsUpOnConstCopy(BlowsUpOnConstCopy const&) {
+ static_assert(!std::is_same<T, T>::value, "");
+ }
+ BlowsUpOnConstCopy(BlowsUpOnConstCopy&) = default;
+};
+
+// Test the following constructors:
+// (1) tuple(Types const&...)
+// (2) tuple(UTypes&&...)
+// Test that (1) short circuits before evaluating the copy constructor of the
+// second argument. Constructor (2) should be selected.
+void test_const_Types_lazy_sfinae()
+{
+ NonConstCopyable v(42);
+ BlowsUpOnConstCopy<int> b;
+ std::tuple<NonConstCopyable, BlowsUpOnConstCopy<int>> t(v, b);
+ assert(std::get<0>(t).value == 42);
+}
+
+int main() {
+ test_tuple_like_lazy_sfinae();
+ test_const_Types_lazy_sfinae();
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.creation/forward_as_tuple.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.creation/forward_as_tuple.pass.cpp
index 0e556b1b6c8e0..2dbe81513a1a3 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.creation/forward_as_tuple.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.creation/forward_as_tuple.pass.cpp
@@ -20,7 +20,7 @@
template <class Tuple>
void
-test0(const Tuple& t)
+test0(const Tuple&)
{
static_assert(std::tuple_size<Tuple>::value == 0, "");
}
@@ -56,8 +56,8 @@ test2a(const Tuple& t)
#if _LIBCPP_STD_VER > 11
template <class Tuple>
-constexpr int
-test3(const Tuple& t)
+constexpr int
+test3(const Tuple&)
{
return std::tuple_size<Tuple>::value;
}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp
index 2ee96dc7ebf45..f27e8a09fb974 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.creation/make_tuple.pass.cpp
@@ -40,7 +40,7 @@ int main()
assert(i == 0);
assert(j == 0);
}
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
{
constexpr auto t1 = std::make_tuple(0, 1, 3.14);
constexpr int i1 = std::get<1>(t1);
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp
index e21768cb6f5fd..002ad148ad6df 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const.pass.cpp
@@ -36,7 +36,7 @@ int main()
assert(std::get<0>(t) == "high");
assert(std::get<1>(t) == 5);
}
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
{
typedef std::tuple<double, int> T;
constexpr T t(2.718, 5);
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp
index 1c2b17ad88325..86d1191db5564 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_non_const.pass.cpp
@@ -21,7 +21,9 @@
#include <string>
#include <cassert>
-#if __cplusplus > 201103L
+#include "test_macros.h"
+
+#if TEST_STD_VER > 11
struct Empty {};
@@ -69,7 +71,7 @@ int main()
assert(std::get<2>(t) == 4);
assert(d == 2.5);
}
-#if _LIBCPP_STD_VER > 11
+#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, "" );
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.fail.cpp
new file mode 100644
index 0000000000000..74e6efd983bd4
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.fail.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+
+#include <tuple>
+#include <string>
+
+struct UserType {};
+
+void test_bad_index() {
+ std::tuple<long, long, char, std::string, char, UserType, char> t1;
+ (void)std::get<int>(t1); // expected-error@tuple:* {{type not found}}
+ (void)std::get<long>(t1); // expected-note {{requested here}}
+ (void)std::get<char>(t1); // expected-note {{requested here}}
+ // expected-error@tuple:* 2 {{type occurs more than once}}
+ std::tuple<> t0;
+ (void)std::get<char*>(t0); // expected-node {{requested here}}
+ // expected-error@tuple:* 1 {{type not in empty type list}}
+}
+
+void test_bad_return_type() {
+ typedef std::unique_ptr<int> upint;
+ std::tuple<upint> t;
+ upint p = std::get<upint>(t); // expected-error{{deleted copy constructor}}
+}
+
+int main()
+{
+ test_bad_index();
+ test_bad_return_type();
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp
index b661a78de8dba..01ee1ca1f4342 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp
@@ -11,6 +11,7 @@
#include <tuple>
#include <utility>
+#include <memory>
#include <string>
#include <complex>
#include <type_traits>
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp
deleted file mode 100644
index 85c32ca6d4955..0000000000000
--- a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++98, c++03, c++11
-
-#include <tuple>
-#include <string>
-#include <complex>
-
-#include <cassert>
-
-int main()
-{
-#if _LIBCPP_STD_VER > 11
- typedef std::complex<float> cf;
- auto t1 = std::make_tuple<int, std::string> ( 42, "Hi" );
- assert (( std::get<cf>(t1) == cf {1,2} )); // no such type
-#else
-#error
-#endif
-}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type2.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type2.fail.cpp
deleted file mode 100644
index 0a8d5829d02b1..0000000000000
--- a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type2.fail.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++98, c++03, c++11
-
-#include <tuple>
-#include <string>
-#include <complex>
-
-#include <cassert>
-
-int main()
-{
-#if _LIBCPP_STD_VER > 11
- typedef std::complex<float> cf;
- auto t1 = std::make_tuple<int, int, std::string, cf> ( 42, 21, "Hi", { 1,2 } );
- assert ( std::get<int>(t1) == 42 ); // two ints here
-#else
-#error
-#endif
-}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type3.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type3.fail.cpp
deleted file mode 100644
index 0a4550f387dc0..0000000000000
--- a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type3.fail.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++98, c++03, c++11
-
-#include <tuple>
-#include <string>
-#include <complex>
-
-#include <cassert>
-
-int main()
-{
-#if _LIBCPP_STD_VER > 11
- typedef std::complex<float> cf;
- auto t1 = std::make_tuple<double, int, std::string, cf, int> ( 42, 21, "Hi", { 1,2 } );
- assert ( std::get<int>(t1) == 42 ); // two ints here (one at the end)
-#else
-#error
-#endif
-}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type4.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type4.fail.cpp
deleted file mode 100644
index ffc715fe9a5bd..0000000000000
--- a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type4.fail.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++98, c++03, c++11
-
-#include <tuple>
-#include <string>
-#include <memory>
-
-#include <cassert>
-
-int main()
-{
-#if _LIBCPP_STD_VER > 11
- typedef std::unique_ptr<int> upint;
- std::tuple<upint> t(upint(new int(4)));
- upint p = std::get<upint>(t);
-#else
-#error
-#endif
-}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.array.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.array.pass.cpp
index d8a72c617cb5c..57da4b04cdfd9 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.array.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.array.pass.cpp
@@ -18,7 +18,7 @@
// typedef Ti type;
// };
//
-// LWG #2212 says that tuple_size and tuple_element must be
+// LWG #2212 says that tuple_size and tuple_element must be
// available after including <utility>
#include <array>
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.utility.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.utility.pass.cpp
index 8c8357d95d994..bd015ab5bbd6e 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.utility.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple.include.utility.pass.cpp
@@ -15,9 +15,10 @@
// class tuple_size<tuple<Types...>>
// : public integral_constant<size_t, sizeof...(Types)> { };
//
-// LWG #2212 says that tuple_size and tuple_element must be
+// LWG #2212 says that tuple_size and tuple_element must be
// available after including <utility>
+#include <cstddef>
#include <utility>
#include <type_traits>
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp
new file mode 100644
index 0000000000000..4cb73573e7c9d
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <size_t I, class... Types>
+// class tuple_element<I, tuple<Types...> >
+// {
+// public:
+// typedef Ti type;
+// };
+
+// UNSUPPORTED: c++98, c++03
+
+#include <tuple>
+#include <type_traits>
+
+int main()
+{
+ using T = std::tuple<int, long, void*>;
+ using E1 = typename std::tuple_element<1, T &>::type; // expected-error{{undefined template}}
+ using E2 = typename std::tuple_element<3, T>::type;
+ using E3 = typename std::tuple_element<4, T const>::type;
+ // expected-error@__tuple:* 2 {{static_assert failed}}
+
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp
new file mode 100644
index 0000000000000..3f132e47b626c
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <tuple>
+
+// template <class... Types>
+// class tuple_size<tuple<Types...>>
+// : public integral_constant<size_t, sizeof...(Types)> { };
+
+// Expect failures with a reference type, pointer type, and a non-tuple type.
+
+#include <tuple>
+
+int main()
+{
+ (void)std::tuple_size<std::tuple<> &>::value; // expected-error {{implicit instantiation of undefined template}}
+ (void)std::tuple_size<int>::value; // expected-error {{implicit instantiation of undefined template}}
+ (void)std::tuple_size<std::tuple<>*>::value; // expected-error {{implicit instantiation of undefined template}}
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp
new file mode 100644
index 0000000000000..957a683b47f85
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <tuple>
+
+// template <class T> constexpr size_t tuple_size_v = tuple_size<T>::value;
+
+// Expect failures with a reference type, pointer type, and a non-tuple type.
+
+#include <tuple>
+
+int main()
+{
+ (void)std::tuple_size_v<std::tuple<> &>; // expected-note {{requested here}}
+ (void)std::tuple_size_v<int>; // expected-note {{requested here}}
+ (void)std::tuple_size_v<std::tuple<>*>; // expected-note {{requested here}}
+ // expected-error@tuple:* 3 {{implicit instantiation of undefined template}}
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp
new file mode 100644
index 0000000000000..24878a1d560e0
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <tuple>
+
+// template <class T> constexpr size_t tuple_size_v = tuple_size<T>::value;
+
+#include <tuple>
+#include <utility>
+#include <array>
+
+template <class Tuple, int Expect>
+void test()
+{
+ static_assert(std::tuple_size_v<Tuple> == Expect, "");
+ static_assert(std::tuple_size_v<Tuple> == std::tuple_size<Tuple>::value, "");
+ static_assert(std::tuple_size_v<Tuple const> == std::tuple_size<Tuple>::value, "");
+ static_assert(std::tuple_size_v<Tuple volatile> == std::tuple_size<Tuple>::value, "");
+ static_assert(std::tuple_size_v<Tuple const volatile> == std::tuple_size<Tuple>::value, "");
+}
+
+int main()
+{
+ test<std::tuple<>, 0>();
+
+ test<std::tuple<int>, 1>();
+ test<std::array<int, 1>, 1>();
+
+ test<std::tuple<int, int>, 2>();
+ test<std::pair<int, int>, 2>();
+ test<std::array<int, 2>, 2>();
+
+ test<std::tuple<int, int, int>, 3>();
+ test<std::array<int, 3>, 3>();
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
index 0d25edc4547b1..e5991df636f8b 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
@@ -143,7 +143,7 @@ int main()
assert(!(t1 == t2));
assert(t1 != t2);
}
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
{
typedef std::tuple<char, int, double> T1;
typedef std::tuple<double, char, int> T2;
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
index eac84a9c35f6a..34aafb1e1347a 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
@@ -195,7 +195,7 @@ int main()
assert(!(t1 > t2));
assert(!(t1 >= t2));
}
-#if _LIBCPP_STD_VER > 11
+#if _LIBCPP_STD_VER > 11
{
typedef std::tuple<char, int, double> T1;
typedef std::tuple<double, char, int> T2;