Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minimal changes to support constexpr allocation in MSVC #1313

Merged
merged 4 commits into from
Sep 22, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
148 changes: 143 additions & 5 deletions stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -284,34 +284,136 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw,
}
#endif // _HAS_IF_CONSTEXPR

// FUNCTION TEMPLATE construct_at
#if _HAS_CXX20
template <class _Ty, class... _Types>
auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept(noexcept(::new (const_cast<void*>(
static_cast<const volatile void*>(_Location))) _Ty(_STD forward<_Types>(_Args)...))) // strengthened
_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept(
noexcept(::new (const_cast<void*>(static_cast<const volatile void*>(_Location)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HM in the uninitialized_meow PR we introduced a voidify Funktion. If it is not too far out we should wait until it is merged or reproduce it here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole point of pushing this through before finishing test coverage is to avoid blocking the compiler team. If we get uninit_meow merged in time, I'll make the voidify change here. Otherwise, I'll do so in the followup. (Leaving this comment open as a reminder.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MSVC-PR-276291 is internally out for review, containing uninit_meow, so it's a race 🚀

Copy link
Member Author

@CaseyCarter CaseyCarter Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've annotated the destroy/destroy_n test coverage followup work item in #39 to mention integration with GH-1164 and _Voidify_iter specifically so this won't be dropped.

_Ty(_STD forward<_Types>(_Args)...))) // strengthened
-> decltype(
::new (const_cast<void*>(static_cast<const volatile void*>(_Location))) _Ty(_STD forward<_Types>(_Args)...)) {
return ::new (const_cast<void*>(static_cast<const volatile void*>(_Location))) _Ty(_STD forward<_Types>(_Args)...);
}

#ifdef __cpp_lib_concepts
namespace ranges {
using _STD construct_at;
// VARIABLE ranges::construct_at
class _Construct_at_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;

// clang-format off
template <class _Ty, class... _Types>
requires requires(void* _Void_ptr, _Types&&... _Args) {
::new (_Void_ptr) _Ty(static_cast<_Types&&>(_Args)...);
}
_CONSTEXPR20_DYNALLOC _Ty* operator()(_Ty* _Location, _Types&&... _Args) const
noexcept(noexcept(::new (const_cast<void*>(static_cast<const volatile void*>(_Location)))
_Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ {
// clang-format on
return ::new (const_cast<void*>(static_cast<const volatile void*>(_Location)))
_Ty(_STD forward<_Types>(_Args)...);
}
};

inline constexpr _Construct_at_fn construct_at{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts
#endif // _HAS_CXX20

#if _HAS_CXX17
// FUNCTION TEMPLATE destroy_at
template <class _Ty>
void destroy_at(_Ty* const _Location) noexcept /* strengthened */ {
_Location->~_Ty();
_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ {
#if _HAS_CXX20
if constexpr (is_array_v<_Ty>) {
_Destroy_range(_STD begin(*_Location), _STD end(*_Location));
} else
#endif // _HAS_CXX20
{
_Location->~_Ty();
}
}

#ifdef __cpp_lib_concepts
namespace ranges {
// VARIABLE ranges::destroy_at
// clang-format off
template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se>
requires destructible<iter_value_t<_It>>
_NODISCARD _CONSTEXPR20_DYNALLOC _It _Destroy_unchecked(_It _First, _Se _Last) noexcept;
// clang-format on

class _Destroy_at_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;

template <destructible _Ty>
_CONSTEXPR20_DYNALLOC void operator()(_Ty* const _Location) const noexcept {
if constexpr (is_array_v<_Ty>) {
(void) _RANGES _Destroy_unchecked(_RANGES begin(*_Location), _RANGES end(*_Location));
} else {
_Location->~_Ty();
}
}
};

inline constexpr _Destroy_at_fn destroy_at{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts

// FUNCTION TEMPLATE destroy
template <class _NoThrowFwdIt>
void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // destroy all elements in [_First, _Last)
_Adl_verify_range(_First, _Last);
_Destroy_range(_Get_unwrapped(_First), _Get_unwrapped(_Last));
}

#ifdef __cpp_lib_concepts
namespace ranges {
// VARIABLE ranges::destroy
// clang-format off
template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se>
requires destructible<iter_value_t<_It>>
_NODISCARD _CONSTEXPR20_DYNALLOC _It _Destroy_unchecked(_It _First, const _Se _Last) noexcept {
// clang-format on
for (; _First != _Last; ++_First) {
_RANGES destroy_at(_STD addressof(*_First));
}

return _First;
}

class _Destroy_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;

// clang-format off
template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se>
requires destructible<iter_value_t<_It>>
/* _CONSTEXPR20_DYNALLOC */ _It operator()(_It _First, _Se _Last) const noexcept {
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
// clang-format on
_Adl_verify_range(_First, _Last);
_Seek_wrapped(_First,
_RANGES _Destroy_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last))));
return _First;
}

// clang-format off
template <_No_throw_input_range _Rng>
requires destructible<range_value_t<_Rng>>
/* _CONSTEXPR20_DYNALLOC */ borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const noexcept {
// clang-format on
auto _First = _RANGES begin(_Range);
_Seek_wrapped(_First, _RANGES _Destroy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range)));
return _First;
}
};

inline constexpr _Destroy_fn destroy{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts

// FUNCTION TEMPLATE destroy_n
template <class _NoThrowFwdIt, class _Diff>
_NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) {
Expand All @@ -335,6 +437,42 @@ _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) {
return _First;
}

#ifdef __cpp_lib_concepts
namespace ranges {
// VARIABLE ranges::destroy_n
class _Destroy_n_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;

// clang-format off
template <_No_throw_input_iterator _It>
requires destructible<iter_value_t<_It>>
/* _CONSTEXPR20_DYNALLOC */ _It operator()(_It _First, const iter_difference_t<_It> _Count) const noexcept {
// clang-format on
if (_Count <= 0) {
return _First;
}

auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count);
if constexpr (is_trivially_destructible_v<iter_value_t<_It>>) {
_RANGES advance(_UFirst, _Count);
} else {
do {
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
_RANGES destroy_at(_STD addressof(*_UFirst));
++_UFirst;
--_Count;
} while (_Count > 0);
}

_Seek_wrapped(_First, _STD move(_UFirst));
return _First;
}
};

inline constexpr _Destroy_n_fn destroy_n{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts

// FUNCTION TEMPLATE uninitialized_default_construct
template <class _NoThrowFwdIt>
void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) {
Expand Down
15 changes: 7 additions & 8 deletions stl/inc/xmemory
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,10 @@ _Pointer _Refancy(_Pointer _Ptr) noexcept {

// FUNCTION TEMPLATE _Destroy_in_place
template <class _NoThrowFwdIt, class _NoThrowSentinel>
/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range(_NoThrowFwdIt _First, _NoThrowSentinel _Last) noexcept;
_CONSTEXPR20_DYNALLOC void _Destroy_range(_NoThrowFwdIt _First, _NoThrowSentinel _Last) noexcept;

template <class _Ty>
/* _CONSTEXPR20_DYNALLOC */ void _Destroy_in_place(_Ty& _Obj) noexcept {
_CONSTEXPR20_DYNALLOC void _Destroy_in_place(_Ty& _Obj) noexcept {
#if _HAS_IF_CONSTEXPR
if constexpr (is_array_v<_Ty>) {
_Destroy_range(_Obj, _Obj + extent_v<_Ty>);
Expand Down Expand Up @@ -951,8 +951,7 @@ void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept {

// FUNCTION TEMPLATE _Destroy_range WITH ALLOC
template <class _Alloc>
/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range(
_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept {
void _Destroy_range(_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept {
// note that this is an optimization for debug mode codegen; in release mode the BE removes all of this
using _Ty = typename _Alloc::value_type;
if _CONSTEXPR_IF (!conjunction_v<is_trivially_destructible<_Ty>, _Uses_default_destroy<_Alloc, _Ty*>>) {
Expand All @@ -964,7 +963,7 @@ template <class _Alloc>

// FUNCTION TEMPLATE _Destroy_range
template <class _NoThrowFwdIt, class _NoThrowSentinel>
/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range(_NoThrowFwdIt _First, const _NoThrowSentinel _Last) noexcept {
_CONSTEXPR20_DYNALLOC void _Destroy_range(_NoThrowFwdIt _First, const _NoThrowSentinel _Last) noexcept {
// note that this is an optimization for debug mode codegen; in release mode the BE removes all of this
if _CONSTEXPR_IF (!is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) {
for (; _First != _Last; ++_First) {
Expand Down Expand Up @@ -1425,18 +1424,18 @@ struct _Uninitialized_backout { // struct to undo partially constructed ranges i
_Uninitialized_backout(const _Uninitialized_backout&) = delete;
_Uninitialized_backout& operator=(const _Uninitialized_backout&) = delete;

/* _CONSTEXPR20_DYNALLOC */ ~_Uninitialized_backout() {
~_Uninitialized_backout() {
_Destroy_range(_First, _Last);
}

template <class... _Types>
/* _CONSTEXPR20_DYNALLOC */ void _Emplace_back(_Types&&... _Vals) {
void _Emplace_back(_Types&&... _Vals) {
// construct a new element at *_Last and increment
_Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...);
++_Last;
}

/* _CONSTEXPR20_DYNALLOC */ _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last
_NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last
_First = _Last;
return _Last;
}
Expand Down
7 changes: 7 additions & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,13 @@
#define _CONSTEXPR20 inline
#endif // ^^^ inline (not constexpr) in C++17 and earlier ^^^

// Functions that became constexpr in C++20 via P0784R7
#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc)
#define _CONSTEXPR20_DYNALLOC constexpr
#else
#define _CONSTEXPR20_DYNALLOC inline
#endif

// P0607R0 Inline Variables For The STL
#if _HAS_CXX17
#define _INLINE_VAR inline
Expand Down
Loading