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 { |
18 | TEST_CONSTEXPR NoDefault(int) { } |
19 | }; |
20 | |
21 | struct test_initialization { |
22 | template <typename T> |
23 | 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 = {._M_elems: {}}; (void)nodefault; |
127 | } |
128 | } |
129 | }; |
130 | |
131 | // Test construction from an 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 { |
165 | TEST_CONSTEXPR NonTrivial() { } |
166 | TEST_CONSTEXPR NonTrivial(NonTrivial const&) { } |
167 | }; |
168 | struct NonEmptyNonTrivial { |
169 | int i; int j; |
170 | TEST_CONSTEXPR NonEmptyNonTrivial() : i(22), j(33) { } |
171 | TEST_CONSTEXPR NonEmptyNonTrivial(NonEmptyNonTrivial const&) : i(22), j(33) { } |
172 | }; |
173 | |
174 | template <typename F> |
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 | |
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 | |