Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,7 @@ set(files
__type_traits/is_reference.h
__type_traits/is_reference_wrapper.h
__type_traits/is_referenceable.h
__type_traits/is_replaceable.h
__type_traits/is_same.h
__type_traits/is_scalar.h
__type_traits/is_signed.h
Expand Down
4 changes: 3 additions & 1 deletion libcxx/include/__exception/exception_ptr.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
friend _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT;

public:
// exception_ptr is basically a COW string.
// exception_ptr is basically a COW string so it is trivially relocatable.
// It is also replaceable because assignment has normal value semantics.
using __trivially_relocatable _LIBCPP_NODEBUG = exception_ptr;
using __replaceable _LIBCPP_NODEBUG = exception_ptr;

_LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {}
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/__expected/expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <__type_traits/is_nothrow_assignable.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_reference.h>
#include <__type_traits/is_replaceable.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_constructible.h>
Expand Down Expand Up @@ -470,6 +471,8 @@ class expected : private __expected_base<_Tp, _Err> {
__conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value && __libcpp_is_trivially_relocatable<_Err>::value,
expected,
void>;
using __replaceable _LIBCPP_NODEBUG =
__conditional_t<__is_replaceable_v<_Tp> && __is_replaceable_v<_Err>, expected, void>;

template <class _Up>
using rebind = expected<_Up, error_type>;
Expand Down
4 changes: 3 additions & 1 deletion libcxx/include/__locale
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ _LIBCPP_HIDE_FROM_ABI const _Facet& use_facet(const locale&);

class _LIBCPP_EXPORTED_FROM_ABI locale {
public:
// locale is essentially a shared_ptr that doesn't support weak_ptrs and never got a move constructor.
// locale is essentially a shared_ptr that doesn't support weak_ptrs and never got a move constructor,
// so it is trivially relocatable. Like shared_ptr, it is also replaceable.
using __trivially_relocatable _LIBCPP_NODEBUG = locale;
using __replaceable _LIBCPP_NODEBUG = locale;

// types:
class _LIBCPP_EXPORTED_FROM_ABI facet;
Expand Down
7 changes: 5 additions & 2 deletions libcxx/include/__memory/shared_ptr.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,10 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr {
#endif

// A shared_ptr contains only two raw pointers which point to the heap and move constructing already doesn't require
// any bookkeeping, so it's always trivially relocatable.
// any bookkeeping, so it's always trivially relocatable. It is also replaceable because assignment just rebinds the
// shared_ptr to manage a different object.
using __trivially_relocatable _LIBCPP_NODEBUG = shared_ptr;
using __replaceable _LIBCPP_NODEBUG = shared_ptr;

private:
element_type* __ptr_;
Expand Down Expand Up @@ -1211,8 +1213,9 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS weak_ptr {
#endif

// A weak_ptr contains only two raw pointers which point to the heap and move constructing already doesn't require
// any bookkeeping, so it's always trivially relocatable.
// any bookkeeping, so it's always trivially relocatable. It's also replaceable for the same reason.
using __trivially_relocatable _LIBCPP_NODEBUG = weak_ptr;
using __replaceable _LIBCPP_NODEBUG = weak_ptr;

private:
element_type* __ptr_;
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/__memory/unique_ptr.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <__type_traits/is_function.h>
#include <__type_traits/is_pointer.h>
#include <__type_traits/is_reference.h>
#include <__type_traits/is_replaceable.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_relocatable.h>
Expand Down Expand Up @@ -144,6 +145,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
__libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<deleter_type>::value,
unique_ptr,
void>;
using __replaceable _LIBCPP_NODEBUG =
__conditional_t<__is_replaceable_v<pointer> && __is_replaceable_v<deleter_type>, unique_ptr, void>;

private:
_LIBCPP_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_);
Expand Down Expand Up @@ -410,6 +413,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
__libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<deleter_type>::value,
unique_ptr,
void>;
using __replaceable _LIBCPP_NODEBUG =
__conditional_t<__is_replaceable_v<pointer> && __is_replaceable_v<deleter_type>, unique_ptr, void>;

private:
template <class _Up, class _OtherDeleter>
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/__split_buffer
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_nothrow_assignable.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_replaceable.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_destructible.h>
#include <__type_traits/is_trivially_relocatable.h>
Expand Down Expand Up @@ -72,6 +73,10 @@ public:
__libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
__split_buffer,
void>;
using __replaceable _LIBCPP_NODEBUG =
__conditional_t<__is_replaceable_v<pointer> && __container_allocator_is_replaceable<__alloc_traits>::value,
__split_buffer,
void>;

pointer __first_;
pointer __begin_;
Expand Down
62 changes: 62 additions & 0 deletions libcxx/include/__type_traits/is_replaceable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===----------------------------------------------------------------------===//
//
// 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_IS_REPLACEABLE_H
#define _LIBCPP___TYPE_TRAITS_IS_REPLACEABLE_H

#include <__config>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_trivially_copyable.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

// A type is replaceable if, with `x` and `y` being different objects, `x = std::move(y)` is equivalent to:
//
// std::destroy_at(&x)
// std::construct_at(&x, std::move(y))
//
// This allows turning a move-assignment into a sequence of destroy + move-construct, which
// is often more efficient. This is especially relevant when the move-construct is in fact
// part of a trivial relocation from somewhere else, in which case there is a huge win.
//
// Note that this requires language support in order to be really effective, but we
// currently emulate the base template with something very conservative.
template <class _Tp, class = void>
struct __is_replaceable : is_trivially_copyable<_Tp> {};

template <class _Tp>
struct __is_replaceable<_Tp, __enable_if_t<is_same<_Tp, typename _Tp::__replaceable>::value> > : true_type {};

template <class _Tp>
inline const bool __is_replaceable_v = __is_replaceable<_Tp>::value;

// Determines whether an allocator member of a container is replaceable.
//
// We take into account whether the allocator is propagated on assignments. If the allocator
// always compares equal, then it doesn't matter whether we propagate it or not on assignments,
// the result will be the same and we can just as much move-construct it instead.
//
// If the allocator does not always compare equal, we check whether it propagates on assignment
// and it is replaceable.
template <class _AllocatorTraits>
struct __container_allocator_is_replaceable
: integral_constant<bool,
_AllocatorTraits::is_always_equal::value ||
(_AllocatorTraits::propagate_on_container_move_assignment::value &&
_AllocatorTraits::propagate_on_container_copy_assignment::value &&
__is_replaceable_v<typename _AllocatorTraits::allocator_type>)> {};

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___TYPE_TRAITS_IS_REPLACEABLE_H
3 changes: 3 additions & 0 deletions libcxx/include/__utility/pair.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <__type_traits/is_implicitly_default_constructible.h>
#include <__type_traits/is_nothrow_assignable.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_replaceable.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/nat.h>
Expand Down Expand Up @@ -72,6 +74,7 @@ struct _LIBCPP_TEMPLATE_VIS pair
__conditional_t<__libcpp_is_trivially_relocatable<_T1>::value && __libcpp_is_trivially_relocatable<_T2>::value,
pair,
void>;
using __replaceable _LIBCPP_NODEBUG = __conditional_t<__is_replaceable_v<_T1> && __is_replaceable_v<_T2>, pair, void>;

_LIBCPP_HIDE_FROM_ABI pair(pair const&) = default;
_LIBCPP_HIDE_FROM_ABI pair(pair&&) = default;
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/__vector/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include <__type_traits/is_nothrow_assignable.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_pointer.h>
#include <__type_traits/is_replaceable.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/type_identity.h>
Expand Down Expand Up @@ -120,6 +121,10 @@ class _LIBCPP_TEMPLATE_VIS vector {
__libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
vector,
void>;
using __replaceable _LIBCPP_NODEBUG =
__conditional_t<__is_replaceable_v<pointer> && __container_allocator_is_replaceable<__alloc_traits>::value,
vector,
void>;

static_assert(__check_valid_allocator<allocator_type>::value, "");
static_assert(is_same<typename allocator_type::value_type, value_type>::value,
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/array
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce
# include <__type_traits/is_const.h>
# include <__type_traits/is_constructible.h>
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_replaceable.h>
# include <__type_traits/is_same.h>
# include <__type_traits/is_swappable.h>
# include <__type_traits/is_trivially_relocatable.h>
Expand Down Expand Up @@ -175,6 +176,7 @@ template <class _Tp, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS array {
using __trivially_relocatable _LIBCPP_NODEBUG =
__conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, array, void>;
using __replaceable _LIBCPP_NODEBUG = __conditional_t<__is_replaceable_v<_Tp>, array, void>;

// types:
using __self _LIBCPP_NODEBUG = array;
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/deque
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ template <class T, class Allocator, class Predicate>
# include <__type_traits/is_convertible.h>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_replaceable.h>
# include <__type_traits/is_same.h>
# include <__type_traits/is_swappable.h>
# include <__type_traits/is_trivially_relocatable.h>
Expand Down Expand Up @@ -530,6 +531,10 @@ public:
__libcpp_is_trivially_relocatable<__map>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
deque,
void>;
using __replaceable _LIBCPP_NODEBUG =
__conditional_t<__is_replaceable_v<__map> && __container_allocator_is_replaceable<__alloc_traits>::value,
deque,
void>;

static_assert(is_nothrow_default_constructible<allocator_type>::value ==
is_nothrow_default_constructible<__pointer_allocator>::value,
Expand Down
4 changes: 4 additions & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ module std_core [system] {
header "__type_traits/is_referenceable.h"
export std_core.type_traits.integral_constant
}
module is_replaceable {
header "__type_traits/is_replaceable.h"
export std_core.type_traits.integral_constant
}
module is_same {
header "__type_traits/is_same.h"
export std_core.type_traits.integral_constant
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/optional
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ namespace std {
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_object.h>
# include <__type_traits/is_reference.h>
# include <__type_traits/is_replaceable.h>
# include <__type_traits/is_same.h>
# include <__type_traits/is_scalar.h>
# include <__type_traits/is_swappable.h>
Expand Down Expand Up @@ -590,6 +591,7 @@ public:

using __trivially_relocatable _LIBCPP_NODEBUG =
conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>;
using __replaceable _LIBCPP_NODEBUG = conditional_t<__is_replaceable_v<_Tp>, optional, void>;

private:
// Disable the reference extension using this static assert.
Expand Down
8 changes: 8 additions & 0 deletions libcxx/include/string
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
# include <__type_traits/is_convertible.h>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_replaceable.h>
# include <__type_traits/is_same.h>
# include <__type_traits/is_standard_layout.h>
# include <__type_traits/is_trivial.h>
Expand Down Expand Up @@ -754,13 +755,20 @@ public:
// external memory. In such cases, the destructor is responsible for unpoisoning
// the memory to avoid triggering false positives.
// Therefore it's crucial to ensure the destructor is called.
//
// However, it is replaceable since implementing move-assignment as a destroy + move-construct
// will maintain the right ASAN state.
using __trivially_relocatable = void;
# else
using __trivially_relocatable _LIBCPP_NODEBUG = __conditional_t<
__libcpp_is_trivially_relocatable<allocator_type>::value && __libcpp_is_trivially_relocatable<pointer>::value,
basic_string,
void>;
# endif
using __replaceable _LIBCPP_NODEBUG =
__conditional_t<__is_replaceable_v<pointer> && __container_allocator_is_replaceable<__alloc_traits>::value,
basic_string,
void>;

# if _LIBCPP_HAS_ASAN && _LIBCPP_INSTRUMENTED_WITH_ASAN
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __asan_volatile_wrapper(pointer const& __ptr) const {
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/tuple
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ template <class... Types>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_reference.h>
# include <__type_traits/is_replaceable.h>
# include <__type_traits/is_same.h>
# include <__type_traits/is_swappable.h>
# include <__type_traits/is_trivially_relocatable.h>
Expand Down Expand Up @@ -555,6 +556,7 @@ class _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS tuple {
public:
using __trivially_relocatable _LIBCPP_NODEBUG =
__conditional_t<_And<__libcpp_is_trivially_relocatable<_Tp>...>::value, tuple, void>;
using __replaceable _LIBCPP_NODEBUG = __conditional_t<_And<__is_replaceable<_Tp>...>::value, tuple, void>;

// [tuple.cnstr]

Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/variant
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ namespace std {
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_reference.h>
# include <__type_traits/is_replaceable.h>
# include <__type_traits/is_same.h>
# include <__type_traits/is_swappable.h>
# include <__type_traits/is_trivially_assignable.h>
Expand Down Expand Up @@ -1176,6 +1177,7 @@ class _LIBCPP_TEMPLATE_VIS _LIBCPP_DECLSPEC_EMPTY_BASES _LIBCPP_NO_SPECIALIZATIO
public:
using __trivially_relocatable _LIBCPP_NODEBUG =
conditional_t<_And<__libcpp_is_trivially_relocatable<_Types>...>::value, variant, void>;
using __replaceable _LIBCPP_NODEBUG = conditional_t<_And<__is_replaceable<_Types>...>::value, variant, void>;

template <bool _Dummy = true,
enable_if_t<__dependent_type<is_default_constructible<__first_type>, _Dummy>::value, int> = 0>
Expand Down
Loading