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 //     const 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<ConstMove>>, std::allocator_arg_t,
41                                        const test_allocator<int>&, const std::tuple<ConstMove>&&>);
42 
43 static_assert(
44     ImplicitlyConstructible< std::tuple<ConvertibleFrom<ConstMove>, ConvertibleFrom<ConstMove>>, std::allocator_arg_t,
45                              const test_allocator<int>&, const std::tuple<ConstMove, ConstMove>&&>);
46 
47 static_assert(!ImplicitlyConstructible<std::tuple<ExplicitConstructibleFrom<ConstMove>>, std::allocator_arg_t,
48                                        const test_allocator<int>&, const std::tuple<ConstMove>&&>);
49 
50 static_assert(!ImplicitlyConstructible<std::tuple<ExplicitConstructibleFrom<ConstMove>, ConvertibleFrom<ConstMove>>,
51                                        std::allocator_arg_t, const test_allocator<int>&,
52                                        const std::tuple<ConstMove, ConstMove>&&>);
53 
test()54 constexpr bool test() {
55   // test implicit conversions.
56   // sizeof...(Types) == 1
57   {
58     const std::tuple<ConstMove> t1{1};
59     std::tuple<ConvertibleFrom<ConstMove>> t2 = {std::allocator_arg, test_allocator<int>{}, std::move(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     const std::tuple<ConstMove, int> t1{1, 2};
68     std::tuple<ConvertibleFrom<ConstMove>, int> t2 = {std::allocator_arg_t{}, test_allocator<int>{}, std::move(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     const std::tuple<ConstMove> t1{1};
78     std::tuple<ExplicitConstructibleFrom<ConstMove>> t2{std::allocator_arg_t{}, test_allocator<int>{}, std::move(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     const std::tuple<ConstMove, int> t1{1, 2};
87     std::tuple<ExplicitConstructibleFrom<ConstMove>, int> t2{std::allocator_arg_t{}, test_allocator<int>{},
88                                                              std::move(t1)};
89     assert(std::get<0>(t2).v.val == 1);
90     assert(std::get<1>(t2) == 2);
91     assert(std::get<0>(t2).alloc_constructed);
92   }
93 
94   // test constraints
95 
96   // sizeof...(Types) != sizeof...(UTypes)
97   static_assert(!std::is_constructible_v<std::tuple<int, int>, std::allocator_arg_t, const test_allocator<int>&,
98                                          const std::tuple<int>&&>);
99   static_assert(!std::is_constructible_v<std::tuple<int, int, int>, std::allocator_arg_t, const test_allocator<int>&,
100                                          const std::tuple<int, int>&&>);
101 
102   // !(is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...)
103   static_assert(!std::is_constructible_v< std::tuple<int, NoConstructorFromInt>, std::allocator_arg_t,
104                                           const test_allocator<int>&, const std::tuple<int, int>&&>);
105 
106   // sizeof...(Types) == 1 && other branch of "||" satisfied
107   {
108     const std::tuple<TracedCopyMove> t1{};
109     std::tuple<ConvertibleFrom<TracedCopyMove>> t2{std::allocator_arg_t{}, test_allocator<int>{}, std::move(t1)};
110     assert(constMoveCtrCalled(std::get<0>(t2).v));
111     assert(std::get<0>(t2).alloc_constructed);
112   }
113 
114   // sizeof...(Types) == 1 && is_same_v<T, U>
115   {
116     const std::tuple<TracedCopyMove> t1{};
117     std::tuple<TracedCopyMove> t2{std::allocator_arg_t{}, test_allocator<int>{}, std::move(t1)};
118     assert(!constMoveCtrCalled(std::get<0>(t2)));
119     assert(std::get<0>(t2).alloc_constructed);
120   }
121 
122   // sizeof...(Types) != 1
123   {
124     const std::tuple<TracedCopyMove, TracedCopyMove> t1{};
125     std::tuple<TracedCopyMove, TracedCopyMove> t2{std::allocator_arg_t{}, test_allocator<int>{}, std::move(t1)};
126     assert(constMoveCtrCalled(std::get<0>(std::move(t2))));
127     assert(std::get<0>(t2).alloc_constructed);
128   }
129 
130   // These two test points cause gcc to ICE
131 #if !defined(TEST_COMPILER_GCC)
132   // sizeof...(Types) == 1 && is_convertible_v<decltype(u), T>
133   {
134     const std::tuple<CvtFromTupleRef> t1{};
135     std::tuple<ConvertibleFrom<CvtFromTupleRef>> t2{std::allocator_arg_t{}, test_allocator<int>{}, std::move(t1)};
136     assert(!constMoveCtrCalled(std::get<0>(t2).v));
137     assert(std::get<0>(t2).alloc_constructed);
138   }
139 
140   // sizeof...(Types) == 1 && is_constructible_v<decltype(u), T>
141   {
142     const std::tuple<ExplicitCtrFromTupleRef> t1{};
143     std::tuple<ConvertibleFrom<ExplicitCtrFromTupleRef>> t2{std::allocator_arg_t{}, test_allocator<int>{},
144                                                             std::move(t1)};
145     assert(!constMoveCtrCalled(std::get<0>(t2).v));
146     assert(std::get<0>(t2).alloc_constructed);
147   }
148 #endif
149   return true;
150 }
151 
main(int,char **)152 int main(int, char**) {
153   test();
154   static_assert(test());
155   return 0;
156 }
157