diff --git a/libcxx/include/array b/libcxx/include/array --- a/libcxx/include/array +++ b/libcxx/include/array @@ -242,31 +242,16 @@ typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; -#ifndef _LIBCPP_CXX03_LANG - union __wrapper { - _LIBCPP_CONSTEXPR __wrapper() : __b() { } - ~__wrapper() = default; - - bool __b; - _Tp __t; - } __w; - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - value_type* data() _NOEXCEPT {return &__w.__t;} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const value_type* data() const _NOEXCEPT {return &__w.__t;} -#else // C++03 typedef typename conditional::value, const char, char>::type _CharType; struct _ArrayInStructT { _Tp __data_[1]; }; _ALIGNAS_TYPE(_ArrayInStructT) _CharType __elems_[sizeof(_ArrayInStructT)]; - _LIBCPP_INLINE_VISIBILITY - value_type* data() _NOEXCEPT {return reinterpret_cast(__elems_);} - _LIBCPP_INLINE_VISIBILITY - const value_type* data() const _NOEXCEPT {return reinterpret_cast(__elems_);} -#endif + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 + value_type* data() _NOEXCEPT {return nullptr;} + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 + const value_type* data() const _NOEXCEPT {return nullptr;} // No explicit construct/copy/destroy for aggregate type _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 diff --git a/libcxx/test/libcxx/containers/sequences/array/triviality.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/triviality.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/array/triviality.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Make sure std::array is trivially copyable whenever T is trivially copyable. +// This is not technically mandated by the Standard, but libc++ has been providing +// this property. + +#include +#include + + +struct Empty { }; + +struct TrivialCopy { + int i; + double j; +}; + +struct NonTrivialCopy { + NonTrivialCopy(NonTrivialCopy const&) { } + NonTrivialCopy& operator=(NonTrivialCopy const&) { return *this; } +}; + +template +void check_trivially_copyable() +{ + static_assert(std::is_trivially_copyable >::value, ""); + static_assert(std::is_trivially_copyable >::value, ""); + static_assert(std::is_trivially_copyable >::value, ""); + static_assert(std::is_trivially_copyable >::value, ""); +} + +int main(int, char**) +{ + check_trivially_copyable(); + check_trivially_copyable(); + check_trivially_copyable(); + check_trivially_copyable(); + check_trivially_copyable(); + check_trivially_copyable(); + + // Check that std::array is still trivially copyable when T is not + static_assert( std::is_trivially_copyable >::value, ""); + static_assert(!std::is_trivially_copyable >::value, ""); + static_assert(!std::is_trivially_copyable >::value, ""); + static_assert(!std::is_trivially_copyable >::value, ""); + + return 0; +} diff --git a/libcxx/test/std/containers/sequences/array/aggregate.pass.cpp b/libcxx/test/std/containers/sequences/array/aggregate.pass.cpp --- a/libcxx/test/std/containers/sequences/array/aggregate.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/aggregate.pass.cpp @@ -7,44 +7,41 @@ //===----------------------------------------------------------------------===// // Make sure std::array is an aggregate type. +// We can only check this in C++17 and above, because we don't have the +// trait before that. +// UNSUPPORTED: c++03, c++11, c++14 #include #include template -void tests() +void check_aggregate() { - // Test aggregate initialization - { - std::array a0 = {}; (void)a0; - std::array a1 = {T()}; (void)a1; - std::array a2 = {T(), T()}; (void)a2; - std::array a3 = {T(), T(), T()}; (void)a3; - } - - // Test the is_aggregate trait. -#if TEST_STD_VER >= 17 // The trait is only available in C++17 and above static_assert(std::is_aggregate >::value, ""); static_assert(std::is_aggregate >::value, ""); static_assert(std::is_aggregate >::value, ""); static_assert(std::is_aggregate >::value, ""); static_assert(std::is_aggregate >::value, ""); -#endif } struct Empty { }; -struct NonEmpty { int i; int j; }; +struct Trivial { int i; int j; }; +struct NonTrivial { + int i; int j; + NonTrivial(NonTrivial const&) { } +}; int main(int, char**) { - tests(); - tests(); - tests(); - tests(); - tests(); - tests(); - tests(); - tests(); + check_aggregate(); + check_aggregate(); + check_aggregate(); + check_aggregate(); + check_aggregate(); + check_aggregate(); + check_aggregate(); + check_aggregate(); + check_aggregate(); return 0; } diff --git a/libcxx/test/std/containers/sequences/array/array.cons/default.pass.cpp b/libcxx/test/std/containers/sequences/array/array.cons/default.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/sequences/array/array.cons/default.pass.cpp +++ /dev/null @@ -1,61 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// - -// array(); - -#include -#include - -// std::array is explicitly allowed to be initialized with A a = { init-list };. -// Disable the missing braces warning for this reason. -#include "test_macros.h" -#include "disable_missing_braces_warning.h" - -struct NoDefault { - TEST_CONSTEXPR NoDefault(int) { } -}; - -struct Default { - TEST_CONSTEXPR Default() { } -}; - -TEST_CONSTEXPR_CXX14 bool tests() -{ - { - std::array array; - assert(array.size() == 3); - } - - { - std::array array; - assert(array.size() == 0); - } - - { - typedef std::array C; - C c; - assert(c.size() == 0); - C c1 = {}; - assert(c1.size() == 0); - C c2 = {{}}; - assert(c2.size() == 0); - } - - return true; -} - -int main(int, char**) -{ - tests(); -#if TEST_STD_VER >= 14 - static_assert(tests(), ""); -#endif - return 0; -} diff --git a/libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp b/libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp --- a/libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp @@ -32,62 +32,82 @@ TEST_CONSTEXPR NoDefault(int) { } }; +struct NonTrivialCopy { + TEST_CONSTEXPR NonTrivialCopy() { } + TEST_CONSTEXPR NonTrivialCopy(NonTrivialCopy const&) { } + TEST_CONSTEXPR_CXX14 NonTrivialCopy& operator=(NonTrivialCopy const&) { return *this; } +}; + TEST_CONSTEXPR_CXX14 bool tests() { { - typedef double T; - typedef std::array C; - C c = {1.1, 2.2, 3.3}; - C c2 = c; - c2 = c; - static_assert(std::is_copy_constructible::value, ""); - static_assert(std::is_copy_assignable::value, ""); + typedef std::array Array; + Array array = {1.1, 2.2, 3.3}; + Array copy = array; + copy = array; + static_assert(std::is_copy_constructible::value, ""); + static_assert(std::is_copy_assignable::value, ""); } { - typedef double T; - typedef std::array C; - C c = {1.1, 2.2, 3.3}; - C c2 = c; - ((void)c2); - static_assert(std::is_copy_constructible::value, ""); - TEST_NOT_COPY_ASSIGNABLE(C); + typedef std::array Array; + Array array = {1.1, 2.2, 3.3}; + Array copy = array; (void)copy; + static_assert(std::is_copy_constructible::value, ""); + TEST_NOT_COPY_ASSIGNABLE(Array); } { - typedef double T; - typedef std::array C; - C c = {}; - C c2 = c; - c2 = c; - static_assert(std::is_copy_constructible::value, ""); - static_assert(std::is_copy_assignable::value, ""); + typedef std::array Array; + Array array = {}; + Array copy = array; + copy = array; + static_assert(std::is_copy_constructible::value, ""); + static_assert(std::is_copy_assignable::value, ""); } { // const arrays of size 0 should disable the implicit copy assignment operator. - typedef double T; - typedef std::array C; - C c = {{}}; - C c2 = c; - ((void)c2); - static_assert(std::is_copy_constructible::value, ""); - TEST_NOT_COPY_ASSIGNABLE(C); + typedef std::array Array; + Array array = {}; + Array copy = array; (void)copy; + static_assert(std::is_copy_constructible::value, ""); + TEST_NOT_COPY_ASSIGNABLE(Array); + } + { + typedef std::array Array; + Array array = {}; + Array copy = array; + copy = array; + static_assert(std::is_copy_constructible::value, ""); + static_assert(std::is_copy_assignable::value, ""); + } + { + typedef std::array Array; + Array array = {}; + Array copy = array; (void)copy; + static_assert(std::is_copy_constructible::value, ""); + TEST_NOT_COPY_ASSIGNABLE(Array); + } + + // Make sure we can implicitly copy a std::array of a non-trivially copyable type + { + typedef std::array Array; + Array array = {}; + Array copy = array; + copy = array; + static_assert(std::is_copy_constructible::value, ""); } { - typedef NoDefault T; - typedef std::array C; - C c = {}; - C c2 = c; - c2 = c; - static_assert(std::is_copy_constructible::value, ""); - static_assert(std::is_copy_assignable::value, ""); + typedef std::array Array; + Array array = {}; + Array copy = array; + copy = array; + static_assert(std::is_copy_constructible::value, ""); } { - typedef NoDefault T; - typedef std::array C; - C c = {{}}; - C c2 = c; - ((void)c2); - static_assert(std::is_copy_constructible::value, ""); - TEST_NOT_COPY_ASSIGNABLE(C); + typedef std::array Array; + Array array = {}; + Array copy = array; + copy = array; + static_assert(std::is_copy_constructible::value, ""); } return true; diff --git a/libcxx/test/std/containers/sequences/array/array.cons/initialization.pass.cpp b/libcxx/test/std/containers/sequences/array/array.cons/initialization.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/array/array.cons/initialization.pass.cpp @@ -0,0 +1,188 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Test all the ways of initializing a std::array. + +#include +#include +#include +#include "test_macros.h" + + +struct NoDefault { + TEST_CONSTEXPR NoDefault(int) { } +}; + +// Test default initialization +// This one isn't constexpr because omitting to initialize fundamental types +// isn't valid in a constexpr context. +struct test_default_initialization { + template + void operator()() const + { + std::array a0; (void)a0; + std::array a1; (void)a1; + std::array a2; (void)a2; + std::array a3; (void)a3; + + std::array nodefault; (void)nodefault; + } +}; + +struct test_nondefault_initialization { + template + TEST_CONSTEXPR_CXX14 void operator()() const + { + // Check direct-list-initialization syntax (introduced in C++11) + #if TEST_STD_VER >= 11 + { + { + std::array a0_0{}; (void)a0_0; + } + { + std::array a1_0{}; (void)a1_0; + std::array a1_1{T()}; (void)a1_1; + } + { + std::array a2_0{}; (void)a2_0; + std::array a2_1{T()}; (void)a2_1; + std::array a2_2{T(), T()}; (void)a2_2; + } + { + std::array a3_0{}; (void)a3_0; + std::array a3_1{T()}; (void)a3_1; + std::array a3_2{T(), T()}; (void)a3_2; + std::array a3_3{T(), T(), T()}; (void)a3_3; + } + + std::array nodefault{}; (void)nodefault; + } + #endif + + // Check copy-list-initialization syntax + { + { + std::array a0_0 = {}; (void)a0_0; + } + { + std::array a1_0 = {}; (void)a1_0; + std::array a1_1 = {T()}; (void)a1_1; + } + { + std::array a2_0 = {}; (void)a2_0; + std::array a2_1 = {T()}; (void)a2_1; + std::array a2_2 = {T(), T()}; (void)a2_2; + } + { + std::array a3_0 = {}; (void)a3_0; + std::array a3_1 = {T()}; (void)a3_1; + std::array a3_2 = {T(), T()}; (void)a3_2; + std::array a3_3 = {T(), T(), T()}; (void)a3_3; + } + + std::array nodefault = {}; (void)nodefault; + } + + // Test aggregate initialization + { + { + std::array a0_0 = {{}}; (void)a0_0; + } + { + std::array a1_0 = {{}}; (void)a1_0; + std::array a1_1 = {{T()}}; (void)a1_1; + } + { + std::array a2_0 = {{}}; (void)a2_0; + std::array a2_1 = {{T()}}; (void)a2_1; + std::array a2_2 = {{T(), T()}}; (void)a2_2; + } + { + std::array a3_0 = {{}}; (void)a3_0; + std::array a3_1 = {{T()}}; (void)a3_1; + std::array a3_2 = {{T(), T()}}; (void)a3_2; + std::array a3_3 = {{T(), T(), T()}}; (void)a3_3; + } + + // See http://wg21.link/LWG2157 + std::array nodefault = {{}}; (void)nodefault; + } + } +}; + +// Test construction from an initializer-list +TEST_CONSTEXPR_CXX14 bool test_initializer_list() +{ + { + std::array const a3_0 = {}; + assert(a3_0[0] == double()); + assert(a3_0[1] == double()); + assert(a3_0[2] == double()); + } + { + std::array const a3_1 = {1}; + assert(a3_1[0] == double(1)); + assert(a3_1[1] == double()); + assert(a3_1[2] == double()); + } + { + std::array const a3_2 = {1, 2.2}; + assert(a3_2[0] == double(1)); + assert(a3_2[1] == 2.2); + assert(a3_2[2] == double()); + } + { + std::array const a3_3 = {1, 2, 3.5}; + assert(a3_3[0] == double(1)); + assert(a3_3[1] == double(2)); + assert(a3_3[2] == 3.5); + } + + return true; +} + +struct Empty { }; +struct Trivial { int i; int j; }; +struct NonTrivial { + TEST_CONSTEXPR NonTrivial() { } + TEST_CONSTEXPR NonTrivial(NonTrivial const&) { } +}; +struct NonEmptyNonTrivial { + int i; int j; + TEST_CONSTEXPR NonEmptyNonTrivial() : i(22), j(33) { } + TEST_CONSTEXPR NonEmptyNonTrivial(NonEmptyNonTrivial const&) : i(22), j(33) { } +}; + +template +TEST_CONSTEXPR_CXX14 bool with_all_types() +{ + F().template operator()(); + F().template operator()(); + F().template operator()(); + F().template operator()(); + F().template operator()(); + F().template operator()(); + F().template operator()(); + F().template operator()(); + F().template operator()(); + F().template operator()(); + return true; +} + +int main(int, char**) +{ + with_all_types(); + with_all_types(); // not constexpr + test_initializer_list(); +#if TEST_STD_VER >= 14 + static_assert(with_all_types(), ""); + static_assert(test_initializer_list(), ""); +#endif + + return 0; +} diff --git a/libcxx/test/std/containers/sequences/array/array.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/sequences/array/array.cons/initializer_list.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/sequences/array/array.cons/initializer_list.pass.cpp +++ /dev/null @@ -1,63 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// - -// Construct with initializer list - -#include -#include - -// std::array is explicitly allowed to be initialized with A a = { init-list };. -// Disable the missing braces warning for this reason. -#include "test_macros.h" -#include "disable_missing_braces_warning.h" - -TEST_CONSTEXPR_CXX14 bool tests() -{ - { - typedef double T; - typedef std::array C; - C const c = {1, 2, 3.5}; - assert(c.size() == 3); - assert(c[0] == 1); - assert(c[1] == 2); - assert(c[2] == 3.5); - } - { - typedef double T; - typedef std::array C; - C const c = {}; - assert(c.size() == 0); - } - - { - typedef double T; - typedef std::array C; - C const c = {1}; - assert(c.size() == 3.0); - assert(c[0] == 1); - } - { - typedef int T; - typedef std::array C; - C const c = {}; - assert(c.size() == 1); - } - - return true; -} - -int main(int, char**) -{ - tests(); -#if TEST_STD_VER >= 14 - static_assert(tests(), ""); -#endif - return 0; -} diff --git a/libcxx/test/std/containers/sequences/array/array.data/data.pass.cpp b/libcxx/test/std/containers/sequences/array/array.data/data.pass.cpp --- a/libcxx/test/std/containers/sequences/array/array.data/data.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/array.data/data.pass.cpp @@ -49,14 +49,14 @@ typedef std::array C; C c = {}; T* p = c.data(); - LIBCPP_ASSERT(p != nullptr); + (void)p; } { typedef double T; typedef std::array C; C c = {{}}; const T* p = c.data(); - LIBCPP_ASSERT(p != nullptr); + (void)p; static_assert((std::is_same::value), ""); } { @@ -64,7 +64,7 @@ typedef std::array C; C c = {}; T* p = c.data(); - LIBCPP_ASSERT(p != nullptr); + (void)p; } { std::array c = {0, 1, 2, 3, 4}; @@ -92,7 +92,6 @@ typedef std::array C; const C c = {}; const T* p = c.data(); - LIBCPP_ASSERT(p != nullptr); std::uintptr_t pint = reinterpret_cast(p); assert(pint % TEST_ALIGNOF(T) == 0); } diff --git a/libcxx/test/std/containers/sequences/array/array.data/data_const.pass.cpp b/libcxx/test/std/containers/sequences/array/array.data/data_const.pass.cpp --- a/libcxx/test/std/containers/sequences/array/array.data/data_const.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/array.data/data_const.pass.cpp @@ -49,14 +49,14 @@ typedef std::array C; const C c = {}; const T* p = c.data(); - LIBCPP_ASSERT(p != nullptr); + (void)p; } { typedef NoDefault T; typedef std::array C; const C c = {}; const T* p = c.data(); - LIBCPP_ASSERT(p != nullptr); + (void)p; } { std::array const c = {0, 1, 2, 3, 4}; @@ -84,7 +84,6 @@ typedef std::array C; const C c = {}; const T* p = c.data(); - LIBCPP_ASSERT(p != nullptr); std::uintptr_t pint = reinterpret_cast(p); assert(pint % TEST_ALIGNOF(T) == 0); } diff --git a/libcxx/test/std/containers/sequences/array/iterators.pass.cpp b/libcxx/test/std/containers/sequences/array/iterators.pass.cpp --- a/libcxx/test/std/containers/sequences/array/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/iterators.pass.cpp @@ -52,8 +52,6 @@ typename C::iterator i = array.begin(); typename C::const_iterator j = array.cbegin(); assert(i == j); - LIBCPP_ASSERT(i != nullptr); - LIBCPP_ASSERT(j != nullptr); } { @@ -63,8 +61,6 @@ typename C::const_iterator j = array.cbegin(); assert(i == array.end()); assert(j == array.cend()); - LIBCPP_ASSERT(i != nullptr); - LIBCPP_ASSERT(j != nullptr); } { typedef std::array C; @@ -101,8 +97,6 @@ typename C::iterator ib = array.begin(); typename C::iterator ie = array.end(); assert(ib == ie); - LIBCPP_ASSERT(ib != nullptr); - LIBCPP_ASSERT(ie != nullptr); } #if TEST_STD_VER >= 14