Skip to content
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
16 changes: 15 additions & 1 deletion stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,24 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw,
}
#endif // _HAS_IF_CONSTEXPR

#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
-> 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)...);
}

namespace ranges {
using _STD construct_at;
} // namespace ranges
#endif // _HAS_CXX20

#if _HAS_CXX17
// FUNCTION TEMPLATE destroy_at
template <class _Ty>
void destroy_at(_Ty* const _Location) { // destroy _Ty at memory address _Location
void destroy_at(_Ty* const _Location) noexcept /* strengthened */ {
_Location->~_Ty();
}

Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ tests\P0674R1_make_shared_for_arrays
tests\P0758R1_is_nothrow_convertible
tests\P0768R1_spaceship_operator
tests\P0769R2_shift_left_shift_right
tests\P0784R7_library_support_for_more_constexpr_containers
tests\P0811R3_midpoint_lerp
tests\P0896R4_P1614R2_comparisons
tests\P0896R4_ranges_iterator_machinery
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_latest_matrix.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <assert.h>
#include <memory>
#include <stddef.h>
#include <string.h>
#include <string>
#include <type_traits>
#include <utility>

using namespace std;

template <class Void, class Ty, class... Types>
inline constexpr bool can_construct_at_impl = false;

template <class Ty, class... Types>
inline constexpr bool
can_construct_at_impl<void_t<decltype(construct_at(declval<Ty*>(), declval<Types>()...))>, Ty, Types...> = true;

template <class Ty, class... Types>
inline constexpr bool can_construct_at = can_construct_at_impl<void, Ty, Types...>;

static_assert(can_construct_at<int>);
static_assert(can_construct_at<const int>);
static_assert(can_construct_at<volatile int>);
static_assert(can_construct_at<const volatile int>);
static_assert(can_construct_at<int, int>);
static_assert(can_construct_at<const int, int>);
static_assert(can_construct_at<volatile int, int>);
static_assert(can_construct_at<const volatile int, int>);
static_assert(can_construct_at<int, int&>);
static_assert(can_construct_at<const int, int&>);
static_assert(can_construct_at<volatile int, int&>);
static_assert(can_construct_at<const volatile int, int&>);

struct X {};

#ifndef __EDG__ // TRANSITION, VSO-1075296
static_assert(!can_construct_at<int, X>);
static_assert(!can_construct_at<X, int>);
#endif // __EDG__

// note that indestructible isn't constructible but is construct_at-ible:
struct indestructible {
void destroy() {
this->~indestructible();
};

private:
~indestructible() = default;
};

static_assert(can_construct_at<indestructible>);
static_assert(can_construct_at<const indestructible>);
static_assert(can_construct_at<volatile indestructible>);
static_assert(can_construct_at<const volatile indestructible>);

static_assert(can_construct_at<X>);
static_assert(can_construct_at<X, X>);
static_assert(can_construct_at<X, const X>);
static_assert(can_construct_at<X, const X&>);
static_assert(can_construct_at<X, X&>);

static_assert(can_construct_at<string>);
static_assert(can_construct_at<string, size_t, char>);
static_assert(!can_construct_at<string, size_t, char, char>);
static_assert(!can_construct_at<string, X>);

// The following static_asserts test our strengthening of noexcept

#ifndef __EDG__ // TRANSITION, VSO-1075296
static_assert(noexcept(construct_at(declval<int*>(), 42)));
static_assert(noexcept(construct_at(declval<const int*>(), 42)));
static_assert(noexcept(construct_at(declval<volatile int*>(), 42)));
static_assert(noexcept(construct_at(declval<const volatile int*>(), 42)));
#endif // __EDG__

static_assert(!noexcept(construct_at(declval<string*>(), "hello")));
static_assert(!noexcept(construct_at(declval<const string*>(), "hello")));
static_assert(!noexcept(construct_at(declval<volatile string*>(), "hello")));
static_assert(!noexcept(construct_at(declval<const volatile string*>(), "hello")));

static_assert(noexcept(destroy_at(declval<int*>())));
static_assert(noexcept(destroy_at(declval<string*>())));
static_assert(noexcept(destroy_at(declval<const int*>())));
static_assert(noexcept(destroy_at(declval<const string*>())));
static_assert(noexcept(destroy_at(declval<volatile int*>())));
static_assert(noexcept(destroy_at(declval<volatile string*>())));
static_assert(noexcept(destroy_at(declval<const volatile int*>())));
static_assert(noexcept(destroy_at(declval<const volatile string*>())));

struct throwing_dtor {
~throwing_dtor() noexcept(false) {}
};

static_assert(noexcept(destroy_at(declval<throwing_dtor*>())));

template <class Ty>
void test_runtime(const Ty& val) {
alignas(Ty) unsigned char storage[sizeof(Ty)];
memset(storage, 42, sizeof(Ty));
const auto asPtrTy = reinterpret_cast<Ty*>(&storage);
assert(asPtrTy == construct_at(asPtrTy, val));
assert(*asPtrTy == val);
destroy_at(asPtrTy);

// test ranges:
assert(asPtrTy == ranges::construct_at(asPtrTy, val));
assert(*asPtrTy == val);
destroy_at(asPtrTy);

// test voidify:
const auto asCv = static_cast<const volatile Ty*>(asPtrTy);
assert(asPtrTy == construct_at(asCv, val));
assert(const_cast<const Ty&>(*asCv) == val);
destroy_at(asCv);
}

int main() {
test_runtime(1234);
test_runtime(string("hello world"));
test_runtime(string("hello to some really long world that certainly doesn't fit in SSO"));

{
alignas(indestructible) unsigned char storage[sizeof(indestructible)];
const auto ptr = reinterpret_cast<indestructible*>(storage);
construct_at(ptr);
ptr->destroy();
}
}