Skip to content

Commit 0680fab

Browse files
Implement P0943R6 Supporting C Atomics In C++ (#2008)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 46477a1 commit 0680fab

File tree

10 files changed

+273
-0
lines changed

10 files changed

+273
-0
lines changed

stl/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ set(HEADERS
184184
${CMAKE_CURRENT_LIST_DIR}/inc/span
185185
${CMAKE_CURRENT_LIST_DIR}/inc/sstream
186186
${CMAKE_CURRENT_LIST_DIR}/inc/stack
187+
${CMAKE_CURRENT_LIST_DIR}/inc/stdatomic.h
187188
${CMAKE_CURRENT_LIST_DIR}/inc/stdexcept
188189
${CMAKE_CURRENT_LIST_DIR}/inc/stop_token
189190
${CMAKE_CURRENT_LIST_DIR}/inc/streambuf

stl/inc/__msvc_all_public_headers.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
#include <barrier>
139139
#include <latch>
140140
#include <semaphore>
141+
#include <stdatomic.h>
141142
#include <stop_token>
142143
#endif // _M_CEE_PURE
143144

stl/inc/header-units.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"span",
9595
"sstream",
9696
"stack",
97+
"stdatomic.h",
9798
"stdexcept",
9899
"stop_token",
99100
"streambuf",

stl/inc/stdatomic.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// stdatomic.h standard header
2+
3+
// Copyright (c) Microsoft Corporation.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
6+
#pragma once
7+
#ifndef _STDATOMIC_H_
8+
#define _STDATOMIC_H_
9+
#include <yvals.h>
10+
#if _STL_COMPILER_PREPROCESSOR
11+
12+
#ifdef _M_CEE_PURE
13+
#error <stdatomic.h> is not supported when compiling with /clr:pure.
14+
#endif // _M_CEE_PURE
15+
16+
#if !_HAS_CXX23
17+
#pragma message("The contents of <stdatomic.h> are available only with C++23 or later.")
18+
#else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv
19+
20+
#include <atomic>
21+
22+
#pragma pack(push, _CRT_PACKING)
23+
#pragma warning(push, _STL_WARNING_LEVEL)
24+
#pragma warning(disable : _STL_DISABLED_WARNINGS)
25+
_STL_DISABLE_CLANG_WARNINGS
26+
#pragma push_macro("new")
27+
#undef new
28+
29+
template <class _Ty>
30+
using _Std_atomic = _STD atomic<_Ty>;
31+
32+
#define _Atomic(T) _Std_atomic<T>
33+
34+
// clang-format off
35+
using _STD memory_order;
36+
using _STD memory_order_relaxed;
37+
using _STD memory_order_consume;
38+
using _STD memory_order_acquire;
39+
using _STD memory_order_release;
40+
using _STD memory_order_acq_rel;
41+
using _STD memory_order_seq_cst;
42+
43+
using _STD atomic_flag;
44+
45+
using _STD atomic_bool;
46+
using _STD atomic_char;
47+
using _STD atomic_schar;
48+
using _STD atomic_uchar;
49+
using _STD atomic_short;
50+
using _STD atomic_ushort;
51+
using _STD atomic_int;
52+
using _STD atomic_uint;
53+
using _STD atomic_long;
54+
using _STD atomic_ulong;
55+
using _STD atomic_llong;
56+
using _STD atomic_ullong;
57+
58+
#ifdef __cpp_lib_char8_t
59+
using _STD atomic_char8_t;
60+
#endif // __cpp_lib_char8_t
61+
62+
using _STD atomic_char16_t;
63+
using _STD atomic_char32_t;
64+
using _STD atomic_wchar_t;
65+
using _STD atomic_int8_t;
66+
using _STD atomic_uint8_t;
67+
using _STD atomic_int16_t;
68+
using _STD atomic_uint16_t;
69+
using _STD atomic_int32_t;
70+
using _STD atomic_uint32_t;
71+
using _STD atomic_int64_t;
72+
using _STD atomic_uint64_t;
73+
using _STD atomic_int_least8_t;
74+
using _STD atomic_uint_least8_t;
75+
using _STD atomic_int_least16_t;
76+
using _STD atomic_uint_least16_t;
77+
using _STD atomic_int_least32_t;
78+
using _STD atomic_uint_least32_t;
79+
using _STD atomic_int_least64_t;
80+
using _STD atomic_uint_least64_t;
81+
using _STD atomic_int_fast8_t;
82+
using _STD atomic_uint_fast8_t;
83+
using _STD atomic_int_fast16_t;
84+
using _STD atomic_uint_fast16_t;
85+
using _STD atomic_int_fast32_t;
86+
using _STD atomic_uint_fast32_t;
87+
using _STD atomic_int_fast64_t;
88+
using _STD atomic_uint_fast64_t;
89+
using _STD atomic_intptr_t;
90+
using _STD atomic_uintptr_t;
91+
using _STD atomic_size_t;
92+
using _STD atomic_ptrdiff_t;
93+
using _STD atomic_intmax_t;
94+
using _STD atomic_uintmax_t;
95+
96+
using _STD atomic_is_lock_free;
97+
using _STD atomic_load;
98+
using _STD atomic_load_explicit;
99+
using _STD atomic_store;
100+
using _STD atomic_store_explicit;
101+
using _STD atomic_exchange;
102+
using _STD atomic_exchange_explicit;
103+
using _STD atomic_compare_exchange_strong;
104+
using _STD atomic_compare_exchange_strong_explicit;
105+
using _STD atomic_compare_exchange_weak;
106+
using _STD atomic_compare_exchange_weak_explicit;
107+
using _STD atomic_fetch_add;
108+
using _STD atomic_fetch_add_explicit;
109+
using _STD atomic_fetch_sub;
110+
using _STD atomic_fetch_sub_explicit;
111+
using _STD atomic_fetch_or;
112+
using _STD atomic_fetch_or_explicit;
113+
using _STD atomic_fetch_and;
114+
using _STD atomic_fetch_and_explicit;
115+
using _STD atomic_flag_test_and_set;
116+
using _STD atomic_flag_test_and_set_explicit;
117+
using _STD atomic_flag_clear;
118+
using _STD atomic_flag_clear_explicit;
119+
120+
using _STD atomic_thread_fence;
121+
using _STD atomic_signal_fence;
122+
// clang-format on
123+
124+
#pragma pop_macro("new")
125+
_STL_RESTORE_CLANG_WARNINGS
126+
#pragma warning(pop)
127+
#pragma pack(pop)
128+
#endif // ^^^ _HAS_CXX23 ^^^
129+
130+
#endif // _STL_COMPILER_PREPROCESSOR
131+
#endif // _STDATOMIC_H_

stl/inc/yvals_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@
263263

264264
// _HAS_CXX23 directly controls:
265265
// P0401R6 Providing Size Feedback In The Allocator Interface
266+
// P0943R6 Supporting C Atomics In C++
266267
// P1048R1 is_scoped_enum
267268
// P1132R7 out_ptr(), inout_ptr()
268269
// P1425R4 Iterator Pair Constructors For stack And queue
@@ -1365,6 +1366,7 @@
13651366
#define __cpp_lib_out_ptr 202106L
13661367
#endif // __cpp_lib_concepts
13671368

1369+
#define __cpp_lib_stdatomic_h 202011L
13681370
#define __cpp_lib_string_contains 202011L
13691371
#define __cpp_lib_to_underlying 202102L
13701372
#endif // _HAS_CXX23

tests/std/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ tests\P0898R3_concepts
405405
tests\P0898R3_identity
406406
tests\P0912R5_coroutine
407407
tests\P0919R3_heterogeneous_unordered_lookup
408+
tests\P0943R6_stdatomic_h
408409
tests\P0966R1_string_reserve_should_not_shrink
409410
tests\P0980R1_constexpr_strings
410411
tests\P1004R2_constexpr_vector
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\usual_latest_matrix.lst
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#include <stdatomic.h>
5+
6+
static_assert(ATOMIC_BOOL_LOCK_FREE == 2);
7+
static_assert(ATOMIC_CHAR_LOCK_FREE == 2);
8+
static_assert(ATOMIC_CHAR16_T_LOCK_FREE == 2);
9+
static_assert(ATOMIC_CHAR32_T_LOCK_FREE == 2);
10+
static_assert(ATOMIC_WCHAR_T_LOCK_FREE == 2);
11+
static_assert(ATOMIC_SHORT_LOCK_FREE == 2);
12+
static_assert(ATOMIC_INT_LOCK_FREE == 2);
13+
static_assert(ATOMIC_LONG_LOCK_FREE == 2);
14+
static_assert(ATOMIC_LLONG_LOCK_FREE == 2);
15+
static_assert(ATOMIC_POINTER_LOCK_FREE == 2);
16+
17+
#include <atomic>
18+
#include <type_traits>
19+
20+
using std::is_same_v;
21+
22+
static_assert(is_same_v<_Atomic(int), std::atomic<int>>);
23+
static_assert(is_same_v<_Atomic(unsigned int), std::atomic<unsigned int>>);
24+
static_assert(is_same_v<_Atomic(float), std::atomic<float>>);
25+
static_assert(is_same_v<_Atomic(char), std::atomic<char>>);
26+
27+
static_assert(is_same_v<std::memory_order, memory_order>);
28+
static_assert(std::memory_order_relaxed == memory_order_relaxed);
29+
static_assert(std::memory_order_consume == memory_order_consume);
30+
static_assert(std::memory_order_acquire == memory_order_acquire);
31+
static_assert(std::memory_order_release == memory_order_release);
32+
static_assert(std::memory_order_acq_rel == memory_order_acq_rel);
33+
static_assert(std::memory_order_seq_cst == memory_order_seq_cst);
34+
35+
static_assert(is_same_v<std::atomic_flag, atomic_flag>);
36+
37+
static_assert(is_same_v<std::atomic_bool, atomic_bool>);
38+
static_assert(is_same_v<std::atomic_char, atomic_char>);
39+
static_assert(is_same_v<std::atomic_schar, atomic_schar>);
40+
static_assert(is_same_v<std::atomic_uchar, atomic_uchar>);
41+
static_assert(is_same_v<std::atomic_short, atomic_short>);
42+
static_assert(is_same_v<std::atomic_ushort, atomic_ushort>);
43+
static_assert(is_same_v<std::atomic_int, atomic_int>);
44+
static_assert(is_same_v<std::atomic_uint, atomic_uint>);
45+
static_assert(is_same_v<std::atomic_long, atomic_long>);
46+
static_assert(is_same_v<std::atomic_ulong, atomic_ulong>);
47+
static_assert(is_same_v<std::atomic_llong, atomic_llong>);
48+
static_assert(is_same_v<std::atomic_ullong, atomic_ullong>);
49+
50+
#ifdef __cpp_lib_char8_t
51+
static_assert(is_same_v<std::atomic_char8_t, atomic_char8_t>);
52+
#endif // __cpp_lib_char8_t
53+
54+
static_assert(is_same_v<std::atomic_char16_t, atomic_char16_t>);
55+
static_assert(is_same_v<std::atomic_char32_t, atomic_char32_t>);
56+
static_assert(is_same_v<std::atomic_wchar_t, atomic_wchar_t>);
57+
static_assert(is_same_v<std::atomic_int8_t, atomic_int8_t>);
58+
static_assert(is_same_v<std::atomic_uint8_t, atomic_uint8_t>);
59+
static_assert(is_same_v<std::atomic_int16_t, atomic_int16_t>);
60+
static_assert(is_same_v<std::atomic_uint16_t, atomic_uint16_t>);
61+
static_assert(is_same_v<std::atomic_int32_t, atomic_int32_t>);
62+
static_assert(is_same_v<std::atomic_uint32_t, atomic_uint32_t>);
63+
static_assert(is_same_v<std::atomic_int64_t, atomic_int64_t>);
64+
static_assert(is_same_v<std::atomic_uint64_t, atomic_uint64_t>);
65+
static_assert(is_same_v<std::atomic_int_least8_t, atomic_int_least8_t>);
66+
static_assert(is_same_v<std::atomic_uint_least8_t, atomic_uint_least8_t>);
67+
static_assert(is_same_v<std::atomic_int_least16_t, atomic_int_least16_t>);
68+
static_assert(is_same_v<std::atomic_uint_least16_t, atomic_uint_least16_t>);
69+
static_assert(is_same_v<std::atomic_int_least32_t, atomic_int_least32_t>);
70+
static_assert(is_same_v<std::atomic_uint_least32_t, atomic_uint_least32_t>);
71+
static_assert(is_same_v<std::atomic_int_least64_t, atomic_int_least64_t>);
72+
static_assert(is_same_v<std::atomic_uint_least64_t, atomic_uint_least64_t>);
73+
static_assert(is_same_v<std::atomic_int_fast8_t, atomic_int_fast8_t>);
74+
static_assert(is_same_v<std::atomic_uint_fast8_t, atomic_uint_fast8_t>);
75+
static_assert(is_same_v<std::atomic_int_fast16_t, atomic_int_fast16_t>);
76+
static_assert(is_same_v<std::atomic_uint_fast16_t, atomic_uint_fast16_t>);
77+
static_assert(is_same_v<std::atomic_int_fast32_t, atomic_int_fast32_t>);
78+
static_assert(is_same_v<std::atomic_uint_fast32_t, atomic_uint_fast32_t>);
79+
static_assert(is_same_v<std::atomic_int_fast64_t, atomic_int_fast64_t>);
80+
static_assert(is_same_v<std::atomic_uint_fast64_t, atomic_uint_fast64_t>);
81+
static_assert(is_same_v<std::atomic_intptr_t, atomic_intptr_t>);
82+
static_assert(is_same_v<std::atomic_uintptr_t, atomic_uintptr_t>);
83+
static_assert(is_same_v<std::atomic_size_t, atomic_size_t>);
84+
static_assert(is_same_v<std::atomic_ptrdiff_t, atomic_ptrdiff_t>);
85+
static_assert(is_same_v<std::atomic_intmax_t, atomic_intmax_t>);
86+
static_assert(is_same_v<std::atomic_uintmax_t, atomic_uintmax_t>);
87+
88+
namespace test {
89+
using ::atomic_compare_exchange_strong;
90+
using ::atomic_compare_exchange_strong_explicit;
91+
using ::atomic_compare_exchange_weak;
92+
using ::atomic_compare_exchange_weak_explicit;
93+
using ::atomic_exchange;
94+
using ::atomic_exchange_explicit;
95+
using ::atomic_fetch_add;
96+
using ::atomic_fetch_add_explicit;
97+
using ::atomic_fetch_and;
98+
using ::atomic_fetch_and_explicit;
99+
using ::atomic_fetch_or;
100+
using ::atomic_fetch_or_explicit;
101+
using ::atomic_fetch_sub;
102+
using ::atomic_fetch_sub_explicit;
103+
using ::atomic_flag_clear;
104+
using ::atomic_flag_clear_explicit;
105+
using ::atomic_flag_test_and_set;
106+
using ::atomic_flag_test_and_set_explicit;
107+
using ::atomic_is_lock_free;
108+
using ::atomic_load;
109+
using ::atomic_load_explicit;
110+
using ::atomic_store;
111+
using ::atomic_store_explicit;
112+
} // namespace test
113+
114+
static_assert(std::atomic_thread_fence == atomic_thread_fence);
115+
static_assert(std::atomic_signal_fence == atomic_signal_fence);
116+
117+
int main() {} // COMPILE-ONLY

tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,20 @@ STATIC_ASSERT(__cpp_lib_starts_ends_with == 201711L);
14981498
#endif
14991499
#endif
15001500

1501+
#if _HAS_CXX23
1502+
#ifndef __cpp_lib_stdatomic_h
1503+
#error __cpp_lib_stdatomic_h is not defined
1504+
#elif __cpp_lib_stdatomic_h != 202011L
1505+
#error __cpp_lib_stdatomic_h is not 202011L
1506+
#else
1507+
STATIC_ASSERT(__cpp_lib_stdatomic_h == 202011L);
1508+
#endif
1509+
#else
1510+
#ifdef __cpp_lib_stdatomic_h
1511+
#error __cpp_lib_stdatomic_h is defined
1512+
#endif
1513+
#endif
1514+
15011515
#if _HAS_CXX23
15021516
#ifndef __cpp_lib_string_contains
15031517
#error __cpp_lib_string_contains is not defined

tests/std/tests/include_each_header_alone_matrix.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ PM_CL="/DMEOW_HEADER=source_location"
6464
PM_CL="/DMEOW_HEADER=span"
6565
PM_CL="/DMEOW_HEADER=sstream"
6666
PM_CL="/DMEOW_HEADER=stack"
67+
PM_CL="/DMEOW_HEADER=stdatomic.h"
6768
PM_CL="/DMEOW_HEADER=stdexcept"
6869
PM_CL="/DMEOW_HEADER=stop_token"
6970
PM_CL="/DMEOW_HEADER=streambuf"

0 commit comments

Comments
 (0)