Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions stl/inc/bit
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ _STL_DISABLE_CLANG_WARNINGS
_STD_BEGIN
enum class endian { little = 0, big = 1, native = little };

#ifdef __cpp_lib_bit_cast // TRANSITION, VSO-1041044
template <class _To, class _From,
enable_if_t<conjunction_v<bool_constant<sizeof(_To) == sizeof(_From)>, is_trivially_copyable<_To>,
is_trivially_copyable<_From>>,
int> = 0>
_NODISCARD constexpr _To bit_cast(const _From& _Val) noexcept {
return __builtin_bit_cast(_To, _Val);
}
#endif // TRANSITION, VSO-1041044

#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
template <class _Ty>
inline constexpr bool _Is_standard_unsigned_integer =
Expand Down
5 changes: 5 additions & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
// P0457R2 starts_with()/ends_with() For basic_string/basic_string_view
// P0458R2 contains() For Ordered And Unordered Associative Containers
// P0463R1 endian
// P0476R2 <bit> bit_cast
// P0482R6 Library Support For char8_t
// (mbrtoc8 and c8rtomb not yet implemented)
// P0487R1 Fixing operator>>(basic_istream&, CharT*)
Expand Down Expand Up @@ -1067,6 +1068,10 @@
#define __cpp_lib_atomic_float 201711L
#define __cpp_lib_bind_front 201907L

#ifndef __EDG__ // TRANSITION, VSO-1041044
#define __cpp_lib_bit_cast 201806L
#endif // __EDG__

#if defined(__clang__) || defined(__EDG__)
#define __cpp_lib_bitops 201907L
#else // ^^^ Clang and EDG / MSVC vvv
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ tests\P0357R3_supporting_incomplete_types_in_reference_wrapper
tests\P0414R2_shared_ptr_for_arrays
tests\P0426R1_constexpr_char_traits
tests\P0433R2_deduction_guides
tests\P0476R2_bit_cast
tests\P0487R1_fixing_operator_shl_basic_istream_char_pointer
tests\P0513R0_poisoning_the_hash
tests\P0553R4_bit_rotating_and_counting_functions
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0476R2_bit_cast/env.lst
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
266 changes: 266 additions & 0 deletions tests/std/tests/P0476R2_bit_cast/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifdef __EDG__ // TRANSITION, VSO-1041044
int main() {}
#else // __EDG__ ^^^ / vvv !__EDG__

#include <assert.h>
#include <bit>
#include <cmath>
#include <limits>
#include <stddef.h>
#include <string.h>
#include <type_traits>
#include <utility>

// structure sizing depends on a packing of 8, which is the default

union test_union_1 {
char a;
int b;
};
union test_union_2 {
char a;
float b;
};

struct middle_class_1 {
double d;
virtual void a_member_function_1() {}
};

struct middle_class_2 {
int a;
virtual void a_member_function_2() {}
};

struct derived_class : middle_class_1, middle_class_2 {
virtual void a_member_function_2() override {}
};

struct test_struct_1 {
char a;
// char[3]
int b;
short c;
// char[6]
double d;

void a_member_function() {}
};

struct test_struct_2 {
short a;
// char[2]
float b;
float c;
int d;
unsigned int e;
char f;
// char[1]
short g;

void a_member_function() {}
};

struct test_struct_3_member_fn_pointer {
char a;
// char[3]
int b;
short c;
char d[2];
void (test_struct_1::*fn)();
};

struct test_struct_4_large_member_fn_pointer {
char a;
// char[3]
int b;
double c;
double d;
void (derived_class::*fn)(); // "large" member fn pointers are aligned to 8 on both x64 and x86
};

struct test_struct_5_struct {
char a;
// char[3]
int b;
double c;
double d;
void* e;
size_t f;
};

struct test_struct_6 {
char a;
// char[3]
int b;
int c;
// char[4] on x64
void* v;
};

struct test_struct_7_member_fn_pointer {
char a;
// char[3]
int b;
int c;
void (test_struct_1::*fn)();
};

struct test_struct_1_not_trivially_copyable {
char a;
// char[3]
int b;
short c;
// char[2]
double d;

test_struct_1_not_trivially_copyable& operator=(const test_struct_1_not_trivially_copyable&) {
return *this;
}
};

#pragma pack(push, 1)
struct test_struct_1_packed {
char a;
int b;
short c;
double d;
};
struct test_struct_2_packed {
short a;
float b;
float c;
int d;
unsigned int e;
char f;
short g;
};
#pragma pack(pop)

static_assert(sizeof(test_struct_1) == sizeof(test_struct_2));

template <typename To, typename From, typename = void>
constexpr bool bit_cast_invocable = false;

template <typename To, typename From>
constexpr bool bit_cast_invocable<To, From, std::void_t<decltype(std::bit_cast<To>(std::declval<From>()))>> = true;

template <int zero = 0, int = ((void) std::bit_cast<test_union_1>(test_union_2{}), zero)>
constexpr bool bit_cast_is_constexpr_union(int) {
return true;
}

constexpr bool bit_cast_is_constexpr_union(long) {
return false;
}

template <int zero = 0, int = ((void) std::bit_cast<float*>(nullptr), zero)>
constexpr bool bit_cast_is_constexpr_pointer(int) {
return true;
}

constexpr bool bit_cast_is_constexpr_pointer(long) {
return false;
}

template <int zero = 0,
int = ((void) std::bit_cast<void (test_struct_1::*)()>(&test_struct_2::a_member_function), zero)>
constexpr bool bit_cast_is_constexpr_member_fn_pointer(int) {
return true;
}

constexpr bool bit_cast_is_constexpr_member_fn_pointer(long) {
return false;
}

template <int zero = 0, int = ((void) std::bit_cast<test_struct_6>(test_struct_3_member_fn_pointer{}), zero)>
constexpr bool bit_cast_is_constexpr_pmf_datamember(int) {
return true;
}

constexpr bool bit_cast_is_constexpr_pmf_datamember(long) {
return false;
}

template <int zero = 0,
int = ((void) std::bit_cast<test_struct_5_struct>(test_struct_4_large_member_fn_pointer{}), zero)>
constexpr bool bit_cast_is_constexpr_large_member_fn_pointer(int) {
return true;
}

constexpr bool bit_cast_is_constexpr_large_member_fn_pointer(long) {
return false;
}

template <typename To, typename From>
void zero_initialized_round_trip() {
From before{};
To middle = std::bit_cast<To>(before);
assert(memcmp(&before, &middle, sizeof(From)) == 0);
From after = std::bit_cast<From>(middle);
assert(memcmp(&before, &after, sizeof(From)) == 0);
}

constexpr bool test_float() {
unsigned int as_int = std::bit_cast<unsigned int>(0x0.000002p-126f);
assert(as_int == 1);
assert(std::bit_cast<float>(as_int) == 0x0.000002p-126f);
as_int = std::bit_cast<unsigned int>(0x1.1p1f);
assert(as_int == 0x40080000);
assert(std::bit_cast<float>(as_int) == 0x1.1p1f);
as_int = std::bit_cast<unsigned int>(0x0.0p0f);
assert(as_int == 0);
assert(std::bit_cast<float>(as_int) == 0x0.0p0f);
if (!std::is_constant_evaluated()) {
assert(std::signbit(std::bit_cast<float>(as_int)) == false);
}
as_int = std::bit_cast<unsigned int>(-0x0.0p0f);
assert(as_int == 0x80000000);
assert(std::bit_cast<float>(as_int) == -0x0.0p0f);
if (!std::is_constant_evaluated()) {
assert(std::signbit(std::bit_cast<float>(as_int)) == true);
}
// signaling nan
as_int = 0x7fc00001;
float snan = std::bit_cast<float>(as_int);
assert(as_int == std::bit_cast<unsigned int>(snan));
as_int = std::bit_cast<unsigned int>(std::numeric_limits<float>::infinity());
assert(as_int == 0x7f800000);
assert(std::bit_cast<float>(as_int) == std::numeric_limits<float>::infinity());
return true;
}

int main() {
static_assert(!bit_cast_invocable<test_struct_2_packed, test_struct_1_packed>);
static_assert(!bit_cast_invocable<test_struct_1_not_trivially_copyable, test_struct_1>);
static_assert(!bit_cast_invocable<test_struct_1, test_struct_1_not_trivially_copyable>);
static_assert(!bit_cast_invocable<test_struct_1_not_trivially_copyable, test_struct_1_not_trivially_copyable>);
static_assert(bit_cast_invocable<test_union_1, test_union_2>);
static_assert(bit_cast_invocable<ptrdiff_t, void (test_struct_1::*)()>);
static_assert(bit_cast_invocable<ptrdiff_t, void (*)()>);
static_assert(bit_cast_invocable<test_struct_1, test_struct_2>);
static_assert(bit_cast_invocable<test_struct_4_large_member_fn_pointer, test_struct_5_struct>);

// tests for conditions on constexprness
static_assert(!bit_cast_is_constexpr_union(0));
static_assert(!bit_cast_is_constexpr_pointer(0));
static_assert(!bit_cast_is_constexpr_member_fn_pointer(0));
static_assert(!bit_cast_is_constexpr_pmf_datamember(0));
static_assert(!bit_cast_is_constexpr_large_member_fn_pointer(0));

zero_initialized_round_trip<test_struct_1, test_struct_2>();
zero_initialized_round_trip<test_struct_3_member_fn_pointer, test_struct_3_member_fn_pointer>();
zero_initialized_round_trip<test_struct_3_member_fn_pointer, test_struct_7_member_fn_pointer>();
zero_initialized_round_trip<test_struct_4_large_member_fn_pointer, test_struct_5_struct>();
zero_initialized_round_trip<test_struct_6, test_struct_3_member_fn_pointer>();
zero_initialized_round_trip<float, int>();
zero_initialized_round_trip<double, long long>();
zero_initialized_round_trip<unsigned int, float>();

assert(test_float());
static_assert(test_float());
}
#endif // __EDG__
14 changes: 14 additions & 0 deletions tests/std/tests/VSO_0157762_feature_test_macros/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,20 @@ STATIC_ASSERT(__cpp_lib_bind_front == 201907L);
#endif
#endif

#if CXX20_MODE && !defined(__EDG__) // TRANSITION, VSO-1041044
#ifndef __cpp_lib_bit_cast
#error BOOM
#elif __cpp_lib_bit_cast != 201806L
#error BOOM
#else
STATIC_ASSERT(__cpp_lib_bit_cast == 201806L);
#endif
#else
#ifdef __cpp_lib_bit_cast
#error BOOM
#endif
#endif

#if CXX20_MODE && (defined(__clang__) || defined(__EDG__)) // TRANSITION, VSO-1020212
#ifndef __cpp_lib_bitops
#error BOOM
Expand Down