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
34 changes: 34 additions & 0 deletions stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -1804,6 +1804,40 @@ 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-Bug #: To Be Filed
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
// STRUCT TEMPLATE is_layout_compatible
template <class _Ty1, class _Ty2>
struct is_layout_compatible : bool_constant<__builtin_is_layout_compatible(_Ty1, _Ty2)> {};

template <class _Ty1, class _Ty2>
inline constexpr bool is_layout_compatible_v = __builtin_is_layout_compatible(_Ty1, _Ty2);

// 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)> {};

template <class _Base, class _Derived>
inline constexpr bool is_pointer_interconvertible_base_of_v = __builtin_is_pointer_interconvertible_base_of(
_Base, _Derived);

// FUNCTION TEMPLATE is_pointer_interconvertible_with_class
template <class _ClassTy, class _MemberTy>
_NODISCARD constexpr bool is_pointer_interconvertible_with_class(_MemberTy _ClassTy::*_Pm) noexcept {
return __builtin_is_pointer_interconvertible_with_class(_ClassTy, _Pm);
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
}

// 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 {
return __builtin_is_corresponding_member(_ClassTy1, _ClassTy2, _Pm1, _Pm2);
}
#endif // __clang
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
#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 @@ -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
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
// P0476R2 <bit> bit_cast
// P0482R6 Library Support For char8_t
// (mbrtoc8 and c8rtomb not yet implemented)
Expand Down Expand Up @@ -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-Bug #: To Be Filed
#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
#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
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,200 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <assert.h>
#include <type_traits>

MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
using namespace std;

#define ASSERT(...) assert((__VA_ARGS__))


constexpr bool test() {
#ifndef __EDG__ // TRANSITION, VSO-1268984
#ifndef __clang__ // TRANSITION, LLVM-Bug #: To Be Filed
// 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<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, char>);
ASSERT(!is_layout_compatible_v<E1, E3>);
ASSERT(!is_layout_compatible_v<E2, E4>);
ASSERT(!is_layout_compatible_v<S1, S3>);
ASSERT(!is_layout_compatible_v<S4, S5>);
}
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
{
class A {};
class B : public A {};
class C : public A {
int : 0;
};
// Disable warning C4408: anonymous union did not declare any data members
#pragma warning(push)
#pragma warning(disable : 4408)
class D : public A {
union {};
};
#pragma warning(pop)
class A1 : public A {};
class A2 : public A {};
class A3 : public A2 {};
class A4 : public A1, public A3 {};

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, 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>);
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
ASSERT(!is_pointer_interconvertible_base_of_v<B, C>);
}
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved

// is_corresponding_member tests
{
struct S1 {
int v1;
int v2;
};

struct S2 {
int v1;
int v2;
};

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

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, &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, &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));
}
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
{
struct A {
int a;
};

struct B {
int b;
};

struct C : A, B {};

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(&U::v1));
ASSERT(is_pointer_interconvertible_with_class(&U::v2));
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
}
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
#endif // __clang__
#endif // __EDG__
return true;
}

int main() {
static_assert(test());
test();
}
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,24 @@ STATIC_ASSERT(__cpp_lib_is_nothrow_convertible == 201806L);
#endif
#endif

#if _HAS_CXX20
MahmoudGSaleh marked this conversation as resolved.
Show resolved Hide resolved
#ifndef __EDG__ // TRANSITION, VSO-1268984
#ifndef __clang__ // TRANSITION, LLVM-Bug #: To Be Filed
#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

#ifndef __cpp_lib_is_null_pointer
#error __cpp_lib_is_null_pointer is not defined
#elif __cpp_lib_is_null_pointer != 201309L
Expand All @@ -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-Bug #: To Be Filed
#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
Expand Down