diff --git a/stl/inc/type_traits b/stl/inc/type_traits index c1a030758bb..2d50aa726cf 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1804,6 +1804,67 @@ inline constexpr bool is_nothrow_invocable_r_v = _Select_invoke_traits<_Callable, _Args...>::template _Is_nothrow_invocable_r<_Rx>::value; #endif // _HAS_CXX17 +#if _HAS_CXX20 +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +// STRUCT TEMPLATE is_layout_compatible +template +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED +struct is_layout_compatible : bool_constant<__is_layout_compatible(_Ty1, _Ty2)> { +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv +struct is_layout_compatible : bool_constant<__builtin_is_layout_compatible(_Ty1, _Ty2)> { +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED +}; + +template +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED +inline constexpr bool is_layout_compatible_v = __is_layout_compatible(_Ty1, _Ty2); +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv +inline constexpr bool is_layout_compatible_v = __builtin_is_layout_compatible(_Ty1, _Ty2); +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED + +// STRUCT TEMPLATE is_pointer_interconvertible_base_of +template +struct is_pointer_interconvertible_base_of +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED + : bool_constant<__is_pointer_interconvertible_base_of(_Base, _Derived)> { +}; +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv + : bool_constant<__builtin_is_pointer_interconvertible_base_of(_Base, _Derived)> { +}; +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED + +template +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED +inline constexpr bool is_pointer_interconvertible_base_of_v = __is_pointer_interconvertible_base_of(_Base, _Derived); +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv +inline constexpr bool is_pointer_interconvertible_base_of_v = __builtin_is_pointer_interconvertible_base_of( + _Base, _Derived); +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED + +// FUNCTION TEMPLATE is_pointer_interconvertible_with_class +template +_NODISCARD constexpr bool is_pointer_interconvertible_with_class(_MemberTy _ClassTy::*_Pm) noexcept { +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED + return __is_pointer_interconvertible_with_class(_ClassTy, _Pm); +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv + return __builtin_is_pointer_interconvertible_with_class(_ClassTy, _Pm); +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED +} + +// FUNCTION TEMPLATE is_corresponding_member +template +_NODISCARD constexpr bool is_corresponding_member(_MemberTy1 _ClassTy1::*_Pm1, _MemberTy2 _ClassTy2::*_Pm2) noexcept { +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED + return __is_corresponding_member(_ClassTy1, _ClassTy2, _Pm1, _Pm2); +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv + return __builtin_is_corresponding_member(_ClassTy1, _ClassTy2, _Pm1, _Pm2); +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED +} +#endif // __clang__ +#endif // __EDG__ +#endif // _HAS_CXX20 + // ALIAS TEMPLATE _Weak_types template struct _Function_args {}; // determine whether _Ty is a function diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 28011748cb5..964dd68338c 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -145,6 +145,7 @@ // P0457R2 starts_with()/ends_with() For basic_string/basic_string_view // P0458R2 contains() For Ordered And Unordered Associative Containers // P0463R1 endian +// P0466R5 Layout-Compatibility And Pointer-Interconvertibility Traits // P0476R2 bit_cast // P0482R6 Library Support For char8_t // (mbrtoc8 and c8rtomb not yet implemented) @@ -1207,19 +1208,33 @@ #define __cpp_lib_integer_comparison_functions 202002L #define __cpp_lib_interpolate 201902L #define __cpp_lib_is_constant_evaluated 201811L -#define __cpp_lib_is_nothrow_convertible 201806L -#define __cpp_lib_jthread 201911L -#define __cpp_lib_latch 201907L -#define __cpp_lib_list_remove_return_type 201806L -#define __cpp_lib_math_constants 201907L -#define __cpp_lib_polymorphic_allocator 201902L -#define __cpp_lib_remove_cvref 201711L -#define __cpp_lib_semaphore 201907L -#define __cpp_lib_shift 201806L -#define __cpp_lib_smart_ptr_for_overwrite 202002L -#define __cpp_lib_span 202002L -#define __cpp_lib_ssize 201902L -#define __cpp_lib_starts_ends_with 201711L + +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +#define __cpp_lib_is_layout_compatible 201907L +#endif // __clang__ +#endif // __EDG__ + +#define __cpp_lib_is_nothrow_convertible 201806L + +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +#define __cpp_lib_is_pointer_interconvertible 201907L +#endif // __clang__ +#endif // __EDG__ + +#define __cpp_lib_jthread 201911L +#define __cpp_lib_latch 201907L +#define __cpp_lib_list_remove_return_type 201806L +#define __cpp_lib_math_constants 201907L +#define __cpp_lib_polymorphic_allocator 201902L +#define __cpp_lib_remove_cvref 201711L +#define __cpp_lib_semaphore 201907L +#define __cpp_lib_shift 201806L +#define __cpp_lib_smart_ptr_for_overwrite 202002L +#define __cpp_lib_span 202002L +#define __cpp_lib_ssize 201902L +#define __cpp_lib_starts_ends_with 201711L #ifdef __cpp_lib_concepts // TRANSITION, GH-395 #define __cpp_lib_three_way_comparison 201711L diff --git a/tests/std/test.lst b/tests/std/test.lst index 3d71f043206..15dae20ad33 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -232,6 +232,7 @@ tests\P0414R2_shared_ptr_for_arrays tests\P0415R1_constexpr_complex tests\P0426R1_constexpr_char_traits tests\P0433R2_deduction_guides +tests\P0466R5_layout_compatibility_and_pointer_interconvertibility_traits tests\P0476R2_bit_cast tests\P0487R1_fixing_operator_shl_basic_istream_char_pointer tests\P0513R0_poisoning_the_hash diff --git a/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/env.lst b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/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/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp new file mode 100644 index 00000000000..78309c6cc21 --- /dev/null +++ b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp @@ -0,0 +1,254 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include + +using namespace std; + +#define ASSERT(...) assert((__VA_ARGS__)) + +struct S { // Must be declared at namespace scope due to static data member + static int s1; + int v1; + int v2; +}; + +constexpr bool test() { +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 + // is_layout_compatible tests + { + struct S0 { + int v1; + int v2; + }; + + struct S1 { + S0 s1; + int v3; + }; + + struct S2 { + S0 s1; + int v2; + }; + + struct S3 { + S0 s1; + int v2; + int v3; + }; + + struct S4 { + int v1; + + private: + int v2; + }; + + struct S5 { + int v1; + + private: + int v2; + }; + + enum E1 { e1, e2, e3, e4 }; + enum E2 : int { e5 }; + enum E3 : unsigned int { e6, e7, e8 }; + enum class E4 : unsigned int { no, yes }; + enum class E5 { zero, fortytwo = 42 }; + + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1269781 + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); +#endif // TRANSITION, VSO-1269781 + + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + } + + // is_pointer_interconvertible_base_of tests + { + class A {}; + class B : public A {}; + class C : public A { + int : 0; + }; + class D : public C {}; +// Disable warning C4408: anonymous union did not declare any data members +#pragma warning(push) +#pragma warning(disable : 4408) + class E : public A { + union {}; + }; +#pragma warning(pop) + class F : private A {}; // Non-public inheritance + class NS : public B, public C {}; // Non-standard layout + class I; // Incomplete + + union U { + int i; + char c; + }; + + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + } + + // is_corresponding_member tests + { + struct S1 { + int v1; + int v2; + }; + + struct S2 { + int w1; + int w2; + }; + + struct S3 { + int v1; + int v2; + int v3; + }; + + struct S4 { + char v1; + int v2; + int v3; + }; + + struct S5 { + int v1; + int v2; + void* v3; + }; + + struct S6 { + int v1; + int v2; + double v3; + }; + + struct S7 { + int f1() { + return 0; + } + }; + + struct NS : S1, S2 {}; // Non-standard layout + + ASSERT(is_corresponding_member(&S1::v1, &S::v1)); + ASSERT(is_corresponding_member(&S1::v2, &S::v2)); + ASSERT(is_corresponding_member(&S1::v1, &S1::v1)); + ASSERT(is_corresponding_member(&S1::v2, &S1::v2)); + ASSERT(is_corresponding_member(&S1::v1, &S2::w1)); + ASSERT(is_corresponding_member(&S1::v2, &S2::w2)); + ASSERT(is_corresponding_member(&S1::v1, &S3::v1)); + ASSERT(is_corresponding_member(&S1::v2, &S3::v2)); + ASSERT(is_corresponding_member(&S5::v1, &S6::v1)); + ASSERT(is_corresponding_member(&S5::v2, &S6::v2)); + + ASSERT(!is_corresponding_member(&S1::v1, &S1::v2)); + ASSERT(!is_corresponding_member(&S1::v2, &S1::v1)); + ASSERT(!is_corresponding_member(&S1::v2, &S2::w1)); + ASSERT(!is_corresponding_member(&S1::v1, &S4::v1)); + ASSERT(!is_corresponding_member(&S1::v2, &S4::v2)); + ASSERT(!is_corresponding_member(&S3::v1, &S4::v1)); + ASSERT(!is_corresponding_member(&S3::v2, &S4::v2)); + ASSERT(!is_corresponding_member(&S5::v1, &S6::v2)); + ASSERT(!is_corresponding_member(&S5::v2, &S6::v1)); + ASSERT(!is_corresponding_member(&S5::v3, &S6::v3)); + ASSERT(!is_corresponding_member(&NS::v1, &NS::w1)); + ASSERT(!is_corresponding_member(&S7::f1, &S7::f1)); + ASSERT(!is_corresponding_member(static_cast(nullptr), static_cast(nullptr))); + ASSERT(!is_corresponding_member(&S1::v1, static_cast(nullptr))); + } + + // is_pointer_interconvertible_with_class tests + { + struct A { + int a; + }; + + struct B { + int b; + }; + + struct C { + int f1() { + return 0; + } + }; + + struct NS : A, B {}; // Non-standard layout + + union U { + int v1; + char v2; + }; + + ASSERT(is_pointer_interconvertible_with_class(&A::a)); + ASSERT(is_pointer_interconvertible_with_class(&NS::b)); + ASSERT(is_pointer_interconvertible_with_class(&U::v1)); + ASSERT(is_pointer_interconvertible_with_class(&U::v2)); + + ASSERT(!is_pointer_interconvertible_with_class(&NS::a)); + ASSERT(!is_pointer_interconvertible_with_class(&NS::b)); + ASSERT(!is_pointer_interconvertible_with_class(&C::f1)); + ASSERT(!is_pointer_interconvertible_with_class(static_cast(nullptr))); + } +#endif // __clang__ +#endif // __EDG__ + return true; +} + +int main() { + static_assert(test()); + test(); +} diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 9a6cd10c972..db066537944 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -850,6 +850,24 @@ STATIC_ASSERT(__cpp_lib_is_invocable == 201703L); #endif #endif +#if _HAS_CXX20 +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +#ifndef __cpp_lib_is_layout_compatible +#error __cpp_lib_is_layout_compatible is not defined +#elif __cpp_lib_is_layout_compatible != 201907L +#error __cpp_lib_is_layout_compatible is not 201907L +#else +STATIC_ASSERT(__cpp_lib_is_layout_compatible == 201907L); +#endif +#else +#ifdef __cpp_lib_is_layout_compatible +#error __cpp_lib_is_layout_compatible is defined +#endif +#endif +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_is_nothrow_convertible #error __cpp_lib_is_nothrow_convertible is not defined @@ -872,6 +890,24 @@ STATIC_ASSERT(__cpp_lib_is_nothrow_convertible == 201806L); STATIC_ASSERT(__cpp_lib_is_null_pointer == 201309L); #endif +#if _HAS_CXX20 +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +#ifndef __cpp_lib_is_pointer_interconvertible +#error __cpp_lib_is_pointer_interconvertible is not defined +#elif __cpp_lib_is_pointer_interconvertible != 201907L +#error __cpp_lib_is_pointer_interconvertible is not 201907L +#else +STATIC_ASSERT(__cpp_lib_is_pointer_interconvertible == 201907L); +#endif +#else +#ifdef __cpp_lib_is_pointer_interconvertible +#error __cpp_lib_is_pointer_interconvertible is defined +#endif +#endif +#endif +#endif + #if _HAS_CXX17 #ifndef __cpp_lib_is_swappable #error __cpp_lib_is_swappable is not defined