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

<type_traits>: Implement Layout-compatibility and Pointer-interconvertibility Traits #1575

Merged
merged 9 commits into from
Jan 31, 2021
35 changes: 31 additions & 4 deletions stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -1806,35 +1806,62 @@ inline constexpr bool is_nothrow_invocable_r_v =

#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, VSO-1268984
#ifndef __clang__ // TRANSITION, LLVM-Bug #: To Be Filed
#ifndef __clang__ // TRANSITION, LLVM-48860
// STRUCT TEMPLATE is_layout_compatible
template <class _Ty1, class _Ty2>
struct is_layout_compatible : bool_constant<__builtin_is_layout_compatible(_Ty1, _Ty2)> {};
#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 <class _Ty1, class _Ty2>
#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 <class _Base, class _Derived>
struct is_pointer_interconvertible_base_of
: bool_constant<__builtin_is_pointer_interconvertible_base_of(_Base, _Derived)> {};
#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 <class _Base, class _Derived>
#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 <class _ClassTy, class _MemberTy>
_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);
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED
}

// FUNCTION TEMPLATE is_corresponding_member
template <class _ClassTy1, class _ClassTy2, class _MemberTy1, class _MemberTy2>
_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 // __clang__
#endif // __EDG__
#endif // _HAS_CXX20

Expand Down
6 changes: 3 additions & 3 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +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
// P0466R5 Layout-Compatibility And Pointer-Interconvertibility Traits
// P0476R2 <bit> bit_cast
// P0482R6 Library Support For char8_t
// (mbrtoc8 and c8rtomb not yet implemented)
Expand Down Expand Up @@ -1210,15 +1210,15 @@
#define __cpp_lib_is_constant_evaluated 201811L

#ifndef __EDG__ // TRANSITION, VSO-1268984
#ifndef __clang__ // TRANSITION, LLVM-Bug #: To Be Filed
#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-Bug #: To Be Filed
#ifndef __clang__ // TRANSITION, LLVM-48860
#define __cpp_lib_is_pointer_interconvertible 201907L
#endif // __clang__
#endif // __EDG__
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ 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-Bug #: To Be Filed
#ifndef __clang__ // TRANSITION, LLVM-48860
// is_layout_compatible tests
{
struct S0 {
Expand Down Expand Up @@ -55,21 +60,35 @@ constexpr bool test() {
enum class E5 { zero, fortytwo = 42 };

ASSERT(is_layout_compatible_v<int, int>);
ASSERT(is_layout_compatible_v<const void, void>);
ASSERT(is_layout_compatible_v<S1, volatile S2>);
ASSERT(is_layout_compatible_v<S1, S2>);
ASSERT(is_layout_compatible_v<S4, S4>);
ASSERT(is_layout_compatible_v<const volatile S4, S4>);
ASSERT(is_layout_compatible_v<E1, E2>);
ASSERT(is_layout_compatible_v<E3, E4>);
ASSERT(is_layout_compatible_v<E5, E1>);
ASSERT(is_layout_compatible_v<const E1, E2>);
ASSERT(is_layout_compatible_v<volatile E3, const E4>);
ASSERT(is_layout_compatible_v<S1, volatile S2>);
ASSERT(is_layout_compatible_v<S1, S2>);
ASSERT(is_layout_compatible_v<S4, S4>);
ASSERT(is_layout_compatible_v<const volatile S4, S4>);
ASSERT(is_layout_compatible_v<int[], int[]>);
ASSERT(is_layout_compatible_v<int[3], int[3]>);

#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1269781
ASSERT(is_layout_compatible_v<const int[], int[]>);
ASSERT(is_layout_compatible_v<const int[3], int[3]>);
ASSERT(is_layout_compatible_v<int[], volatile int[]>);
#endif // TRANSITION, VSO-1269781

ASSERT(!is_layout_compatible_v<int, char>);
ASSERT(!is_layout_compatible_v<E1, E3>);
ASSERT(!is_layout_compatible_v<E2, E4>);
ASSERT(!is_layout_compatible_v<int, void>);
ASSERT(!is_layout_compatible_v<S1, void>);
ASSERT(!is_layout_compatible_v<S1, S3>);
ASSERT(!is_layout_compatible_v<S4, S5>);
ASSERT(!is_layout_compatible_v<E1, void>);
ASSERT(!is_layout_compatible_v<E1, E3>);
ASSERT(!is_layout_compatible_v<E2, E4>);
ASSERT(!is_layout_compatible_v<int[], int[2]>);
ASSERT(!is_layout_compatible_v<int[3], int[1]>);
}
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved

// is_pointer_interconvertible_base_of tests
Expand All @@ -79,17 +98,22 @@ constexpr bool test() {
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 D : public A {
class E : public A {
union {};
};
#pragma warning(pop)
class A1 : public A {};
class A2 : public A {};
class A3 : public A2 {};
class A4 : public A1, public A3 {};
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<A, A>);
ASSERT(is_pointer_interconvertible_base_of_v<A, B>);
Expand All @@ -98,14 +122,21 @@ constexpr bool test() {
ASSERT(is_pointer_interconvertible_base_of_v<A, volatile C>);
ASSERT(is_pointer_interconvertible_base_of_v<volatile A, const C>);
ASSERT(is_pointer_interconvertible_base_of_v<A, D>);
ASSERT(is_pointer_interconvertible_base_of_v<A, A1>);
ASSERT(is_pointer_interconvertible_base_of_v<A, A2>);
ASSERT(is_pointer_interconvertible_base_of_v<A, A3>);
ASSERT(is_pointer_interconvertible_base_of_v<A2, A3>);

ASSERT(!is_pointer_interconvertible_base_of_v<A1, A2>);
ASSERT(!is_pointer_interconvertible_base_of_v<A4, A>);
ASSERT(is_pointer_interconvertible_base_of_v<A, E>);
ASSERT(is_pointer_interconvertible_base_of_v<A, F>);
ASSERT(is_pointer_interconvertible_base_of_v<C, D>);
ASSERT(is_pointer_interconvertible_base_of_v<I, I>);
ASSERT(is_pointer_interconvertible_base_of_v<const I, I>);

ASSERT(!is_pointer_interconvertible_base_of_v<int, int>);
ASSERT(!is_pointer_interconvertible_base_of_v<void, void>);
ASSERT(!is_pointer_interconvertible_base_of_v<A, int>);
ASSERT(!is_pointer_interconvertible_base_of_v<B, C>);
ASSERT(!is_pointer_interconvertible_base_of_v<A, NS>);
ASSERT(!is_pointer_interconvertible_base_of_v<B, NS>);
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
ASSERT(!is_pointer_interconvertible_base_of_v<int, I>);
ASSERT(!is_pointer_interconvertible_base_of_v<U, U>);
ASSERT(!is_pointer_interconvertible_base_of_v<U, I>);
}
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved

// is_corresponding_member tests
Expand All @@ -116,8 +147,8 @@ constexpr bool test() {
};

struct S2 {
int v1;
int v2;
int w1;
int w2;
};

struct S3 {
Expand All @@ -144,26 +175,39 @@ constexpr bool test() {
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, &S1::v2));
ASSERT(!is_corresponding_member(&S1::v2, &S1::v1));
ASSERT(is_corresponding_member(&S1::v1, &S2::v1));
ASSERT(is_corresponding_member(&S1::v2, &S2::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, &S2::v2));
ASSERT(!is_corresponding_member(&S1::v2, &S2::v1));
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, NS>(&NS::v1, &NS::w1));
ASSERT(!is_corresponding_member(&S7::f1, &S7::f1));
ASSERT(!is_corresponding_member<S1, S2, int, int>(nullptr, nullptr));
ASSERT(!is_corresponding_member<S1, S2, int, int>(&S1::v1, nullptr));
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
}
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved

// is_pointer_interconvertible_with_class tests
Expand All @@ -176,18 +220,28 @@ constexpr bool test() {
int b;
};

struct C : A, 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(&C::b));
ASSERT(!is_pointer_interconvertible_with_class<C>(&C::b));

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));
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved

ASSERT(!is_pointer_interconvertible_with_class<NS>(&NS::a));
ASSERT(!is_pointer_interconvertible_with_class<NS>(&NS::b));
ASSERT(!is_pointer_interconvertible_with_class(&C::f1));
ASSERT(!is_pointer_interconvertible_with_class<A, int>(nullptr));
}
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
#endif // __clang__
#endif // __EDG__
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ STATIC_ASSERT(__cpp_lib_is_invocable == 201703L);

#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, VSO-1268984
#ifndef __clang__ // TRANSITION, LLVM-Bug #: To Be Filed
#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
Expand Down Expand Up @@ -892,7 +892,7 @@ STATIC_ASSERT(__cpp_lib_is_null_pointer == 201309L);

#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, VSO-1268984
#ifndef __clang__ // TRANSITION, LLVM-Bug #: To Be Filed
#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
Expand Down