[libcxx-commits] [libcxx] [libc++] Enable C++ stdatomic.h for all C++ versions (PR #95498)

Ryan Prichard via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 14 17:11:12 PDT 2024


================
@@ -589,10 +589,6 @@ template <class T>
 
 #include <__config>
 
-#if _LIBCPP_STD_VER < 23 && defined(_LIBCPP_STDATOMIC_H)
-#  error <atomic> is incompatible with <stdatomic.h> before C++23. Please compile with -std=c++23.
----------------
rprichard wrote:

C++ versions before C++23 don't specify a `<stdatomic.h>`, so including `<stdatomic.h>` in a C++ file typically finds `<stdatomic.h`> from the C library (or maybe from Clang's resource directory). That header typically implements `<stdatomic.h>` from C11, which typically implements type-generic operations using macros. For example, `atomic_is_lock_free` is a macro that works with any `_Atomic`-qualified object:

>From clang/lib/Headers/stdatomic.h:
```
#define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj)))
```

If `<stdatomic.h>` is included first, then this macro will break the parsing of `std::atomic_is_lock_free` when `<atomic>` is included later (e.g. libcxx/include/__atomic/atomic.h):
```
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const volatile atomic<_Tp>* __o) _NOEXCEPT {
  return __o->is_lock_free();
}
```

It can be possible to use the C11 `<stdatomic.h>` in a C++ file, as long as `<atomic>` is included first (or not at all), and only if the C++ compiler and `<stdatomic.h>` are compatible. For example:
 * GCC can't include its C11 `<stdatomic.h>` in C++ mode because GCC only provides the `_Atomic` qualifier in C mode, not C++.
 * Clang can include its C11 `<stdatomic.h>` in C++ mode.

Other STL headers that use the C11 `<stdatomic.h>` identifiers can also be an issue. For example, including `<memory>` after `<stdatomic.h>` also hits the incompatibility:
```c++
$ cat test.cpp
#include <stdatomic.h>
#include <memory>

$ clang++-19 -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES test.cpp -c -stdlib=libc++ -std=c++23
# works fine -- libc++ provides the C++23 stdatomic.h

$ clang++-19 -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES test.cpp -c -stdlib=libc++ -std=c++20
In file included from test.cpp:2:
In file included from /usr/lib/llvm-19/bin/../include/c++/v1/memory:937:
/usr/lib/llvm-19/bin/../include/c++/v1/__memory/shared_ptr.h:1587:35: error: expected expression
 1587 | inline _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const shared_ptr<_Tp>*) {
      |                                   ^
/usr/lib/llvm-19/lib/clang/19/include/stdatomic.h:87:73: note: expanded from macro 'atomic_is_lock_free'
   87 | #define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj)))
      |                                                                         ^
```

Including `<memory>` defines `std::atomic_*` function overloads for `std::shared_ptr` (until C++26, when they are removed). https://en.cppreference.com/w/cpp/memory/shared_ptr/atomic




https://github.com/llvm/llvm-project/pull/95498


More information about the libcxx-commits mailing list