diff options
author | Arthur O'Dwyer <arthur.j.odwyer@gmail.com> | 2022-02-27 20:41:22 +0300 |
---|---|---|
committer | Arthur O'Dwyer <arthur.j.odwyer@gmail.com> | 2022-03-07 19:50:00 +0300 |
commit | 1c6e752cfc1a753a0fd04c6201c9c48e477663de (patch) | |
tree | c5ab704b231909fbcb52ecfec066a6240241fd1e /libcxx | |
parent | d229765e6137978d367b15bcb77f89eeb412f379 (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')
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; +} |