xref: /llvm-project/libcxx/test/std/containers/sequences/array/array.cons/initialization.pass.cpp (revision 1c7607e8ee6ec4ca3abce1561dd39a98d4efac96)
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 // Test all the ways of initializing a std::array.
10 
11 #include <array>
12 #include <cassert>
13 #include <type_traits>
14 #include "test_macros.h"
15 
16 
17 struct NoDefault {
NoDefaultNoDefault18     TEST_CONSTEXPR NoDefault(int) { }
19 };
20 
21 struct test_initialization {
22     template <typename T>
operator ()test_initialization23     TEST_CONSTEXPR_CXX14 void operator()() const
24     {
25         // Check default initalization
26         {
27             std::array<T, 0> a0; (void)a0;
28             // Before C++20, default initialization doesn't work inside constexpr for
29             // trivially default constructible types. This only apply to non-empty arrays,
30             // since empty arrays don't hold an element of type T.
31 #if TEST_STD_VER < 20
32             if (!(TEST_IS_CONSTANT_EVALUATED && std::is_trivially_default_constructible<T>::value))
33 #endif
34             {
35               std::array<T, 1> a1;
36               (void)a1;
37               std::array<T, 2> a2;
38               (void)a2;
39               std::array<T, 3> a3;
40               (void)a3;
41             }
42 
43             std::array<NoDefault, 0> nodefault; (void)nodefault;
44         }
45 
46         // A const empty array can also be default-initialized regardless of the type
47         // it contains. For non-empty arrays, this doesn't work whenever T doesn't
48         // have a user-provided default constructor.
49         {
50             const std::array<T, 0> a0; (void)a0;
51             const std::array<NoDefault, 0> nodefault; (void)nodefault;
52         }
53 
54         // Check direct-list-initialization syntax (introduced in C++11)
55     #if TEST_STD_VER >= 11
56         {
57             {
58                 std::array<T, 0> a0_0{}; (void)a0_0;
59             }
60             {
61                 std::array<T, 1> a1_0{}; (void)a1_0;
62                 std::array<T, 1> a1_1{T()}; (void)a1_1;
63             }
64             {
65                 std::array<T, 2> a2_0{}; (void)a2_0;
66                 std::array<T, 2> a2_1{T()}; (void)a2_1;
67                 std::array<T, 2> a2_2{T(), T()}; (void)a2_2;
68             }
69             {
70                 std::array<T, 3> a3_0{}; (void)a3_0;
71                 std::array<T, 3> a3_1{T()}; (void)a3_1;
72                 std::array<T, 3> a3_2{T(), T()}; (void)a3_2;
73                 std::array<T, 3> a3_3{T(), T(), T()}; (void)a3_3;
74             }
75 
76             std::array<NoDefault, 0> nodefault{}; (void)nodefault;
77         }
78     #endif
79 
80         // Check copy-list-initialization syntax
81         {
82             {
83                 std::array<T, 0> a0_0 = {}; (void)a0_0;
84             }
85             {
86                 std::array<T, 1> a1_0 = {}; (void)a1_0;
87                 std::array<T, 1> a1_1 = {T()}; (void)a1_1;
88             }
89             {
90                 std::array<T, 2> a2_0 = {}; (void)a2_0;
91                 std::array<T, 2> a2_1 = {T()}; (void)a2_1;
92                 std::array<T, 2> a2_2 = {T(), T()}; (void)a2_2;
93             }
94             {
95                 std::array<T, 3> a3_0 = {}; (void)a3_0;
96                 std::array<T, 3> a3_1 = {T()}; (void)a3_1;
97                 std::array<T, 3> a3_2 = {T(), T()}; (void)a3_2;
98                 std::array<T, 3> a3_3 = {T(), T(), T()}; (void)a3_3;
99             }
100 
101             std::array<NoDefault, 0> nodefault = {}; (void)nodefault;
102         }
103 
104         // Test aggregate initialization
105         {
106             {
107                 std::array<T, 0> a0_0 = {{}}; (void)a0_0;
108             }
109             {
110                 std::array<T, 1> a1_0 = {{}}; (void)a1_0;
111                 std::array<T, 1> a1_1 = {{T()}}; (void)a1_1;
112             }
113             {
114                 std::array<T, 2> a2_0 = {{}}; (void)a2_0;
115                 std::array<T, 2> a2_1 = {{T()}}; (void)a2_1;
116                 std::array<T, 2> a2_2 = {{T(), T()}}; (void)a2_2;
117             }
118             {
119                 std::array<T, 3> a3_0 = {{}}; (void)a3_0;
120                 std::array<T, 3> a3_1 = {{T()}}; (void)a3_1;
121                 std::array<T, 3> a3_2 = {{T(), T()}}; (void)a3_2;
122                 std::array<T, 3> a3_3 = {{T(), T(), T()}}; (void)a3_3;
123             }
124 
125             // See http://wg21.link/LWG2157
126             std::array<NoDefault, 0> nodefault = {{}}; (void)nodefault;
127         }
128     }
129 };
130 
131 // Test construction from an initializer-list
test_initializer_list()132 TEST_CONSTEXPR_CXX14 bool test_initializer_list()
133 {
134     {
135         std::array<double, 3> const a3_0 = {};
136         assert(a3_0[0] == double());
137         assert(a3_0[1] == double());
138         assert(a3_0[2] == double());
139     }
140     {
141         std::array<double, 3> const a3_1 = {1};
142         assert(a3_1[0] == double(1));
143         assert(a3_1[1] == double());
144         assert(a3_1[2] == double());
145     }
146     {
147         std::array<double, 3> const a3_2 = {1, 2.2};
148         assert(a3_2[0] == double(1));
149         assert(a3_2[1] == 2.2);
150         assert(a3_2[2] == double());
151     }
152     {
153         std::array<double, 3> const a3_3 = {1, 2, 3.5};
154         assert(a3_3[0] == double(1));
155         assert(a3_3[1] == double(2));
156         assert(a3_3[2] == 3.5);
157     }
158 
159     return true;
160 }
161 
162 struct Empty { };
163 struct Trivial { int i; int j; };
164 struct NonTrivial {
NonTrivialNonTrivial165     TEST_CONSTEXPR NonTrivial() { }
NonTrivialNonTrivial166     TEST_CONSTEXPR NonTrivial(NonTrivial const&) { }
167 };
168 struct NonEmptyNonTrivial {
169     int i; int j;
NonEmptyNonTrivialNonEmptyNonTrivial170     TEST_CONSTEXPR NonEmptyNonTrivial() : i(22), j(33) { }
NonEmptyNonTrivialNonEmptyNonTrivial171     TEST_CONSTEXPR NonEmptyNonTrivial(NonEmptyNonTrivial const&) : i(22), j(33) { }
172 };
173 
174 template <typename F>
with_all_types()175 TEST_CONSTEXPR_CXX14 bool with_all_types()
176 {
177     F().template operator()<char>();
178     F().template operator()<int>();
179     F().template operator()<long>();
180     F().template operator()<float>();
181     F().template operator()<double>();
182     F().template operator()<long double>();
183     F().template operator()<Empty>();
184     F().template operator()<Trivial>();
185     F().template operator()<NonTrivial>();
186     F().template operator()<NonEmptyNonTrivial>();
187     return true;
188 }
189 
190 // This is a regression test -- previously, libc++ would implement empty arrays by
191 // storing an array of characters, which means that the array would be initializable
192 // from nonsense like an integer (or anything else that can be narrowed to char).
193 #if TEST_STD_VER >= 20
194 template <class T>
195 concept is_list_initializable_int = requires {
196     { T{123} };
197 };
198 
199 struct Foo { };
200 static_assert(!is_list_initializable_int<std::array<Foo, 0>>);
201 static_assert(!is_list_initializable_int<std::array<Foo, 1>>);
202 #endif
203 
main(int,char **)204 int main(int, char**)
205 {
206     with_all_types<test_initialization>();
207     test_initializer_list();
208 #if TEST_STD_VER >= 14
209     static_assert(with_all_types<test_initialization>(), "");
210     static_assert(test_initializer_list(), "");
211 #endif
212 
213     return 0;
214 }
215