-
Notifications
You must be signed in to change notification settings - Fork 15.1k
Description
This issue was discovered using Apple toolchain, but its roots is in the upstream.
Steps to reproduce:
Consider a code snippet:
#include <iostream>
#include <latch>
#include <version>
int main()
{
#if !__cpp_lib_latch
std::latch this_must_not_compile {42};
std::cout << "std::latch compiles, although __cpp_lib_latch is undefined\n";
#endif
}
Using Apple clang:
% xcrun clang++ --version
Apple clang version 16.0.0 (clang-1600.0.26.4)
Target: arm64-apple-darwin24.1.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
% xcrun clang++ -std=c++20 -mmacosx-version-min=10.15 latch.cpp
% ./a.out
std::latch compiles, although __cpp_lib_latch is undefined
Using upstream clang:
Reproducing the issue with upstream clang is not as straightforward. We must tell the compiler that vendor availability annotations are enabled (even if they are not). Passing -D_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS=1
does not work. The easiest solution, though a little messy, is to modify ${llvm_prefix}/include/c++/v1/__config_site
file and set #define _LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS 1
. This should suffice to reproduce the issue:
% /opt/homebrew/Cellar/llvm/20.1.4/bin/clang++ --version
Homebrew clang version 20.1.4
Target: arm64-apple-darwin24.1.0
Thread model: posix
InstalledDir: /opt/homebrew/Cellar/llvm/20.1.4/bin
Configuration file: /opt/homebrew/etc/clang/arm64-apple-darwin24.cfg
% /opt/homebrew/Cellar/llvm/20.1.4/bin/clang++ -std=c++20 -mmacosx-version-min=10.15 latch.cpp
% ./a.out
std::latch compiles, although __cpp_lib_latch is undefined
My little bits of investigation:
__cpp_lib_latch
is defined when both _LIBCPP_HAS_THREADS
and _LIBCPP_AVAILABILITY_HAS_SYNC
are true:
llvm-project/libcxx/include/version
Lines 438 to 440 in 0db0405
# if _LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC | |
# define __cpp_lib_latch 201907L | |
# endif |
However, the definition of std::latch
is only protected by _LIBCPP_HAS_THREADS
macro:
llvm-project/libcxx/include/latch
Lines 48 to 50 in 3275291
# if _LIBCPP_HAS_THREADS | |
# include <__assert> |
When compiling for MacOS < 11, if availability annotations are enabled, i.e. _LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS = 1
, then _LIBCPP_INTRODUCED_IN_LLVM_11
is defined as 0:
llvm-project/libcxx/include/__configuration/availability.h
Lines 222 to 226 in 9602216
# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000) || \ | |
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 140000) || \ | |
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 140000) || \ | |
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 70000) | |
# define _LIBCPP_INTRODUCED_IN_LLVM_11 0 |
This macro in turn is used to define _LIBCPP_AVAILABILITY_HAS_SYNC
:
#define _LIBCPP_AVAILABILITY_HAS_SYNC _LIBCPP_INTRODUCED_IN_LLVM_11 |
As a result, when -mmacosx-version-min < 11
and vendor availability annotations are enabled, then _LIBCPP_HAS_THREADS = 1
and _LIBCPP_AVAILABILITY_HAS_SYNC = 0
. This makes __cpp_lib_latch
undefined, but std::latch compiles nevertheless.