[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