xref: /aosp_15_r20/external/cronet/third_party/libc++/src/utils/libcxx/test/features.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1# ===----------------------------------------------------------------------===##
2#
3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4# See https://llvm.org/LICENSE.txt for license information.
5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6#
7# ===----------------------------------------------------------------------===##
8
9from libcxx.test.dsl import *
10from lit.BooleanExpression import BooleanExpression
11import re
12import shutil
13import subprocess
14import sys
15
16_isAnyClang = lambda cfg: "__clang__" in compilerMacros(cfg)
17_isAppleClang = lambda cfg: "__apple_build_version__" in compilerMacros(cfg)
18_isAnyGCC = lambda cfg: "__GNUC__" in compilerMacros(cfg)
19_isClang = lambda cfg: _isAnyClang(cfg) and not _isAppleClang(cfg)
20_isGCC = lambda cfg: _isAnyGCC(cfg) and not _isAnyClang(cfg)
21_isAnyClangOrGCC = lambda cfg: _isAnyClang(cfg) or _isAnyGCC(cfg)
22_isClExe = lambda cfg: not _isAnyClangOrGCC(cfg)
23_isMSVC = lambda cfg: "_MSC_VER" in compilerMacros(cfg)
24_msvcVersion = lambda cfg: (int(compilerMacros(cfg)["_MSC_VER"]) // 100, int(compilerMacros(cfg)["_MSC_VER"]) % 100)
25
26def _getAndroidDeviceApi(cfg):
27    return int(
28        programOutput(
29            cfg,
30            r"""
31                #include <android/api-level.h>
32                #include <stdio.h>
33                int main() {
34                    printf("%d\n", android_get_device_api_level());
35                    return 0;
36                }
37            """,
38        )
39    )
40
41# Lit features are evaluated in order. Some checks may require the compiler detection to have
42# run first in order to work properly.
43DEFAULT_FEATURES = [
44    # gcc-style-warnings detects compilers that understand -Wno-meow flags, unlike MSVC's compiler driver cl.exe.
45    Feature(name="gcc-style-warnings", when=_isAnyClangOrGCC),
46    Feature(name="cl-style-warnings", when=_isClExe),
47    Feature(name="apple-clang", when=_isAppleClang),
48    Feature(
49        name=lambda cfg: "apple-clang-{__clang_major__}".format(**compilerMacros(cfg)),
50        when=_isAppleClang,
51    ),
52    Feature(
53        name=lambda cfg: "apple-clang-{__clang_major__}.{__clang_minor__}".format(**compilerMacros(cfg)),
54        when=_isAppleClang,
55    ),
56    Feature(
57        name=lambda cfg: "apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format(**compilerMacros(cfg)),
58        when=_isAppleClang,
59    ),
60    Feature(name="clang", when=_isClang),
61    Feature(
62        name=lambda cfg: "clang-{__clang_major__}".format(**compilerMacros(cfg)),
63        when=_isClang,
64    ),
65    Feature(
66        name=lambda cfg: "clang-{__clang_major__}.{__clang_minor__}".format(**compilerMacros(cfg)),
67        when=_isClang,
68    ),
69    Feature(
70        name=lambda cfg: "clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format(**compilerMacros(cfg)),
71        when=_isClang,
72    ),
73    # Note: Due to a GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104760), we must disable deprecation warnings
74    #       on GCC or spurious diagnostics are issued.
75    #
76    # TODO:
77    # - Enable -Wplacement-new with GCC.
78    # - Enable -Wclass-memaccess with GCC.
79    Feature(
80        name="gcc",
81        when=_isGCC,
82        actions=[
83            AddCompileFlag("-D_LIBCPP_DISABLE_DEPRECATION_WARNINGS"),
84            AddCompileFlag("-Wno-placement-new"),
85            AddCompileFlag("-Wno-class-memaccess"),
86            AddFeature("GCC-ALWAYS_INLINE-FIXME"),
87        ],
88    ),
89    Feature(
90        name=lambda cfg: "gcc-{__GNUC__}".format(**compilerMacros(cfg)), when=_isGCC
91    ),
92    Feature(
93        name=lambda cfg: "gcc-{__GNUC__}.{__GNUC_MINOR__}".format(**compilerMacros(cfg)),
94        when=_isGCC,
95    ),
96    Feature(
97        name=lambda cfg: "gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}".format(**compilerMacros(cfg)),
98        when=_isGCC,
99    ),
100    Feature(name="msvc", when=_isMSVC),
101    Feature(name=lambda cfg: "msvc-{}".format(*_msvcVersion(cfg)), when=_isMSVC),
102    Feature(name=lambda cfg: "msvc-{}.{}".format(*_msvcVersion(cfg)), when=_isMSVC),
103
104    Feature(
105        name="thread-safety",
106        when=lambda cfg: hasCompileFlag(cfg, "-Werror=thread-safety"),
107        actions=[AddCompileFlag("-Werror=thread-safety")],
108    ),
109    Feature(
110        name="diagnose-if-support",
111        when=lambda cfg: hasCompileFlag(cfg, "-Wuser-defined-warnings"),
112        actions=[AddCompileFlag("-Wuser-defined-warnings")],
113    ),
114    # Tests to validate whether the compiler has a way to set the maximum number
115    # of steps during constant evaluation. Since the flag differs per compiler
116    # store the "valid" flag as a feature. This allows passing the proper compile
117    # flag to the compiler:
118    # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12345678
119    # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=12345678
120    Feature(
121        name="has-fconstexpr-steps",
122        when=lambda cfg: hasCompileFlag(cfg, "-fconstexpr-steps=1"),
123    ),
124    Feature(
125        name="has-fconstexpr-ops-limit",
126        when=lambda cfg: hasCompileFlag(cfg, "-fconstexpr-ops-limit=1"),
127    ),
128    Feature(name="has-fblocks", when=lambda cfg: hasCompileFlag(cfg, "-fblocks")),
129    Feature(
130        name="-fsized-deallocation",
131        when=lambda cfg: hasCompileFlag(cfg, "-fsized-deallocation"),
132    ),
133    Feature(
134        name="-faligned-allocation",
135        when=lambda cfg: hasCompileFlag(cfg, "-faligned-allocation"),
136    ),
137    Feature(
138        name="fdelayed-template-parsing",
139        when=lambda cfg: hasCompileFlag(cfg, "-fdelayed-template-parsing"),
140    ),
141    Feature(
142        name="has-fobjc-arc",
143        when=lambda cfg: hasCompileFlag(cfg, "-xobjective-c++ -fobjc-arc")
144        and sys.platform.lower().strip() == "darwin",
145    ),  # TODO: this doesn't handle cross-compiling to Apple platforms.
146    Feature(
147        name="objective-c++",
148        when=lambda cfg: hasCompileFlag(cfg, "-xobjective-c++ -fobjc-arc"),
149    ),
150    Feature(
151        name="verify-support",
152        when=lambda cfg: hasCompileFlag(cfg, "-Xclang -verify-ignore-unexpected"),
153    ),
154    Feature(
155        name="add-latomic-workaround",  # https://github.com/llvm/llvm-project/issues/73361
156        when=lambda cfg: sourceBuilds(
157            cfg, "int main(int, char**) { return 0; }", ["-latomic"]
158        ),
159        actions=[AddLinkFlag("-latomic")],
160    ),
161    Feature(
162        name="has-64-bit-atomics",
163        when=lambda cfg: sourceBuilds(
164            cfg,
165            """
166            #include <atomic>
167            struct Large { char storage[64/8]; };
168            std::atomic<Large> x;
169            int main(int, char**) { (void)x.load(); (void)x.is_lock_free(); return 0; }
170          """,
171        ),
172    ),
173    Feature(
174        name="has-1024-bit-atomics",
175        when=lambda cfg: sourceBuilds(
176            cfg,
177            """
178            #include <atomic>
179            struct Large { char storage[1024/8]; };
180            std::atomic<Large> x;
181            int main(int, char**) { (void)x.load(); (void)x.is_lock_free(); return 0; }
182          """,
183        ),
184    ),
185    # Tests that require 64-bit architecture
186    Feature(
187        name="32-bit-pointer",
188        when=lambda cfg: sourceBuilds(
189            cfg,
190            """
191            int main(int, char**) {
192              static_assert(sizeof(void *) == 4);
193            }
194          """,
195        ),
196    ),
197    # Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.20348.0):
198    # https://developercommunity.visualstudio.com/t/utf-8-locales-break-ctype-functions-for-wchar-type/1653678
199    Feature(
200        name="win32-broken-utf8-wchar-ctype",
201        when=lambda cfg: not "_LIBCPP_HAS_NO_LOCALIZATION" in compilerMacros(cfg)
202        and "_WIN32" in compilerMacros(cfg)
203        and not programSucceeds(
204            cfg,
205            """
206            #include <locale.h>
207            #include <wctype.h>
208            int main(int, char**) {
209              setlocale(LC_ALL, "en_US.UTF-8");
210              return towlower(L'\\xDA') != L'\\xFA';
211            }
212          """,
213        ),
214    ),
215    # Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.19041.0).
216    # https://developercommunity.visualstudio.com/t/printf-formatting-with-g-outputs-too/1660837
217    Feature(
218        name="win32-broken-printf-g-precision",
219        when=lambda cfg: "_WIN32" in compilerMacros(cfg)
220        and not programSucceeds(
221            cfg,
222            """
223            #include <stdio.h>
224            #include <string.h>
225            int main(int, char**) {
226              char buf[100];
227              snprintf(buf, sizeof(buf), "%#.*g", 0, 0.0);
228              return strcmp(buf, "0.");
229            }
230          """,
231        ),
232    ),
233    # Check for Glibc < 2.27, where the ru_RU.UTF-8 locale had
234    # mon_decimal_point == ".", which our tests don't handle.
235    Feature(
236        name="glibc-old-ru_RU-decimal-point",
237        when=lambda cfg: not "_LIBCPP_HAS_NO_LOCALIZATION" in compilerMacros(cfg)
238        and not programSucceeds(
239            cfg,
240            """
241            #include <locale.h>
242            #include <string.h>
243            int main(int, char**) {
244              setlocale(LC_ALL, "ru_RU.UTF-8");
245              return strcmp(localeconv()->mon_decimal_point, ",");
246            }
247          """,
248        ),
249    ),
250    Feature(
251        name="has-unix-headers",
252        when=lambda cfg: sourceBuilds(
253            cfg,
254            """
255            #include <unistd.h>
256            #include <sys/wait.h>
257            int main(int, char**) {
258              int fd[2];
259              return pipe(fd);
260            }
261          """,
262        ),
263    ),
264    # Whether Bash can run on the executor.
265    # This is not always the case, for example when running on embedded systems.
266    #
267    # For the corner case of bash existing, but it being missing in the path
268    # set in %{exec} as "--env PATH=one-single-dir", the executor does find
269    # and executes bash, but bash then can't find any other common shell
270    # utilities. Test executing "bash -c 'bash --version'" to see if bash
271    # manages to find binaries to execute.
272    Feature(
273        name="executor-has-no-bash",
274        when=lambda cfg: runScriptExitCode(cfg, ["%{exec} bash -c 'bash --version'"]) != 0,
275    ),
276    # Whether module support for the platform is available.
277    Feature(
278        name="has-no-cxx-module-support",
279        # The libc of these platforms have functions with internal linkage.
280        # This is not allowed per C11 7.1.2 Standard headers/6
281        #  Any declaration of a library function shall have external linkage.
282        when=lambda cfg: "__ANDROID__" in compilerMacros(cfg)
283        or "__FreeBSD__" in compilerMacros(cfg)
284        or "_WIN32" in compilerMacros(cfg)
285        or platform.system().lower().startswith("aix")
286        # Avoid building on platforms that don't support modules properly.
287        or not hasCompileFlag(cfg, "-Wno-reserved-module-identifier"),
288    ),
289]
290
291# Deduce and add the test features that that are implied by the #defines in
292# the <__config_site> header.
293#
294# For each macro of the form `_LIBCPP_XXX_YYY_ZZZ` defined below that
295# is defined after including <__config_site>, add a Lit feature called
296# `libcpp-xxx-yyy-zzz`. When a macro is defined to a specific value
297# (e.g. `_LIBCPP_ABI_VERSION=2`), the feature is `libcpp-xxx-yyy-zzz=<value>`.
298#
299# Note that features that are more strongly tied to libc++ are named libcpp-foo,
300# while features that are more general in nature are not prefixed with 'libcpp-'.
301macros = {
302    "_LIBCPP_HAS_NO_MONOTONIC_CLOCK": "no-monotonic-clock",
303    "_LIBCPP_HAS_NO_THREADS": "no-threads",
304    "_LIBCPP_HAS_THREAD_API_EXTERNAL": "libcpp-has-thread-api-external",
305    "_LIBCPP_HAS_THREAD_API_PTHREAD": "libcpp-has-thread-api-pthread",
306    "_LIBCPP_NO_VCRUNTIME": "libcpp-no-vcruntime",
307    "_LIBCPP_ABI_VERSION": "libcpp-abi-version",
308    "_LIBCPP_ABI_BOUNDED_ITERATORS": "libcpp-has-abi-bounded-iterators",
309    "_LIBCPP_HAS_NO_FILESYSTEM": "no-filesystem",
310    "_LIBCPP_HAS_NO_RANDOM_DEVICE": "no-random-device",
311    "_LIBCPP_HAS_NO_LOCALIZATION": "no-localization",
312    "_LIBCPP_HAS_NO_WIDE_CHARACTERS": "no-wide-characters",
313    "_LIBCPP_HAS_NO_TIME_ZONE_DATABASE": "no-tzdb",
314    "_LIBCPP_HAS_NO_UNICODE": "libcpp-has-no-unicode",
315    "_LIBCPP_PSTL_CPU_BACKEND_LIBDISPATCH": "libcpp-pstl-cpu-backend-libdispatch",
316}
317for macro, feature in macros.items():
318    DEFAULT_FEATURES.append(
319        Feature(
320            name=lambda cfg, m=macro, f=feature: f + ("={}".format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ""),
321            when=lambda cfg, m=macro: m in compilerMacros(cfg),
322        )
323    )
324
325
326# Mapping from canonical locale names (used in the tests) to possible locale
327# names on various systems. Each locale is considered supported if any of the
328# alternative names is supported.
329locales = {
330    "en_US.UTF-8": ["en_US.UTF-8", "en_US.utf8", "English_United States.1252"],
331    "fr_FR.UTF-8": ["fr_FR.UTF-8", "fr_FR.utf8", "French_France.1252"],
332    "ja_JP.UTF-8": ["ja_JP.UTF-8", "ja_JP.utf8", "Japanese_Japan.923"],
333    "ru_RU.UTF-8": ["ru_RU.UTF-8", "ru_RU.utf8", "Russian_Russia.1251"],
334    "zh_CN.UTF-8": ["zh_CN.UTF-8", "zh_CN.utf8", "Chinese_China.936"],
335    "fr_CA.ISO8859-1": ["fr_CA.ISO8859-1", "French_Canada.1252"],
336    "cs_CZ.ISO8859-2": ["cs_CZ.ISO8859-2", "Czech_Czech Republic.1250"],
337}
338for locale, alts in locales.items():
339    # Note: Using alts directly in the lambda body here will bind it to the value at the
340    # end of the loop. Assigning it to a default argument works around this issue.
341    DEFAULT_FEATURES.append(
342        Feature(
343            name="locale.{}".format(locale),
344            when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts),
345        )
346    )
347
348
349# Add features representing the target platform name: darwin, linux, windows, etc...
350DEFAULT_FEATURES += [
351    Feature(name="darwin", when=lambda cfg: "__APPLE__" in compilerMacros(cfg)),
352    Feature(name="windows", when=lambda cfg: "_WIN32" in compilerMacros(cfg)),
353    Feature(
354        name="windows-dll",
355        when=lambda cfg: "_WIN32" in compilerMacros(cfg)
356        and sourceBuilds(
357            cfg,
358            """
359            #include <iostream>
360            int main(int, char**) { return 0; }
361          """,
362        )
363        and programSucceeds(
364            cfg,
365            """
366            #include <iostream>
367            #include <windows.h>
368            #include <winnt.h>
369            int main(int, char**) {
370              // Get a pointer to a data member that gets linked from the C++
371              // library. This must be a data member (functions can get
372              // thunk inside the calling executable), and must not be
373              // something that is defined inline in headers.
374              void *ptr = &std::cout;
375              // Get a handle to the current main executable.
376              void *exe = GetModuleHandle(NULL);
377              // The handle points at the PE image header. Navigate through
378              // the header structure to find the size of the PE image (the
379              // executable).
380              PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER)exe;
381              PIMAGE_NT_HEADERS ntheader = (PIMAGE_NT_HEADERS)((BYTE *)dosheader + dosheader->e_lfanew);
382              PIMAGE_OPTIONAL_HEADER peheader = &ntheader->OptionalHeader;
383              void *exeend = (BYTE*)exe + peheader->SizeOfImage;
384              // Check if the tested pointer - the data symbol from the
385              // C++ library - is located within the exe.
386              if (ptr >= exe && ptr <= exeend)
387                return 1;
388              // Return success if it was outside of the executable, i.e.
389              // loaded from a DLL.
390              return 0;
391            }
392          """,
393        ),
394        actions=[AddCompileFlag("-DTEST_WINDOWS_DLL")],
395    ),
396    Feature(name="linux", when=lambda cfg: "__linux__" in compilerMacros(cfg)),
397    Feature(name="android", when=lambda cfg: "__ANDROID__" in compilerMacros(cfg)),
398    Feature(
399        name=lambda cfg: "android-device-api={}".format(_getAndroidDeviceApi(cfg)),
400        when=lambda cfg: "__ANDROID__" in compilerMacros(cfg),
401    ),
402    Feature(
403        name="LIBCXX-ANDROID-FIXME",
404        when=lambda cfg: "__ANDROID__" in compilerMacros(cfg),
405    ),
406    Feature(name="netbsd", when=lambda cfg: "__NetBSD__" in compilerMacros(cfg)),
407    Feature(name="freebsd", when=lambda cfg: "__FreeBSD__" in compilerMacros(cfg)),
408    Feature(
409        name="LIBCXX-FREEBSD-FIXME",
410        when=lambda cfg: "__FreeBSD__" in compilerMacros(cfg),
411    ),
412    Feature(
413        name="LIBCXX-PICOLIBC-FIXME",
414        when=lambda cfg: sourceBuilds(
415            cfg,
416            """
417            #include <string.h>
418            #ifndef __PICOLIBC__
419            #error not picolibc
420            #endif
421            int main(int, char**) { return 0; }
422          """,
423        ),
424    ),
425    Feature(
426        name="can-create-symlinks",
427        when=lambda cfg: "_WIN32" not in compilerMacros(cfg)
428        or programSucceeds(
429            cfg,
430            # Creation of symlinks require elevated privileges on Windows unless
431            # Windows developer mode is enabled.
432            """
433            #include <stdio.h>
434            #include <windows.h>
435            int main() {
436              CHAR tempDirPath[MAX_PATH];
437              DWORD tempPathRet = GetTempPathA(MAX_PATH, tempDirPath);
438              if (tempPathRet == 0 || tempPathRet > MAX_PATH) {
439                return 1;
440              }
441
442              CHAR tempFilePath[MAX_PATH];
443              UINT uRetVal = GetTempFileNameA(
444                tempDirPath,
445                "cxx", // Prefix
446                0, // Unique=0 also implies file creation.
447                tempFilePath);
448              if (uRetVal == 0) {
449                return 1;
450              }
451
452              CHAR symlinkFilePath[MAX_PATH];
453              int ret = sprintf_s(symlinkFilePath, MAX_PATH, "%s_symlink", tempFilePath);
454              if (ret == -1) {
455                DeleteFileA(tempFilePath);
456                return 1;
457              }
458
459              // Requires either administrator, or developer mode enabled.
460              BOOL bCreatedSymlink = CreateSymbolicLinkA(symlinkFilePath,
461                tempFilePath,
462                SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE);
463              if (!bCreatedSymlink) {
464                DeleteFileA(tempFilePath);
465                return 1;
466              }
467
468              DeleteFileA(tempFilePath);
469              DeleteFileA(symlinkFilePath);
470              return 0;
471            }
472            """,
473        ),
474    ),
475]
476
477# Add features representing the build host platform name.
478# The build host could differ from the target platform for cross-compilation.
479DEFAULT_FEATURES += [
480    Feature(name="buildhost={}".format(sys.platform.lower().strip())),
481    # sys.platform can often be represented by a "sub-system", such as 'win32', 'cygwin', 'mingw', freebsd13 & etc.
482    # We define a consolidated feature on a few platforms.
483    Feature(
484        name="buildhost=windows",
485        when=lambda cfg: platform.system().lower().startswith("windows"),
486    ),
487    Feature(
488        name="buildhost=freebsd",
489        when=lambda cfg: platform.system().lower().startswith("freebsd"),
490    ),
491    Feature(
492        name="buildhost=aix",
493        when=lambda cfg: platform.system().lower().startswith("aix"),
494    ),
495]
496
497# Detect whether GDB is on the system, has Python scripting and supports
498# adding breakpoint commands. If so add a substitution to access it.
499def check_gdb(cfg):
500    gdb_path = shutil.which("gdb")
501    if gdb_path is None:
502        return False
503
504    # Check that we can set breakpoint commands, which was added in 8.3.
505    # Using the quit command here means that gdb itself exits, not just
506    # the "python <...>" command.
507    test_src = """\
508try:
509  gdb.Breakpoint(\"main\").commands=\"foo\"
510except AttributeError:
511  gdb.execute(\"quit 1\")
512gdb.execute(\"quit\")"""
513
514    try:
515        stdout = subprocess.check_output(
516            [gdb_path, "-ex", "python " + test_src, "--batch"],
517            stderr=subprocess.DEVNULL,
518            universal_newlines=True,
519        )
520    except subprocess.CalledProcessError:
521        # We can't set breakpoint commands
522        return False
523
524    # Check we actually ran the Python
525    return not "Python scripting is not supported" in stdout
526
527
528DEFAULT_FEATURES += [
529    Feature(
530        name="host-has-gdb-with-python",
531        when=check_gdb,
532        actions=[AddSubstitution("%{gdb}", lambda cfg: shutil.which("gdb"))],
533    )
534]
535
536# Define features for back-deployment testing.
537#
538# These features can be used to XFAIL tests that fail when deployed on (or compiled
539# for) an older system. For example, if a test exhibits a bug in the libc on a
540# particular system version, or if it uses a symbol that is not available on an
541# older version of the dylib, it can be marked as XFAIL with these features.
542#
543# It is sometimes useful to check that a test fails specifically when compiled for a
544# given deployment target. For example, this is the case when testing availability
545# markup, where we want to make sure that using the annotated facility on a deployment
546# target that doesn't support it will fail at compile time, not at runtime. This can
547# be achieved by creating a `.verify.cpp` test that checks for the right errors, and
548# mark that test as requiring `stdlib=<vendor>-libc++ && target=<target>`.
549#
550# Since it is not always known which deployment target to pick there are
551# short-hands based on the LLVM version like using-built-library-before-llvm-xx.
552# These short-hands make it easy for libc++ developers to select the proper
553# version the feature will be available in and allows vendors to set the proper
554# target information.
555DEFAULT_FEATURES += [
556    # Backdeployment short-hands
557    Feature(
558        name="using-built-library-before-llvm-11",
559        when=lambda cfg: BooleanExpression.evaluate(
560            "stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0)(.0)?}}",
561            cfg.available_features,
562        ),
563    ),
564    Feature(
565        name="using-built-library-before-llvm-12",
566        when=lambda cfg: BooleanExpression.evaluate(
567            "using-built-library-before-llvm-11 || (stdlib=apple-libc++ && target={{.+}}-apple-macosx12.{{(0|1|2)}}.0)",
568            cfg.available_features,
569        ),
570    ),
571
572    Feature(
573        name="using-built-library-before-llvm-13",
574        when=lambda cfg: BooleanExpression.evaluate(
575            "using-built-library-before-llvm-12 || (stdlib=apple-libc++ && target={{.+}}-apple-macosx{{((12.(3|4|5|6|7))|(13.(0|1|2|3)))}}.0)",
576            cfg.available_features,
577        ),
578    ),
579
580    Feature(
581        name="using-built-library-before-llvm-14",
582        when=lambda cfg: BooleanExpression.evaluate(
583            "using-built-library-before-llvm-13",
584            cfg.available_features,
585        ),
586    ),
587
588    Feature(
589        name="using-built-library-before-llvm-15",
590        when=lambda cfg: BooleanExpression.evaluate(
591            "using-built-library-before-llvm-14 || (stdlib=apple-libc++ && target={{.+}}-apple-macosx13.{{(4|5|6)}}.0)",
592            cfg.available_features,
593        ),
594    ),
595
596    Feature(
597        name="using-built-library-before-llvm-16",
598        when=lambda cfg: BooleanExpression.evaluate(
599            "using-built-library-before-llvm-15 || (stdlib=apple-libc++ && target={{.+}}-apple-macosx14.{{(0|1|2|3)}}.0)",
600            cfg.available_features,
601        ),
602    ),
603
604    Feature(
605        name="using-built-library-before-llvm-17",
606        when=lambda cfg: BooleanExpression.evaluate(
607            "using-built-library-before-llvm-16",
608            cfg.available_features,
609        ),
610    ),
611
612    Feature(
613        name="using-built-library-before-llvm-18",
614        when=lambda cfg: BooleanExpression.evaluate(
615            # For now, no released version of macOS contains LLVM 18
616            # TODO(ldionne) Please provide the correct value.
617            "using-built-library-before-llvm-17 || stdlib=apple-libc++ && target={{.+}}-apple-macosx{{.+}}",
618            cfg.available_features,
619        ),
620    ),
621
622    Feature(
623        name="using-built-library-before-llvm-19",
624        when=lambda cfg: BooleanExpression.evaluate(
625            # For now, no released version of macOS contains LLVM 19
626            # TODO(ldionne) Please provide the correct value.
627            "using-built-library-before-llvm-18 || stdlib=apple-libc++ && target={{.+}}-apple-macosx{{.+}}",
628            cfg.available_features,
629        ),
630    ),
631
632    # Tests that require std::to_chars(floating-point) in the built library
633    Feature(
634        name="availability-fp_to_chars-missing",
635        when=lambda cfg: BooleanExpression.evaluate(
636            "using-built-library-before-llvm-13",
637            cfg.available_features,
638        ),
639    ),
640    # Tests that require https://wg21.link/P0482 support in the built library
641    Feature(
642        name="availability-char8_t_support-missing",
643        when=lambda cfg: BooleanExpression.evaluate(
644            "using-built-library-before-llvm-11",
645            cfg.available_features,
646        ),
647    ),
648    # Tests that require __libcpp_verbose_abort support in the built library
649    Feature(
650        name="availability-verbose_abort-missing",
651        when=lambda cfg: BooleanExpression.evaluate(
652            "using-built-library-before-llvm-13",
653            cfg.available_features,
654        ),
655    ),
656    # Tests that require std::pmr support in the built library
657    Feature(
658        name="availability-pmr-missing",
659        when=lambda cfg: BooleanExpression.evaluate(
660            "using-built-library-before-llvm-13",
661            cfg.available_features,
662        ),
663    ),
664    # Tests that require std::filesystem support in the built library
665    Feature(
666        name="availability-filesystem-missing",
667        when=lambda cfg: BooleanExpression.evaluate(
668            "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(13|14)(.0)?}}",
669            cfg.available_features,
670        ),
671    ),
672    # Tests that require the C++20 synchronization library (P1135R6 implemented by https://llvm.org/D68480) in the built library
673    Feature(
674        name="availability-synchronization_library-missing",
675        when=lambda cfg: BooleanExpression.evaluate(
676            "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(13|14|15)(.0)?}}",
677            cfg.available_features,
678        ),
679    ),
680    # Tests that require time zone database support in the built library
681    Feature(
682        name="availability-tzdb-missing",
683        when=lambda cfg: BooleanExpression.evaluate(
684            "using-built-library-before-llvm-19",
685            cfg.available_features,
686        ),
687    ),
688    # Tests that require support for <print> and std::print in <ostream> in the built library.
689    Feature(
690        name="availability-print-missing",
691        when=lambda cfg: BooleanExpression.evaluate(
692            "using-built-library-before-llvm-18",
693            cfg.available_features,
694        ),
695    ),
696]
697