xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp (revision 83ead2bbc5e14ca1beb776c062ebc36c38e8bb1c)
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... UTypes>
13 //   constexpr explicit(see below) tuple<Types>::tuple(const
14 //   tuple<UTypes...>&&);
15 //
16 // Constraints:
17 //  sizeof...(Types) equals sizeof...(UTypes) &&
18 //  (is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...) is true &&
19 //  (
20 //    sizeof...(Types) is not 1 ||
21 //    (
22 //      !is_convertible_v<decltype(u), T> &&
23 //      !is_constructible_v<T, decltype(u)> &&
24 //      !is_same_v<T, U>
25 //    )
26 //  )
27 
28 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
29 
30 #include <cassert>
31 #include <tuple>
32 
33 #include "copy_move_types.h"
34 #include "test_macros.h"
35 
36 // test: The expression inside explicit is equivalent to:
37 // !(is_convertible_v<decltype(get<I>(FWD(u))), Types> && ...)
38 static_assert(std::is_convertible_v<const std::tuple<ConstMove>&&, std::tuple<ConvertibleFrom<ConstMove>>>);
39 
40 static_assert(std::is_convertible_v<const std::tuple<ConstMove, ConstMove>&&,
41                                     std::tuple<ConvertibleFrom<ConstMove>, ConvertibleFrom<ConstMove>>>);
42 
43 static_assert(
44     !std::is_convertible_v<const std::tuple<MutableCopy>&&, std::tuple<ExplicitConstructibleFrom<ConstMove>>>);
45 
46 static_assert(!std::is_convertible_v<const std::tuple<ConstMove, ConstMove>&&,
47                                      std::tuple<ConvertibleFrom<ConstMove>, ExplicitConstructibleFrom<ConstMove>>>);
48 
test()49 constexpr bool test() {
50   // test implicit conversions.
51   // sizeof...(Types) == 1
52   {
53     const std::tuple<ConstMove> t1{1};
54     std::tuple<ConvertibleFrom<ConstMove>> t2 = std::move(t1);
55     assert(std::get<0>(t2).v.val == 1);
56   }
57 
58   // test implicit conversions.
59   // sizeof...(Types) > 1
60   {
61     const std::tuple<ConstMove, int> t1{1, 2};
62     std::tuple<ConvertibleFrom<ConstMove>, int> t2 = std::move(t1);
63     assert(std::get<0>(t2).v.val == 1);
64     assert(std::get<1>(t2) == 2);
65   }
66 
67   // test explicit conversions.
68   // sizeof...(Types) == 1
69   {
70     const std::tuple<ConstMove> t1{1};
71     std::tuple<ExplicitConstructibleFrom<ConstMove>> t2{std::move(t1)};
72     assert(std::get<0>(t2).v.val == 1);
73   }
74 
75   // test explicit conversions.
76   // sizeof...(Types) > 1
77   {
78     const std::tuple<ConstMove, int> t1{1, 2};
79     std::tuple<ExplicitConstructibleFrom<ConstMove>, int> t2{std::move(t1)};
80     assert(std::get<0>(t2).v.val == 1);
81     assert(std::get<1>(t2) == 2);
82   }
83 
84   // test constraints
85 
86   // sizeof...(Types) != sizeof...(UTypes)
87   static_assert(!std::is_constructible_v<std::tuple<int, int>, const std::tuple<int>&&>);
88   static_assert(!std::is_constructible_v<std::tuple<int, int, int>, const std::tuple<int, int>&&>);
89 
90   // !(is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...)
91   static_assert(!std::is_constructible_v<std::tuple<int, NoConstructorFromInt>, const std::tuple<int, int>&&>);
92 
93   // sizeof...(Types) == 1 && other branch of "||" satisfied
94   {
95     const std::tuple<TracedCopyMove> t1{};
96     std::tuple<ConvertibleFrom<TracedCopyMove>> t2{std::move(t1)};
97     assert(constMoveCtrCalled(std::get<0>(t2).v));
98   }
99 
100   // sizeof...(Types) == 1 && is_same_v<T, U>
101   {
102     const std::tuple<TracedCopyMove> t1{};
103     std::tuple<TracedCopyMove> t2{t1};
104     assert(!constMoveCtrCalled(std::get<0>(t2)));
105   }
106 
107   // sizeof...(Types) != 1
108   {
109     const std::tuple<TracedCopyMove, TracedCopyMove> t1{};
110     std::tuple<TracedCopyMove, TracedCopyMove> t2{std::move(t1)};
111     assert(constMoveCtrCalled(std::get<0>(t2)));
112   }
113 
114   // These two test points cause gcc to ICE
115 #if !defined(TEST_COMPILER_GCC)
116   // sizeof...(Types) == 1 && is_convertible_v<decltype(u), T>
117   {
118     const std::tuple<CvtFromConstTupleRefRef> t1{};
119     std::tuple<ConvertibleFrom<CvtFromConstTupleRefRef>> t2{std::move(t1)};
120     assert(!constMoveCtrCalled(std::get<0>(t2).v));
121   }
122 
123   // sizeof...(Types) == 1 && is_constructible_v<decltype(u), T>
124   {
125     const std::tuple<ExplicitCtrFromConstTupleRefRef> t1{};
126     std::tuple<ConvertibleFrom<ExplicitCtrFromConstTupleRefRef>> t2{std::move(t1)};
127     assert(!constMoveCtrCalled(std::get<0>(t2).v));
128   }
129 #endif
130 
131   return true;
132 }
133 
main(int,char **)134 int main(int, char**) {
135   test();
136   static_assert(test());
137   return 0;
138 }
139