Skip to content

Commit

Permalink
P0466R5 Layout-Compatibility And Pointer-Interconvertibility Traits (#…
Browse files Browse the repository at this point in the history
…1575)

Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
  • Loading branch information
MahmoudGSaleh and StephanTLavavej authored Jan 31, 2021
1 parent 721e3ad commit c319a7b
Show file tree
Hide file tree
Showing 6 changed files with 384 additions and 13 deletions.
61 changes: 61 additions & 0 deletions stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class _Ty1, class _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
#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);
#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 // __EDG__
#endif // _HAS_CXX20

// ALIAS TEMPLATE _Weak_types
template <class _Ty>
struct _Function_args {}; // determine whether _Ty is a function
Expand Down
41 changes: 28 additions & 13 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,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> bit_cast
// P0482R6 Library Support For char8_t
// (mbrtoc8 and c8rtomb not yet implemented)
Expand Down Expand Up @@ -1208,19 +1209,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
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,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
@@ -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,254 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <assert.h>
#include <type_traits>

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<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<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<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]>);
}

// 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<A, A>);
ASSERT(is_pointer_interconvertible_base_of_v<A, B>);
ASSERT(is_pointer_interconvertible_base_of_v<A, const B>);
ASSERT(is_pointer_interconvertible_base_of_v<A, C>);
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, 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>);
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>);
}

// 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, NS>(&NS::v1, &NS::w1));
ASSERT(!is_corresponding_member(&S7::f1, &S7::f1));
ASSERT(!is_corresponding_member(static_cast<int S1::*>(nullptr), static_cast<int S2::*>(nullptr)));
ASSERT(!is_corresponding_member(&S1::v1, static_cast<int S2::*>(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>(&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(static_cast<int A::*>(nullptr)));
}
#endif // __clang__
#endif // __EDG__
return true;
}

int main() {
static_assert(test());
test();
}
Loading

0 comments on commit c319a7b

Please sign in to comment.