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