[libcxx] [libunwind] [libc++] Harden the test suite for running against older libc++ versions (PR #214820)
Louis Dionne via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 10 06:01:56 PDT 2026
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/214820
>From f4809a4a11e405f68f6258b308ebffd14770839e Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 7 Aug 2026 14:18:17 -0400
Subject: [PATCH 1/5] [libc++] Harden the test suite for running against older
libc++ versions
When running against older libc++ versions, the test suite had problems
when sniffing carve-out macros. Since we changed from e.g. _LIBCPP_HAS_NO_LOCALIZATION
to _LIBCPP_HAS_LOCALIZATION == 0|1, we would mis-detect the absence of
_LIBCPP_HAS_NO_LOCALIZATION being defined for localization being supported.
Fix this by explicitly handling checks for older versions. Note that this
also simplifies how we deal with the C++03 frozen headers, since in most
cases the same handling covers both the frozen headers and older versions
of the library.
Also, move the detection of Lit features for carve-outs from ad-hoc Python
checks to using <test_macros.h> directly, since that centralizes the
logic in a single place. This requires making "test_macros.h" available
to libunwind tests, which previously didn't have the proper include path.
---
libcxx/test/support/test_macros.h | 64 +++++++++++--------
libcxx/utils/libcxx/test/dsl.py | 54 +++++++++++-----
libcxx/utils/libcxx/test/features/__init__.py | 11 +++-
.../utils/libcxx/test/features/carveouts.py | 34 ++++++++++
.../libcxx/test/features/libcxx_macros.py | 7 --
.../libcxx/test/features/localization.py | 9 +--
libcxx/utils/libcxx/test/features/misc.py | 1 +
.../configs/apple-libunwind-system.cfg.in | 2 +-
.../configs/armv7m-picolibc-libunwind.cfg.in | 2 +-
libunwind/test/configs/cmake-bridge.cfg.in | 1 +
.../test/configs/ibm-libunwind-shared.cfg.in | 2 +-
.../test/configs/llvm-libunwind-merged.cfg.in | 2 +-
.../llvm-libunwind-shared-mingw.cfg.in | 2 +-
.../test/configs/llvm-libunwind-shared.cfg.in | 2 +-
.../llvm-libunwind-static-mingw.cfg.in | 2 +-
.../test/configs/llvm-libunwind-static.cfg.in | 2 +-
16 files changed, 137 insertions(+), 60 deletions(-)
create mode 100644 libcxx/utils/libcxx/test/features/carveouts.py
diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index 82975a38884f0..9c07f08b7d573 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -229,11 +229,9 @@
# define TEST_IS_EXECUTED_IN_A_SLOW_ENVIRONMENT
#endif
-#ifdef _LIBCPP_USE_FROZEN_CXX03_HEADERS
-# ifdef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
-# define TEST_HAS_NO_ALIGNED_ALLOCATION
-# endif
-#elif defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_ALIGNED_ALLOCATION
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_ALIGNED_ALLOCATION) && !_LIBCPP_HAS_ALIGNED_ALLOCATION
+# define TEST_HAS_NO_ALIGNED_ALLOCATION
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) /* old libc++ version */
# define TEST_HAS_NO_ALIGNED_ALLOCATION
#elif TEST_STD_VER < 17 && (!defined(__cpp_aligned_new) || __cpp_aligned_new < 201606L)
# define TEST_HAS_NO_ALIGNED_ALLOCATION
@@ -287,9 +285,12 @@
#define TEST_IGNORE_NODISCARD (void)
-#ifdef _LIBCPP_USE_FROZEN_CXX03_HEADERS
-// from-chars is a C++17 feature, so it's never available anyways
-#elif !defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT) && \
+ !_LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT
+// not available
+#elif defined(_LIBCPP_VERSION) && !defined(_LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT) /* old libc++ version */
+// not available
+#else
# define TEST_HAS_FROM_CHARS_FLOATING_POINT
#endif
@@ -420,11 +421,13 @@ inline Tp const& DoNotOptimize(Tp const& value) {
#endif
// Support for carving out parts of the test suite, like removing wide characters, etc.
-#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_WIDE_CHARACTERS
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_WIDE_CHARACTERS) && !_LIBCPP_HAS_WIDE_CHARACTERS
+# define TEST_HAS_NO_WIDE_CHARACTERS
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) /* old libc++ version */
# define TEST_HAS_NO_WIDE_CHARACTERS
#endif
-#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_UNICODE
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_UNICODE) && !_LIBCPP_HAS_UNICODE
# define TEST_HAS_NO_UNICODE
#elif defined(_MSVC_EXECUTION_CHARACTER_SET) && _MSVC_EXECUTION_CHARACTER_SET != 65001
# define TEST_HAS_NO_UNICODE
@@ -434,7 +437,7 @@ inline Tp const& DoNotOptimize(Tp const& value) {
# ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
# define TEST_HAS_OPEN_WITH_WCHAR
# endif
-#elif defined(_LIBCPP_VERSION) && _LIBCPP_HAS_OPEN_WITH_WCHAR
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_OPEN_WITH_WCHAR) && _LIBCPP_HAS_OPEN_WITH_WCHAR
# define TEST_HAS_OPEN_WITH_WCHAR
#endif
@@ -442,11 +445,17 @@ inline Tp const& DoNotOptimize(Tp const& value) {
# ifdef _LIBCPP_HAS_NO_INT128
# define TEST_HAS_NO_INT128
# endif
-#elif (defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_INT128) || defined(_MSVC_STL_VERSION)
+#elif defined(_LIBCPP_VERSION) && (defined(_LIBCPP_HAS_INT128) && !_LIBCPP_HAS_INT128)
+# define TEST_HAS_NO_INT128
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_INT128) /* old libc++ version */
+# define TEST_HAS_NO_INT128
+#elif defined(_MSVC_STL_VERSION)
# define TEST_HAS_NO_INT128
#endif
-#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_LOCALIZATION
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_LOCALIZATION) && !_LIBCPP_HAS_LOCALIZATION
+# define TEST_HAS_NO_LOCALIZATION
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_LOCALIZATION) /* old libc++ version */
# define TEST_HAS_NO_LOCALIZATION
#endif
@@ -454,34 +463,39 @@ inline Tp const& DoNotOptimize(Tp const& value) {
# define TEST_HAS_NO_CHAR8_T
#endif
-#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_THREADS
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_THREADS) && !_LIBCPP_HAS_THREADS
+# define TEST_HAS_NO_THREADS
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_THREADS) /* old libc++ version */
# define TEST_HAS_NO_THREADS
#endif
-#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_FILESYSTEM
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_FILESYSTEM) && !_LIBCPP_HAS_FILESYSTEM
+# define TEST_HAS_NO_FILESYSTEM
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_FILESYSTEM) /* old libc++ version */
# define TEST_HAS_NO_FILESYSTEM
#endif
-#ifdef _LIBCPP_USE_FROZEN_CXX03_HEADERS
-# ifdef _LIBCPP_HAS_NO_C8RTOMB_MBRTOC8
-# define TEST_HAS_NO_C8RTOMB_MBRTOC8
-# endif
-#elif defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_C8RTOMB_MBRTOC8
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_C8RTOMB_MBRTOC8) && !_LIBCPP_HAS_C8RTOMB_MBRTOC8
+# define TEST_HAS_NO_C8RTOMB_MBRTOC8
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_C8RTOMB_MBRTOC8) /* old libc++ version */
# define TEST_HAS_NO_C8RTOMB_MBRTOC8
#endif
-#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_RANDOM_DEVICE
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_RANDOM_DEVICE) && !_LIBCPP_HAS_RANDOM_DEVICE
+# define TEST_HAS_NO_RANDOM_DEVICE
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_RANDOM_DEVICE) /* old libc++ version */
# define TEST_HAS_NO_RANDOM_DEVICE
#endif
-#ifdef _LIBCPP_USE_FROZEN_CXX03_HEADERS
-// This is a C++20 feature, so it's never available anyways
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_EXPERIMENTAL_TZDB) && !_LIBCPP_HAS_EXPERIMENTAL_TZDB
# define TEST_HAS_NO_EXPERIMENTAL_TZDB
-#elif defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_EXPERIMENTAL_TZDB
+#elif defined(_LIBCPP_VERSION) && !defined(_LIBCPP_HAS_EXPERIMENTAL_TZDB) /* old libc++ version */
# define TEST_HAS_NO_EXPERIMENTAL_TZDB
#endif
-#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_TIME_ZONE_DATABASE
+#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_TIME_ZONE_DATABASE) && !_LIBCPP_HAS_TIME_ZONE_DATABASE
+# define TEST_HAS_NO_TIME_ZONE_DATABASE
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) /* old libc++ version */
# define TEST_HAS_NO_TIME_ZONE_DATABASE
#endif
diff --git a/libcxx/utils/libcxx/test/dsl.py b/libcxx/utils/libcxx/test/dsl.py
index c7db35fd629b6..d44752278c0a9 100644
--- a/libcxx/utils/libcxx/test/dsl.py
+++ b/libcxx/utils/libcxx/test/dsl.py
@@ -307,7 +307,8 @@ def hasAnyLocale(config, locales):
program = (
"""
#include <stddef.h>
- #if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_LOCALIZATION
+ #include <test_macros.h>
+ #ifdef TEST_HAS_NO_LOCALIZATION
int main(int, char**) { return 1; }
#else
#include <locale.h>
@@ -330,32 +331,22 @@ def hasAnyLocale(config, locales):
return programSucceeds(config, program)
- at _memoizeExpensiveOperation(lambda c, flags="": (c.substitutions, c.environment, flags))
-def compilerMacros(config, flags=""):
+def _macrosFromSource(config, source, flags=""):
"""
- Return a dictionary of predefined compiler macros.
+ Preprocess the given source and return a dictionary of the macros it defines.
The keys are strings representing macros, and the values are strings
representing what each macro is defined to.
-
- If the optional `flags` argument (a string) is provided, these flags will
- be added to the compiler invocation when generating the macros.
"""
with _makeConfigTest(config) as test:
with open(test.getSourcePath(), "w") as sourceFile:
- sourceFile.write(
- """
- #if __has_include(<__config>)
- # include <__config>
- #endif
- """
- )
+ sourceFile.write(source)
unparsedOutput, err, exitCode, _, cmd, _ = _executeWithFakeConfig(
test, ["%{{cxx}} %s -dM -E %{{flags}} %{{compile_flags}} {}".format(flags)]
)
if exitCode != 0:
raise ConfigurationCompilationError(
- "Failed to retrieve compiler macros, compiler invocation is:\n{}\nstderr is:\n{}".format(
+ "Failed to retrieve macros, compiler invocation is:\n{}\nstderr is:\n{}".format(
cmd, err
)
)
@@ -370,6 +361,39 @@ def compilerMacros(config, flags=""):
return parsedMacros
+ at _memoizeExpensiveOperation(lambda c, flags="": (c.substitutions, c.environment, flags))
+def compilerMacros(config, flags=""):
+ """
+ Return a dictionary of predefined compiler macros.
+
+ The keys are strings representing macros, and the values are strings
+ representing what each macro is defined to.
+
+ If the optional `flags` argument (a string) is provided, these flags will
+ be added to the compiler invocation when generating the macros.
+ """
+ source = """
+ #if __has_include(<__config>)
+ # include <__config>
+ #endif
+ """
+ return _macrosFromSource(config, source, flags)
+
+
+ at _memoizeExpensiveOperation(lambda c, flags="": (c.substitutions, c.environment, flags))
+def testMacros(config, flags=""):
+ """
+ Return a dictionary of the macros defined by the test suite's <test_macros.h>.
+
+ The keys are strings representing macros, and the values are strings
+ representing what each macro is defined to.
+
+ If the optional `flags` argument (a string) is provided, these flags will
+ be added to the compiler invocation when generating the macros.
+ """
+ return _macrosFromSource(config, "#include <test_macros.h>\n", flags)
+
+
def featureTestMacros(config, flags=""):
"""
Return a dictionary of feature test macros.
diff --git a/libcxx/utils/libcxx/test/features/__init__.py b/libcxx/utils/libcxx/test/features/__init__.py
index 8e9bc0e97b2d6..7516f4fc2f188 100644
--- a/libcxx/utils/libcxx/test/features/__init__.py
+++ b/libcxx/utils/libcxx/test/features/__init__.py
@@ -6,7 +6,15 @@
#
# ===----------------------------------------------------------------------===##
-from . import availability, compiler, gdb, hardening, libcxx_macros, localization, misc, platform
+from . import availability
+from . import carveouts
+from . import compiler
+from . import gdb
+from . import hardening
+from . import libcxx_macros
+from . import localization
+from . import misc
+from . import platform
# Lit features are evaluated in order. Some features depend on other features, so
# we are careful to define them in the correct order. For example, several features
@@ -14,6 +22,7 @@
DEFAULT_FEATURES = []
DEFAULT_FEATURES += compiler.features
DEFAULT_FEATURES += libcxx_macros.features
+DEFAULT_FEATURES += carveouts.features
DEFAULT_FEATURES += platform.features
DEFAULT_FEATURES += localization.features
DEFAULT_FEATURES += gdb.features
diff --git a/libcxx/utils/libcxx/test/features/carveouts.py b/libcxx/utils/libcxx/test/features/carveouts.py
new file mode 100644
index 0000000000000..f485b15cdf464
--- /dev/null
+++ b/libcxx/utils/libcxx/test/features/carveouts.py
@@ -0,0 +1,34 @@
+# ===----------------------------------------------------------------------===##
+#
+# 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
+#
+# ===----------------------------------------------------------------------===##
+
+from libcxx.test.dsl import Feature, testMacros
+
+features = []
+
+# Features describing parts of the library that can be carved out, like localization
+# or threading support.
+#
+# These are detected by asking <test_macros.h> whether it considers the carve-out to be
+# in effect. This keeps the logic for determining whether a carve-out applies in a single
+# place, and it guarantees that these Lit features agree with what the tests use.
+carveouts = {
+ "TEST_HAS_NO_FILESYSTEM": "no-filesystem",
+ "TEST_HAS_NO_LOCALIZATION": "no-localization",
+ "TEST_HAS_NO_RANDOM_DEVICE": "no-random-device",
+ "TEST_HAS_NO_THREADS": "no-threads",
+ "TEST_HAS_NO_TIME_ZONE_DATABASE": "no-tzdb",
+ "TEST_HAS_NO_UNICODE": "libcpp-has-no-unicode",
+ "TEST_HAS_NO_WIDE_CHARACTERS": "no-wide-characters",
+}
+for macro, feature in carveouts.items():
+ features.append(
+ Feature(
+ name=feature,
+ when=lambda cfg, m=macro: m in testMacros(cfg),
+ )
+ )
diff --git a/libcxx/utils/libcxx/test/features/libcxx_macros.py b/libcxx/utils/libcxx/test/features/libcxx_macros.py
index ec149bef1a40e..9ac22e07c549c 100644
--- a/libcxx/utils/libcxx/test/features/libcxx_macros.py
+++ b/libcxx/utils/libcxx/test/features/libcxx_macros.py
@@ -60,15 +60,8 @@
)
inverted_macros = {
- "_LIBCPP_HAS_TIME_ZONE_DATABASE": "no-tzdb",
- "_LIBCPP_HAS_FILESYSTEM": "no-filesystem",
- "_LIBCPP_HAS_LOCALIZATION": "no-localization",
- "_LIBCPP_HAS_THREADS": "no-threads",
"_LIBCPP_HAS_MONOTONIC_CLOCK": "no-monotonic-clock",
- "_LIBCPP_HAS_WIDE_CHARACTERS": "no-wide-characters",
"_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS": "libcpp-has-no-availability-markup",
- "_LIBCPP_HAS_RANDOM_DEVICE": "no-random-device",
- "_LIBCPP_HAS_UNICODE": "libcpp-has-no-unicode",
}
for macro, feature in inverted_macros.items():
features.append(
diff --git a/libcxx/utils/libcxx/test/features/localization.py b/libcxx/utils/libcxx/test/features/localization.py
index 95e1bb5c1afa4..b45c0bf5fd8c0 100644
--- a/libcxx/utils/libcxx/test/features/localization.py
+++ b/libcxx/utils/libcxx/test/features/localization.py
@@ -6,7 +6,7 @@
#
# ===----------------------------------------------------------------------===##
-from libcxx.test.dsl import compilerMacros, Feature, programSucceeds, hasAnyLocale, programOutput, AddSubstitution
+from libcxx.test.dsl import Feature, programSucceeds, hasAnyLocale, programOutput, testMacros, AddSubstitution
import re
features = [
@@ -23,8 +23,10 @@
#include <locale.h>
#endif
+ #include "test_macros.h"
+
int main(int, char**) {
- #if __has_include(<locale.h>) && (!defined(_LIBCPP_HAS_LOCALIZATION) || _LIBCPP_HAS_LOCALIZATION == 1)
+ #if __has_include(<locale.h>) && !defined(TEST_HAS_NO_LOCALIZATION)
setlocale(LC_ALL, "ru_RU.UTF-8");
return strcmp(localeconv()->mon_decimal_point, ".") == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
#else
@@ -63,8 +65,7 @@
cfg, locale, alts, _provide_locale_conversions[locale]
)
if locale in _provide_locale_conversions
- and ("_LIBCPP_HAS_WIDE_CHARACTERS" not in compilerMacros(cfg) or
- compilerMacros(cfg)["_LIBCPP_HAS_WIDE_CHARACTERS"] == "1")
+ and "TEST_HAS_NO_WIDE_CHARACTERS" not in testMacros(cfg)
else [],
),
)
diff --git a/libcxx/utils/libcxx/test/features/misc.py b/libcxx/utils/libcxx/test/features/misc.py
index 3701498f595dc..4b74ec7c0d6f4 100644
--- a/libcxx/utils/libcxx/test/features/misc.py
+++ b/libcxx/utils/libcxx/test/features/misc.py
@@ -121,6 +121,7 @@ def _mingwSupportsModules(cfg):
# Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.20348.0):
# https://developercommunity.visualstudio.com/t/utf-8-locales-break-ctype-functions-for-wchar-type/1653678
Feature(
+ # TODO: Update once https://github.com/llvm/llvm-project/pull/214797 has been merged
name="win32-broken-utf8-wchar-ctype",
when=lambda cfg: not "_LIBCPP_HAS_LOCALIZATION" in compilerMacros(cfg)
or compilerMacros(cfg)["_LIBCPP_HAS_LOCALIZATION"] == "1"
diff --git a/libunwind/test/configs/apple-libunwind-system.cfg.in b/libunwind/test/configs/apple-libunwind-system.cfg.in
index 2349ca394b58b..d0465d5550fdc 100644
--- a/libunwind/test/configs/apple-libunwind-system.cfg.in
+++ b/libunwind/test/configs/apple-libunwind-system.cfg.in
@@ -13,7 +13,7 @@ config.substitutions.append(('%{flags}',
'-isysroot {}'.format('@CMAKE_OSX_SYSROOT@') if '@CMAKE_OSX_SYSROOT@' else ''
))
-compile_flags = ['-nostdinc++', '-I', '%{include}']
+compile_flags = ['-nostdinc++', '-I', '%{include}', '-I', '%{libcxx}/test/support']
if @HAVE_CFI_SET_RA_STATE@:
compile_flags.append('-DHAVE_CFI_SET_RA_STATE')
diff --git a/libunwind/test/configs/armv7m-picolibc-libunwind.cfg.in b/libunwind/test/configs/armv7m-picolibc-libunwind.cfg.in
index 6ffdd70c6177e..11a0f61f5720e 100644
--- a/libunwind/test/configs/armv7m-picolibc-libunwind.cfg.in
+++ b/libunwind/test/configs/armv7m-picolibc-libunwind.cfg.in
@@ -5,7 +5,7 @@ libc_linker_script = '@CMAKE_INSTALL_PREFIX@/lib/picolibcpp.ld'
config.substitutions.append(('%{flags}', '--sysroot=@CMAKE_INSTALL_PREFIX@'))
config.substitutions.append(('%{compile_flags}',
- '-nostdinc++ -I %{include}'
+ '-nostdinc++ -I %{include} -I %{libcxx}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-fuse-ld=lld -nostdlib -nostdlib++ -L %{lib} -lunwind'
diff --git a/libunwind/test/configs/cmake-bridge.cfg.in b/libunwind/test/configs/cmake-bridge.cfg.in
index 09bd92ab9fee2..ed0b2afbc0c0d 100644
--- a/libunwind/test/configs/cmake-bridge.cfg.in
+++ b/libunwind/test/configs/cmake-bridge.cfg.in
@@ -41,6 +41,7 @@ if _norm_triple != config.target_triple:
config.available_features.add('target={}'.format(_norm_triple))
# Add substitutions for bootstrapping the test suite configuration
+config.substitutions.append(('%{libcxx}', '@LIBUNWIND_LIBCXX_PATH@'))
config.substitutions.append(('%{install-prefix}', '@LIBUNWIND_TESTING_INSTALL_PREFIX@'))
config.substitutions.append(('%{include}', '@LIBUNWIND_TESTING_INSTALL_PREFIX@/include'))
config.substitutions.append(('%{lib}', '@LIBUNWIND_TESTING_INSTALL_PREFIX@/@LIBUNWIND_INSTALL_LIBRARY_DIR@'))
diff --git a/libunwind/test/configs/ibm-libunwind-shared.cfg.in b/libunwind/test/configs/ibm-libunwind-shared.cfg.in
index 99f4a9061d19a..6848bf9dbbc45 100644
--- a/libunwind/test/configs/ibm-libunwind-shared.cfg.in
+++ b/libunwind/test/configs/ibm-libunwind-shared.cfg.in
@@ -11,7 +11,7 @@ if lit.util.isAIXTriple(config.target_triple):
config.substitutions.append(('%{flags}', ''))
config.substitutions.append(('%{compile_flags}',
- '-nostdinc++ -I %{include}'
+ '-nostdinc++ -I %{include} -I %{libcxx}/test/support'
))
config.substitutions.append(('%{link_flags}',
'-nostdlib++ -L %{lib} -lunwind -ldl -Wl,-bbigtoc'
diff --git a/libunwind/test/configs/llvm-libunwind-merged.cfg.in b/libunwind/test/configs/llvm-libunwind-merged.cfg.in
index 231849f5c4e56..b05a55e40559b 100644
--- a/libunwind/test/configs/llvm-libunwind-merged.cfg.in
+++ b/libunwind/test/configs/llvm-libunwind-merged.cfg.in
@@ -38,7 +38,7 @@ config.substitutions.append(('%{flags}',
'-isysroot {}'.format(local_sysroot) if local_sysroot else ''
))
config.substitutions.append(('%{compile_flags}',
- '-nostdinc++ -I %{{include}} {}'.format(' '.join(compile_flags))
+ '-nostdinc++ -I %{{include}} -I %{{libcxx}}/test/support {}'.format(' '.join(compile_flags))
))
config.substitutions.append(('%{link_flags}',
'-L %{{lib}} -Wl,-rpath,%{{lib}} -lc++ {}'.format(' '.join(link_flags))
diff --git a/libunwind/test/configs/llvm-libunwind-shared-mingw.cfg.in b/libunwind/test/configs/llvm-libunwind-shared-mingw.cfg.in
index 1e77638b8cee3..de3029d579921 100644
--- a/libunwind/test/configs/llvm-libunwind-shared-mingw.cfg.in
+++ b/libunwind/test/configs/llvm-libunwind-shared-mingw.cfg.in
@@ -5,7 +5,7 @@ lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')
config.substitutions.append(('%{flags}', ''))
config.substitutions.append(('%{compile_flags}',
- '-nostdinc++ -I %{include} -funwind-tables'
+ '-nostdinc++ -I %{include} -I %{libcxx}/test/support -funwind-tables'
))
config.substitutions.append(('%{link_flags}',
'-L %{lib} -lunwind'
diff --git a/libunwind/test/configs/llvm-libunwind-shared.cfg.in b/libunwind/test/configs/llvm-libunwind-shared.cfg.in
index 0a7a24eb08c5e..8ae618fd7f6ae 100644
--- a/libunwind/test/configs/llvm-libunwind-shared.cfg.in
+++ b/libunwind/test/configs/llvm-libunwind-shared.cfg.in
@@ -37,7 +37,7 @@ config.substitutions.append(('%{flags}',
'-isysroot {}'.format(local_sysroot) if local_sysroot else ''
))
config.substitutions.append(('%{compile_flags}',
- '-nostdinc++ -I %{{include}} {}'.format(' '.join(compile_flags))
+ '-nostdinc++ -I %{{include}} -I %{{libcxx}}/test/support {}'.format(' '.join(compile_flags))
))
config.substitutions.append(('%{link_flags}',
'-L %{{lib}} -Wl,-rpath,%{{lib}} -lunwind {}'.format(' '.join(link_flags))
diff --git a/libunwind/test/configs/llvm-libunwind-static-mingw.cfg.in b/libunwind/test/configs/llvm-libunwind-static-mingw.cfg.in
index 37d20a7c9a449..47921e9c32a36 100644
--- a/libunwind/test/configs/llvm-libunwind-static-mingw.cfg.in
+++ b/libunwind/test/configs/llvm-libunwind-static-mingw.cfg.in
@@ -5,7 +5,7 @@ lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')
config.substitutions.append(('%{flags}', ''))
config.substitutions.append(('%{compile_flags}',
- '-nostdinc++ -I %{include} -funwind-tables'
+ '-nostdinc++ -I %{include} -I %{libcxx}/test/support -funwind-tables'
))
config.substitutions.append(('%{link_flags}',
'-L %{lib} -lunwind'
diff --git a/libunwind/test/configs/llvm-libunwind-static.cfg.in b/libunwind/test/configs/llvm-libunwind-static.cfg.in
index f831c74948579..f4b8e1b03b9b5 100644
--- a/libunwind/test/configs/llvm-libunwind-static.cfg.in
+++ b/libunwind/test/configs/llvm-libunwind-static.cfg.in
@@ -40,7 +40,7 @@ config.substitutions.append(('%{flags}',
'-isysroot {}'.format(local_sysroot) if local_sysroot else ''
))
config.substitutions.append(('%{compile_flags}',
- '-nostdinc++ -I %{{include}} {}'.format(' '.join(compile_flags))
+ '-nostdinc++ -I %{{include}} -I %{{libcxx}}/test/support {}'.format(' '.join(compile_flags))
))
config.substitutions.append(('%{link_flags}',
'%{{lib}}/libunwind.a {}'.format(' '.join(link_flags))
>From 3fc8b3fa6acb8fbdd4e0cc2f4c8f918a6918ab1e Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 7 Aug 2026 14:44:51 -0400
Subject: [PATCH 2/5] Redundant parens
---
libcxx/test/support/test_macros.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index 9c07f08b7d573..1c5447a772f3f 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -445,7 +445,7 @@ inline Tp const& DoNotOptimize(Tp const& value) {
# ifdef _LIBCPP_HAS_NO_INT128
# define TEST_HAS_NO_INT128
# endif
-#elif defined(_LIBCPP_VERSION) && (defined(_LIBCPP_HAS_INT128) && !_LIBCPP_HAS_INT128)
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_INT128) && !_LIBCPP_HAS_INT128
# define TEST_HAS_NO_INT128
#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_INT128) /* old libc++ version */
# define TEST_HAS_NO_INT128
>From fc174a9d0fd07821eed4601f91f972def90af08d Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 10 Aug 2026 08:48:26 -0400
Subject: [PATCH 3/5] Handle no unicode
---
libcxx/test/support/test_macros.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index 1c5447a772f3f..a06826104a324 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -429,6 +429,8 @@ inline Tp const& DoNotOptimize(Tp const& value) {
#if defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_UNICODE) && !_LIBCPP_HAS_UNICODE
# define TEST_HAS_NO_UNICODE
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_UNICODE) /* old libc++ version */
+# define TEST_HAS_NO_UNICODE
#elif defined(_MSVC_EXECUTION_CHARACTER_SET) && _MSVC_EXECUTION_CHARACTER_SET != 65001
# define TEST_HAS_NO_UNICODE
#endif
>From 07fe5f025ddac0a2b150dda097a5634196fc6758 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 10 Aug 2026 08:49:39 -0400
Subject: [PATCH 4/5] Handle no <ciso646> being available
---
libcxx/test/support/test_macros.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index a06826104a324..de6fa29234106 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -13,7 +13,7 @@
#ifdef __has_include
# if __has_include(<version>)
# include <version>
-# else
+# elif __has_include(<ciso646>)
# include <ciso646>
# endif
#else
>From f8b4eeffe33cb6e515b92c7b340d09e71eae244a Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 10 Aug 2026 09:01:39 -0400
Subject: [PATCH 5/5] Adjust after landing win32-broken-utf8-wchar-ctype
simplification
---
libcxx/utils/libcxx/test/dsl.py | 4 +++-
libcxx/utils/libcxx/test/features/misc.py | 5 +++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/libcxx/utils/libcxx/test/dsl.py b/libcxx/utils/libcxx/test/dsl.py
index d44752278c0a9..bc65c9b74219f 100644
--- a/libcxx/utils/libcxx/test/dsl.py
+++ b/libcxx/utils/libcxx/test/dsl.py
@@ -307,7 +307,9 @@ def hasAnyLocale(config, locales):
program = (
"""
#include <stddef.h>
- #include <test_macros.h>
+
+ #include "test_macros.h"
+
#ifdef TEST_HAS_NO_LOCALIZATION
int main(int, char**) { return 1; }
#else
diff --git a/libcxx/utils/libcxx/test/features/misc.py b/libcxx/utils/libcxx/test/features/misc.py
index df53d006ed66d..1f4b808e40820 100644
--- a/libcxx/utils/libcxx/test/features/misc.py
+++ b/libcxx/utils/libcxx/test/features/misc.py
@@ -121,7 +121,6 @@ def _mingwSupportsModules(cfg):
# Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.20348.0):
# https://developercommunity.visualstudio.com/t/utf-8-locales-break-ctype-functions-for-wchar-type/1653678
Feature(
- # TODO: Update once https://github.com/llvm/llvm-project/pull/214797 has been merged
name="win32-broken-utf8-wchar-ctype",
when=lambda cfg: "_WIN32" in compilerMacros(cfg)
and programSucceeds(
@@ -133,8 +132,10 @@ def _mingwSupportsModules(cfg):
#include <stdlib.h>
#include <wctype.h>
+ #include "test_macros.h"
+
int main(int, char**) {
- #if !defined(_LIBCPP_VERSION) || (defined(_LIBCPP_HAS_LOCALIZATION) && _LIBCPP_HAS_LOCALIZATION)
+ #ifndef TEST_HAS_NO_LOCALIZATION
setlocale(LC_ALL, "en_US.UTF-8");
return towlower(L'\\xDA') == L'\\xFA' ? EXIT_FAILURE : EXIT_SUCCESS;
#else
More information about the cfe-commits
mailing list