[libc++] Fix PR35491 - std::array of zero-size doesn't work with non-default constructible types.

Summary:
This patch fixes llvm.org/PR35491 and LWG2157  (https://cplusplus.github.io/LWG/issue2157)

The fix attempts to maintain ABI compatibility by replacing the array with a instance of `aligned_storage`.

Reviewers: mclow.lists, EricWF

Reviewed By: EricWF

Subscribers: lichray, cfe-commits

Differential Revision: https://reviews.llvm.org/D41223

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@324526 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2018-02-07 21:06:13 +00:00
parent f003d63c40
commit 6cb35ede81
19 changed files with 805 additions and 26 deletions

View File

@@ -793,8 +793,13 @@ namespace std {
# if !defined(_LIBCPP_DEBUG)
# error cannot use _LIBCPP_DEBUG_USE_EXCEPTIONS unless _LIBCPP_DEBUG is defined
# endif
# 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)

View File

@@ -108,6 +108,8 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce
#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 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS array
{
@@ -134,31 +137,27 @@ struct _LIBCPP_TEMPLATE_VIS array
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 @@ struct _LIBCPP_TEMPLATE_VIS array
_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,8 +196,8 @@ struct _LIBCPP_TEMPLATE_VIS array
_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_;}
@@ -206,6 +205,7 @@ struct _LIBCPP_TEMPLATE_VIS array
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 @@ array<_Tp, _Size>::at(size_type __n) const
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 @@ inline _LIBCPP_INLINE_VISIBILITY
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>

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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 @@ int main()
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);
}
}

View File

@@ -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);
}
}

View File

@@ -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 @@ int main()
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);
}
}

View File

@@ -38,6 +38,25 @@ int main()
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;

View File

@@ -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}}
}
}

View File

@@ -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}}
}
}

View File

@@ -56,6 +56,26 @@ int main()
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;

View File

@@ -18,6 +18,7 @@
// Disable the missing braces warning for this reason.
#include "disable_missing_braces_warning.h"
int main()
{
{
@@ -31,4 +32,13 @@ int main()
*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());
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -23,6 +23,9 @@
int main ()
{
std::array<int, 1> c;
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}}
}

View File

@@ -64,7 +64,38 @@ int main()
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;

View File

@@ -56,7 +56,34 @@ int main()
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;

View File

@@ -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>();
}