This revision was automatically updated to reflect the committed changes. Closed by commit rL324526: [libc++] Fix PR35491 - std::array of zero-size doesn't work with non-default… (authored by EricWF, committed by ). Herald added a subscriber: llvm-commits.
Changed prior to commit: https://reviews.llvm.org/D41223?vs=133285&id=133288#toc Repository: rL LLVM https://reviews.llvm.org/D41223 Files: libcxx/trunk/include/__config libcxx/trunk/include/array libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp libcxx/trunk/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp libcxx/trunk/test/std/containers/sequences/array/array.fill/fill.fail.cpp libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.fail.cpp libcxx/trunk/test/std/containers/sequences/array/at.pass.cpp libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp libcxx/trunk/test/std/containers/sequences/array/compare.fail.cpp libcxx/trunk/test/std/containers/sequences/array/compare.pass.cpp libcxx/trunk/test/std/containers/sequences/array/empty.fail.cpp libcxx/trunk/test/std/containers/sequences/array/front_back.pass.cpp libcxx/trunk/test/std/containers/sequences/array/indexing.pass.cpp libcxx/trunk/test/std/containers/sequences/array/size_and_alignment.pass.cpp
Index: libcxx/trunk/include/__config =================================================================== --- libcxx/trunk/include/__config +++ libcxx/trunk/include/__config @@ -793,8 +793,13 @@ # if !defined(_LIBCPP_DEBUG) # error cannot use _LIBCPP_DEBUG_USE_EXCEPTIONS unless _LIBCPP_DEBUG is defined # endif -# define _NOEXCEPT_DEBUG noexcept(false) -# define _NOEXCEPT_DEBUG_(x) noexcept(false) +# ifdef _LIBCPP_HAS_NO_NOEXCEPT +# define _NOEXCEPT_DEBUG +# define _NOEXCEPT_DEBUG_(x) +# else +# define _NOEXCEPT_DEBUG noexcept(false) +# define _NOEXCEPT_DEBUG_(x) noexcept(false) +#endif #else # define _NOEXCEPT_DEBUG _NOEXCEPT # define _NOEXCEPT_DEBUG_(x) _NOEXCEPT_(x) Index: libcxx/trunk/include/array =================================================================== --- libcxx/trunk/include/array +++ libcxx/trunk/include/array @@ -108,6 +108,8 @@ #include <iterator> #include <algorithm> #include <stdexcept> +#include <cstdlib> // for _LIBCPP_UNREACHABLE +#include <__debug> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -117,6 +119,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD + template <class _Tp, size_t _Size> struct _LIBCPP_TEMPLATE_VIS array { @@ -134,31 +137,27 @@ typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - value_type __elems_[_Size > 0 ? _Size : 1]; + _Tp __elems_[_Size]; // No explicit construct/copy/destroy for aggregate type - _LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u) - {_VSTD::fill_n(__elems_, _Size, __u);} - _LIBCPP_INLINE_VISIBILITY - void swap(array& __a) _NOEXCEPT_(_Size == 0 || __is_nothrow_swappable<_Tp>::value) - { __swap_dispatch((std::integral_constant<bool, _Size == 0>()), __a); } + _LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u) { + _VSTD::fill_n(__elems_, _Size, __u); + } _LIBCPP_INLINE_VISIBILITY - void __swap_dispatch(std::true_type, array&) {} - - _LIBCPP_INLINE_VISIBILITY - void __swap_dispatch(std::false_type, array& __a) - { _VSTD::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);} + void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) { + std::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_); + } // iterators: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - iterator begin() _NOEXCEPT {return iterator(__elems_);} + iterator begin() _NOEXCEPT {return iterator(data());} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_iterator begin() const _NOEXCEPT {return const_iterator(__elems_);} + const_iterator begin() const _NOEXCEPT {return const_iterator(data());} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - iterator end() _NOEXCEPT {return iterator(__elems_ + _Size);} + iterator end() _NOEXCEPT {return iterator(data() + _Size);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_iterator end() const _NOEXCEPT {return const_iterator(__elems_ + _Size);} + const_iterator end() const _NOEXCEPT {return const_iterator(data() + _Size);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reverse_iterator rbegin() _NOEXCEPT {return reverse_iterator(end());} @@ -184,7 +183,7 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT {return _Size;} _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return _Size == 0;} + _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return false; } // element access: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -197,15 +196,16 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference front() {return __elems_[0];} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference front() const {return __elems_[0];} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference back() {return __elems_[_Size > 0 ? _Size-1 : 0];} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference back() const {return __elems_[_Size > 0 ? _Size-1 : 0];} + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference back() {return __elems_[_Size - 1];} + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference back() const {return __elems_[_Size - 1];} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 value_type* data() _NOEXCEPT {return __elems_;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const value_type* data() const _NOEXCEPT {return __elems_;} }; + template <class _Tp, size_t _Size> _LIBCPP_CONSTEXPR_AFTER_CXX14 typename array<_Tp, _Size>::reference @@ -227,12 +227,138 @@ return __elems_[__n]; } +template <class _Tp> +struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0> +{ + // types: + typedef array __self; + typedef _Tp value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + + typedef typename conditional<is_const<_Tp>::value, const char, + char>::type _CharType; + _ALIGNAS(alignment_of<_Tp[1]>::value) _CharType __elems_[sizeof(_Tp[1])]; + + // No explicit construct/copy/destroy for aggregate type + _LIBCPP_INLINE_VISIBILITY void fill(const value_type&) { + static_assert(!is_const<_Tp>::value, + "cannot fill zero-sized array of type 'const T'"); + } + + _LIBCPP_INLINE_VISIBILITY + void swap(array&) _NOEXCEPT { + static_assert(!is_const<_Tp>::value, + "cannot swap zero-sized array of type 'const T'"); + } + + // iterators: + _LIBCPP_INLINE_VISIBILITY + iterator begin() _NOEXCEPT {return iterator(data());} + _LIBCPP_INLINE_VISIBILITY + const_iterator begin() const _NOEXCEPT {return const_iterator(data());} + _LIBCPP_INLINE_VISIBILITY + iterator end() _NOEXCEPT {return iterator(data());} + _LIBCPP_INLINE_VISIBILITY + const_iterator end() const _NOEXCEPT {return const_iterator(data());} + + _LIBCPP_INLINE_VISIBILITY + reverse_iterator rbegin() _NOEXCEPT {return reverse_iterator(end());} + _LIBCPP_INLINE_VISIBILITY + const_reverse_iterator rbegin() const _NOEXCEPT {return const_reverse_iterator(end());} + _LIBCPP_INLINE_VISIBILITY + reverse_iterator rend() _NOEXCEPT {return reverse_iterator(begin());} + _LIBCPP_INLINE_VISIBILITY + const_reverse_iterator rend() const _NOEXCEPT {return const_reverse_iterator(begin());} + + _LIBCPP_INLINE_VISIBILITY + const_iterator cbegin() const _NOEXCEPT {return begin();} + _LIBCPP_INLINE_VISIBILITY + const_iterator cend() const _NOEXCEPT {return end();} + _LIBCPP_INLINE_VISIBILITY + const_reverse_iterator crbegin() const _NOEXCEPT {return rbegin();} + _LIBCPP_INLINE_VISIBILITY + const_reverse_iterator crend() const _NOEXCEPT {return rend();} + + // capacity: + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT {return 0; } + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT {return 0;} + _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return true;} + + // element access: + _LIBCPP_INLINE_VISIBILITY + reference operator[](size_type) { + _LIBCPP_ASSERT(false, "cannot call array<T, 0>::operator[] on a zero-sized array"); + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + const_reference operator[](size_type) const { + _LIBCPP_ASSERT(false, "cannot call array<T, 0>::operator[] on a zero-sized array"); + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + reference at(size_type) { + __throw_out_of_range("array<T, 0>::at"); + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + const_reference at(size_type) const { + __throw_out_of_range("array<T, 0>::at"); + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + reference front() { + _LIBCPP_ASSERT(false, "cannot call array<T, 0>::front() on a zero-sized array"); + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + const_reference front() const { + _LIBCPP_ASSERT(false, "cannot call array<T, 0>::front() on a zero-sized array"); + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + reference back() { + _LIBCPP_ASSERT(false, "cannot call array<T, 0>::back() on a zero-sized array"); + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + const_reference back() const { + _LIBCPP_ASSERT(false, "cannot call array<T, 0>::back() on a zero-sized array"); + _LIBCPP_UNREACHABLE(); + } + + _LIBCPP_INLINE_VISIBILITY + value_type* data() _NOEXCEPT {return reinterpret_cast<value_type*>(__elems_);} + _LIBCPP_INLINE_VISIBILITY + const value_type* data() const _NOEXCEPT {return reinterpret_cast<const value_type*>(__elems_);} +}; + + template <class _Tp, size_t _Size> inline _LIBCPP_INLINE_VISIBILITY bool operator==(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) { - return _VSTD::equal(__x.__elems_, __x.__elems_ + _Size, __y.__elems_); + return _VSTD::equal(__x.begin(), __x.end(), __y.begin()); } template <class _Tp, size_t _Size> @@ -248,7 +374,8 @@ bool operator<(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) { - return _VSTD::lexicographical_compare(__x.__elems_, __x.__elems_ + _Size, __y.__elems_, __y.__elems_ + _Size); + return _VSTD::lexicographical_compare(__x.begin(), __x.end(), + __y.begin(), __y.end()); } template <class _Tp, size_t _Size> Index: libcxx/trunk/test/std/containers/sequences/array/array.fill/fill.fail.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/array.fill/fill.fail.cpp +++ libcxx/trunk/test/std/containers/sequences/array/array.fill/fill.fail.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <array> + +// void fill(const T& u); + +#include <array> +#include <cassert> + +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + +int main() { + { + typedef double T; + typedef std::array<const T, 0> C; + C c = {}; + // expected-error-re@array:* {{static_assert failed {{.*}} "cannot fill zero-sized array of type 'const T'"}} + c.fill(5.5); // expected-note {{requested here}} + } +} Index: libcxx/trunk/test/std/containers/sequences/array/front_back.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/front_back.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/front_back.pass.cpp @@ -64,7 +64,38 @@ C::const_reference r2 = c.back(); assert(r2 == 3.5); } - + { + typedef double T; + typedef std::array<T, 0> C; + C c = {}; + C const& cc = c; + static_assert((std::is_same<decltype(c.front()), T &>::value), ""); + static_assert((std::is_same<decltype(cc.front()), const T &>::value), ""); + static_assert((std::is_same<decltype(c.back()), T &>::value), ""); + static_assert((std::is_same<decltype(cc.back()), const T &>::value), ""); + if (c.size() > (0)) { // always false + TEST_IGNORE_NODISCARD c.front(); + TEST_IGNORE_NODISCARD c.back(); + TEST_IGNORE_NODISCARD cc.front(); + TEST_IGNORE_NODISCARD cc.back(); + } + } + { + typedef double T; + typedef std::array<const T, 0> C; + C c = {{}}; + C const& cc = c; + static_assert((std::is_same<decltype(c.front()), const T &>::value), ""); + static_assert((std::is_same<decltype(cc.front()), const T &>::value), ""); + static_assert((std::is_same<decltype(c.back()), const T &>::value), ""); + static_assert((std::is_same<decltype(cc.back()), const T &>::value), ""); + if (c.size() > (0)) { + TEST_IGNORE_NODISCARD c.front(); + TEST_IGNORE_NODISCARD c.back(); + TEST_IGNORE_NODISCARD cc.front(); + TEST_IGNORE_NODISCARD cc.back(); + } + } #if TEST_STD_VER > 11 { typedef double T; Index: libcxx/trunk/test/std/containers/sequences/array/indexing.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/indexing.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/indexing.pass.cpp @@ -56,7 +56,34 @@ C::const_reference r2 = c[2]; assert(r2 == 3.5); } - + { // Test operator[] "works" on zero sized arrays + typedef double T; + typedef std::array<T, 0> C; + C c = {}; + C const& cc = c; + static_assert((std::is_same<decltype(c[0]), T &>::value), ""); + static_assert((std::is_same<decltype(cc[0]), const T &>::value), ""); + if (c.size() > (0)) { // always false + C::reference r1 = c[0]; + C::const_reference r2 = cc[0]; + ((void)r1); + ((void)r2); + } + } + { // Test operator[] "works" on zero sized arrays + typedef double T; + typedef std::array<const T, 0> C; + C c = {{}}; + C const& cc = c; + static_assert((std::is_same<decltype(c[0]), const T &>::value), ""); + static_assert((std::is_same<decltype(cc[0]), const T &>::value), ""); + if (c.size() > (0)) { // always false + C::reference r1 = c[0]; + C::const_reference r2 = cc[0]; + ((void)r1); + ((void)r2); + } + } #if TEST_STD_VER > 11 { typedef double T; Index: libcxx/trunk/test/std/containers/sequences/array/at.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/at.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/at.pass.cpp @@ -56,6 +56,26 @@ catch (const std::out_of_range &) {} #endif } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + typedef double T; + typedef std::array<T, 0> C; + C c = {}; + C const& cc = c; + try + { + TEST_IGNORE_NODISCARD c.at(0); + assert(false); + } + catch (const std::out_of_range &) {} + try + { + TEST_IGNORE_NODISCARD cc.at(0); + assert(false); + } + catch (const std::out_of_range &) {} + } +#endif { typedef double T; typedef std::array<T, 3> C; Index: libcxx/trunk/test/std/containers/sequences/array/empty.fail.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/empty.fail.cpp +++ libcxx/trunk/test/std/containers/sequences/array/empty.fail.cpp @@ -23,6 +23,9 @@ int main () { + std::array<int, 1> c; - c.empty(); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}} + c.empty(); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}} + std::array<int, 0> c0; + c0.empty(); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}} } Index: libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.fail.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.fail.cpp +++ libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.fail.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <array> + +// void swap(array& a); + +#include <array> +#include <cassert> + +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + +int main() { + { + typedef double T; + typedef std::array<const T, 0> C; + C c = {}; + C c2 = {}; + // expected-error-re@array:* {{static_assert failed {{.*}} "cannot swap zero-sized array of type 'const T'"}} + c.swap(c2); // expected-note {{requested here}} + } +} Index: libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp @@ -38,6 +38,25 @@ const T* p = c.data(); (void)p; // to placate scan-build } + { + struct NoDefault { + NoDefault(int) {} + }; + typedef NoDefault T; + typedef std::array<T, 0> C; + const C c = {}; + const T* p = c.data(); + assert(p != nullptr); + } + { + typedef std::max_align_t T; + typedef std::array<T, 0> C; + const C c = {}; + const T* p = c.data(); + assert(p != nullptr); + std::uintptr_t pint = reinterpret_cast<std::uintptr_t>(p); + assert(pint % TEST_ALIGNOF(std::max_align_t) == 0); + } #if TEST_STD_VER > 14 { typedef std::array<int, 5> C; Index: libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp @@ -13,6 +13,7 @@ #include <array> #include <cassert> +#include "test_macros.h" // std::array is explicitly allowed to be initialized with A a = { init-list };. // Disable the missing braces warning for this reason. @@ -34,6 +35,33 @@ typedef std::array<T, 0> C; C c = {}; T* p = c.data(); - (void)p; // to placate scan-build + assert(p != nullptr); + } + { + typedef double T; + typedef std::array<const T, 0> C; + C c = {{}}; + const T* p = c.data(); + static_assert((std::is_same<decltype(c.data()), const T*>::value), ""); + assert(p != nullptr); + } + { + typedef std::max_align_t T; + typedef std::array<T, 0> C; + const C c = {}; + const T* p = c.data(); + assert(p != nullptr); + std::uintptr_t pint = reinterpret_cast<std::uintptr_t>(p); + assert(pint % TEST_ALIGNOF(std::max_align_t) == 0); + } + { + struct NoDefault { + NoDefault(int) {} + }; + typedef NoDefault T; + typedef std::array<T, 0> C; + C c = {}; + T* p = c.data(); + assert(p != nullptr); } } Index: libcxx/trunk/test/std/containers/sequences/array/compare.fail.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/compare.fail.cpp +++ libcxx/trunk/test/std/containers/sequences/array/compare.fail.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <array> + +// bool operator==(array<T, N> const&, array<T, N> const&); +// bool operator!=(array<T, N> const&, array<T, N> const&); +// bool operator<(array<T, N> const&, array<T, N> const&); +// bool operator<=(array<T, N> const&, array<T, N> const&); +// bool operator>(array<T, N> const&, array<T, N> const&); +// bool operator>=(array<T, N> const&, array<T, N> const&); + + +#include <array> +#include <vector> +#include <cassert> + +#include "test_macros.h" + +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + +template <class Array> +void test_compare(const Array& LHS, const Array& RHS) { + typedef std::vector<typename Array::value_type> Vector; + const Vector LHSV(LHS.begin(), LHS.end()); + const Vector RHSV(RHS.begin(), RHS.end()); + assert((LHS == RHS) == (LHSV == RHSV)); + assert((LHS != RHS) == (LHSV != RHSV)); + assert((LHS < RHS) == (LHSV < RHSV)); + assert((LHS <= RHS) == (LHSV <= RHSV)); + assert((LHS > RHS) == (LHSV > RHSV)); + assert((LHS >= RHS) == (LHSV >= RHSV)); +} + +template <int Dummy> struct NoCompare {}; + +int main() +{ + { + typedef NoCompare<0> T; + typedef std::array<T, 3> C; + C c1 = {{}}; + // expected-error@algorithm:* 2 {{invalid operands to binary expression}} + TEST_IGNORE_NODISCARD (c1 == c1); + TEST_IGNORE_NODISCARD (c1 < c1); + } + { + typedef NoCompare<1> T; + typedef std::array<T, 3> C; + C c1 = {{}}; + // expected-error@algorithm:* 2 {{invalid operands to binary expression}} + TEST_IGNORE_NODISCARD (c1 != c1); + TEST_IGNORE_NODISCARD (c1 > c1); + } + { + typedef NoCompare<2> T; + typedef std::array<T, 0> C; + C c1 = {{}}; + // expected-error@algorithm:* 2 {{invalid operands to binary expression}} + TEST_IGNORE_NODISCARD (c1 == c1); + TEST_IGNORE_NODISCARD (c1 < c1); + } +} Index: libcxx/trunk/test/std/containers/sequences/array/size_and_alignment.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/size_and_alignment.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/size_and_alignment.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <array> + +// template <class T, size_t N > +// struct array + +// Test the size and alignment matches that of an array of a given type. + +#include <array> +#include <iterator> +#include <type_traits> +#include <cstddef> + +#include "test_macros.h" + +template <class T, size_t Size> +void test() { + typedef T CArrayT[Size == 0 ? 1 : Size]; + typedef std::array<T, Size> ArrayT; + static_assert(sizeof(CArrayT) == sizeof(ArrayT), ""); + static_assert(TEST_ALIGNOF(CArrayT) == TEST_ALIGNOF(ArrayT), ""); +} + +template <class T> +void test_type() { + test<T, 1>(); + test<T, 42>(); + test<T, 0>(); +} + +struct TEST_ALIGNAS(TEST_ALIGNOF(std::max_align_t) * 2) TestType1 { + +}; + +struct TEST_ALIGNAS(TEST_ALIGNOF(std::max_align_t) * 2) TestType2 { + char data[1000]; +}; + +int main() { + test_type<char>(); + test_type<int>(); + test_type<double>(); + test_type<long double>(); + test_type<std::max_align_t>(); + test_type<TestType1>(); + test_type<TestType2>(); +} Index: libcxx/trunk/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <array> + +// implicitly generated array constructors / assignment operators + +#include <array> +#include <type_traits> +#include <cassert> +#include "test_macros.h" + +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + +// In C++03 the copy assignment operator is not deleted when the implicitly +// generated operator would be ill-formed; like in the case of a struct with a +// const member. +#if TEST_STD_VER < 11 +#define TEST_NOT_COPY_ASSIGNABLE(T) ((void)0) +#else +#define TEST_NOT_COPY_ASSIGNABLE(T) static_assert(!std::is_copy_assignable<T>::value, "") +#endif + +struct NoDefault { + NoDefault(int) {} +}; + +int main() { + { + typedef double T; + typedef std::array<T, 3> C; + C c = {1.1, 2.2, 3.3}; + C c2 = c; + c2 = c; + static_assert(std::is_copy_constructible<C>::value, ""); + static_assert(std::is_copy_assignable<C>::value, ""); + } + { + typedef double T; + typedef std::array<const T, 3> C; + C c = {1.1, 2.2, 3.3}; + C c2 = c; + ((void)c2); + static_assert(std::is_copy_constructible<C>::value, ""); + TEST_NOT_COPY_ASSIGNABLE(C); + } + { + typedef double T; + typedef std::array<T, 0> C; + C c = {}; + C c2 = c; + c2 = c; + static_assert(std::is_copy_constructible<C>::value, ""); + static_assert(std::is_copy_assignable<C>::value, ""); + } + { + // const arrays of size 0 should disable the implicit copy assignment operator. + typedef double T; + typedef std::array<const T, 0> C; + C c = {{}}; + C c2 = c; + ((void)c2); + static_assert(std::is_copy_constructible<C>::value, ""); + TEST_NOT_COPY_ASSIGNABLE(C); + } + { + typedef NoDefault T; + typedef std::array<T, 0> C; + C c = {}; + C c2 = c; + c2 = c; + static_assert(std::is_copy_constructible<C>::value, ""); + static_assert(std::is_copy_assignable<C>::value, ""); + } + { + typedef NoDefault T; + typedef std::array<const T, 0> C; + C c = {{}}; + C c2 = c; + ((void)c2); + static_assert(std::is_copy_constructible<C>::value, ""); + TEST_NOT_COPY_ASSIGNABLE(C); + } + +} Index: libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp @@ -14,6 +14,14 @@ #include <array> #include <cassert> +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + +struct NoDefault { + NoDefault(int) {} +}; + int main() { { @@ -28,4 +36,13 @@ C c; assert(c.size() == 0); } + { + typedef std::array<NoDefault, 0> C; + C c; + assert(c.size() == 0); + C c1 = {}; + assert(c1.size() == 0); + C c2 = {{}}; + assert(c2.size() == 0); + } } Index: libcxx/trunk/test/std/containers/sequences/array/compare.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/compare.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/compare.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <array> + +// bool operator==(array<T, N> const&, array<T, N> const&); +// bool operator!=(array<T, N> const&, array<T, N> const&); +// bool operator<(array<T, N> const&, array<T, N> const&); +// bool operator<=(array<T, N> const&, array<T, N> const&); +// bool operator>(array<T, N> const&, array<T, N> const&); +// bool operator>=(array<T, N> const&, array<T, N> const&); + + +#include <array> +#include <vector> +#include <cassert> + +#include "test_macros.h" + +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + +template <class Array> +void test_compare(const Array& LHS, const Array& RHS) { + typedef std::vector<typename Array::value_type> Vector; + const Vector LHSV(LHS.begin(), LHS.end()); + const Vector RHSV(RHS.begin(), RHS.end()); + assert((LHS == RHS) == (LHSV == RHSV)); + assert((LHS != RHS) == (LHSV != RHSV)); + assert((LHS < RHS) == (LHSV < RHSV)); + assert((LHS <= RHS) == (LHSV <= RHSV)); + assert((LHS > RHS) == (LHSV > RHSV)); + assert((LHS >= RHS) == (LHSV >= RHSV)); +} + +int main() +{ + { + typedef int T; + typedef std::array<T, 3> C; + C c1 = {1, 2, 3}; + C c2 = {1, 2, 3}; + C c3 = {3, 2, 1}; + C c4 = {1, 2, 1}; + test_compare(c1, c2); + test_compare(c1, c3); + test_compare(c1, c4); + } + { + typedef int T; + typedef std::array<T, 0> C; + C c1 = {}; + C c2 = {}; + test_compare(c1, c2); + } +} Index: libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp =================================================================== --- libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp +++ libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp @@ -18,6 +18,7 @@ // Disable the missing braces warning for this reason. #include "disable_missing_braces_warning.h" + int main() { { @@ -31,4 +32,13 @@ *i = 5.5; assert(c[0] == 5.5); } + { + struct NoDefault { + NoDefault(int) {} + }; + typedef NoDefault T; + typedef std::array<T, 0> C; + C c = {}; + assert(c.begin() == c.end()); + } } Index: libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp =================================================================== --- libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp +++ libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-no-exceptions +// MODULES_DEFINES: _LIBCPP_DEBUG=1 +// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS + +// Can't test the system lib because this test enables debug mode +// UNSUPPORTED: with_system_cxx_lib + +// test array<T, 0>::front() throws a debug exception. + +#define _LIBCPP_DEBUG 1 +#define _LIBCPP_DEBUG_USE_EXCEPTIONS +#include <array> + +template <class Array> +inline bool CheckDebugThrows(Array& Arr) { + try { + Arr.front(); + } catch (std::__libcpp_debug_exception const&) { + return true; + } + return false; +} + +int main() +{ + { + typedef std::array<int, 0> C; + C c = {}; + C const& cc = c; + assert(CheckDebugThrows(c)); + assert(CheckDebugThrows(cc)); + } + { + typedef std::array<const int, 0> C; + C c = {{}}; + C const& cc = c; + assert(CheckDebugThrows(c)); + assert(CheckDebugThrows(cc)); + } +} Index: libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp =================================================================== --- libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp +++ libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-no-exceptions +// MODULES_DEFINES: _LIBCPP_DEBUG=1 +// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS + +// Can't test the system lib because this test enables debug mode +// UNSUPPORTED: with_system_cxx_lib + +// test array<T, 0>::operator[] throws a debug exception. + +#define _LIBCPP_DEBUG 1 +#define _LIBCPP_DEBUG_USE_EXCEPTIONS +#include <array> + +template <class Array> +inline bool CheckDebugThrows(Array& Arr, size_t Index) { + try { + Arr[Index]; + } catch (std::__libcpp_debug_exception const&) { + return true; + } + return false; +} + +int main() +{ + { + typedef std::array<int, 0> C; + C c = {}; + C const& cc = c; + assert(CheckDebugThrows(c, 0)); + assert(CheckDebugThrows(c, 1)); + assert(CheckDebugThrows(cc, 0)); + assert(CheckDebugThrows(cc, 1)); + } + { + typedef std::array<const int, 0> C; + C c = {{}}; + C const& cc = c; + assert(CheckDebugThrows(c, 0)); + assert(CheckDebugThrows(c, 1)); + assert(CheckDebugThrows(cc, 0)); + assert(CheckDebugThrows(cc, 1)); + } +} Index: libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp =================================================================== --- libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp +++ libcxx/trunk/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-no-exceptions +// MODULES_DEFINES: _LIBCPP_DEBUG=1 +// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS + +// Can't test the system lib because this test enables debug mode +// UNSUPPORTED: with_system_cxx_lib + +// test array<T, 0>::front() throws a debug exception. + +#define _LIBCPP_DEBUG 1 +#define _LIBCPP_DEBUG_USE_EXCEPTIONS +#include <array> + +template <class Array> +inline bool CheckDebugThrows(Array& Arr) { + try { + Arr.back(); + } catch (std::__libcpp_debug_exception const&) { + return true; + } + return false; +} + +int main() +{ + { + typedef std::array<int, 0> C; + C c = {}; + C const& cc = c; + assert(CheckDebugThrows(c)); + assert(CheckDebugThrows(cc)); + } + { + typedef std::array<const int, 0> C; + C c = {{}}; + C const& cc = c; + assert(CheckDebugThrows(c)); + assert(CheckDebugThrows(cc)); + } +}
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits