1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // <tuple>
10
11 // template <class... Types>
12 // template<class Alloc, class... UTypes>
13 // constexpr explicit(see below)
14 // tuple<Types...>::tuple(allocator_arg_t, const Alloc& a,
15 // tuple<UTypes...>&);
16 //
17 // Constraints:
18 // sizeof...(Types) equals sizeof...(UTypes) &&
19 // (is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...) is true &&
20 // (
21 // sizeof...(Types) is not 1 ||
22 // (
23 // !is_convertible_v<decltype(u), T> &&
24 // !is_constructible_v<T, decltype(u)> &&
25 // !is_same_v<T, U>
26 // )
27 // )
28
29 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
30
31 #include <cassert>
32 #include <tuple>
33
34 #include "copy_move_types.h"
35 #include "test_allocator.h"
36 #include "test_macros.h"
37
38 // test: The expression inside explicit is equivalent to:
39 // !(is_convertible_v<decltype(get<I>(FWD(u))), Types> && ...)
40 static_assert(ImplicitlyConstructible< std::tuple<ConvertibleFrom<MutableCopy>>, std::allocator_arg_t,
41 const test_allocator<int>&, std::tuple<MutableCopy>&>);
42
43 static_assert(
44 ImplicitlyConstructible< std::tuple<ConvertibleFrom<MutableCopy>, ConvertibleFrom<MutableCopy>>,
45 std::allocator_arg_t, const test_allocator<int>&, std::tuple<MutableCopy, MutableCopy>&>);
46
47 static_assert(!ImplicitlyConstructible<std::tuple<ExplicitConstructibleFrom<MutableCopy>>, std::allocator_arg_t,
48 const test_allocator<int>&, std::tuple<MutableCopy>&>);
49
50 static_assert(
51 !ImplicitlyConstructible<std::tuple<ExplicitConstructibleFrom<MutableCopy>, ConvertibleFrom<MutableCopy>>,
52 std::allocator_arg_t, const test_allocator<int>&, std::tuple<MutableCopy, MutableCopy>&>);
53
test()54 constexpr bool test() {
55 // test implicit conversions.
56 // sizeof...(Types) == 1
57 {
58 std::tuple<MutableCopy> t1{1};
59 std::tuple<ConvertibleFrom<MutableCopy>> t2 = {std::allocator_arg, test_allocator<int>{}, t1};
60 assert(std::get<0>(t2).v.val == 1);
61 assert(std::get<0>(t2).alloc_constructed);
62 }
63
64 // test implicit conversions.
65 // sizeof...(Types) > 1
66 {
67 std::tuple<MutableCopy, int> t1{1, 2};
68 std::tuple<ConvertibleFrom<MutableCopy>, int> t2 = {std::allocator_arg_t{}, test_allocator<int>{}, t1};
69 assert(std::get<0>(t2).v.val == 1);
70 assert(std::get<1>(t2) == 2);
71 assert(std::get<0>(t2).alloc_constructed);
72 }
73
74 // test explicit conversions.
75 // sizeof...(Types) == 1
76 {
77 std::tuple<MutableCopy> t1{1};
78 std::tuple<ExplicitConstructibleFrom<MutableCopy>> t2{std::allocator_arg_t{}, test_allocator<int>{}, t1};
79 assert(std::get<0>(t2).v.val == 1);
80 assert(std::get<0>(t2).alloc_constructed);
81 }
82
83 // test explicit conversions.
84 // sizeof...(Types) > 1
85 {
86 std::tuple<MutableCopy, int> t1{1, 2};
87 std::tuple<ExplicitConstructibleFrom<MutableCopy>, int> t2{std::allocator_arg_t{}, test_allocator<int>{}, t1};
88 assert(std::get<0>(t2).v.val == 1);
89 assert(std::get<1>(t2) == 2);
90 assert(std::get<0>(t2).alloc_constructed);
91 }
92
93 // test constraints
94
95 // sizeof...(Types) != sizeof...(UTypes)
96 static_assert(!std::is_constructible_v<std::tuple<int, int>, std::allocator_arg_t, const test_allocator<int>&,
97 std::tuple<int>&>);
98 static_assert(!std::is_constructible_v<std::tuple<int, int, int>, std::allocator_arg_t, const test_allocator<int>&,
99 std::tuple<int, int>&>);
100
101 // !(is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...)
102 static_assert(!std::is_constructible_v< std::tuple<int, NoConstructorFromInt>, std::allocator_arg_t,
103 const test_allocator<int>&, std::tuple<int, int>&>);
104
105 // sizeof...(Types) == 1 && other branch of "||" satisfied
106 {
107 std::tuple<TracedCopyMove> t1{};
108 std::tuple<ConvertibleFrom<TracedCopyMove>> t2{std::allocator_arg_t{}, test_allocator<int>{}, t1};
109 assert(nonConstCopyCtrCalled(std::get<0>(t2).v));
110 assert(std::get<0>(t2).alloc_constructed);
111 }
112
113 // sizeof...(Types) == 1 && is_same_v<T, U>
114 {
115 std::tuple<TracedCopyMove> t1{};
116 std::tuple<TracedCopyMove> t2{std::allocator_arg_t{}, test_allocator<int>{}, t1};
117 assert(!nonConstCopyCtrCalled(std::get<0>(t2)));
118 assert(std::get<0>(t2).alloc_constructed);
119 }
120
121 // sizeof...(Types) != 1
122 {
123 std::tuple<TracedCopyMove, TracedCopyMove> t1{};
124 std::tuple<TracedCopyMove, TracedCopyMove> t2{std::allocator_arg_t{}, test_allocator<int>{}, t1};
125 assert(nonConstCopyCtrCalled(std::get<0>(t2)));
126 assert(std::get<0>(t2).alloc_constructed);
127 }
128
129 // These two test points cause gcc to ICE
130 #if !defined(TEST_COMPILER_GCC)
131 // sizeof...(Types) == 1 && is_convertible_v<decltype(u), T>
132 {
133 std::tuple<CvtFromTupleRef> t1{};
134 std::tuple<ConvertibleFrom<CvtFromTupleRef>> t2{std::allocator_arg_t{}, test_allocator<int>{}, t1};
135 assert(!nonConstCopyCtrCalled(std::get<0>(t2).v));
136 assert(std::get<0>(t2).alloc_constructed);
137 }
138
139 // sizeof...(Types) == 1 && is_constructible_v<decltype(u), T>
140 {
141 std::tuple<ExplicitCtrFromTupleRef> t1{};
142 std::tuple<ConvertibleFrom<ExplicitCtrFromTupleRef>> t2{std::allocator_arg_t{}, test_allocator<int>{}, t1};
143 assert(!nonConstCopyCtrCalled(std::get<0>(t2).v));
144 assert(std::get<0>(t2).alloc_constructed);
145 }
146 #endif
147 return true;
148 }
149
main(int,char **)150 int main(int, char**) {
151 test();
152 static_assert(test());
153 return 0;
154 }
155