[libcxx-commits] [libcxx] 5d1c1a2 - [libc++] [C++2b] [P0943] Add stdatomic.h header.
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Feb 14 13:39:27 PST 2022
Author: Marek Kurdej
Date: 2022-02-14T16:39:22-05:00
New Revision: 5d1c1a243c4d60249444189526ac63ced7ae999c
URL: https://github.com/llvm/llvm-project/commit/5d1c1a243c4d60249444189526ac63ced7ae999c
DIFF: https://github.com/llvm/llvm-project/commit/5d1c1a243c4d60249444189526ac63ced7ae999c.diff
LOG: [libc++] [C++2b] [P0943] Add stdatomic.h header.
* https://wg21.link/P0943
* https://eel.is/c++draft/stdatomic.h.syn
Differential Revision: https://reviews.llvm.org/D97044
Added:
libcxx/include/stdatomic.h
libcxx/test/libcxx/atomics/stdatomic.h.syn/dont_hijack_header.compile.pass.cpp
libcxx/test/std/atomics/stdatomic.h.syn/types.compile.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/stdatomic.h.version.pass.cpp
Modified:
libcxx/docs/FeatureTestMacroTable.rst
libcxx/docs/Status/Cxx2bPapers.csv
libcxx/include/CMakeLists.txt
libcxx/include/atomic
libcxx/include/module.modulemap
libcxx/include/version
libcxx/test/libcxx/double_include.sh.cpp
libcxx/test/libcxx/min_max_macros.compile.pass.cpp
libcxx/test/libcxx/nasty_macros.compile.pass.cpp
libcxx/test/libcxx/no_assert_include.compile.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
libcxx/utils/generate_feature_test_macro_components.py
libcxx/utils/generate_header_tests.py
Removed:
################################################################################
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 8877ec0a48bc6..a6c658c0ac188 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -342,7 +342,7 @@ Status
------------------------------------------------- -----------------
``__cpp_lib_stacktrace`` *unimplemented*
------------------------------------------------- -----------------
- ``__cpp_lib_stdatomic_h`` *unimplemented*
+ ``__cpp_lib_stdatomic_h`` ``202011L``
------------------------------------------------- -----------------
``__cpp_lib_string_contains`` ``202011L``
------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv
index c0ef6882a5135..12fb513237591 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -1,6 +1,6 @@
"Paper #","Group","Paper Name","Meeting","Status","First released version"
"`P0881R7 <https://wg21.link/P0881R7>`__","LWG","A Proposal to add stacktrace library","Autumn 2020","",""
-"`P0943R6 <https://wg21.link/P0943R6>`__","LWG","Support C atomics in C++","Autumn 2020","",""
+"`P0943R6 <https://wg21.link/P0943R6>`__","LWG","Support C atomics in C++","Autumn 2020","|Complete|","15.0"
"`P1048R1 <https://wg21.link/P1048R1>`__","LWG","A proposal for a type trait to detect scoped enumerations","Autumn 2020","|Complete|","12.0"
"`P1679R3 <https://wg21.link/P1679R3>`__","LWG","string contains function","Autumn 2020","|Complete|","12.0"
"","","","","",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fb2b5be63510a..d463d208566d9 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -517,6 +517,7 @@ set(files
span
sstream
stack
+ stdatomic.h
stdbool.h
stddef.h
stdexcept
diff --git a/libcxx/include/atomic b/libcxx/include/atomic
index 7fed8713e03a7..a58a44a3fd59a 100644
--- a/libcxx/include/atomic
+++ b/libcxx/include/atomic
@@ -540,7 +540,7 @@ template <class T>
# error <atomic> is not implemented
#endif
#ifdef kill_dependency
-# error C++ standard library is incompatible with <stdatomic.h>
+# error C++ standard library is incompatible with <stdatomic.h> before C++23. Please compile with -std=c++23.
#endif
#define _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) \
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 95ff1ecddd69f..b958737645144 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -50,6 +50,10 @@ module std [system] {
header "setjmp.h"
export *
}
+ module stdatomic_h {
+ header "stdatomic.h"
+ export *
+ }
// FIXME: <stdalign.h> is missing.
// <signal.h> provided by C library.
// <stdarg.h> provided by compiler.
diff --git a/libcxx/include/stdatomic.h b/libcxx/include/stdatomic.h
new file mode 100644
index 0000000000000..d9550c44061c5
--- /dev/null
+++ b/libcxx/include/stdatomic.h
@@ -0,0 +1,235 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_STDATOMIC_H
+#define _LIBCPP_STDATOMIC_H
+
+/*
+ stdatomic.h synopsis
+
+template<class T>
+ using std-atomic = std::atomic<T>; // exposition only
+
+#define _Atomic(T) std-atomic<T>
+
+#define ATOMIC_BOOL_LOCK_FREE see below
+#define ATOMIC_CHAR_LOCK_FREE see below
+#define ATOMIC_CHAR16_T_LOCK_FREE see below
+#define ATOMIC_CHAR32_T_LOCK_FREE see below
+#define ATOMIC_WCHAR_T_LOCK_FREE see below
+#define ATOMIC_SHORT_LOCK_FREE see below
+#define ATOMIC_INT_LOCK_FREE see below
+#define ATOMIC_LONG_LOCK_FREE see below
+#define ATOMIC_LLONG_LOCK_FREE see below
+#define ATOMIC_POINTER_LOCK_FREE see below
+
+using std::memory_order // see below
+using std::memory_order_relaxed // see below
+using std::memory_order_consume // see below
+using std::memory_order_acquire // see below
+using std::memory_order_release // see below
+using std::memory_order_acq_rel // see below
+using std::memory_order_seq_cst // see below
+
+using std::atomic_flag // see below
+
+using std::atomic_bool // see below
+using std::atomic_char // see below
+using std::atomic_schar // see below
+using std::atomic_uchar // see below
+using std::atomic_short // see below
+using std::atomic_ushort // see below
+using std::atomic_int // see below
+using std::atomic_uint // see below
+using std::atomic_long // see below
+using std::atomic_ulong // see below
+using std::atomic_llong // see below
+using std::atomic_ullong // see below
+using std::atomic_char8_t // see below
+using std::atomic_char16_t // see below
+using std::atomic_char32_t // see below
+using std::atomic_wchar_t // see below
+using std::atomic_int8_t // see below
+using std::atomic_uint8_t // see below
+using std::atomic_int16_t // see below
+using std::atomic_uint16_t // see below
+using std::atomic_int32_t // see below
+using std::atomic_uint32_t // see below
+using std::atomic_int64_t // see below
+using std::atomic_uint64_t // see below
+using std::atomic_int_least8_t // see below
+using std::atomic_uint_least8_t // see below
+using std::atomic_int_least16_t // see below
+using std::atomic_uint_least16_t // see below
+using std::atomic_int_least32_t // see below
+using std::atomic_uint_least32_t // see below
+using std::atomic_int_least64_t // see below
+using std::atomic_uint_least64_t // see below
+using std::atomic_int_fast8_t // see below
+using std::atomic_uint_fast8_t // see below
+using std::atomic_int_fast16_t // see below
+using std::atomic_uint_fast16_t // see below
+using std::atomic_int_fast32_t // see below
+using std::atomic_uint_fast32_t // see below
+using std::atomic_int_fast64_t // see below
+using std::atomic_uint_fast64_t // see below
+using std::atomic_intptr_t // see below
+using std::atomic_uintptr_t // see below
+using std::atomic_size_t // see below
+using std::atomic_ptr
diff _t // see below
+using std::atomic_intmax_t // see below
+using std::atomic_uintmax_t // see below
+
+using std::atomic_is_lock_free // see below
+using std::atomic_load // see below
+using std::atomic_load_explicit // see below
+using std::atomic_store // see below
+using std::atomic_store_explicit // see below
+using std::atomic_exchange // see below
+using std::atomic_exchange_explicit // see below
+using std::atomic_compare_exchange_strong // see below
+using std::atomic_compare_exchange_strong_explicit // see below
+using std::atomic_compare_exchange_weak // see below
+using std::atomic_compare_exchange_weak_explicit // see below
+using std::atomic_fetch_add // see below
+using std::atomic_fetch_add_explicit // see below
+using std::atomic_fetch_sub // see below
+using std::atomic_fetch_sub_explicit // see below
+using std::atomic_fetch_or // see below
+using std::atomic_fetch_or_explicit // see below
+using std::atomic_fetch_and // see below
+using std::atomic_fetch_and_explicit // see below
+using std::atomic_flag_test_and_set // see below
+using std::atomic_flag_test_and_set_explicit // see below
+using std::atomic_flag_clear // see below
+using std::atomic_flag_clear_explicit // see below
+
+using std::atomic_thread_fence // see below
+using std::atomic_signal_fence // see below
+
+*/
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER > 20
+
+#include <atomic>
+#include <version>
+
+#ifdef _Atomic
+# undef _Atomic
+#endif
+
+#define _Atomic(_Tp) ::std::atomic<_Tp>
+
+using std::memory_order _LIBCPP_USING_IF_EXISTS;
+using std::memory_order_relaxed _LIBCPP_USING_IF_EXISTS;
+using std::memory_order_consume _LIBCPP_USING_IF_EXISTS;
+using std::memory_order_acquire _LIBCPP_USING_IF_EXISTS;
+using std::memory_order_release _LIBCPP_USING_IF_EXISTS;
+using std::memory_order_acq_rel _LIBCPP_USING_IF_EXISTS;
+using std::memory_order_seq_cst _LIBCPP_USING_IF_EXISTS;
+
+using std::atomic_flag _LIBCPP_USING_IF_EXISTS;
+
+using std::atomic_bool _LIBCPP_USING_IF_EXISTS;
+using std::atomic_char _LIBCPP_USING_IF_EXISTS;
+using std::atomic_schar _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uchar _LIBCPP_USING_IF_EXISTS;
+using std::atomic_short _LIBCPP_USING_IF_EXISTS;
+using std::atomic_ushort _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint _LIBCPP_USING_IF_EXISTS;
+using std::atomic_long _LIBCPP_USING_IF_EXISTS;
+using std::atomic_ulong _LIBCPP_USING_IF_EXISTS;
+using std::atomic_llong _LIBCPP_USING_IF_EXISTS;
+using std::atomic_ullong _LIBCPP_USING_IF_EXISTS;
+using std::atomic_char8_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_char16_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_char32_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_wchar_t _LIBCPP_USING_IF_EXISTS;
+
+using std::atomic_int8_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint8_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int16_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint16_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int32_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint32_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int64_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint64_t _LIBCPP_USING_IF_EXISTS;
+
+using std::atomic_int_least8_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint_least8_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int_least16_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint_least16_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int_least32_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint_least32_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int_least64_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint_least64_t _LIBCPP_USING_IF_EXISTS;
+
+using std::atomic_int_fast8_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint_fast8_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int_fast16_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint_fast16_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int_fast32_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint_fast32_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_int_fast64_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uint_fast64_t _LIBCPP_USING_IF_EXISTS;
+
+using std::atomic_intptr_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uintptr_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_size_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_ptr
diff _t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_intmax_t _LIBCPP_USING_IF_EXISTS;
+using std::atomic_uintmax_t _LIBCPP_USING_IF_EXISTS;
+
+using std::atomic_compare_exchange_strong _LIBCPP_USING_IF_EXISTS;
+using std::atomic_compare_exchange_strong_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_compare_exchange_weak _LIBCPP_USING_IF_EXISTS;
+using std::atomic_compare_exchange_weak_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_exchange _LIBCPP_USING_IF_EXISTS;
+using std::atomic_exchange_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_fetch_add _LIBCPP_USING_IF_EXISTS;
+using std::atomic_fetch_add_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_fetch_and _LIBCPP_USING_IF_EXISTS;
+using std::atomic_fetch_and_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_fetch_or _LIBCPP_USING_IF_EXISTS;
+using std::atomic_fetch_or_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_fetch_sub _LIBCPP_USING_IF_EXISTS;
+using std::atomic_fetch_sub_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_flag_clear _LIBCPP_USING_IF_EXISTS;
+using std::atomic_flag_clear_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_flag_test_and_set _LIBCPP_USING_IF_EXISTS;
+using std::atomic_flag_test_and_set_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_is_lock_free _LIBCPP_USING_IF_EXISTS;
+using std::atomic_load _LIBCPP_USING_IF_EXISTS;
+using std::atomic_load_explicit _LIBCPP_USING_IF_EXISTS;
+using std::atomic_store _LIBCPP_USING_IF_EXISTS;
+using std::atomic_store_explicit _LIBCPP_USING_IF_EXISTS;
+
+using std::atomic_signal_fence _LIBCPP_USING_IF_EXISTS;
+using std::atomic_thread_fence _LIBCPP_USING_IF_EXISTS;
+
+#elif defined(_LIBCPP_COMPILER_CLANG_BASED)
+
+// Before C++23, we include the next <stdatomic.h> on the path to avoid hijacking
+// the header. We do this because Clang has historically shipped a <stdatomic.h>
+// header that would be available in all Standard modes, and we don't want to
+// break that use case.
+# if __has_include_next(<stdatomic.h>)
+# include_next <stdatomic.h>
+# endif
+
+#endif // _LIBCPP_STD_VER > 20
+
+#endif // _LIBCPP_STDATOMIC_H
diff --git a/libcxx/include/version b/libcxx/include/version
index 3aed750c6ec50..5cbe474150ee8 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -396,7 +396,7 @@ __cpp_lib_void_t 201411L <type_traits>
// # define __cpp_lib_reference_from_temporary 202202L
// # define __cpp_lib_spanstream 202106L
// # define __cpp_lib_stacktrace 202011L
-// # define __cpp_lib_stdatomic_h 202011L
+# define __cpp_lib_stdatomic_h 202011L
# define __cpp_lib_string_contains 202011L
# define __cpp_lib_string_resize_and_overwrite 202110L
# define __cpp_lib_to_underlying 202102L
diff --git a/libcxx/test/libcxx/atomics/stdatomic.h.syn/dont_hijack_header.compile.pass.cpp b/libcxx/test/libcxx/atomics/stdatomic.h.syn/dont_hijack_header.compile.pass.cpp
new file mode 100644
index 0000000000000..f00c3efa8cf75
--- /dev/null
+++ b/libcxx/test/libcxx/atomics/stdatomic.h.syn/dont_hijack_header.compile.pass.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: libcpp-has-no-threads
+
+// This test ensures that we don't hijack the <stdatomic.h> header even when compiling
+// before C++23, since Clang used to provide that header before libc++ provided one.
+
+// On GCC, the compiler-provided <stdatomic.h> is not C++ friendly, so including <stdatomic.h>
+// doesn't work at all if we don't use the <stdatomic.h> provided by libc++ in C++23 and above.
+// XFAIL: (c++11 || c++14 || c++17 || c++20) && gcc
+
+#include <stdatomic.h>
+
+void f() {
+ atomic_int i; // just make sure the header isn't empty
+ (void)i;
+}
diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp
index 6e2c2ab0e6f9e..7eda8fccfefd8 100644
--- a/libcxx/test/libcxx/double_include.sh.cpp
+++ b/libcxx/test/libcxx/double_include.sh.cpp
@@ -165,6 +165,9 @@
# include <sstream>
#endif
#include <stack>
+#ifndef _LIBCPP_HAS_NO_THREADS
+# include <stdatomic.h>
+#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdexcept>
diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp
index 4bde1336de026..2ff617a73319b 100644
--- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp
+++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp
@@ -254,6 +254,10 @@ TEST_MACROS();
#endif
#include <stack>
TEST_MACROS();
+#ifndef _LIBCPP_HAS_NO_THREADS
+# include <stdatomic.h>
+TEST_MACROS();
+#endif
#include <stdbool.h>
TEST_MACROS();
#include <stddef.h>
diff --git a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp
index d94e3b3a54ec8..70855513ea750 100644
--- a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp
+++ b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp
@@ -275,6 +275,9 @@
# include <sstream>
#endif
#include <stack>
+#ifndef _LIBCPP_HAS_NO_THREADS
+# include <stdatomic.h>
+#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdexcept>
diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp
index 37e88f7db0c4b..34e0b677ef4a7 100644
--- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp
+++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp
@@ -160,6 +160,9 @@
# include <sstream>
#endif
#include <stack>
+#ifndef _LIBCPP_HAS_NO_THREADS
+# include <stdatomic.h>
+#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdexcept>
diff --git a/libcxx/test/std/atomics/stdatomic.h.syn/types.compile.pass.cpp b/libcxx/test/std/atomics/stdatomic.h.syn/types.compile.pass.cpp
new file mode 100644
index 0000000000000..82ee041902f9a
--- /dev/null
+++ b/libcxx/test/std/atomics/stdatomic.h.syn/types.compile.pass.cpp
@@ -0,0 +1,237 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: libcpp-has-no-threads
+
+// <stdatomic.h>
+
+// template<class T>
+// using std-atomic = std::atomic<T>; // exposition only
+//
+// #define _Atomic(T) std-atomic<T>
+//
+// #define ATOMIC_BOOL_LOCK_FREE see below
+// #define ATOMIC_CHAR_LOCK_FREE see below
+// #define ATOMIC_CHAR16_T_LOCK_FREE see below
+// #define ATOMIC_CHAR32_T_LOCK_FREE see below
+// #define ATOMIC_WCHAR_T_LOCK_FREE see below
+// #define ATOMIC_SHORT_LOCK_FREE see below
+// #define ATOMIC_INT_LOCK_FREE see below
+// #define ATOMIC_LONG_LOCK_FREE see below
+// #define ATOMIC_LLONG_LOCK_FREE see below
+// #define ATOMIC_POINTER_LOCK_FREE see below
+//
+// using std::memory_order // see below
+// using std::memory_order_relaxed // see below
+// using std::memory_order_consume // see below
+// using std::memory_order_acquire // see below
+// using std::memory_order_release // see below
+// using std::memory_order_acq_rel // see below
+// using std::memory_order_seq_cst // see below
+//
+// using std::atomic_flag // see below
+//
+// using std::atomic_bool // see below
+// using std::atomic_char // see below
+// using std::atomic_schar // see below
+// using std::atomic_uchar // see below
+// using std::atomic_short // see below
+// using std::atomic_ushort // see below
+// using std::atomic_int // see below
+// using std::atomic_uint // see below
+// using std::atomic_long // see below
+// using std::atomic_ulong // see below
+// using std::atomic_llong // see below
+// using std::atomic_ullong // see below
+// using std::atomic_char8_t // see below
+// using std::atomic_char16_t // see below
+// using std::atomic_char32_t // see below
+// using std::atomic_wchar_t // see below
+// using std::atomic_int8_t // see below
+// using std::atomic_uint8_t // see below
+// using std::atomic_int16_t // see below
+// using std::atomic_uint16_t // see below
+// using std::atomic_int32_t // see below
+// using std::atomic_uint32_t // see below
+// using std::atomic_int64_t // see below
+// using std::atomic_uint64_t // see below
+// using std::atomic_int_least8_t // see below
+// using std::atomic_uint_least8_t // see below
+// using std::atomic_int_least16_t // see below
+// using std::atomic_uint_least16_t // see below
+// using std::atomic_int_least32_t // see below
+// using std::atomic_uint_least32_t // see below
+// using std::atomic_int_least64_t // see below
+// using std::atomic_uint_least64_t // see below
+// using std::atomic_int_fast8_t // see below
+// using std::atomic_uint_fast8_t // see below
+// using std::atomic_int_fast16_t // see below
+// using std::atomic_uint_fast16_t // see below
+// using std::atomic_int_fast32_t // see below
+// using std::atomic_uint_fast32_t // see below
+// using std::atomic_int_fast64_t // see below
+// using std::atomic_uint_fast64_t // see below
+// using std::atomic_intptr_t // see below
+// using std::atomic_uintptr_t // see below
+// using std::atomic_size_t // see below
+// using std::atomic_ptr
diff _t // see below
+// using std::atomic_intmax_t // see below
+// using std::atomic_uintmax_t // see below
+//
+// using std::atomic_is_lock_free // see below
+// using std::atomic_load // see below
+// using std::atomic_load_explicit // see below
+// using std::atomic_store // see below
+// using std::atomic_store_explicit // see below
+// using std::atomic_exchange // see below
+// using std::atomic_exchange_explicit // see below
+// using std::atomic_compare_exchange_strong // see below
+// using std::atomic_compare_exchange_strong_explicit // see below
+// using std::atomic_compare_exchange_weak // see below
+// using std::atomic_compare_exchange_weak_explicit // see below
+// using std::atomic_fetch_add // see below
+// using std::atomic_fetch_add_explicit // see below
+// using std::atomic_fetch_sub // see below
+// using std::atomic_fetch_sub_explicit // see below
+// using std::atomic_fetch_or // see below
+// using std::atomic_fetch_or_explicit // see below
+// using std::atomic_fetch_and // see below
+// using std::atomic_fetch_and_explicit // see below
+// using std::atomic_flag_test_and_set // see below
+// using std::atomic_flag_test_and_set_explicit // see below
+// using std::atomic_flag_clear // see below
+// using std::atomic_flag_clear_explicit // see below
+//
+// using std::atomic_thread_fence // see below
+// using std::atomic_signal_fence // see below
+
+#include <stdatomic.h>
+#include <type_traits>
+
+#include "test_macros.h"
+
+static_assert(std::atomic<bool>::is_always_lock_free == (2 == ATOMIC_BOOL_LOCK_FREE));
+static_assert(std::atomic<char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE));
+static_assert(std::atomic<signed char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE));
+static_assert(std::atomic<unsigned char>::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE));
+static_assert(std::atomic<char16_t>::is_always_lock_free == (2 == ATOMIC_CHAR16_T_LOCK_FREE));
+static_assert(std::atomic<char32_t>::is_always_lock_free == (2 == ATOMIC_CHAR32_T_LOCK_FREE));
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::atomic<wchar_t>::is_always_lock_free == (2 == ATOMIC_WCHAR_T_LOCK_FREE));
+#endif
+static_assert(std::atomic<short>::is_always_lock_free == (2 == ATOMIC_SHORT_LOCK_FREE));
+static_assert(std::atomic<unsigned short>::is_always_lock_free == (2 == ATOMIC_SHORT_LOCK_FREE));
+static_assert(std::atomic<int>::is_always_lock_free == (2 == ATOMIC_INT_LOCK_FREE));
+static_assert(std::atomic<unsigned int>::is_always_lock_free == (2 == ATOMIC_INT_LOCK_FREE));
+static_assert(std::atomic<long>::is_always_lock_free == (2 == ATOMIC_LONG_LOCK_FREE));
+static_assert(std::atomic<unsigned long>::is_always_lock_free == (2 == ATOMIC_LONG_LOCK_FREE));
+static_assert(std::atomic<long long>::is_always_lock_free == (2 == ATOMIC_LLONG_LOCK_FREE));
+static_assert(std::atomic<unsigned long long>::is_always_lock_free == (2 == ATOMIC_LLONG_LOCK_FREE));
+static_assert(std::atomic<void*>::is_always_lock_free == (2 == ATOMIC_POINTER_LOCK_FREE));
+static_assert(std::atomic<std::nullptr_t>::is_always_lock_free == (2 == ATOMIC_POINTER_LOCK_FREE));
+
+void f() {
+ static_assert(std::is_same_v<std::atomic<char>, _Atomic(char)>);
+ static_assert(std::is_same_v<std::atomic<int>, _Atomic(int)>);
+ static_assert(std::is_same_v<std::atomic<const long>, _Atomic(const long)>);
+
+ static_assert(std::is_same_v<std::memory_order, ::memory_order>);
+ static_assert(&std::memory_order_relaxed == &::memory_order_relaxed);
+ static_assert(&std::memory_order_consume == &::memory_order_consume);
+ static_assert(&std::memory_order_acquire == &::memory_order_acquire);
+ static_assert(&std::memory_order_release == &::memory_order_release);
+ static_assert(&std::memory_order_acq_rel == &::memory_order_acq_rel);
+ static_assert(&std::memory_order_seq_cst == &::memory_order_seq_cst);
+
+ static_assert(std::is_same_v<std::atomic_flag, ::atomic_flag>);
+
+ static_assert(std::is_same_v<std::atomic<bool>, ::atomic_bool>);
+ static_assert(std::is_same_v<std::atomic<char>, ::atomic_char>);
+ static_assert(std::is_same_v<std::atomic<signed char>, ::atomic_schar>);
+ static_assert(std::is_same_v<std::atomic<unsigned char>, ::atomic_uchar>);
+ static_assert(std::is_same_v<std::atomic<short>, ::atomic_short>);
+ static_assert(std::is_same_v<std::atomic<unsigned short>, ::atomic_ushort>);
+ static_assert(std::is_same_v<std::atomic<int>, ::atomic_int>);
+ static_assert(std::is_same_v<std::atomic<unsigned int>, ::atomic_uint>);
+ static_assert(std::is_same_v<std::atomic<long>, ::atomic_long>);
+ static_assert(std::is_same_v<std::atomic<unsigned long>, ::atomic_ulong>);
+ static_assert(std::is_same_v<std::atomic<long long>, ::atomic_llong>);
+ static_assert(std::is_same_v<std::atomic<unsigned long long>, ::atomic_ullong>);
+
+#ifndef _LIBCPP_HAS_NO_CHAR8_T
+ static_assert(std::is_same_v<std::atomic<char8_t>, ::atomic_char8_t>);
+#endif
+ static_assert(std::is_same_v<std::atomic<char16_t>, ::atomic_char16_t>);
+ static_assert(std::is_same_v<std::atomic<char32_t>, ::atomic_char32_t>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ static_assert(std::is_same_v<std::atomic<wchar_t>, ::atomic_wchar_t>);
+#endif
+
+ static_assert(std::is_same_v<std::atomic<int8_t>, ::atomic_int8_t>);
+ static_assert(std::is_same_v<std::atomic<uint8_t>, ::atomic_uint8_t>);
+ static_assert(std::is_same_v<std::atomic<int16_t>, ::atomic_int16_t>);
+ static_assert(std::is_same_v<std::atomic<uint16_t>, ::atomic_uint16_t>);
+ static_assert(std::is_same_v<std::atomic<int32_t>, ::atomic_int32_t>);
+ static_assert(std::is_same_v<std::atomic<uint32_t>, ::atomic_uint32_t>);
+ static_assert(std::is_same_v<std::atomic<int64_t>, ::atomic_int64_t>);
+ static_assert(std::is_same_v<std::atomic<uint64_t>, ::atomic_uint64_t>);
+
+ static_assert(std::is_same_v<std::atomic<int_least8_t>, ::atomic_int_least8_t>);
+ static_assert(std::is_same_v<std::atomic<uint_least8_t>, ::atomic_uint_least8_t>);
+ static_assert(std::is_same_v<std::atomic<int_least16_t>, ::atomic_int_least16_t>);
+ static_assert(std::is_same_v<std::atomic<uint_least16_t>, ::atomic_uint_least16_t>);
+ static_assert(std::is_same_v<std::atomic<int_least32_t>, ::atomic_int_least32_t>);
+ static_assert(std::is_same_v<std::atomic<uint_least32_t>, ::atomic_uint_least32_t>);
+ static_assert(std::is_same_v<std::atomic<int_least64_t>, ::atomic_int_least64_t>);
+ static_assert(std::is_same_v<std::atomic<uint_least64_t>, ::atomic_uint_least64_t>);
+
+ static_assert(std::is_same_v<std::atomic<int_fast8_t>, ::atomic_int_fast8_t>);
+ static_assert(std::is_same_v<std::atomic<uint_fast8_t>, ::atomic_uint_fast8_t>);
+ static_assert(std::is_same_v<std::atomic<int_fast16_t>, ::atomic_int_fast16_t>);
+ static_assert(std::is_same_v<std::atomic<uint_fast16_t>, ::atomic_uint_fast16_t>);
+ static_assert(std::is_same_v<std::atomic<int_fast32_t>, ::atomic_int_fast32_t>);
+ static_assert(std::is_same_v<std::atomic<uint_fast32_t>, ::atomic_uint_fast32_t>);
+ static_assert(std::is_same_v<std::atomic<int_fast64_t>, ::atomic_int_fast64_t>);
+ static_assert(std::is_same_v<std::atomic<uint_fast64_t>, ::atomic_uint_fast64_t>);
+
+ static_assert(std::is_same_v<std::atomic<intptr_t>, ::atomic_intptr_t>);
+ static_assert(std::is_same_v<std::atomic<uintptr_t>, ::atomic_uintptr_t>);
+ static_assert(std::is_same_v<std::atomic<size_t>, ::atomic_size_t>);
+ static_assert(std::is_same_v<std::atomic<ptr
diff _t>, ::atomic_ptr
diff _t>);
+ static_assert(std::is_same_v<std::atomic<intmax_t>, ::atomic_intmax_t>);
+ static_assert(std::is_same_v<std::atomic<uintmax_t>, ::atomic_uintmax_t>);
+
+ // Just check that the symbols in the global namespace are visible.
+ using ::atomic_compare_exchange_strong;
+ using ::atomic_compare_exchange_strong_explicit;
+ using ::atomic_compare_exchange_weak;
+ using ::atomic_compare_exchange_weak_explicit;
+ using ::atomic_exchange;
+ using ::atomic_exchange_explicit;
+ using ::atomic_fetch_add;
+ using ::atomic_fetch_add_explicit;
+ using ::atomic_fetch_and;
+ using ::atomic_fetch_and_explicit;
+ using ::atomic_fetch_or;
+ using ::atomic_fetch_or_explicit;
+ using ::atomic_fetch_sub;
+ using ::atomic_fetch_sub_explicit;
+ using ::atomic_flag_clear;
+ using ::atomic_flag_clear_explicit;
+ using ::atomic_flag_test_and_set;
+ using ::atomic_flag_test_and_set_explicit;
+ using ::atomic_is_lock_free;
+ using ::atomic_load;
+ using ::atomic_load_explicit;
+ using ::atomic_store;
+ using ::atomic_store_explicit;
+
+ using ::atomic_signal_fence;
+ using ::atomic_thread_fence;
+}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/stdatomic.h.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/stdatomic.h.version.pass.cpp
new file mode 100644
index 0000000000000..8c55b8c6a18e7
--- /dev/null
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/stdatomic.h.version.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// WARNING: This test was generated by generate_feature_test_macro_components.py
+// and should not be edited manually.
+//
+// clang-format off
+
+// UNSUPPORTED: libcpp-has-no-threads
+
+// <stdatomic.h>
+
+// Test the feature test macros defined by <stdatomic.h>
+
+/* Constant Value
+ __cpp_lib_stdatomic_h 202011L [C++2b]
+*/
+
+#include <stdatomic.h>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 14
+
+# ifdef __cpp_lib_stdatomic_h
+# error "__cpp_lib_stdatomic_h should not be defined before c++2b"
+# endif
+
+#elif TEST_STD_VER == 14
+
+# ifdef __cpp_lib_stdatomic_h
+# error "__cpp_lib_stdatomic_h should not be defined before c++2b"
+# endif
+
+#elif TEST_STD_VER == 17
+
+# ifdef __cpp_lib_stdatomic_h
+# error "__cpp_lib_stdatomic_h should not be defined before c++2b"
+# endif
+
+#elif TEST_STD_VER == 20
+
+# ifdef __cpp_lib_stdatomic_h
+# error "__cpp_lib_stdatomic_h should not be defined before c++2b"
+# endif
+
+#elif TEST_STD_VER > 20
+
+# ifndef __cpp_lib_stdatomic_h
+# error "__cpp_lib_stdatomic_h should be defined in c++2b"
+# endif
+# if __cpp_lib_stdatomic_h != 202011L
+# error "__cpp_lib_stdatomic_h should have the value 202011L in c++2b"
+# endif
+
+#endif // TEST_STD_VER > 20
+
+int main(int, char**) { return 0; }
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
index d69ae81d33f96..43df8d7dc8330 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
@@ -4848,17 +4848,11 @@
# error "__cpp_lib_starts_ends_with should have the value 201711L in c++2b"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_stdatomic_h
-# error "__cpp_lib_stdatomic_h should be defined in c++2b"
-# endif
-# if __cpp_lib_stdatomic_h != 202011L
-# error "__cpp_lib_stdatomic_h should have the value 202011L in c++2b"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_stdatomic_h
-# error "__cpp_lib_stdatomic_h should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_stdatomic_h
+# error "__cpp_lib_stdatomic_h should be defined in c++2b"
+# endif
+# if __cpp_lib_stdatomic_h != 202011L
+# error "__cpp_lib_stdatomic_h should have the value 202011L in c++2b"
# endif
# ifndef __cpp_lib_string_contains
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index f2140ed41f1d0..1daaea005210a 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -664,7 +664,6 @@ def add_version_header(tc):
"name": "__cpp_lib_stdatomic_h",
"values": { "c++2b": 202011 },
"headers": ["stdatomic.h"],
- "unimplemented": True,
}, {
"name": "__cpp_lib_string_contains",
"values": { "c++2b": 202011 },
@@ -786,7 +785,8 @@ def add_version_header(tc):
"regex": ["UNSUPPORTED: libcpp-has-no-localization"],
"semaphore": ["UNSUPPORTED: libcpp-has-no-threads"],
"shared_mutex": ["UNSUPPORTED: libcpp-has-no-threads"],
- "thread": ["UNSUPPORTED: libcpp-has-no-threads"]
+ "stdatomic.h": ["UNSUPPORTED: libcpp-has-no-threads"],
+ "thread": ["UNSUPPORTED: libcpp-has-no-threads"],
}
def get_std_dialects():
diff --git a/libcxx/utils/generate_header_tests.py b/libcxx/utils/generate_header_tests.py
index 55bbc58e39b5c..6783972e119fd 100755
--- a/libcxx/utils/generate_header_tests.py
+++ b/libcxx/utils/generate_header_tests.py
@@ -27,6 +27,7 @@ def get_libcxx_paths():
"mutex": ["ifndef _LIBCPP_HAS_NO_THREADS"],
"semaphore": ["ifndef _LIBCPP_HAS_NO_THREADS"],
"shared_mutex": ["ifndef _LIBCPP_HAS_NO_THREADS"],
+ "stdatomic.h": ["ifndef _LIBCPP_HAS_NO_THREADS"],
"thread": ["ifndef _LIBCPP_HAS_NO_THREADS"],
"filesystem": ["ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY"],
More information about the libcxx-commits
mailing list