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_isClang = lambda cfg: '__clang__' in compilerMacros(cfg) and '__apple_build_version__' not in compilerMacros(cfg) 17_isAppleClang = lambda cfg: '__apple_build_version__' in compilerMacros(cfg) 18_isGCC = lambda cfg: '__GNUC__' in compilerMacros(cfg) and '__clang__' not in compilerMacros(cfg) 19_isMSVC = lambda cfg: '_MSC_VER' in compilerMacros(cfg) 20_msvcVersion = lambda cfg: (int(compilerMacros(cfg)['_MSC_VER']) // 100, int(compilerMacros(cfg)['_MSC_VER']) % 100) 21 22def _getSuitableClangTidy(cfg): 23 try: 24 # If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests. 25 if runScriptExitCode(cfg, ['stat %{test-tools}/clang_tidy_checks/libcxx-tidy.plugin']) != 0: 26 return None 27 28 # TODO This should be the last stable release. 29 if runScriptExitCode(cfg, ['clang-tidy-16 --version']) == 0: 30 return 'clang-tidy-16' 31 32 if int(re.search('[0-9]+', commandOutput(cfg, ['clang-tidy --version'])).group()) >= 16: 33 return 'clang-tidy' 34 35 except ConfigurationRuntimeError: 36 return None 37 38DEFAULT_FEATURES = [ 39 Feature(name='thread-safety', 40 when=lambda cfg: hasCompileFlag(cfg, '-Werror=thread-safety'), 41 actions=[AddCompileFlag('-Werror=thread-safety')]), 42 43 Feature(name='diagnose-if-support', 44 when=lambda cfg: hasCompileFlag(cfg, '-Wuser-defined-warnings'), 45 actions=[AddCompileFlag('-Wuser-defined-warnings')]), 46 47 # Tests to validate whether the compiler has a way to set the maximum number 48 # of steps during constant evaluation. Since the flag differs per compiler 49 # store the "valid" flag as a feature. This allows passing the proper compile 50 # flag to the compiler: 51 # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12345678 52 # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=12345678 53 Feature(name='has-fconstexpr-steps', 54 when=lambda cfg: hasCompileFlag(cfg, '-fconstexpr-steps=1')), 55 56 Feature(name='has-fconstexpr-ops-limit', 57 when=lambda cfg: hasCompileFlag(cfg, '-fconstexpr-ops-limit=1')), 58 59 Feature(name='has-fblocks', when=lambda cfg: hasCompileFlag(cfg, '-fblocks')), 60 Feature(name='-fsized-deallocation', when=lambda cfg: hasCompileFlag(cfg, '-fsized-deallocation')), 61 Feature(name='-faligned-allocation', when=lambda cfg: hasCompileFlag(cfg, '-faligned-allocation')), 62 Feature(name='fdelayed-template-parsing', when=lambda cfg: hasCompileFlag(cfg, '-fdelayed-template-parsing')), 63 Feature(name='libcpp-no-coroutines', when=lambda cfg: featureTestMacros(cfg).get('__cpp_impl_coroutine', 0) < 201902), 64 Feature(name='has-fobjc-arc', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc') and 65 sys.platform.lower().strip() == 'darwin'), # TODO: this doesn't handle cross-compiling to Apple platforms. 66 Feature(name='objective-c++', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc')), 67 Feature(name='verify-support', when=lambda cfg: hasCompileFlag(cfg, '-Xclang -verify-ignore-unexpected')), 68 69 Feature(name='non-lockfree-atomics', 70 when=lambda cfg: sourceBuilds(cfg, """ 71 #include <atomic> 72 struct Large { int storage[100]; }; 73 std::atomic<Large> x; 74 int main(int, char**) { (void)x.load(); return 0; } 75 """)), 76 # TODO: Remove this feature once compiler-rt includes __atomic_is_lockfree() 77 # on all supported platforms. 78 Feature(name='is-lockfree-runtime-function', 79 when=lambda cfg: sourceBuilds(cfg, """ 80 #include <atomic> 81 struct Large { int storage[100]; }; 82 std::atomic<Large> x; 83 int main(int, char**) { return x.is_lock_free(); } 84 """)), 85 86 # Some tests rely on creating shared libraries which link in the C++ Standard Library. In some 87 # cases, this doesn't work (e.g. if the library was built as a static archive and wasn't compiled 88 # as position independent). This feature informs the test suite of whether it's possible to create 89 # a shared library in a shell test by using the '-shared' compiler flag. 90 # 91 # Note: To implement this check properly, we need to make sure that we use something inside the 92 # compiled library, not only in the headers. It should be safe to assume that all implementations 93 # define `operator new` in the compiled library. 94 Feature(name='cant-build-shared-library', 95 when=lambda cfg: not sourceBuilds(cfg, """ 96 void f() { new int(3); } 97 """, ['-shared'])), 98 99 # Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.20348.0): 100 # https://developercommunity.visualstudio.com/t/utf-8-locales-break-ctype-functions-for-wchar-type/1653678 101 Feature(name='win32-broken-utf8-wchar-ctype', 102 when=lambda cfg: not '_LIBCPP_HAS_NO_LOCALIZATION' in compilerMacros(cfg) and '_WIN32' in compilerMacros(cfg) and not programSucceeds(cfg, """ 103 #include <locale.h> 104 #include <wctype.h> 105 int main(int, char**) { 106 setlocale(LC_ALL, "en_US.UTF-8"); 107 return towlower(L'\\xDA') != L'\\xFA'; 108 } 109 """)), 110 111 # Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.19041.0). 112 # https://developercommunity.visualstudio.com/t/printf-formatting-with-g-outputs-too/1660837 113 Feature(name='win32-broken-printf-g-precision', 114 when=lambda cfg: '_WIN32' in compilerMacros(cfg) and not programSucceeds(cfg, """ 115 #include <stdio.h> 116 #include <string.h> 117 int main(int, char**) { 118 char buf[100]; 119 snprintf(buf, sizeof(buf), "%#.*g", 0, 0.0); 120 return strcmp(buf, "0."); 121 } 122 """)), 123 124 # Check for Glibc < 2.27, where the ru_RU.UTF-8 locale had 125 # mon_decimal_point == ".", which our tests don't handle. 126 Feature(name='glibc-old-ru_RU-decimal-point', 127 when=lambda cfg: not '_LIBCPP_HAS_NO_LOCALIZATION' in compilerMacros(cfg) and not programSucceeds(cfg, """ 128 #include <locale.h> 129 #include <string.h> 130 int main(int, char**) { 131 setlocale(LC_ALL, "ru_RU.UTF-8"); 132 return strcmp(localeconv()->mon_decimal_point, ","); 133 } 134 """)), 135 136 Feature(name='has-unix-headers', 137 when=lambda cfg: sourceBuilds(cfg, """ 138 #include <unistd.h> 139 #include <sys/wait.h> 140 int main(int, char**) { 141 return 0; 142 } 143 """)), 144 145 # Whether Bash can run on the executor. 146 # This is not always the case, for example when running on embedded systems. 147 # 148 # For the corner case of bash existing, but it being missing in the path 149 # set in %{exec} as "--env PATH=one-single-dir", the executor does find 150 # and executes bash, but bash then can't find any other common shell 151 # utilities. Test executing "bash -c 'bash --version'" to see if bash 152 # manages to find binaries to execute. 153 Feature(name='executor-has-no-bash', 154 when=lambda cfg: runScriptExitCode(cfg, ['%{exec} bash -c \'bash --version\'']) != 0), 155 Feature(name='has-clang-tidy', 156 when=lambda cfg: _getSuitableClangTidy(cfg) is not None, 157 actions=[AddSubstitution('%{clang-tidy}', lambda cfg: _getSuitableClangTidy(cfg))]), 158 159 Feature(name='apple-clang', when=_isAppleClang), 160 Feature(name=lambda cfg: 'apple-clang-{__clang_major__}'.format(**compilerMacros(cfg)), when=_isAppleClang), 161 Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)), when=_isAppleClang), 162 Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isAppleClang), 163 164 Feature(name='clang', when=_isClang), 165 Feature(name=lambda cfg: 'clang-{__clang_major__}'.format(**compilerMacros(cfg)), when=_isClang), 166 Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)), when=_isClang), 167 Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isClang), 168 169 # Note: Due to a GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104760), we must disable deprecation warnings 170 # on GCC or spurious diagnostics are issued. 171 # 172 # TODO: 173 # - Enable -Wplacement-new with GCC. 174 # - Enable -Wclass-memaccess with GCC. 175 Feature(name='gcc', when=_isGCC, 176 actions=[AddCompileFlag('-D_LIBCPP_DISABLE_DEPRECATION_WARNINGS'), 177 AddCompileFlag('-Wno-placement-new'), 178 AddCompileFlag('-Wno-class-memaccess')]), 179 Feature(name=lambda cfg: 'gcc-{__GNUC__}'.format(**compilerMacros(cfg)), when=_isGCC), 180 Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}'.format(**compilerMacros(cfg)), when=_isGCC), 181 Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}'.format(**compilerMacros(cfg)), when=_isGCC), 182 183 Feature(name='msvc', when=_isMSVC), 184 Feature(name=lambda cfg: 'msvc-{}'.format(*_msvcVersion(cfg)), when=_isMSVC), 185 Feature(name=lambda cfg: 'msvc-{}.{}'.format(*_msvcVersion(cfg)), when=_isMSVC), 186] 187 188# Deduce and add the test features that that are implied by the #defines in 189# the <__config_site> header. 190# 191# For each macro of the form `_LIBCPP_XXX_YYY_ZZZ` defined below that 192# is defined after including <__config_site>, add a Lit feature called 193# `libcpp-xxx-yyy-zzz`. When a macro is defined to a specific value 194# (e.g. `_LIBCPP_ABI_VERSION=2`), the feature is `libcpp-xxx-yyy-zzz=<value>`. 195# 196# Note that features that are more strongly tied to libc++ are named libcpp-foo, 197# while features that are more general in nature are not prefixed with 'libcpp-'. 198macros = { 199 '_LIBCPP_HAS_NO_MONOTONIC_CLOCK': 'no-monotonic-clock', 200 '_LIBCPP_HAS_NO_THREADS': 'no-threads', 201 '_LIBCPP_HAS_THREAD_API_EXTERNAL': 'libcpp-has-thread-api-external', 202 '_LIBCPP_HAS_THREAD_API_PTHREAD': 'libcpp-has-thread-api-pthread', 203 '_LIBCPP_NO_VCRUNTIME': 'libcpp-no-vcruntime', 204 '_LIBCPP_ABI_VERSION': 'libcpp-abi-version', 205 '_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY': 'no-filesystem', 206 '_LIBCPP_HAS_NO_RANDOM_DEVICE': 'no-random-device', 207 '_LIBCPP_HAS_NO_LOCALIZATION': 'no-localization', 208 '_LIBCPP_HAS_NO_FSTREAM': 'no-fstream', 209 '_LIBCPP_HAS_NO_WIDE_CHARACTERS': 'no-wide-characters', 210 '_LIBCPP_HAS_NO_UNICODE': 'libcpp-has-no-unicode', 211 '_LIBCPP_ENABLE_DEBUG_MODE': 'libcpp-has-debug-mode', 212} 213for macro, feature in macros.items(): 214 DEFAULT_FEATURES.append( 215 Feature(name=lambda cfg, m=macro, f=feature: f + ('={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''), 216 when=lambda cfg, m=macro: m in compilerMacros(cfg)) 217 ) 218 219 220# Mapping from canonical locale names (used in the tests) to possible locale 221# names on various systems. Each locale is considered supported if any of the 222# alternative names is supported. 223locales = { 224 'en_US.UTF-8': ['en_US.UTF-8', 'en_US.utf8', 'English_United States.1252'], 225 'fr_FR.UTF-8': ['fr_FR.UTF-8', 'fr_FR.utf8', 'French_France.1252'], 226 'ja_JP.UTF-8': ['ja_JP.UTF-8', 'ja_JP.utf8', 'Japanese_Japan.923'], 227 'ru_RU.UTF-8': ['ru_RU.UTF-8', 'ru_RU.utf8', 'Russian_Russia.1251'], 228 'zh_CN.UTF-8': ['zh_CN.UTF-8', 'zh_CN.utf8', 'Chinese_China.936'], 229 'fr_CA.ISO8859-1': ['fr_CA.ISO8859-1', 'French_Canada.1252'], 230 'cs_CZ.ISO8859-2': ['cs_CZ.ISO8859-2', 'Czech_Czech Republic.1250'] 231} 232for locale, alts in locales.items(): 233 # Note: Using alts directly in the lambda body here will bind it to the value at the 234 # end of the loop. Assigning it to a default argument works around this issue. 235 DEFAULT_FEATURES.append(Feature(name='locale.{}'.format(locale), 236 when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts))) 237 238 239# Add features representing the target platform name: darwin, linux, windows, etc... 240DEFAULT_FEATURES += [ 241 Feature(name='darwin', when=lambda cfg: '__APPLE__' in compilerMacros(cfg)), 242 Feature(name='windows', when=lambda cfg: '_WIN32' in compilerMacros(cfg)), 243 Feature(name='windows-dll', when=lambda cfg: '_WIN32' in compilerMacros(cfg) and sourceBuilds(cfg, """ 244 #include <iostream> 245 int main(int, char**) { return 0; } 246 """) and programSucceeds(cfg, """ 247 #include <iostream> 248 #include <windows.h> 249 #include <winnt.h> 250 int main(int, char**) { 251 // Get a pointer to a data member that gets linked from the C++ 252 // library. This must be a data member (functions can get 253 // thunk inside the calling executable), and must not be 254 // something that is defined inline in headers. 255 void *ptr = &std::cout; 256 // Get a handle to the current main executable. 257 void *exe = GetModuleHandle(NULL); 258 // The handle points at the PE image header. Navigate through 259 // the header structure to find the size of the PE image (the 260 // executable). 261 PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER)exe; 262 PIMAGE_NT_HEADERS ntheader = (PIMAGE_NT_HEADERS)((BYTE *)dosheader + dosheader->e_lfanew); 263 PIMAGE_OPTIONAL_HEADER peheader = &ntheader->OptionalHeader; 264 void *exeend = (BYTE*)exe + peheader->SizeOfImage; 265 // Check if the tested pointer - the data symbol from the 266 // C++ library - is located within the exe. 267 if (ptr >= exe && ptr <= exeend) 268 return 1; 269 // Return success if it was outside of the executable, i.e. 270 // loaded from a DLL. 271 return 0; 272 } 273 """), actions=[AddCompileFlag('-DTEST_WINDOWS_DLL')]), 274 Feature(name='linux', when=lambda cfg: '__linux__' in compilerMacros(cfg)), 275 Feature(name='netbsd', when=lambda cfg: '__NetBSD__' in compilerMacros(cfg)), 276 Feature(name='freebsd', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg)), 277 Feature(name='LIBCXX-FREEBSD-FIXME', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg)), 278] 279 280# Add features representing the build host platform name. 281# The build host could differ from the target platform for cross-compilation. 282DEFAULT_FEATURES += [ 283 Feature(name='buildhost={}'.format(sys.platform.lower().strip())), 284 # sys.platform can often be represented by a "sub-system", such as 'win32', 'cygwin', 'mingw', freebsd13 & etc. 285 # We define a consolidated feature on a few platforms. 286 Feature(name='buildhost=windows', when=lambda cfg: platform.system().lower().startswith('windows')), 287 Feature(name='buildhost=freebsd', when=lambda cfg: platform.system().lower().startswith('freebsd')), 288 Feature(name='buildhost=aix', when=lambda cfg: platform.system().lower().startswith('aix')) 289] 290 291# Detect whether GDB is on the system, has Python scripting and supports 292# adding breakpoint commands. If so add a substitution to access it. 293def check_gdb(cfg): 294 gdb_path = shutil.which('gdb') 295 if gdb_path is None: 296 return False 297 298 # Check that we can set breakpoint commands, which was added in 8.3. 299 # Using the quit command here means that gdb itself exits, not just 300 # the "python <...>" command. 301 test_src = """\ 302try: 303 gdb.Breakpoint(\"main\").commands=\"foo\" 304except AttributeError: 305 gdb.execute(\"quit 1\") 306gdb.execute(\"quit\")""" 307 308 try: 309 stdout = subprocess.check_output( 310 [gdb_path, "-ex", "python " + test_src, "--batch"], 311 stderr=subprocess.DEVNULL, universal_newlines=True) 312 except subprocess.CalledProcessError: 313 # We can't set breakpoint commands 314 return False 315 316 # Check we actually ran the Python 317 return not "Python scripting is not supported" in stdout 318 319DEFAULT_FEATURES += [ 320 Feature(name='host-has-gdb-with-python', 321 when=check_gdb, 322 actions=[AddSubstitution('%{gdb}', lambda cfg: shutil.which('gdb'))] 323 ) 324] 325 326# Define features for back-deployment testing. 327# 328# These features can be used to XFAIL tests that fail when deployed on (or compiled 329# for) an older system. For example, if a test exhibits a bug in the libc on a 330# particular system version, or if it uses a symbol that is not available on an 331# older version of the dylib, it can be marked as XFAIL with these features. 332# 333# It is sometimes useful to check that a test fails specifically when compiled for a 334# given deployment target. For example, this is the case when testing availability 335# markup, where we want to make sure that using the annotated facility on a deployment 336# target that doesn't support it will fail at compile time, not at runtime. This can 337# be achieved by creating a `.verify.cpp` test that checks for the right errors, and 338# mark that test as requiring `stdlib=<vendor>-libc++ && target=<target>`. 339DEFAULT_FEATURES += [ 340 # Tests that require std::to_chars(floating-point) in the built library 341 Feature(name='availability-fp_to_chars-missing', 342 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}', cfg.available_features)), 343 344 # Tests that require https://wg21.link/P0482 support in the built library 345 Feature(name='availability-char8_t_support-missing', 346 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0)(.0)?}}', cfg.available_features)), 347 348 # Tests that require __libcpp_verbose_abort support in the built library 349 Feature(name='availability-verbose_abort-missing', 350 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}', cfg.available_features)), 351 352 # Tests that require std::bad_variant_access in the built library 353 Feature(name='availability-bad_variant_access-missing', 354 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)), 355 356 # Tests that require std::bad_optional_access in the built library 357 Feature(name='availability-bad_optional_access-missing', 358 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)), 359 360 # Tests that require std::bad_any_cast in the built library 361 Feature(name='availability-bad_any_cast-missing', 362 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)), 363 364 # Tests that require std::pmr support in the built library 365 Feature(name='availability-pmr-missing', 366 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0)(.0)?}}', cfg.available_features)), 367 368 # Tests that require std::filesystem support in the built library 369 Feature(name='availability-filesystem-missing', 370 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14)(.0)?}}', cfg.available_features)), 371 372 # Tests that require the C++20 synchronization library (P1135R6 implemented by https://llvm.org/D68480) in the built library 373 Feature(name='availability-synchronization_library-missing', 374 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14|15)(.0)?}}', cfg.available_features)), 375 376 # Tests that require support for std::shared_mutex and std::shared_timed_mutex in the built library 377 Feature(name='availability-shared_mutex-missing', 378 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11)(.0)?}}', cfg.available_features)), 379 380 # Tests that require support for aligned allocation in the built library. This is about `operator new(..., std::align_val_t, ...)` specifically, 381 # not other forms of aligned allocation. 382 Feature(name='availability-aligned_allocation-missing', 383 when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)), 384] 385