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

Hans Wennborg via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 5 07:19:43 PST 2018


This broke the Chromium build, see
https://bugs.chromium.org/p/chromium/issues/detail?id=809050#c2

I see there were a lot of changes landed around the same time, so I'm
not sure what to revert here exactly.

On Sun, Feb 4, 2018 at 2:03 AM, Eric Fiselier via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
> Author: ericwf
> Date: Sat Feb  3 17:03:08 2018
> New Revision: 324182
>
> URL: http://llvm.org/viewvc/llvm-project?rev=324182&view=rev
> Log:
> [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
>
> Modified:
>     libcxx/trunk/include/array
>     libcxx/trunk/test/std/containers/sequences/array/array.cons/default.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/begin.pass.cpp
>
> Modified: libcxx/trunk/include/array
> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/array?rev=324182&r1=324181&r2=324182&view=diff
> ==============================================================================
> --- libcxx/trunk/include/array (original)
> +++ libcxx/trunk/include/array Sat Feb  3 17:03:08 2018
> @@ -118,6 +118,55 @@ template <size_t I, class T, size_t N> c
>  _LIBCPP_BEGIN_NAMESPACE_STD
>
>  template <class _Tp, size_t _Size>
> +struct __array_traits {
> +  typedef _Tp _StorageT[_Size];
> +
> +  _LIBCPP_INLINE_VISIBILITY
> +  static _LIBCPP_CONSTEXPR_AFTER_CXX14 _Tp* __data(_StorageT& __store) {
> +    return __store;
> +  }
> +
> +  _LIBCPP_INLINE_VISIBILITY
> +  static _LIBCPP_CONSTEXPR_AFTER_CXX14 _Tp const* __data(const _StorageT& __store) {
> +    return __store;
> +  }
> +
> +  _LIBCPP_INLINE_VISIBILITY
> +  static void __swap(_StorageT& __lhs, _StorageT& __rhs) {
> +    std::swap_ranges(__lhs, __lhs + _Size, __rhs);
> +  }
> +
> +  _LIBCPP_INLINE_VISIBILITY
> +  static void __fill(_StorageT& __arr, _Tp const& __val) {
> +    _VSTD::fill_n(__arr, _Size, __val);
> +  }
> +};
> +
> +template <class _Tp>
> +struct __array_traits<_Tp, 0> {
> +  typedef typename aligned_storage<sizeof(_Tp), alignment_of<_Tp>::value>::type _StorageT;
> +
> +  _LIBCPP_INLINE_VISIBILITY
> +  static _Tp* __data(_StorageT& __store) {
> +    _StorageT *__ptr = std::addressof(__store);
> +    return reinterpret_cast<_Tp*>(__ptr);
> +  }
> +
> +  _LIBCPP_INLINE_VISIBILITY
> +  static const _Tp* __data(const _StorageT& __store) {
> +    const _StorageT *__ptr = std::addressof(__store);
> +    return reinterpret_cast<const _Tp*>(__ptr);
> +  }
> +
> +  _LIBCPP_INLINE_VISIBILITY
> +  static void __swap(_StorageT&, _StorageT&) {}
> +
> +  _LIBCPP_INLINE_VISIBILITY
> +  static void __fill(_StorageT&, _Tp const&) {
> +  }
> +};
> +
> +template <class _Tp, size_t _Size>
>  struct _LIBCPP_TEMPLATE_VIS array
>  {
>      // types:
> @@ -134,31 +183,26 @@ 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];
> +    typedef __array_traits<_Tp, _Size> _Traits;
> +    typename _Traits::_StorageT __elems_;
>
>      // 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); }
> +        {_Traits::__fill(__elems_, __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_(_Size == 0 || __is_nothrow_swappable<_Tp>::value)
> +        { _Traits::__swap(__elems_, __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());}
> @@ -201,9 +245,9 @@ struct _LIBCPP_TEMPLATE_VIS array
>      _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
> -    value_type* data() _NOEXCEPT {return __elems_;}
> +    value_type* data() _NOEXCEPT {return _Traits::__data(__elems_);}
>      _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
> -    const value_type* data() const _NOEXCEPT {return __elems_;}
> +    const value_type* data() const _NOEXCEPT {return _Traits::__data(__elems_);}
>  };
>
>  template <class _Tp, size_t _Size>
>
> Modified: libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp
> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp?rev=324182&r1=324181&r2=324182&view=diff
> ==============================================================================
> --- libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp (original)
> +++ libcxx/trunk/test/std/containers/sequences/array/array.cons/default.pass.cpp Sat Feb  3 17:03:08 2018
> @@ -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);
> +    }
>  }
>
> Modified: libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp
> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp?rev=324182&r1=324181&r2=324182&view=diff
> ==============================================================================
> --- libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp (original)
> +++ libcxx/trunk/test/std/containers/sequences/array/array.data/data.pass.cpp Sat Feb  3 17:03:08 2018
> @@ -36,4 +36,14 @@ int main()
>          T* p = c.data();
>          (void)p; // to placate scan-build
>      }
> +    {
> +      struct NoDefault {
> +        NoDefault(int) {}
> +      };
> +      typedef NoDefault T;
> +      typedef std::array<T, 0> C;
> +      C c = {};
> +      T* p = c.data();
> +      assert(p != nullptr);
> +    }
>  }
>
> Modified: libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp
> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp?rev=324182&r1=324181&r2=324182&view=diff
> ==============================================================================
> --- libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp (original)
> +++ libcxx/trunk/test/std/containers/sequences/array/array.data/data_const.pass.cpp Sat Feb  3 17:03:08 2018
> @@ -38,6 +38,16 @@ 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);
> +    }
>  #if TEST_STD_VER > 14
>      {
>          typedef std::array<int, 5> C;
>
> Modified: libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp
> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp?rev=324182&r1=324181&r2=324182&view=diff
> ==============================================================================
> --- libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp (original)
> +++ libcxx/trunk/test/std/containers/sequences/array/begin.pass.cpp Sat Feb  3 17:03:08 2018
> @@ -31,4 +31,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());
> +    }
>  }
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


More information about the cfe-commits mailing list