diff --git a/libcxx/include/array b/libcxx/include/array --- a/libcxx/include/array +++ b/libcxx/include/array @@ -67,8 +67,8 @@ reference back(); // constexpr in C++17 const_reference back() const; // constexpr in C++14 - T* data() noexcept; // constexpr in C++17 - const T* data() const noexcept; // constexpr in C++17 + T* data() noexcept; // constexpr in C++14 (extension -- should be in C++17) + const T* data() const noexcept; // constexpr in C++14 (extension -- should be in C++17) }; template @@ -115,7 +115,6 @@ #include #include #include -#include // for _LIBCPP_UNREACHABLE #include #include <__debug> @@ -124,15 +123,53 @@ #endif - _LIBCPP_BEGIN_NAMESPACE_STD +namespace __detail { + template + struct __array_storage { + typedef _Tp type[_Size]; + + static _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR + _Tp* __get(type& __storage) _NOEXCEPT { + return __storage; + } + }; + +#ifndef _LIBCPP_CXX03_LANG + template + struct __array_storage<_Tp, 0> { + union type { + _LIBCPP_CONSTEXPR type() : __b() { } + ~type() = default; + bool __b; + _Tp __t; + }; + + static _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR + _Tp* __get(type& __storage) _NOEXCEPT { + return &__storage.__t; + } + }; +#else // C++03 + template + struct __array_storage<_Tp, 0> { + typedef typename conditional::value, const char, char>::type _CharType; + struct _ArrayInStructT { _Tp __data_[1]; }; + typedef _ALIGNAS_TYPE(_ArrayInStructT) _CharType type[sizeof(_ArrayInStructT)]; + + static _LIBCPP_INLINE_VISIBILITY + _Tp* __get(type& __storage) _NOEXCEPT { + return reinterpret_cast<_Tp*>(__storage); + } + }; +#endif +} // end namespace __detail template struct _LIBCPP_TEMPLATE_VIS array { // types: - typedef array __self; typedef _Tp value_type; typedef value_type& reference; typedef const value_type& const_reference; @@ -145,17 +182,34 @@ typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - _Tp __elems_[_Size]; - // No explicit construct/copy/destroy for aggregate type + typedef __detail::__array_storage<_Tp, _Size> _ArrayStorage; + typename _ArrayStorage::type __elems_; + + template ::type> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void fill(const value_type& __u) { - _VSTD::fill_n(__elems_, _Size, __u); + _VSTD::fill_n(data(), _Size, __u); } + template ::type> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + void fill(const value_type&) { + static_assert(!is_const<_Tp>::value, + "cannot fill zero-sized array of type 'const T'"); + } + + template ::type> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) { - std::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_); + std::swap_ranges(data(), data() + _Size, __a.data()); + } + + template ::type> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + void swap(array&) _NOEXCEPT { + static_assert(!is_const<_Tp>::value, + "cannot swap zero-sized array of type 'const T'"); } // iterators: @@ -192,182 +246,51 @@ _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 false; } + _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return _Size == 0;} // element access: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reference operator[](size_type __n) _NOEXCEPT {return __elems_[__n];} + reference operator[](size_type __n) _NOEXCEPT { + _LIBCPP_ASSERT(__n < _Size, "out-of-bounds access in std::array"); + return data()[__n]; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - const_reference operator[](size_type __n) const _NOEXCEPT {return __elems_[__n];} + const_reference operator[](size_type __n) const _NOEXCEPT { + _LIBCPP_ASSERT(__n < _Size, "out-of-bounds access in std::array"); + return data()[__n]; + } _LIBCPP_CONSTEXPR_AFTER_CXX14 reference at(size_type __n) { if (__n >= _Size) __throw_out_of_range("array::at"); - return __elems_[__n]; + return data()[__n]; } _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference at(size_type __n) const { if (__n >= _Size) __throw_out_of_range("array::at"); - return __elems_[__n]; + return data()[__n]; } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference front() _NOEXCEPT {return __elems_[0];} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference front() const _NOEXCEPT {return __elems_[0];} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference back() _NOEXCEPT {return __elems_[_Size - 1];} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference back() const _NOEXCEPT {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 -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 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 - - // No explicit construct/copy/destroy for aggregate type - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - void fill(const value_type&) { - static_assert(!is_const<_Tp>::value, - "cannot fill zero-sized array of type 'const T'"); - } - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 - void swap(array&) _NOEXCEPT { - static_assert(!is_const<_Tp>::value, - "cannot swap zero-sized array of type 'const T'"); - } - - // iterators: - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - iterator begin() _NOEXCEPT {return iterator(data());} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_iterator begin() const _NOEXCEPT {return const_iterator(data());} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - iterator end() _NOEXCEPT {return iterator(data());} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_iterator end() const _NOEXCEPT {return const_iterator(data());} - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reverse_iterator rbegin() _NOEXCEPT {return reverse_iterator(end());} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_reverse_iterator rbegin() const _NOEXCEPT {return const_reverse_iterator(end());} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reverse_iterator rend() _NOEXCEPT {return reverse_iterator(begin());} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_reverse_iterator rend() const _NOEXCEPT {return const_reverse_iterator(begin());} - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_iterator cbegin() const _NOEXCEPT {return begin();} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_iterator cend() const _NOEXCEPT {return end();} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - const_reverse_iterator crbegin() const _NOEXCEPT {return rbegin();} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - 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 _LIBCPP_CONSTEXPR_AFTER_CXX14 - reference operator[](size_type) _NOEXCEPT { - _LIBCPP_ASSERT(false, "cannot call array::operator[] on a zero-sized array"); - _LIBCPP_UNREACHABLE(); - } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference front() _NOEXCEPT {return (*this)[0];} + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference front() const _NOEXCEPT {return (*this)[0];} + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference back() _NOEXCEPT {return (*this)[_Size - 1];} + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference back() const _NOEXCEPT {return (*this)[_Size - 1];} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - const_reference operator[](size_type) const _NOEXCEPT { - _LIBCPP_ASSERT(false, "cannot call array::operator[] on a zero-sized array"); - _LIBCPP_UNREACHABLE(); - } - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reference at(size_type) { - __throw_out_of_range("array::at"); - _LIBCPP_UNREACHABLE(); + value_type* data() _NOEXCEPT { + return _ArrayStorage::__get(__elems_); } _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - const_reference at(size_type) const { - __throw_out_of_range("array::at"); - _LIBCPP_UNREACHABLE(); - } - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reference front() _NOEXCEPT { - _LIBCPP_ASSERT(false, "cannot call array::front() on a zero-sized array"); - _LIBCPP_UNREACHABLE(); - } - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - const_reference front() const _NOEXCEPT { - _LIBCPP_ASSERT(false, "cannot call array::front() on a zero-sized array"); - _LIBCPP_UNREACHABLE(); - } - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 - reference back() _NOEXCEPT { - _LIBCPP_ASSERT(false, "cannot call array::back() on a zero-sized array"); - _LIBCPP_UNREACHABLE(); - } - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 - const_reference back() const _NOEXCEPT { - _LIBCPP_ASSERT(false, "cannot call array::back() on a zero-sized array"); - _LIBCPP_UNREACHABLE(); + const value_type* data() const _NOEXCEPT { + return _ArrayStorage::__get(const_cast(__elems_)); } }; - #ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES template::value...>::value> @@ -456,7 +379,7 @@ get(array<_Tp, _Size>& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array)"); - return __a.__elems_[_Ip]; + return __a.data()[_Ip]; } template @@ -465,7 +388,7 @@ get(const array<_Tp, _Size>& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array)"); - return __a.__elems_[_Ip]; + return __a.data()[_Ip]; } #ifndef _LIBCPP_CXX03_LANG @@ -476,7 +399,7 @@ get(array<_Tp, _Size>&& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array &&)"); - return _VSTD::move(__a.__elems_[_Ip]); + return _VSTD::move(__a.data()[_Ip]); } template @@ -485,7 +408,7 @@ get(const array<_Tp, _Size>&& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array &&)"); - return _VSTD::move(__a.__elems_[_Ip]); + return _VSTD::move(__a.data()[_Ip]); } #endif // !_LIBCPP_CXX03_LANG diff --git a/libcxx/test/libcxx/containers/sequences/array/data_constexpr_extension.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/data_constexpr_extension.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/array/data_constexpr_extension.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11 + +// Check that std::array::data() is constexpr in C++14, as an extension. + +#include + + +constexpr bool tests() +{ + { + std::array array = {}; + std::array const carray = {}; + int* d1 = array.data(); (void)d1; + int const* d2 = carray.data(); (void)d2; + } + { + std::array array = {1}; + std::array const carray = {1}; + int* d1 = array.data(); (void)d1; + int const* d2 = carray.data(); (void)d2; + } + { + std::array array = {1, 2}; + std::array const carray = {1, 2}; + int* d1 = array.data(); (void)d1; + int const* d2 = carray.data(); (void)d2; + } + + return true; +} + +int main(int, char**) +{ + static_assert(tests(), ""); + return 0; +}