From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 97E1B3848592; Wed, 4 May 2022 15:34:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 97E1B3848592 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-113] libstdc++: Simplify std::array accessors [PR104719] X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 9c6a4beeed572f9e235f881e00ad8c63b6bcc9df X-Git-Newrev: ef8d5ac08b5e60f35c52087d88c0235c8ce6b65b Message-Id: <20220504153442.97E1B3848592@sourceware.org> Date: Wed, 4 May 2022 15:34:42 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 04 May 2022 15:34:42 -0000 https://gcc.gnu.org/g:ef8d5ac08b5e60f35c52087d88c0235c8ce6b65b commit r13-113-gef8d5ac08b5e60f35c52087d88c0235c8ce6b65b Author: Jonathan Wakely Date: Fri Mar 25 10:28:28 2022 +0000 libstdc++: Simplify std::array accessors [PR104719] This removes the __array_traits::_S_ref and __array_traits::_S_ptr accessors, which only exist to make the special case of std::array syntactically well-formed. By changing the empty type used as the std::array::_M_elems data member to support operator[] and conversion to a pointer, we can write code using the natural syntax. The indirection through _S_ref and _S_ptr is removed for the common case, and a function call is only used for the special case of zero-size arrays. The invalid member access for zero-sized arrays is changed to use __builtin_trap() instead of a null dereference. This guarantees a runtime error if it ever gets called, instead of undefined behaviour that is likely to get optimized out as unreachable. libstdc++-v3/ChangeLog: PR libstdc++/104719 * include/std/array (__array_traits::_S_ref): Remove. (__array_traits::_S_ptr): Remove. (__array_traits::_Type): Define operator[] and operator T* to provide an array-like API. (array::_AT_Type): Remove public typeef. (array::operator[], array::at, array::front, array::back): Use index operator to access _M_elems instead of _S_ref. (array::data): Use implicit conversion from _M_elems to pointer. (swap(array&, array&)): Use __enable_if_t helper. (get): Use index operator to access _M_elems. * testsuite/23_containers/array/tuple_interface/get_neg.cc: Adjust dg-error line numbers. Diff: --- libstdc++-v3/include/std/array | 80 ++++++++++------------ .../23_containers/array/tuple_interface/get_neg.cc | 6 +- 2 files changed, 38 insertions(+), 48 deletions(-) diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index e45143fb329..d1daffee425 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -49,36 +49,31 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template + template struct __array_traits { - typedef _Tp _Type[_Nm]; - typedef __is_swappable<_Tp> _Is_swappable; - typedef __is_nothrow_swappable<_Tp> _Is_nothrow_swappable; - - static constexpr _Tp& - _S_ref(const _Type& __t, std::size_t __n) noexcept - { return const_cast<_Tp&>(__t[__n]); } - - static constexpr _Tp* - _S_ptr(const _Type& __t) noexcept - { return const_cast<_Tp*>(__t); } + using _Type = _Tp[_Nm]; + using _Is_swappable = __is_swappable<_Tp>; + using _Is_nothrow_swappable = __is_nothrow_swappable<_Tp>; }; template struct __array_traits<_Tp, 0> { - struct _Type { }; - typedef true_type _Is_swappable; - typedef true_type _Is_nothrow_swappable; - - static constexpr _Tp& - _S_ref(const _Type&, std::size_t) noexcept - { return *static_cast<_Tp*>(nullptr); } - - static constexpr _Tp* - _S_ptr(const _Type&) noexcept - { return nullptr; } + // Empty type used instead of _Tp[0] for std::array<_Tp, 0>. + struct _Type + { + // Indexing is undefined. + __attribute__((__always_inline__,__artificial__,__noreturn__)) + _Tp& operator[](size_t) const noexcept { __builtin_trap(); } + + // Conversion to a pointer produces a null pointer. + __attribute__((__always_inline__,__artificial__)) + operator _Tp*() const noexcept { return nullptr; } + }; + + using _Is_swappable = true_type; + using _Is_nothrow_swappable = true_type; }; /** @@ -111,8 +106,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef std::reverse_iterator const_reverse_iterator; // Support for zero-sized arrays mandatory. - typedef __array_traits<_Tp, _Nm> _AT_Type; - typename _AT_Type::_Type _M_elems; + typename __array_traits<_Tp, _Nm>::_Type _M_elems; // No explicit construct/copy/destroy for aggregate type. @@ -123,7 +117,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX20_CONSTEXPR void swap(array& __other) - noexcept(_AT_Type::_Is_nothrow_swappable::value) + noexcept(__array_traits<_Tp, _Nm>::_Is_nothrow_swappable::value) { std::swap_ranges(begin(), end(), __other.begin()); } // Iterators. @@ -206,7 +200,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator[](size_type __n) noexcept { __glibcxx_requires_subscript(__n); - return _AT_Type::_S_ref(_M_elems, __n); + return _M_elems[__n]; } [[__nodiscard__]] @@ -216,7 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus >= 201402L __glibcxx_requires_subscript(__n); #endif - return _AT_Type::_S_ref(_M_elems, __n); + return _M_elems[__n]; } _GLIBCXX17_CONSTEXPR reference @@ -226,7 +220,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) " ">= _Nm (which is %zu)"), __n, _Nm); - return _AT_Type::_S_ref(_M_elems, __n); + return _M_elems[__n]; } constexpr const_reference @@ -234,11 +228,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { // Result of conditional expression must be an lvalue so use // boolean ? lvalue : (throw-expr, lvalue) - return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n) + return __n < _Nm ? _M_elems[__n] : (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) " ">= _Nm (which is %zu)"), __n, _Nm), - _AT_Type::_S_ref(_M_elems, 0)); + _M_elems[__n]); } [[__nodiscard__]] @@ -246,7 +240,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION front() noexcept { __glibcxx_requires_nonempty(); - return *begin(); + return _M_elems[0]; } [[__nodiscard__]] @@ -256,7 +250,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus >= 201402L __glibcxx_requires_nonempty(); #endif - return _AT_Type::_S_ref(_M_elems, 0); + return _M_elems[0]; } [[__nodiscard__]] @@ -264,7 +258,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION back() noexcept { __glibcxx_requires_nonempty(); - return _Nm ? *(end() - 1) : *end(); + return _M_elems[_Nm - 1]; } [[__nodiscard__]] @@ -274,19 +268,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus >= 201402L __glibcxx_requires_nonempty(); #endif - return _Nm ? _AT_Type::_S_ref(_M_elems, _Nm - 1) - : _AT_Type::_S_ref(_M_elems, 0); + return _M_elems[_Nm - 1]; } [[__gnu__::__const__, __nodiscard__]] _GLIBCXX17_CONSTEXPR pointer data() noexcept - { return _AT_Type::_S_ptr(_M_elems); } + { return _M_elems; } [[__nodiscard__]] _GLIBCXX17_CONSTEXPR const_pointer data() const noexcept - { return _AT_Type::_S_ptr(_M_elems); } + { return _M_elems; } }; #if __cpp_deduction_guides >= 201606 @@ -371,9 +364,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 // Constrained free swap overload, see p0185r1 - typename enable_if< - __array_traits<_Tp, _Nm>::_Is_swappable::value - >::type + __enable_if_t<__array_traits<_Tp, _Nm>::_Is_swappable::value> #else void #endif @@ -383,8 +374,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 template - typename enable_if< - !__array_traits<_Tp, _Nm>::_Is_swappable::value>::type + __enable_if_t::_Is_swappable::value> swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&) = delete; #endif @@ -394,7 +384,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION get(array<_Tp, _Nm>& __arr) noexcept { static_assert(_Int < _Nm, "array index is within bounds"); - return __array_traits<_Tp, _Nm>::_S_ref(__arr._M_elems, _Int); + return __arr._M_elems[_Int]; } template @@ -412,7 +402,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION get(const array<_Tp, _Nm>& __arr) noexcept { static_assert(_Int < _Nm, "array index is within bounds"); - return __array_traits<_Tp, _Nm>::_S_ref(__arr._M_elems, _Int); + return __arr._M_elems[_Int]; } template diff --git a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc index ea1fd9f2f96..b97149474c9 100644 --- a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc @@ -26,6 +26,6 @@ int n1 = std::get<1>(a); int n2 = std::get<1>(std::move(a)); int n3 = std::get<1>(ca); -// { dg-error "static assertion failed" "" { target *-*-* } 396 } -// { dg-error "static assertion failed" "" { target *-*-* } 405 } -// { dg-error "static assertion failed" "" { target *-*-* } 414 } +// { dg-error "static assertion failed" "" { target *-*-* } 386 } +// { dg-error "static assertion failed" "" { target *-*-* } 395 } +// { dg-error "static assertion failed" "" { target *-*-* } 404 }