[libcxx-commits] [libcxx] Improvements to std::array<T, 0>. (PR #74657)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Dec 7 06:12:44 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Ryan Nicholl (rnicholl-google)

<details>
<summary>Changes</summary>

In the unstable ABI, std::array<T, 0> now uses only 1 byte with empty base optimization. In the stable ABI, it now can be used in constexpr context like std::array<int, 0> a; a.fill(1); return a;

Fixes llvm/llvm-project#<!-- -->74375

---
Full diff: https://github.com/llvm/llvm-project/pull/74657.diff


6 Files Affected:

- (modified) libcxx/include/__config (+4) 
- (modified) libcxx/include/array (+8-1) 
- (modified) libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp (-1) 
- (modified) libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp (-15) 
- (modified) libcxx/test/std/containers/sequences/array/size_and_alignment.pass.cpp (+13-2) 
- (modified) libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h (+1-1) 


``````````diff
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 51eb484297f6b..9d256aeb222fa 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -168,6 +168,10 @@
 // pointer from 16 to 8. This changes the output of std::string::max_size,
 // which makes it ABI breaking
 #    define _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT
+// Make std::array<T, N> where N == 0 have no data
+// This allows it to be used in constexpr contexts without
+// introducing runtime overhead
+#    define _LIBCPP_ABI_ZERO_SIZE_ARRAY_HAS_NO_DATA
 #  elif _LIBCPP_ABI_VERSION == 1
 #    if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
 // Enable compiling copies of now inline methods into the dylib to support
diff --git a/libcxx/include/array b/libcxx/include/array
index c01d13ef358a5..d4df7cd302b99 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -263,8 +263,13 @@ struct _LIBCPP_TEMPLATE_VIS array
     const value_type* data() const _NOEXCEPT {return __elems_;}
 };
 
+struct _EmptyAggregateType {};
+
 template <class _Tp>
 struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0>
+#ifdef _LIBCPP_ABI_ZERO_SIZE_ARRAY_HAS_NO_DATA
+: _EmptyAggregateType
+#endif
 {
     // types:
     typedef array __self;
@@ -282,8 +287,10 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0>
 
     typedef __conditional_t<is_const<_Tp>::value, const char, char> _CharType;
 
+#ifndef _LIBCPP_ABI_ZERO_SIZE_ARRAY_HAS_NO_DATA
     struct  _ArrayInStructT { _Tp __data_[1]; };
-    _ALIGNAS_TYPE(_ArrayInStructT) _CharType __elems_[sizeof(_ArrayInStructT)];
+    _ALIGNAS_TYPE(_ArrayInStructT) array<_EmptyAggregateType,sizeof(_ArrayInStructT)> __elems_;
+#endif
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
     value_type* data() _NOEXCEPT {return nullptr;}
diff --git a/libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp b/libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp
index 4921a48bcccc1..07d346333f451 100644
--- a/libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp
+++ b/libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp
@@ -199,7 +199,6 @@ void test()
     test_not_const<void(Empty::*)(const int&) noexcept(false)>();
 
     // Sequence containers
-    test_not_const<std::array<               int, 0>>();
     test_not_const<std::array<               int, 1>>();
     test_false    <std::array<const          int, 1>>();
     test_not_const<std::array<      volatile int, 1>>();
diff --git a/libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp b/libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp
index 0e1e77fc5f181..08634d242b0d6 100644
--- a/libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/array.cons/implicit_copy.pass.cpp
@@ -59,14 +59,6 @@ TEST_CONSTEXPR_CXX14 bool tests()
         static_assert(std::is_copy_constructible<Array>::value, "");
         static_assert(std::is_copy_assignable<Array>::value, "");
     }
-    {
-        // const arrays of size 0 should disable the implicit copy assignment operator.
-        typedef std::array<double const, 0> Array;
-        Array array = {};
-        Array copy = array; (void)copy;
-        static_assert(std::is_copy_constructible<Array>::value, "");
-        TEST_NOT_COPY_ASSIGNABLE(Array);
-    }
     {
         typedef std::array<NoDefault, 0> Array;
         Array array = {};
@@ -75,13 +67,6 @@ TEST_CONSTEXPR_CXX14 bool tests()
         static_assert(std::is_copy_constructible<Array>::value, "");
         static_assert(std::is_copy_assignable<Array>::value, "");
     }
-    {
-        typedef std::array<NoDefault const, 0> Array;
-        Array array = {};
-        Array copy = array; (void)copy;
-        static_assert(std::is_copy_constructible<Array>::value, "");
-        TEST_NOT_COPY_ASSIGNABLE(Array);
-    }
 
     // Make sure we can implicitly copy a std::array of a non-trivially copyable type
     {
diff --git a/libcxx/test/std/containers/sequences/array/size_and_alignment.pass.cpp b/libcxx/test/std/containers/sequences/array/size_and_alignment.pass.cpp
index 6fbc844a11eac..0477cef42e43e 100644
--- a/libcxx/test/std/containers/sequences/array/size_and_alignment.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/size_and_alignment.pass.cpp
@@ -31,14 +31,25 @@ struct MyArray {
 };
 
 template <class T, std::size_t Size>
-void test() {
+struct test {
   typedef T CArrayT[Size == 0 ? 1 : Size];
   typedef std::array<T, Size> ArrayT;
   typedef MyArray<T, Size == 0 ? 1 : Size> MyArrayT;
+
   static_assert(sizeof(ArrayT) == sizeof(CArrayT), "");
   static_assert(sizeof(ArrayT) == sizeof(MyArrayT), "");
   static_assert(TEST_ALIGNOF(ArrayT) == TEST_ALIGNOF(MyArrayT), "");
-}
+};
+
+
+#ifdef _LIBCPP_ABI_ZERO_SIZE_ARRAY_HAS_NO_DATA
+template <class T>
+struct test<T, 0> {
+  using ArrayT = std::array<T, 0>;
+  static_assert(sizeof(ArrayT) == 1, "");
+  static_assert(TEST_ALIGNOF(ArrayT) == 1, "");
+};
+#endif
 
 template <class T>
 void test_type() {
diff --git a/libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h b/libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h
index 02731f8895ed8..62da3e0ca0089 100644
--- a/libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h
+++ b/libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h
@@ -45,7 +45,7 @@ constexpr void test_construction(AllExtents all_ext) {
 
   // test construction from just dynamic extents
   // create an array of just the extents corresponding to dynamic values
-  std::array<typename AllExtents::value_type, E::rank_dynamic()> dyn_ext{0};
+  std::array<typename AllExtents::value_type, E::rank_dynamic()> dyn_ext{};
   size_t dynamic_idx = 0;
   for (size_t r = 0; r < E::rank(); r++) {
     if (E::static_extent(r) == std::dynamic_extent) {

``````````

</details>


https://github.com/llvm/llvm-project/pull/74657


More information about the libcxx-commits mailing list