diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 8877ec0a48bc..a6c658c0ac18 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 c0ef6882a513..12fb51323759 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 `__","LWG","A Proposal to add stacktrace library","Autumn 2020","","" -"`P0943R6 `__","LWG","Support C atomics in C++","Autumn 2020","","" +"`P0943R6 `__","LWG","Support C atomics in C++","Autumn 2020","|Complete|","15.0" "`P1048R1 `__","LWG","A proposal for a type trait to detect scoped enumerations","Autumn 2020","|Complete|","12.0" "`P1679R3 `__","LWG","string contains function","Autumn 2020","|Complete|","12.0" "","","","","","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index fb2b5be63510..d463d208566d 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 7fed8713e03a..a58a44a3fd59 100644 --- a/libcxx/include/atomic +++ b/libcxx/include/atomic @@ -540,7 +540,7 @@ template # error is not implemented #endif #ifdef kill_dependency -# error C++ standard library is incompatible with +# error C++ standard library is incompatible with 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 95ff1ecddd69..b95873764514 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: is missing. // provided by C library. // provided by compiler. diff --git a/libcxx/include/stdatomic.h b/libcxx/include/stdatomic.h new file mode 100644 index 000000000000..d9550c44061c --- /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 + using std-atomic = std::atomic; // exposition only + +#define _Atomic(T) std-atomic + +#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_ptrdiff_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 +#include + +#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_ptrdiff_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 on the path to avoid hijacking +// the header. We do this because Clang has historically shipped a +// header that would be available in all Standard modes, and we don't want to +// break that use case. +# if __has_include_next() +# include_next +# endif + +#endif // _LIBCPP_STD_VER > 20 + +#endif // _LIBCPP_STDATOMIC_H diff --git a/libcxx/include/version b/libcxx/include/version index 3aed750c6ec5..5cbe474150ee 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -396,7 +396,7 @@ __cpp_lib_void_t 201411L // # 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 000000000000..f00c3efa8cf7 --- /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 header even when compiling +// before C++23, since Clang used to provide that header before libc++ provided one. + +// On GCC, the compiler-provided is not C++ friendly, so including +// doesn't work at all if we don't use the provided by libc++ in C++23 and above. +// XFAIL: (c++11 || c++14 || c++17 || c++20) && gcc + +#include + +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 6e2c2ab0e6f9..7eda8fccfefd 100644 --- a/libcxx/test/libcxx/double_include.sh.cpp +++ b/libcxx/test/libcxx/double_include.sh.cpp @@ -165,6 +165,9 @@ # include #endif #include +#ifndef _LIBCPP_HAS_NO_THREADS +# include +#endif #include #include #include diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp index 4bde1336de02..2ff617a73319 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 TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_THREADS +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #include diff --git a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp index d94e3b3a54ec..70855513ea75 100644 --- a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp @@ -275,6 +275,9 @@ # include #endif #include +#ifndef _LIBCPP_HAS_NO_THREADS +# include +#endif #include #include #include diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp index 37e88f7db0c4..34e0b677ef4a 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 #endif #include +#ifndef _LIBCPP_HAS_NO_THREADS +# include +#endif #include #include #include 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 000000000000..82ee041902f9 --- /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 + +// + +// template +// using std-atomic = std::atomic; // exposition only +// +// #define _Atomic(T) std-atomic +// +// #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_ptrdiff_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 +#include + +#include "test_macros.h" + +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_BOOL_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_CHAR_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_CHAR16_T_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_CHAR32_T_LOCK_FREE)); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_WCHAR_T_LOCK_FREE)); +#endif +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_SHORT_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_SHORT_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_INT_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_INT_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_LONG_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_LONG_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_LLONG_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_LLONG_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_POINTER_LOCK_FREE)); +static_assert(std::atomic::is_always_lock_free == (2 == ATOMIC_POINTER_LOCK_FREE)); + +void f() { + static_assert(std::is_same_v, _Atomic(char)>); + static_assert(std::is_same_v, _Atomic(int)>); + static_assert(std::is_same_v, _Atomic(const long)>); + + static_assert(std::is_same_v); + 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); + + static_assert(std::is_same_v, ::atomic_bool>); + static_assert(std::is_same_v, ::atomic_char>); + static_assert(std::is_same_v, ::atomic_schar>); + static_assert(std::is_same_v, ::atomic_uchar>); + static_assert(std::is_same_v, ::atomic_short>); + static_assert(std::is_same_v, ::atomic_ushort>); + static_assert(std::is_same_v, ::atomic_int>); + static_assert(std::is_same_v, ::atomic_uint>); + static_assert(std::is_same_v, ::atomic_long>); + static_assert(std::is_same_v, ::atomic_ulong>); + static_assert(std::is_same_v, ::atomic_llong>); + static_assert(std::is_same_v, ::atomic_ullong>); + +#ifndef _LIBCPP_HAS_NO_CHAR8_T + static_assert(std::is_same_v, ::atomic_char8_t>); +#endif + static_assert(std::is_same_v, ::atomic_char16_t>); + static_assert(std::is_same_v, ::atomic_char32_t>); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + static_assert(std::is_same_v, ::atomic_wchar_t>); +#endif + + static_assert(std::is_same_v, ::atomic_int8_t>); + static_assert(std::is_same_v, ::atomic_uint8_t>); + static_assert(std::is_same_v, ::atomic_int16_t>); + static_assert(std::is_same_v, ::atomic_uint16_t>); + static_assert(std::is_same_v, ::atomic_int32_t>); + static_assert(std::is_same_v, ::atomic_uint32_t>); + static_assert(std::is_same_v, ::atomic_int64_t>); + static_assert(std::is_same_v, ::atomic_uint64_t>); + + static_assert(std::is_same_v, ::atomic_int_least8_t>); + static_assert(std::is_same_v, ::atomic_uint_least8_t>); + static_assert(std::is_same_v, ::atomic_int_least16_t>); + static_assert(std::is_same_v, ::atomic_uint_least16_t>); + static_assert(std::is_same_v, ::atomic_int_least32_t>); + static_assert(std::is_same_v, ::atomic_uint_least32_t>); + static_assert(std::is_same_v, ::atomic_int_least64_t>); + static_assert(std::is_same_v, ::atomic_uint_least64_t>); + + static_assert(std::is_same_v, ::atomic_int_fast8_t>); + static_assert(std::is_same_v, ::atomic_uint_fast8_t>); + static_assert(std::is_same_v, ::atomic_int_fast16_t>); + static_assert(std::is_same_v, ::atomic_uint_fast16_t>); + static_assert(std::is_same_v, ::atomic_int_fast32_t>); + static_assert(std::is_same_v, ::atomic_uint_fast32_t>); + static_assert(std::is_same_v, ::atomic_int_fast64_t>); + static_assert(std::is_same_v, ::atomic_uint_fast64_t>); + + static_assert(std::is_same_v, ::atomic_intptr_t>); + static_assert(std::is_same_v, ::atomic_uintptr_t>); + static_assert(std::is_same_v, ::atomic_size_t>); + static_assert(std::is_same_v, ::atomic_ptrdiff_t>); + static_assert(std::is_same_v, ::atomic_intmax_t>); + static_assert(std::is_same_v, ::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 000000000000..8c55b8c6a18e --- /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 + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_stdatomic_h 202011L [C++2b] +*/ + +#include +#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 d69ae81d33f9..43df8d7dc833 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 f2140ed41f1d..1daaea005210 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -664,7 +664,6 @@ feature_test_macros = [ add_version_header(x) for x in [ "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 @@ lit_markup = { "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 55bbc58e39b5..6783972e119f 100755 --- a/libcxx/utils/generate_header_tests.py +++ b/libcxx/utils/generate_header_tests.py @@ -27,6 +27,7 @@ header_markup = { "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"],