[libcxx-commits] [libcxx] 1c6e752 - [libc++] Better handling for zero-sized types.

Arthur O'Dwyer via libcxx-commits libcxx-commits at lists.llvm.org
Mon Mar 7 08:50:43 PST 2022


Author: Arthur O'Dwyer
Date: 2022-03-07T11:50:00-05:00
New Revision: 1c6e752cfc1a753a0fd04c6201c9c48e477663de

URL: https://github.com/llvm/llvm-project/commit/1c6e752cfc1a753a0fd04c6201c9c48e477663de
DIFF: https://github.com/llvm/llvm-project/commit/1c6e752cfc1a753a0fd04c6201c9c48e477663de.diff

LOG: [libc++] Better handling for zero-sized types.

Zero-sized types are a GCC extension, also supported by Clang.
In theory it's already invalid to `delete` a void pointer or a
pointer-to-incomplete, so we shouldn't need any special code
to catch those cases; but in practice Clang accepts both
constructs with just a warning, and GCC even accepts `sizeof(void)`
with just a warning! So we must keep the static_asserts.
The hard errors are tested in `unique_ptr_dltr_dflt/*.compile.fail.cpp`.

In ranges::begin/end, check `sizeof >= 0` instead of `sizeof != 0`,
so as to permit zero-sized types while still disallowing incomplete
types.

Fixes #54100.

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

Added: 
    libcxx/test/std/ranges/range.access/begin.sizezero.pass.cpp
    libcxx/test/std/ranges/range.access/end.sizezero.pass.cpp
    libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique.sizezero.pass.cpp

Modified: 
    libcxx/include/__memory/unique_ptr.h
    libcxx/include/__ranges/access.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 348c90325e6ff..ff09726aceddf 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -46,10 +46,8 @@ struct _LIBCPP_TEMPLATE_VIS default_delete {
                      0) _NOEXCEPT {}
 
   _LIBCPP_INLINE_VISIBILITY void operator()(_Tp* __ptr) const _NOEXCEPT {
-    static_assert(sizeof(_Tp) > 0,
-                  "default_delete can not delete incomplete type");
-    static_assert(!is_void<_Tp>::value,
-                  "default_delete can not delete incomplete type");
+    static_assert(sizeof(_Tp) >= 0, "cannot delete an incomplete type");
+    static_assert(!is_void<_Tp>::value, "cannot delete an incomplete type");
     delete __ptr;
   }
 };
@@ -77,10 +75,7 @@ struct _LIBCPP_TEMPLATE_VIS default_delete<_Tp[]> {
   _LIBCPP_INLINE_VISIBILITY
   typename _EnableIfConvertible<_Up>::type
   operator()(_Up* __ptr) const _NOEXCEPT {
-    static_assert(sizeof(_Tp) > 0,
-                  "default_delete can not delete incomplete type");
-    static_assert(!is_void<_Tp>::value,
-                  "default_delete can not delete void type");
+    static_assert(sizeof(_Up) >= 0, "cannot delete an incomplete type");
     delete[] __ptr;
   }
 };

diff  --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h
index 2ebdab4eb8cd9..fd7b4224e0e1e 100644
--- a/libcxx/include/__ranges/access.h
+++ b/libcxx/include/__ranges/access.h
@@ -58,14 +58,14 @@ namespace __begin {
   struct __fn {
     template <class _Tp>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[]) const noexcept
-      requires (sizeof(_Tp) != 0)  // Disallow incomplete element types.
+      requires (sizeof(_Tp) >= 0)  // Disallow incomplete element types.
     {
       return __t + 0;
     }
 
     template <class _Tp, size_t _Np>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept
-      requires (sizeof(_Tp) != 0)  // Disallow incomplete element types.
+      requires (sizeof(_Tp) >= 0)  // Disallow incomplete element types.
     {
       return __t + 0;
     }
@@ -132,7 +132,7 @@ namespace __end {
   public:
     template <class _Tp, size_t _Np>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept
-      requires (sizeof(_Tp) != 0)  // Disallow incomplete element types.
+      requires (sizeof(_Tp) >= 0)  // Disallow incomplete element types.
     {
       return __t + _Np;
     }

diff  --git a/libcxx/test/std/ranges/range.access/begin.sizezero.pass.cpp b/libcxx/test/std/ranges/range.access/begin.sizezero.pass.cpp
new file mode 100644
index 0000000000000..d455f7fa2ffe1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/begin.sizezero.pass.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: msvc
+
+// std::ranges::begin
+// std::ranges::cbegin
+//   Test the fix for https://llvm.org/PR54100
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+
+struct A {
+  int m[0];
+};
+static_assert(sizeof(A) == 0); // an extension supported by GCC and Clang
+
+int main(int, char**)
+{
+  A a[10];
+  std::same_as<A*> auto p = std::ranges::begin(a);
+  assert(p == a);
+  std::same_as<const A*> auto cp = std::ranges::cbegin(a);
+  assert(cp == a);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.access/end.sizezero.pass.cpp b/libcxx/test/std/ranges/range.access/end.sizezero.pass.cpp
new file mode 100644
index 0000000000000..c89a8fe80eb90
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/end.sizezero.pass.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: msvc
+
+// std::ranges::end
+// std::ranges::cend
+//   Test the fix for https://llvm.org/PR54100
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+
+struct A {
+  int m[0];
+};
+static_assert(sizeof(A) == 0); // an extension supported by GCC and Clang
+
+int main(int, char**)
+{
+  A a[10];
+  std::same_as<A*> auto p = std::ranges::end(a);
+  assert(p == a + 10);
+  std::same_as<const A*> auto cp = std::ranges::cend(a);
+  assert(cp == a + 10);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique.sizezero.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique.sizezero.pass.cpp
new file mode 100644
index 0000000000000..b5df01bbe65f4
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique.sizezero.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// This code triggers https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104568
+// UNSUPPORTED: gcc-11
+// UNSUPPORTED: msvc
+
+// Test the fix for https://llvm.org/PR54100
+
+#include <memory>
+#include <cassert>
+
+#include "test_macros.h"
+
+struct A {
+  int m[0];
+};
+static_assert(sizeof(A) == 0, "");  // an extension supported by GCC and Clang
+
+int main(int, char**)
+{
+  {
+    std::unique_ptr<A> p = std::unique_ptr<A>(new A);
+    assert(p != nullptr);
+  }
+  {
+    std::unique_ptr<A[]> p = std::unique_ptr<A[]>(new A[1]);
+    assert(p != nullptr);
+  }
+#if TEST_STD_VER > 11
+  {
+    std::unique_ptr<A> p = std::make_unique<A>();
+    assert(p != nullptr);
+  }
+  {
+    std::unique_ptr<A[]> p = std::make_unique<A[]>(1);
+    assert(p != nullptr);
+  }
+#endif
+  return 0;
+}


        


More information about the libcxx-commits mailing list