[libcxx-commits] [libcxx] 586efd5 - [libc++][P0943] Add stdatomic.h header.

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Fri May 6 06:52:57 PDT 2022


Author: Louis Dionne
Date: 2022-05-06T09:52:48-04:00
New Revision: 586efd52b93f083d095bf3319da7e42f221c3f4a

URL: https://github.com/llvm/llvm-project/commit/586efd52b93f083d095bf3319da7e42f221c3f4a
DIFF: https://github.com/llvm/llvm-project/commit/586efd52b93f083d095bf3319da7e42f221c3f4a.diff

LOG: [libc++][P0943] Add stdatomic.h header.

* https://wg21.link/P0943
* https://eel.is/c++draft/stdatomic.h.syn

This is a re-application of 5d1c1a24, which was reverted in 987c7f407
because it broke the LLDB build.

Co-authored-by: Marek Kurdej <marek.kurdej at gmail.com>

Differential Revision: https://reviews.llvm.org/D97044

Added: 
    libcxx/include/stdatomic.h
    libcxx/test/libcxx/atomics/atomics.syn/incompatible_with_stdatomic.verify.cpp
    libcxx/test/libcxx/atomics/stdatomic.h.syn/dont_hijack_header.compile.pass.cpp
    libcxx/test/libcxx/atomics/stdatomic.h.syn/incompatible_with_atomic.verify.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.compile.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/assertions/headers_declare_assertion_handler.sh.cpp
    libcxx/test/libcxx/clang_tidy.sh.cpp
    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.compile.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 4f2ce96427a1c..5d82ad26aca73 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -344,7 +344,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 4aad9a6d66785..15531dff1e481 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 b79f286a71994..6069704fcf071 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -563,6 +563,7 @@ set(files
   span
   sstream
   stack
+  stdatomic.h
   stdbool.h
   stddef.h
   stdexcept

diff  --git a/libcxx/include/atomic b/libcxx/include/atomic
index b5c6e5182a4f2..1d83e37734f32 100644
--- a/libcxx/include/atomic
+++ b/libcxx/include/atomic
@@ -542,7 +542,7 @@ template <class T>
 # error <atomic> is not implemented
 #endif
 #ifdef kill_dependency
-# error C++ standard library is incompatible with <stdatomic.h>
+# error <atomic> 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 c291901c6bba0..65e628d44da84 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..8495504b07a1c
--- /dev/null
+++ b/libcxx/include/stdatomic.h
@@ -0,0 +1,242 @@
+// -*- 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.
+//
+// However, if the user has already used <atomic> before, the two headers are
+// incompatible before C++23, so we issue a clear error here to avoid obscure
+// issues down the line.
+# if __has_include_next(<stdatomic.h>)
+#   ifdef _LIBCPP_ATOMIC
+#     error <stdatomic.h> is incompatible with <atomic> before C++23. Please compile with -std=c++23.
+#   endif
+#   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 d65ccdc46a7a8..95b863cbdd9af 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/assertions/headers_declare_assertion_handler.sh.cpp b/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp
index 875cbc72678d3..167da28a7add2 100644
--- a/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp
+++ b/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp
@@ -532,236 +532,236 @@ int main(int, char**) { return 0; }
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_92
-#if defined(TEST_92)
+// RUN: %{build} -DTEST_93
+#if defined(TEST_93)
 #   include <stdexcept>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_96
-#if defined(TEST_96) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+// RUN: %{build} -DTEST_97
+#if defined(TEST_97) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
 #   include <streambuf>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_97
-#if defined(TEST_97)
+// RUN: %{build} -DTEST_98
+#if defined(TEST_98)
 #   include <string>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_99
-#if defined(TEST_99)
+// RUN: %{build} -DTEST_100
+#if defined(TEST_100)
 #   include <string_view>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_100
-#if defined(TEST_100) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+// RUN: %{build} -DTEST_101
+#if defined(TEST_101) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
 #   include <strstream>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_101
-#if defined(TEST_101)
+// RUN: %{build} -DTEST_102
+#if defined(TEST_102)
 #   include <system_error>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_103
-#if defined(TEST_103) && !defined(_LIBCPP_HAS_NO_THREADS)
-#   include <thread>
-    using HandlerType = decltype(std::__libcpp_assertion_handler);
-#endif
-
 // RUN: %{build} -DTEST_104
-#if defined(TEST_104)
-#   include <tuple>
+#if defined(TEST_104) && !defined(_LIBCPP_HAS_NO_THREADS)
+#   include <thread>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_105
 #if defined(TEST_105)
-#   include <type_traits>
+#   include <tuple>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_106
 #if defined(TEST_106)
-#   include <typeindex>
+#   include <type_traits>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_107
 #if defined(TEST_107)
-#   include <typeinfo>
+#   include <typeindex>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_109
-#if defined(TEST_109)
-#   include <unordered_map>
+// RUN: %{build} -DTEST_108
+#if defined(TEST_108)
+#   include <typeinfo>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_110
 #if defined(TEST_110)
-#   include <unordered_set>
+#   include <unordered_map>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_111
 #if defined(TEST_111)
-#   include <utility>
+#   include <unordered_set>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_112
 #if defined(TEST_112)
-#   include <valarray>
+#   include <utility>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_113
 #if defined(TEST_113)
-#   include <variant>
+#   include <valarray>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_114
 #if defined(TEST_114)
-#   include <vector>
+#   include <variant>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_115
 #if defined(TEST_115)
-#   include <version>
+#   include <vector>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
-// RUN: %{build} -DTEST_118
-#if defined(TEST_118)
-#   include <experimental/algorithm>
+// RUN: %{build} -DTEST_116
+#if defined(TEST_116)
+#   include <version>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_119
-#if defined(TEST_119) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES)
-#   include <experimental/coroutine>
+#if defined(TEST_119)
+#   include <experimental/algorithm>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_120
-#if defined(TEST_120) && __cplusplus >= 201103L
-#   include <experimental/deque>
+#if defined(TEST_120) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES)
+#   include <experimental/coroutine>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_121
 #if defined(TEST_121) && __cplusplus >= 201103L
-#   include <experimental/forward_list>
+#   include <experimental/deque>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_122
-#if defined(TEST_122)
-#   include <experimental/functional>
+#if defined(TEST_122) && __cplusplus >= 201103L
+#   include <experimental/forward_list>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_123
 #if defined(TEST_123)
-#   include <experimental/iterator>
+#   include <experimental/functional>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_124
-#if defined(TEST_124) && __cplusplus >= 201103L
-#   include <experimental/list>
+#if defined(TEST_124)
+#   include <experimental/iterator>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_125
 #if defined(TEST_125) && __cplusplus >= 201103L
-#   include <experimental/map>
+#   include <experimental/list>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_126
 #if defined(TEST_126) && __cplusplus >= 201103L
-#   include <experimental/memory_resource>
+#   include <experimental/map>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_127
-#if defined(TEST_127)
-#   include <experimental/propagate_const>
+#if defined(TEST_127) && __cplusplus >= 201103L
+#   include <experimental/memory_resource>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_128
-#if defined(TEST_128) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L
-#   include <experimental/regex>
+#if defined(TEST_128)
+#   include <experimental/propagate_const>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_129
-#if defined(TEST_129) && __cplusplus >= 201103L
-#   include <experimental/set>
+#if defined(TEST_129) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L
+#   include <experimental/regex>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_130
-#if defined(TEST_130)
-#   include <experimental/simd>
+#if defined(TEST_130) && __cplusplus >= 201103L
+#   include <experimental/set>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_131
-#if defined(TEST_131) && __cplusplus >= 201103L
-#   include <experimental/string>
+#if defined(TEST_131)
+#   include <experimental/simd>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_132
-#if defined(TEST_132)
-#   include <experimental/type_traits>
+#if defined(TEST_132) && __cplusplus >= 201103L
+#   include <experimental/string>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_133
-#if defined(TEST_133) && __cplusplus >= 201103L
-#   include <experimental/unordered_map>
+#if defined(TEST_133)
+#   include <experimental/type_traits>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_134
 #if defined(TEST_134) && __cplusplus >= 201103L
-#   include <experimental/unordered_set>
+#   include <experimental/unordered_map>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_135
-#if defined(TEST_135)
-#   include <experimental/utility>
+#if defined(TEST_135) && __cplusplus >= 201103L
+#   include <experimental/unordered_set>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_136
-#if defined(TEST_136) && __cplusplus >= 201103L
-#   include <experimental/vector>
+#if defined(TEST_136)
+#   include <experimental/utility>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_137
-#if defined(TEST_137)
-#   include <ext/hash_map>
+#if defined(TEST_137) && __cplusplus >= 201103L
+#   include <experimental/vector>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif
 
 // RUN: %{build} -DTEST_138
 #if defined(TEST_138)
+#   include <ext/hash_map>
+    using HandlerType = decltype(std::__libcpp_assertion_handler);
+#endif
+
+// RUN: %{build} -DTEST_139
+#if defined(TEST_139)
 #   include <ext/hash_set>
     using HandlerType = decltype(std::__libcpp_assertion_handler);
 #endif

diff  --git a/libcxx/test/libcxx/atomics/atomics.syn/incompatible_with_stdatomic.verify.cpp b/libcxx/test/libcxx/atomics/atomics.syn/incompatible_with_stdatomic.verify.cpp
new file mode 100644
index 0000000000000..49bc2dcc7fd1b
--- /dev/null
+++ b/libcxx/test/libcxx/atomics/atomics.syn/incompatible_with_stdatomic.verify.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// REQUIRES: c++03 || c++11 || c++14 || c++17 || c++20
+
+// This test ensures that we issue a reasonable diagnostic when using <atomic> while <stdatomic.h>
+// is in use too. Before C++23, this otherwise leads to obscure errors because <atomic> may try
+// to redefine things defined by <stdatomic.h>.
+
+// Ignore additional weird errors that happen when the two headers are mixed.
+// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error -Xclang -verify-ignore-unexpected=warning
+
+#include <stdatomic.h>
+#include <atomic>
+
+// expected-error@*:* {{<atomic> is incompatible with <stdatomic.h> before C++23.}}

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/atomics/stdatomic.h.syn/incompatible_with_atomic.verify.cpp b/libcxx/test/libcxx/atomics/stdatomic.h.syn/incompatible_with_atomic.verify.cpp
new file mode 100644
index 0000000000000..ff4124ac2490c
--- /dev/null
+++ b/libcxx/test/libcxx/atomics/stdatomic.h.syn/incompatible_with_atomic.verify.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// REQUIRES: c++03 || c++11 || c++14 || c++17 || c++20
+
+// This test ensures that we issue a reasonable diagnostic when using <stdatomic.h> while <atomic>
+// is in use too. Before C++23, this otherwise leads to obscure errors because <stdatomic.h> tries
+// to redefine things defined by <atomic>.
+
+// Ignore additional weird errors that happen when the two headers are mixed.
+// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error -Xclang -verify-ignore-unexpected=warning
+
+#include <atomic>
+#include <stdatomic.h>
+
+// expected-error@*:* {{<stdatomic.h> is incompatible with <atomic> before C++23}}

diff  --git a/libcxx/test/libcxx/clang_tidy.sh.cpp b/libcxx/test/libcxx/clang_tidy.sh.cpp
index b06cac9c8204f..c1ace4d3201f4 100644
--- a/libcxx/test/libcxx/clang_tidy.sh.cpp
+++ b/libcxx/test/libcxx/clang_tidy.sh.cpp
@@ -166,6 +166,9 @@ END-SCRIPT
 #   include <sstream>
 #endif
 #include <stack>
+#if __cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS)
+#   include <stdatomic.h>
+#endif
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdexcept>

diff  --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp
index 6701908caab43..39c5c9860309b 100644
--- a/libcxx/test/libcxx/double_include.sh.cpp
+++ b/libcxx/test/libcxx/double_include.sh.cpp
@@ -169,6 +169,9 @@ END-SCRIPT
 #   include <sstream>
 #endif
 #include <stack>
+#if __cplusplus > 202002L && !defined(_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 57d04e177b04a..faa3ec0ef2576 100644
--- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp
+++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp
@@ -259,6 +259,10 @@ TEST_MACROS();
 #endif
 #include <stack>
 TEST_MACROS();
+#if __cplusplus > 202002L && !defined(_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 1e4d185d5e953..d9162c1bca42b 100644
--- a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp
+++ b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp
@@ -280,6 +280,9 @@ END-SCRIPT
 #   include <sstream>
 #endif
 #include <stack>
+#if __cplusplus > 202002L && !defined(_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 b173c4651a4a5..1609c588c7b75 100644
--- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp
+++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp
@@ -166,6 +166,9 @@ END-SCRIPT
 #   include <sstream>
 #endif
 #include <stack>
+#if __cplusplus > 202002L && !defined(_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..6d2f810f0163b
--- /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.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/stdatomic.h.version.compile.pass.cpp
new file mode 100644
index 0000000000000..a2e1aa026d4f8
--- /dev/null
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/stdatomic.h.version.compile.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index c287aabc5af54..e51624fbf7901 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -4807,17 +4807,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 fd8a52911f845..1e31677fb7576 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -658,7 +658,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 },
@@ -780,7 +779,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 3f361ef83f75d..04d4d7de4a6e5 100755
--- a/libcxx/utils/generate_header_tests.py
+++ b/libcxx/utils/generate_header_tests.py
@@ -14,6 +14,7 @@
     "mutex": "!defined(_LIBCPP_HAS_NO_THREADS)",
     "semaphore": "!defined(_LIBCPP_HAS_NO_THREADS)",
     "shared_mutex": "!defined(_LIBCPP_HAS_NO_THREADS)",
+    "stdatomic.h": "__cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS)",
     "thread": "!defined(_LIBCPP_HAS_NO_THREADS)",
 
     "filesystem": "!defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY)",


        


More information about the libcxx-commits mailing list