I was using swift-corelibs-libdispatch as part of a broader Bazel-based
system. While porting that project from C++20 to C++23, I found a problem with
the way libdispatch uses <stdatomic.h>.
Steps to validate (in standalone swift-corelibs-libdispatch)
- Edit
CMakeLists.txt and set CMAKE_CXX_STANDARD to 23.
- Build
swift-corelibs-libdispatch.
- Check whether the build succeeds.
Expected
Build succeeds.
Actual
Build fails with both libstdc++ and libc++.
With libstdc++, the failure looks like:
In file included from /path/to/swift-corelibs-libdispatch/src/block.cpp:31:
In file included from /path/to/swift-corelibs-libdispatch/src/internal.h:667:
In file included from /path/to/swift-corelibs-libdispatch/src/shims.h:220:
In file included from /path/to/swift-corelibs-libdispatch/src/shims/atomic.h:41:
In file included from /usr/lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/stdatomic.h:36:
In file included from /usr/lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/atomic:52:
In file included from /usr/lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/bits/atomic_base.h:38:
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/new:230:3: error: templates must have C++ linkage
230 | template<typename _Tp>
| ^~~~~~~~~~~~~~~~~~~~~~
/path/to/swift-corelibs-libdispatch/src/internal.h:326:1: note: extern "C" language linkage specification begins here
326 | __BEGIN_DECLS
| ^
/usr/include/sys/cdefs.h:140:24: note: expanded from macro '__BEGIN_DECLS'
140 | # define __BEGIN_DECLS extern "C" {
| ^
In file included from /path/to/swift-corelibs-libdispatch/src/block.cpp:31:
In file included from /path/to/swift-corelibs-libdispatch/src/internal.h:667:
In file included from /path/to/swift-corelibs-libdispatch/src/shims.h:220:
In file included from /path/to/swift-corelibs-libdispatch/src/shims/atomic.h:41:
In file included from /usr/lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/stdatomic.h:36:
In file included from /usr/lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/atomic:52:
In file included from /usr/lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/bits/atomic_base.h:40:
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/bits/move.h:49:3: error: templates must have C++ linkage
49 | template<typename _Tp>
| ^~~~~~~~~~~~~~~~~~~~~~
With libc++, the failure looks like:
In file included from /path/to/swift-corelibs-libdispatch/src/block.cpp:31:
In file included from /path/to/swift-corelibs-libdispatch/src/internal.h:667:
In file included from /path/to/swift-corelibs-libdispatch/src/shims.h:220:
In file included from /path/to/swift-corelibs-libdispatch/src/shims/atomic.h:41:
In file included from /usr/include/c++/v1/stdatomic.h:131:
In file included from /usr/include/c++/v1/atomic:605:
In file included from /usr/include/c++/v1/__atomic/aliases.h:12:
In file included from /usr/include/c++/v1/__atomic/atomic.h:12:
In file included from /usr/include/c++/v1/__atomic/atomic_sync.h:12:
In file included from /usr/include/c++/v1/__atomic/contention_t.h:12:
In file included from /usr/include/c++/v1/__atomic/support.h:108:
In file included from /usr/include/c++/v1/__atomic/support/c11.h:12:
In file included from /usr/include/c++/v1/__atomic/memory_order.h:13:
/usr/include/c++/v1/__type_traits/is_same.h:21:1: error: templates must have C++ linkage
21 | template <class _Tp, class _Up>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/path/to/swift-corelibs-libdispatch/src/internal.h:326:1: note: extern "C" language linkage specification begins here
326 | __BEGIN_DECLS
| ^
Environment
Tested on Linux x86_64 (Fedora 43) with:
swift-corelibs-libdispatch at 330412f
- Clang 21
- C++23
libstdc++ repro: clang++ using GCC 15 C++ headers
libc++ repro: clang++ -stdlib=libc++ using /usr/include/c++/v1
Root cause
src/shims/atomic.h contains an internal shim built around Clang C _Atomic
storage and C11 atomic operations.
In C++23, both libstdc++ and libc++ implement <stdatomic.h> in C++ mode
using the C++ atomics model instead of the old C11-style interface that
libdispatch's shim expects.
That does not match what libdispatch's shim expects. In practice, this causes
src/block.cpp to fail to compile through the include chain:
src/block.cpp -> src/internal.h -> src/shims.h -> src/shims/atomic.h -> <stdatomic.h>
Possible solution
One possible fix would be to make src/shims/atomic.h use private libdispatch
atomic aliases instead of directly relying on the public atomic_* names from
<stdatomic.h>.
For C and older C++ modes, those aliases could continue to map to
<stdatomic.h>.
For C++23 and newer, they could instead map directly to Clang
__c11_atomic_* builtins and __ATOMIC_* memory-order constants. That would
preserve the shim's current _Atomic-based model without depending on the
C++23 std::atomic-based behavior of <stdatomic.h>.
I was using
swift-corelibs-libdispatchas part of a broader Bazel-basedsystem. While porting that project from C++20 to C++23, I found a problem with
the way libdispatch uses
<stdatomic.h>.Steps to validate (in standalone swift-corelibs-libdispatch)
CMakeLists.txtand setCMAKE_CXX_STANDARDto23.swift-corelibs-libdispatch.Expected
Build succeeds.
Actual
Build fails with both
libstdc++andlibc++.With
libstdc++, the failure looks like:With
libc++, the failure looks like:Environment
Tested on Linux x86_64 (Fedora 43) with:
swift-corelibs-libdispatchat 330412flibstdc++repro:clang++using GCC 15 C++ headerslibc++repro:clang++ -stdlib=libc++using/usr/include/c++/v1Root cause
src/shims/atomic.hcontains an internal shim built around Clang C_Atomicstorage and C11 atomic operations.
In C++23, both
libstdc++andlibc++implement<stdatomic.h>in C++ modeusing the C++ atomics model instead of the old C11-style interface that
libdispatch's shim expects.
That does not match what libdispatch's shim expects. In practice, this causes
src/block.cppto fail to compile through the include chain:Possible solution
One possible fix would be to make
src/shims/atomic.huse private libdispatchatomic aliases instead of directly relying on the public
atomic_*names from<stdatomic.h>.For C and older C++ modes, those aliases could continue to map to
<stdatomic.h>.For C++23 and newer, they could instead map directly to Clang
__c11_atomic_*builtins and__ATOMIC_*memory-order constants. That wouldpreserve the shim's current
_Atomic-based model without depending on theC++23
std::atomic-based behavior of<stdatomic.h>.