From 1af6f6965f367b323b26f91948ae41be2fa5e73e Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Sun, 9 Jun 2024 10:35:22 +0200 Subject: [PATCH] [libc++] Add tombstone traits to use in optional, variant --- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__expected/expected.h | 1 + .../include/__functional/reference_wrapper.h | 9 + libcxx/include/__locale | 4 + libcxx/include/__memory/shared_ptr.h | 12 ++ libcxx/include/__memory/tombstone_traits.h | 171 ++++++++++++++++++ libcxx/include/__memory/unique_ptr.h | 9 + libcxx/include/__type_traits/datasizeof.h | 2 +- libcxx/include/__type_traits/enable_if.h | 3 + libcxx/include/__utility/pair.h | 13 ++ libcxx/include/optional | 60 +++++- libcxx/include/string | 11 ++ libcxx/include/string_view | 6 + libcxx/include/vector | 5 + .../optional.object/optional_size.pass.cpp | 28 +++ .../optional/tombstone_types.pass.cpp | 56 ++++++ libcxx/utils/generate_iwyu_mapping.py | 1 + 17 files changed, 388 insertions(+), 4 deletions(-) create mode 100644 libcxx/include/__memory/tombstone_traits.h create mode 100644 libcxx/test/std/utilities/optional/tombstone_types.pass.cpp diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 07dd25604a9c76..69f934f2ccff53 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -541,6 +541,7 @@ set(files __memory/swap_allocator.h __memory/temp_value.h __memory/temporary_buffer.h + __memory/tombstone_traits.h __memory/uninitialized_algorithms.h __memory/unique_ptr.h __memory/uses_allocator.h diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h index f618b20603e609..c1ed54b87a16c3 100644 --- a/libcxx/include/__expected/expected.h +++ b/libcxx/include/__expected/expected.h @@ -17,6 +17,7 @@ #include <__functional/invoke.h> #include <__memory/addressof.h> #include <__memory/construct_at.h> +#include <__memory/tombstone_traits.h> #include <__type_traits/conjunction.h> #include <__type_traits/disjunction.h> #include <__type_traits/integral_constant.h> diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h index 3570e2673c8005..712dee1dccf411 100644 --- a/libcxx/include/__functional/reference_wrapper.h +++ b/libcxx/include/__functional/reference_wrapper.h @@ -10,12 +10,15 @@ #ifndef _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H #define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H +#include <__bit/bit_cast.h> #include <__compare/synth_three_way.h> #include <__concepts/boolean_testable.h> #include <__config> #include <__functional/invoke.h> #include <__functional/weak_result_type.h> #include <__memory/addressof.h> +#include <__memory/tombstone_traits.h> +#include <__type_traits/datasizeof.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_const.h> #include <__type_traits/remove_cvref.h> @@ -122,6 +125,12 @@ template reference_wrapper(_Tp&) -> reference_wrapper<_Tp>; #endif +template +struct __tombstone_memory_layout> { + static constexpr uintptr_t __disengaged_value_ = 0; + static constexpr size_t __is_disengaged_offset_ = 0; +}; + template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<_Tp> ref(_Tp& __t) _NOEXCEPT { return reference_wrapper<_Tp>(__t); diff --git a/libcxx/include/__locale b/libcxx/include/__locale index 4b382764b44645..42c15effa0542c 100644 --- a/libcxx/include/__locale +++ b/libcxx/include/__locale @@ -13,6 +13,7 @@ #include <__config> #include <__locale_dir/locale_base_api.h> #include <__memory/shared_ptr.h> // __shared_count +#include <__memory/tombstone_traits.h> #include <__mutex/once_flag.h> #include <__type_traits/make_unsigned.h> #include <__utility/no_destroy.h> @@ -114,6 +115,9 @@ private: friend const _Facet& use_facet(const locale&); }; +template <> +struct __tombstone_memory_layout : __tombstone_pointer_layout {}; + class _LIBCPP_EXPORTED_FROM_ABI locale::facet : public __shared_count { protected: _LIBCPP_HIDE_FROM_ABI explicit facet(size_t __refs = 0) : __shared_count(static_cast(__refs) - 1) {} diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index d487e4fbe3a953..e3eb195829d432 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -832,6 +832,12 @@ template shared_ptr(unique_ptr<_Tp, _Dp>) -> shared_ptr<_Tp>; #endif +template +struct __tombstone_memory_layout> { + static constexpr auto __disengaged_value_ = __tombstone_pointer_layout::__disengaged_value_; + static constexpr size_t __is_disengaged_offset_ = sizeof(void*) + __tombstone_pointer_layout::__is_disengaged_offset_; +}; + // // std::allocate_shared and std::make_shared // @@ -1382,6 +1388,12 @@ template weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>; #endif +template +struct __tombstone_memory_layout> { + static constexpr auto __disengaged_value_ = __tombstone_pointer_layout::__disengaged_value_; + static constexpr size_t __is_disengaged_offset_ = sizeof(void*) + __tombstone_pointer_layout::__is_disengaged_offset_; +}; + template inline _LIBCPP_CONSTEXPR weak_ptr<_Tp>::weak_ptr() _NOEXCEPT : __ptr_(nullptr), __cntrl_(nullptr) {} diff --git a/libcxx/include/__memory/tombstone_traits.h b/libcxx/include/__memory/tombstone_traits.h new file mode 100644 index 00000000000000..72063057efaa58 --- /dev/null +++ b/libcxx/include/__memory/tombstone_traits.h @@ -0,0 +1,171 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_DISENGAGED_TRAITS_H +#define _LIBCPP___TYPE_TRAITS_DISENGAGED_TRAITS_H + +#include <__config> +#include <__memory/construct_at.h> +#include <__type_traits/datasizeof.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_fundamental.h> +#include <__type_traits/is_trivially_destructible.h> +#include <__type_traits/void_t.h> +#include <__utility/forward_like.h> +#include <__utility/in_place.h> +#include <__utility/piecewise_construct.h> +#include <__utility/pointer_int_pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __tombstone_memory_layout; + +// bools have always exactly one bit set. If there is more than one set it's disengaged. +template <> +struct __tombstone_memory_layout { + static constexpr uint8_t __disengaged_value_ = 3; + static constexpr size_t __is_disengaged_offset_ = 0; +}; + +struct __tombstone_pointer_layout { + static constexpr uint8_t __disengaged_value_ = 1; +#ifdef _LIBCPP_LITTLE_ENDIAN + static constexpr size_t __is_disengaged_offset_ = 0; +#else + static constexpr size_t __is_disengaged_offset_ = sizeof(void*) - 1; +#endif +}; + +// TODO: Look into +// - filesystem::directory_iterator +// - vector with alignof(T) == 1 + +template +struct __tombstone_memory_layout<__enable_specialization_if && alignof(_Tp) >= 2, _Tp*>> + : __tombstone_pointer_layout {}; + +template +struct __tombstone_memory_layout<_Tp**> : __tombstone_pointer_layout {}; + +inline constexpr struct __init_engaged_t { +} __init_engaged; +inline constexpr struct __init_disengaged_t { +} __init_disengaged; + +template +struct __tombstone_data { + using _TombstoneLayout = __tombstone_memory_layout<_Tp>; + using _IsDisengagedT = remove_cv_t; + + _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_; + char __padding_[_TombstoneLayout::__is_disengaged_offset_ - __datasizeof_v<_Payload>]; + _IsDisengagedT __is_disengaged_; + + template + _LIBCPP_HIDE_FROM_ABI constexpr __tombstone_data(_Args&&... __args) + : __payload_(std::forward<_Args>(__args)...), __is_disengaged_(_TombstoneLayout::__disengaged_value_) {} +}; + +template + requires(__tombstone_memory_layout<_Tp>::__is_disengaged_offset_ == 0) +struct __tombstone_data<_Tp, _Payload> { + using _TombstoneLayout = __tombstone_memory_layout<_Tp>; + using _IsDisengagedT = remove_cv_t; + + _IsDisengagedT __is_disengaged_; + _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_; + + template + _LIBCPP_HIDE_FROM_ABI constexpr __tombstone_data(_Args&&... __args) + : __is_disengaged_(_TombstoneLayout::__disengaged_value_), __payload_(std::forward<_Args>(__args)...) {} +}; + +template +struct __tombstone_traits { + using _TombstoneLayout = __tombstone_memory_layout<_Tp>; + using _TombstoneData = __tombstone_data<_Tp, _Payload>; + + union { + _Tp __value_; + _TombstoneData __tombstone_; + }; + + static_assert(sizeof(__tombstone_data<_Tp, _Payload>) <= sizeof(_Tp)); + static_assert(is_integral_v); + static_assert(offsetof(_TombstoneData, __is_disengaged_) == _TombstoneLayout::__is_disengaged_offset_); + + template + _LIBCPP_HIDE_FROM_ABI constexpr __tombstone_traits(__init_disengaged_t, _Args&&... __args) + : __tombstone_(std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr __tombstone_traits(__init_engaged_t, _Args&&... __args) + : __value_(std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value(this _Class&& __self) noexcept { + return std::forward<_Class>(__self).__value_; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload(this _Class&& __self) noexcept { + return std::forward<_Class>(__self).__tombstone_.__payload_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr bool __is_engaged() const noexcept { + if (__libcpp_is_constant_evaluated()) + return !__builtin_constant_p(__tombstone_.__is_disengaged_ == _TombstoneLayout::__disengaged_value_); + return __tombstone_.__is_disengaged_ != _TombstoneLayout::__disengaged_value_; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __engage(this _Class& __self, piecewise_construct_t, _Args&&... __args) { + std::destroy_at(&__self.__tombstone_); + std::construct_at(&__self.__value_, std::forward<_Args>(__args)...); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __disengage(this _Class& __self, piecewise_construct_t, _Args&&... __args) { + std::destroy_at(&__self.__data_.__value_); + std::construct_at(&__self.__data_.__payload_, std::forward<_Args>(__args)...); + __self.__data_.__is_disengaged_ = _TombstoneLayout::__disengaged_value_; + } + + __tombstone_traits(const __tombstone_traits&) = default; + __tombstone_traits(__tombstone_traits&&) = default; + __tombstone_traits& operator=(const __tombstone_traits&) = default; + __tombstone_traits& operator=(__tombstone_traits&&) = default; + + _LIBCPP_HIDE_FROM_ABI constexpr ~__tombstone_traits() { + if (__is_engaged()) { + std::destroy_at(&__value_); + } else { + std::destroy_at(&__tombstone_); + } + } + + ~__tombstone_traits() + requires is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Payload> + = default; +}; + +template +inline constexpr bool __has_tombstone_v = false; + +template +inline constexpr bool __has_tombstone_v<_Tp, void_t))>> = true; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_DISENGAGED_TRAITS_H diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h index 9519e4283868ba..f40fb711a07fa3 100644 --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -19,6 +19,7 @@ #include <__memory/allocator_traits.h> // __pointer #include <__memory/auto_ptr.h> #include <__memory/compressed_pair.h> +#include <__memory/tombstone_traits.h> #include <__type_traits/add_lvalue_reference.h> #include <__type_traits/common_type.h> #include <__type_traits/conditional.h> @@ -281,6 +282,14 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr { _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT { __ptr_.swap(__u.__ptr_); } }; +template +struct __tombstone_memory_layout<__enable_specialization_if<__has_tombstone_v<_Tp*>, unique_ptr<_Tp>>> + : __tombstone_memory_layout<_Tp*> {}; + +template +struct __tombstone_memory_layout<__enable_specialization_if<__has_tombstone_v<_Tp*>, unique_ptr<_Tp[]>>> + : __tombstone_memory_layout<_Tp*> {}; + template class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> { public: diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h index 35c12921e8ffa1..382e5522060f25 100644 --- a/libcxx/include/__type_traits/datasizeof.h +++ b/libcxx/include/__type_traits/datasizeof.h @@ -26,7 +26,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if __has_keyword(__datasizeof) || __has_extension(datasizeof) +#if __has_extension(datasizeof) && 0 template inline const size_t __datasizeof_v = __datasizeof(_Tp); #else diff --git a/libcxx/include/__type_traits/enable_if.h b/libcxx/include/__type_traits/enable_if.h index 77da9622ca28fc..14ffa9c280923f 100644 --- a/libcxx/include/__type_traits/enable_if.h +++ b/libcxx/include/__type_traits/enable_if.h @@ -32,6 +32,9 @@ template using enable_if_t = typename enable_if<_Bp, _Tp>::type; #endif +template > +using __enable_specialization_if = _Tp; + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TYPE_TRAITS_ENABLE_IF_H diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index 0afbebcdc9f2ae..9b01c3a3229428 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -16,6 +16,7 @@ #include <__fwd/array.h> #include <__fwd/pair.h> #include <__fwd/tuple.h> +#include <__memory/tombstone_traits.h> #include <__tuple/sfinae_helpers.h> #include <__tuple/tuple_element.h> #include <__tuple/tuple_indices.h> @@ -448,6 +449,18 @@ template pair(_T1, _T2) -> pair<_T1, _T2>; #endif +template + requires __has_tombstone_v<_Up> +struct __tombstone_memory_layout> { + static constexpr auto __disengaged_value_ = __tombstone_memory_layout<_Up>::__disengaged_value_; + static constexpr size_t __is_disengaged_offset_ = + sizeof(_Tp) + __tombstone_memory_layout<_Up>::__is_disengaged_offset_; +}; + +template + requires(!__has_tombstone_v<_Up> && __has_tombstone_v<_Tp>) +struct __tombstone_memory_layout> : __tombstone_memory_layout<_Tp> {}; + // [pairs.spec], specialized algorithms template diff --git a/libcxx/include/optional b/libcxx/include/optional index e550745c17c00a..e8287e557dc6ad 100644 --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -189,6 +189,7 @@ namespace std { #include <__fwd/functional.h> #include <__memory/addressof.h> #include <__memory/construct_at.h> +#include <__memory/tombstone_traits.h> #include <__tuple/sfinae_helpers.h> #include <__type_traits/add_pointer.h> #include <__type_traits/conditional.h> @@ -215,6 +216,7 @@ namespace std { #include <__type_traits/remove_cvref.h> #include <__type_traits/remove_reference.h> #include <__utility/declval.h> +#include <__utility/empty.h> #include <__utility/forward.h> #include <__utility/in_place.h> #include <__utility/move.h> @@ -344,8 +346,11 @@ struct __optional_destruct_base<_Tp, true> { } }; -template ::value> -struct __optional_storage_base : __optional_destruct_base<_Tp> { +template ::value, bool = __has_tombstone_v<_Tp>> +struct __optional_storage_base; + +template +struct __optional_storage_base<_Tp, false, false> : __optional_destruct_base<_Tp> { using __base = __optional_destruct_base<_Tp>; using value_type = _Tp; using __base::__base; @@ -388,7 +393,7 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> { // be allowed in the future. For this reason, it has already been implemented // to ensure we can make the change in an ABI-compatible manner. template -struct __optional_storage_base<_Tp, true> { +struct __optional_storage_base<_Tp, true, false> { using value_type = _Tp; using __raw_type = remove_reference_t<_Tp>; __raw_type* __value_; @@ -456,6 +461,55 @@ struct __optional_storage_base<_Tp, true> { } }; +template +struct __optional_storage_base<_Tp, _Bp, true> { + using value_type = _Tp; + __tombstone_traits<_Tp, __empty> __storage_; + + _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __storage_(__init_disengaged) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _Args&&... __args) + : __storage_(__init_engaged, std::forward<_Args>(__args)...) {} + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { + if (__storage_.__is_engaged()) + __storage_.__disengage(piecewise_construct); + } + + _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __storage_.__is_engaged(); } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __get() & { return __storage_.__get_value(); } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& __get() && { return std::move(__storage_.__get_value()); } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& __get() const& { return __storage_.__get_value(); } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& __get() const&& { return std::move(__storage_.__get_value()); } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_Args&&... __args) { + _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage_base"); + __storage_.__engage(piecewise_construct, std::forward<_Args>(__args)...); + } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_Other&& __opt) { + if (__opt.has_value()) + __construct(std::forward<_Other>(__opt).__get()); + } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_Other&& __opt) { + if (has_value() == __opt.has_value()) { + if (has_value()) + __storage_.__get_value() = std::forward<_Other>(__opt).__get(); + } else { + if (has_value()) + __storage_.__disengage(piecewise_construct); + else + __construct(std::forward<_Other>(__opt).__get()); + } + } +}; + template ::value> struct __optional_copy_base : __optional_storage_base<_Tp> { using __optional_storage_base<_Tp>::__optional_storage_base; diff --git a/libcxx/include/string b/libcxx/include/string index 9a52ab6aef41e8..a020b857db759d 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -592,6 +592,7 @@ basic_string operator""s( const char32_t *str, size_t len ); #include <__memory/construct_at.h> #include <__memory/pointer_traits.h> #include <__memory/swap_allocator.h> +#include <__memory/tombstone_traits.h> #include <__memory_resource/polymorphic_allocator.h> #include <__ranges/access.h> #include <__ranges/concepts.h> @@ -2201,6 +2202,16 @@ basic_string(from_range_t, _Range&&, _Allocator = _Allocator()) -> basic_string, char_traits>, _Allocator>; #endif +template +struct __tombstone_memory_layout< basic_string<_CharT, _Traits, _Allocator>> { + static constexpr uint8_t __disengaged_value_ = 65; +#ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT + static constexpr size_t __is_disengaged_offset_ = -1; +#else + static constexpr size_t __is_disengaged_offset_ = 0; +#endif +}; + template _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve) { diff --git a/libcxx/include/string_view b/libcxx/include/string_view index b2a4db4e7519ad..a51d5f9c99db6a 100644 --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -686,6 +686,12 @@ template inline constexpr bool ranges::enable_borrowed_range > = true; #endif // _LIBCPP_STD_VER >= 20 +template +struct __tombstone_memory_layout> { + static constexpr size_t __disengaged_value_ = basic_string_view<_CharT, _Traits>::npos; + static constexpr size_t __is_disengaged_offset_ = sizeof(void*); +}; + // [string.view.deduct] #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/vector b/libcxx/include/vector index aaf51d18fe30fb..8e613be5156d71 100644 --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -1006,6 +1006,11 @@ template vector, _Alloc>; #endif +template +struct __tombstone_memory_layout< + __enable_specialization_if<__has_tombstone_v::pointer>, vector<_Tp, _Allocator>>> + : __tombstone_memory_layout::pointer> {}; + // __swap_out_circular_buffer relocates the objects in [__begin_, __end_) into the front of __v and swaps the buffers of // *this and __v. It is assumed that __v provides space for exactly (__end_ - __begin_) objects in the front. This // function has a strong exception guarantee. diff --git a/libcxx/test/libcxx/utilities/optional/optional.object/optional_size.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.object/optional_size.pass.cpp index b928ed7432791e..993a554105cc6c 100644 --- a/libcxx/test/libcxx/utilities/optional/optional.object/optional_size.pass.cpp +++ b/libcxx/test/libcxx/utilities/optional/optional.object/optional_size.pass.cpp @@ -12,7 +12,11 @@ // template class optional; +#include +#include #include +#include +#include template struct type_with_bool { @@ -20,6 +24,8 @@ struct type_with_bool { bool has_value; }; +struct alignas(void*) aligned_s {}; + int main(int, char**) { // Test that std::optional achieves the expected size. See https://llvm.org/PR61095. static_assert(sizeof(std::optional) == sizeof(type_with_bool)); @@ -27,5 +33,27 @@ int main(int, char**) { static_assert(sizeof(std::optional) == sizeof(type_with_bool)); static_assert(sizeof(std::optional) == sizeof(type_with_bool)); + // Check that the optionals using a tombstone have the expected size + static_assert(sizeof(std::optional) == sizeof(bool)); + static_assert(sizeof(std::optional) == sizeof(std::string)); + static_assert(sizeof(std::optional) == sizeof(void*)); + static_assert(sizeof(std::optional) == sizeof(void*)); + static_assert(sizeof(std::optional) == sizeof(void*) * 2); + static_assert(sizeof(std::optional) == sizeof(void*) * 2); + static_assert(sizeof(std::optional>) == sizeof(void*)); + static_assert(sizeof(std::optional>) == sizeof(void*)); + static_assert(sizeof(std::optional>) == sizeof(void*) * 2); + static_assert(sizeof(std::optional>) == sizeof(void*)); + static_assert(sizeof(std::optional) == sizeof(void*)); + static_assert(sizeof(std::optional>) == sizeof(void*) * 2); + static_assert(sizeof(std::optional>) == sizeof(void*) * 2); + static_assert(sizeof(std::optional>) == sizeof(void*) * 2); + static_assert(sizeof(std::optional>) == sizeof(void*) * 2); + static_assert(sizeof(std::optional>) == sizeof(int) * 3); + static_assert(sizeof(std::optional>) == sizeof(void*) * 4); + static_assert(sizeof(std::optional>) == sizeof(void*) * 4); + static_assert(sizeof(std::optional>) == sizeof(void*) * 3); + static_assert(sizeof(std::optional>) == sizeof(void*) * 4); + return 0; } diff --git a/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp b/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp new file mode 100644 index 00000000000000..175c5f6e5d07c8 --- /dev/null +++ b/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// + +#include +#include +#include + +constexpr bool test() { + { + std::optional opt; + assert(!opt); + opt = true; + assert(opt); + assert(*opt); + opt = false; + assert(opt); + assert(!*opt); + } + + { + std::optional opt; + assert(!opt); + opt = ""; + assert(opt); + assert(*opt == ""); + opt = "23 letter string to SSO"; + assert(opt); + assert(*opt == "23 letter string to SSO"); + } + + { + std::optional opt; + assert(!opt); + opt = ""; + assert(opt); + assert(*opt == ""); + opt = "23 letter string to SSO"; + assert(opt); + assert(*opt == "23 letter string to SSO"); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +} diff --git a/libcxx/utils/generate_iwyu_mapping.py b/libcxx/utils/generate_iwyu_mapping.py index b0ebe1b9e93d26..c08347f208a0ec 100644 --- a/libcxx/utils/generate_iwyu_mapping.py +++ b/libcxx/utils/generate_iwyu_mapping.py @@ -12,6 +12,7 @@ def IWYU_mapping(header: str) -> typing.Optional[typing.List[str]]: ignore = [ "__debug_utils/.+", "__fwd/get[.]h", + "__fwd/disengaged_objects.h", "__pstl/.+", "__support/.+", "__utility/private_constructor_tag.h",