diff --git a/stl/inc/memory b/stl/inc/memory index 2a264e011a9..c3bc6e6718c 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -308,10 +308,24 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, } #endif // _HAS_IF_CONSTEXPR +#if _HAS_CXX20 +template +auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept(noexcept(::new (const_cast( + static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...))) // strengthened + -> decltype( + ::new (const_cast(static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...)) { + return ::new (const_cast(static_cast(_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 -void destroy_at(_Ty* const _Location) { // destroy _Ty at memory address _Location +void destroy_at(_Ty* const _Location) noexcept /* strengthened */ { _Location->~_Ty(); } diff --git a/tests/std/test.lst b/tests/std/test.lst index e4db82afbca..873da5cdf40 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -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 diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/env.lst b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp new file mode 100644 index 00000000000..733265ddd20 --- /dev/null +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +template +inline constexpr bool can_construct_at_impl = false; + +template +inline constexpr bool + can_construct_at_impl(), declval()...))>, Ty, Types...> = true; + +template +inline constexpr bool can_construct_at = can_construct_at_impl; + +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); + +struct X {}; + +#ifndef __EDG__ // TRANSITION, VSO-1075296 +static_assert(!can_construct_at); +static_assert(!can_construct_at); +#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); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); + +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(can_construct_at); + +static_assert(can_construct_at); +static_assert(can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); + +// The following static_asserts test our strengthening of noexcept + +#ifndef __EDG__ // TRANSITION, VSO-1075296 +static_assert(noexcept(construct_at(declval(), 42))); +static_assert(noexcept(construct_at(declval(), 42))); +static_assert(noexcept(construct_at(declval(), 42))); +static_assert(noexcept(construct_at(declval(), 42))); +#endif // __EDG__ + +static_assert(!noexcept(construct_at(declval(), "hello"))); +static_assert(!noexcept(construct_at(declval(), "hello"))); +static_assert(!noexcept(construct_at(declval(), "hello"))); +static_assert(!noexcept(construct_at(declval(), "hello"))); + +static_assert(noexcept(destroy_at(declval()))); +static_assert(noexcept(destroy_at(declval()))); +static_assert(noexcept(destroy_at(declval()))); +static_assert(noexcept(destroy_at(declval()))); +static_assert(noexcept(destroy_at(declval()))); +static_assert(noexcept(destroy_at(declval()))); +static_assert(noexcept(destroy_at(declval()))); +static_assert(noexcept(destroy_at(declval()))); + +struct throwing_dtor { + ~throwing_dtor() noexcept(false) {} +}; + +static_assert(noexcept(destroy_at(declval()))); + +template +void test_runtime(const Ty& val) { + alignas(Ty) unsigned char storage[sizeof(Ty)]; + memset(storage, 42, sizeof(Ty)); + const auto asPtrTy = reinterpret_cast(&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(asPtrTy); + assert(asPtrTy == construct_at(asCv, val)); + assert(const_cast(*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(storage); + construct_at(ptr); + ptr->destroy(); + } +}