Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/libcxx
diff options
context:
space:
mode:
authorArthur O'Dwyer <arthur.j.odwyer@gmail.com>2022-02-27 20:41:22 +0300
committerArthur O'Dwyer <arthur.j.odwyer@gmail.com>2022-03-07 19:50:00 +0300
commit1c6e752cfc1a753a0fd04c6201c9c48e477663de (patch)
treec5ab704b231909fbcb52ecfec066a6240241fd1e /libcxx
parentd229765e6137978d367b15bcb77f89eeb412f379 (diff)
[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
Diffstat (limited to 'libcxx')
-rw-r--r--libcxx/include/__memory/unique_ptr.h11
-rw-r--r--libcxx/include/__ranges/access.h6
-rw-r--r--libcxx/test/std/ranges/range.access/begin.sizezero.pass.cpp36
-rw-r--r--libcxx/test/std/ranges/range.access/end.sizezero.pass.cpp36
-rw-r--r--libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique.sizezero.pass.cpp46
5 files changed, 124 insertions, 11 deletions
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 348c90325e6f..ff09726acedd 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 @@ public:
_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 2ebdab4eb8cd..fd7b4224e0e1 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 000000000000..d455f7fa2ffe
--- /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 000000000000..c89a8fe80eb9
--- /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 000000000000..b5df01bbe65f
--- /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;
+}