diff --git a/libcxx/include/__vector/layout.h b/libcxx/include/__vector/layout.h index 3318a13a8ede1..af03556dc2636 100644 --- a/libcxx/include/__vector/layout.h +++ b/libcxx/include/__vector/layout.h @@ -199,6 +199,7 @@ class __vector_layout { [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __size() const _NOEXCEPT; [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __capacity() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __empty() const _NOEXCEPT; [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __end_ptr() _NOEXCEPT; [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __end_ptr() const _NOEXCEPT; [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __capacity_ptr() _NOEXCEPT; @@ -313,6 +314,11 @@ __vector_layout<_Tp, _Alloc>::__capacity() const _NOEXCEPT { return __capacity_; } +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __vector_layout<_Tp, _Alloc>::__empty() const _NOEXCEPT { + return __size_ == 0; +} + template _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::pointer __vector_layout<_Tp, _Alloc>::__end_ptr() _NOEXCEPT { @@ -425,6 +431,11 @@ __vector_layout<_Tp, _Alloc>::__capacity() const _NOEXCEPT { return static_cast(__capacity_ - __begin_); } +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __vector_layout<_Tp, _Alloc>::__empty() const _NOEXCEPT { + return __begin_ == __end_; +} + template _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __vector_layout<_Tp, _Alloc>::pointer __vector_layout<_Tp, _Alloc>::__end_ptr() _NOEXCEPT { diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 8226a7f87a119..5e9fa4a7d0030 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -398,7 +398,7 @@ class vector { return __layout_.__capacity(); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { - return size() == 0; + return __layout_.__empty(); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { diff --git a/libcxx/test/libcxx/containers/sequences/vector/incomplete_type.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/incomplete_type.compile.pass.cpp new file mode 100644 index 0000000000000..029d29eb437f8 --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/vector/incomplete_type.compile.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 test pins down the current libc++ behavior that vector::empty() can be +// called even when T is an incomplete type. The standard does not require this: +// [vector.overview] only guarantees that an incomplete type may be used to +// instantiate vector, and requires the type to be complete before any method is +// called. +// +// However, libc++ made that work previously, and this test pins down that behavior +// to avoid breaking it unintentionally. Note that this is not a guarantee to users +// that we will support this in the future: this merely guards against changing this +// behavior unknowingly. + +#include + +struct Incomplete; + +bool call_empty(std::vector& v) { return v.empty(); } +bool call_empty_const(const std::vector& v) { return v.empty(); }