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# ===----------------------------------------------------------------------===## 8import sys 9import re 10import shlex 11from pathlib import Path 12 13from libcxx.test.dsl import * 14from libcxx.test.features import _isClang, _isAppleClang, _isGCC, _isMSVC 15 16 17_warningFlags = [ 18 "-Werror", 19 "-Wall", 20 "-Wctad-maybe-unsupported", 21 "-Wextra", 22 "-Wshadow", 23 "-Wundef", 24 "-Wunused-template", 25 "-Wno-unused-command-line-argument", 26 "-Wno-attributes", 27 "-Wno-pessimizing-move", 28 "-Wno-noexcept-type", 29 "-Wno-aligned-allocation-unavailable", 30 "-Wno-atomic-alignment", 31 "-Wno-reserved-module-identifier", 32 '-Wdeprecated-copy', 33 '-Wdeprecated-copy-dtor', 34 # GCC warns about places where we might want to add sized allocation/deallocation 35 # functions, but we know better what we're doing/testing in the test suite. 36 "-Wno-sized-deallocation", 37 # Turn off warnings about user-defined literals with reserved suffixes. Those are 38 # just noise since we are testing the Standard Library itself. 39 "-Wno-literal-suffix", # GCC 40 "-Wno-user-defined-literals", # Clang 41 # GCC warns about this when TEST_IS_CONSTANT_EVALUATED is used on a non-constexpr 42 # function. (This mostly happens in C++11 mode.) 43 # TODO(mordante) investigate a solution for this issue. 44 "-Wno-tautological-compare", 45 # -Wstringop-overread and -Wstringop-overflow seem to be a bit buggy currently 46 "-Wno-stringop-overread", 47 "-Wno-stringop-overflow", 48 # These warnings should be enabled in order to support the MSVC 49 # team using the test suite; They enable the warnings below and 50 # expect the test suite to be clean. 51 "-Wsign-compare", 52 "-Wunused-variable", 53 "-Wunused-parameter", 54 "-Wunreachable-code", 55 "-Wno-unused-local-typedef", 56 57 # Disable warnings for extensions used in C++03 58 "-Wno-local-type-template-args", 59 "-Wno-c++11-extensions", 60 61 # TODO(philnik) This fails with the PSTL. 62 "-Wno-unknown-pragmas", 63 # Don't fail compilation in case the compiler fails to perform the requested 64 # loop vectorization. 65 "-Wno-pass-failed", 66 67 # TODO: Find out why GCC warns in lots of places (is this a problem with always_inline?) 68 "-Wno-dangling-reference", 69 "-Wno-mismatched-new-delete", 70 "-Wno-redundant-move", 71 72 # This doesn't make sense in real code, but we have to test it because the standard requires us to not break 73 "-Wno-self-move", 74] 75 76_allStandards = ["c++03", "c++11", "c++14", "c++17", "c++20", "c++23", "c++26"] 77 78 79def getStdFlag(cfg, std): 80 if hasCompileFlag(cfg, "-std=" + std): 81 return "-std=" + std 82 # TODO(LLVM-19) Remove the fallbacks needed for Clang 16. 83 fallbacks = { 84 "c++23": "c++2b", 85 } 86 if std in fallbacks and hasCompileFlag(cfg, "-std=" + fallbacks[std]): 87 return "-std=" + fallbacks[std] 88 return None 89 90 91def getDefaultStdValue(cfg): 92 viable = [s for s in reversed(_allStandards) if getStdFlag(cfg, s)] 93 94 if not viable: 95 raise RuntimeError( 96 "Unable to successfully detect the presence of any -std=c++NN flag. This likely indicates an issue with your compiler." 97 ) 98 99 return viable[0] 100 101 102def getSpeedOptimizationFlag(cfg): 103 if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg): 104 return "-O3" 105 elif _isMSVC(cfg): 106 return "/O2" 107 else: 108 raise RuntimeError( 109 "Can't figure out what compiler is used in the configuration" 110 ) 111 112 113def getSizeOptimizationFlag(cfg): 114 if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg): 115 return "-Os" 116 elif _isMSVC(cfg): 117 return "/O1" 118 else: 119 raise RuntimeError( 120 "Can't figure out what compiler is used in the configuration" 121 ) 122 123 124def testClangTidy(cfg, version, executable): 125 try: 126 if version in commandOutput(cfg, [f"{executable} --version"]): 127 return executable 128 except ConfigurationRuntimeError: 129 return None 130 131 132def getSuitableClangTidy(cfg): 133 # If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests. 134 if ( 135 runScriptExitCode( 136 cfg, ["stat %{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin"] 137 ) 138 != 0 139 ): 140 return None 141 142 version = "{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format( 143 **compilerMacros(cfg) 144 ) 145 exe = testClangTidy( 146 cfg, version, "clang-tidy-{__clang_major__}".format(**compilerMacros(cfg)) 147 ) 148 149 if not exe: 150 exe = testClangTidy(cfg, version, "clang-tidy") 151 152 return exe 153 154 155# fmt: off 156DEFAULT_PARAMETERS = [ 157 Parameter( 158 name="compiler", 159 type=str, 160 help="The path of the compiler to use for testing.", 161 actions=lambda cxx: [ 162 AddSubstitution("%{cxx}", shlex.quote(cxx)), 163 ], 164 ), 165 Parameter( 166 name="target_triple", 167 type=str, 168 help="The target triple to compile the test suite for. This must be " 169 "compatible with the target that the tests will be run on.", 170 actions=lambda triple: filter( 171 None, 172 [ 173 AddFeature("target={}".format(triple)), 174 AddFlagIfSupported("--target={}".format(triple)), 175 AddSubstitution("%{triple}", triple), 176 ], 177 ), 178 ), 179 Parameter( 180 name="std", 181 choices=_allStandards, 182 type=str, 183 help="The version of the standard to compile the test suite with.", 184 default=lambda cfg: getDefaultStdValue(cfg), 185 actions=lambda std: [ 186 AddFeature(std), 187 AddSubstitution("%{cxx_std}", re.sub(r"\+", "x", std)), 188 AddCompileFlag(lambda cfg: getStdFlag(cfg, std)), 189 ], 190 ), 191 Parameter( 192 name="optimization", 193 choices=["none", "speed", "size"], 194 type=str, 195 help="The optimization level to use when compiling the test suite.", 196 default="none", 197 actions=lambda opt: filter(None, [ 198 AddCompileFlag(lambda cfg: getSpeedOptimizationFlag(cfg)) if opt == "speed" else None, 199 AddCompileFlag(lambda cfg: getSizeOptimizationFlag(cfg)) if opt == "size" else None, 200 AddFeature(f'optimization={opt}'), 201 ]), 202 ), 203 Parameter( 204 name="enable_modules", 205 choices=["none", "clang", "clang-lsv"], 206 type=str, 207 help="Whether to build the test suite with modules enabled. " 208 "Select `clang` for Clang modules, and 'clang-lsv' for Clang modules with Local Submodule Visibility.", 209 default="none", 210 actions=lambda modules: filter(None, [ 211 AddFeature("clang-modules-build") if modules in ("clang", "clang-lsv") else None, 212 213 # Note: AppleClang disregards -fmodules entirely when compiling C++, so we also pass -fcxx-modules 214 # to enable modules for C++. 215 AddCompileFlag("-fmodules -fcxx-modules") if modules in ("clang", "clang-lsv") else None, 216 217 # Note: We use a custom modules cache path to make sure that we don't reuse 218 # the default one, which can be shared across CI builds with different 219 # configurations. 220 AddCompileFlag(lambda cfg: f"-fmodules-cache-path={cfg.test_exec_root}/ModuleCache") if modules in ("clang", "clang-lsv") else None, 221 222 AddCompileFlag("-Xclang -fmodules-local-submodule-visibility") if modules == "clang-lsv" else None, 223 ]) 224 ), 225 Parameter( 226 name="enable_exceptions", 227 choices=[True, False], 228 type=bool, 229 default=True, 230 help="Whether to enable exceptions when compiling the test suite.", 231 actions=lambda exceptions: [] if exceptions else [ 232 AddFeature("no-exceptions"), 233 AddCompileFlag("-fno-exceptions") 234 ], 235 ), 236 Parameter( 237 name="enable_rtti", 238 choices=[True, False], 239 type=bool, 240 default=True, 241 help="Whether to enable RTTI when compiling the test suite.", 242 actions=lambda rtti: [] if rtti else [ 243 AddFeature("no-rtti"), 244 AddCompileFlag("-fno-rtti") 245 ], 246 ), 247 Parameter( 248 name="stdlib", 249 choices=["llvm-libc++", "apple-libc++", "libstdc++", "msvc"], 250 type=str, 251 default="llvm-libc++", 252 help="""The C++ Standard Library implementation being tested. 253 254 Note that this parameter can also be used to encode different 'flavors' of the same 255 standard library, such as libc++ as shipped by a different vendor, if it has different 256 properties worth testing. 257 258 The Standard libraries currently supported are: 259 - llvm-libc++: The 'upstream' libc++ as shipped with LLVM. 260 - apple-libc++: libc++ as shipped by Apple. This is basically like the LLVM one, but 261 there are a few differences like installation paths, the use of 262 universal dylibs and the existence of availability markup. 263 - libstdc++: The GNU C++ library typically shipped with GCC. 264 - msvc: The Microsoft implementation of the C++ Standard Library. 265 """, 266 actions=lambda stdlib: filter( 267 None, 268 [ 269 AddFeature("stdlib={}".format(stdlib)), 270 # Also add an umbrella feature 'stdlib=libc++' for all flavors of libc++, to simplify 271 # the test suite. 272 AddFeature("stdlib=libc++") if re.match(r".+-libc\+\+", stdlib) else None, 273 ], 274 ), 275 ), 276 Parameter( 277 name="using_system_stdlib", 278 choices=[True, False], 279 type=bool, 280 default=False, 281 help="""Whether the Standard Library being tested is the one that shipped with the system by default. 282 283 This is different from the 'stdlib' parameter, which describes the flavor of libc++ being 284 tested. 'using_system_stdlib' describes whether the target system passed with 'target_triple' 285 also corresponds to the version of the library being tested. 286 """, 287 actions=lambda is_system: [AddFeature("stdlib=system")] if is_system else [], 288 ), 289 Parameter( 290 name="enable_warnings", 291 choices=[True, False], 292 type=bool, 293 default=True, 294 help="Whether to enable warnings when compiling the test suite.", 295 actions=lambda warnings: [] if not warnings else 296 [AddOptionalWarningFlag(w) for w in _warningFlags] + 297 [AddCompileFlag("-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER")], 298 ), 299 Parameter( 300 name="use_sanitizer", 301 choices=[ 302 "", 303 "Address", 304 "HWAddress", 305 "Undefined", 306 "Memory", 307 "MemoryWithOrigins", 308 "Thread", 309 "DataFlow", 310 "Leaks", 311 ], 312 type=str, 313 default="", 314 help="An optional sanitizer to enable when building and running the test suite.", 315 actions=lambda sanitizer: filter( 316 None, 317 [ 318 AddFlag("-g -fno-omit-frame-pointer") if sanitizer else None, 319 320 AddFlag("-fsanitize=undefined -fno-sanitize=float-divide-by-zero -fno-sanitize-recover=all") if sanitizer == "Undefined" else None, 321 AddFeature("ubsan") if sanitizer == "Undefined" else None, 322 323 AddFlag("-fsanitize=address") if sanitizer == "Address" else None, 324 AddFeature("asan") if sanitizer == "Address" else None, 325 326 AddFlag("-fsanitize=hwaddress") if sanitizer == "HWAddress" else None, 327 AddFeature("hwasan") if sanitizer == "HWAddress" else None, 328 329 AddFlag("-fsanitize=memory") if sanitizer in ["Memory", "MemoryWithOrigins"] else None, 330 AddFeature("msan") if sanitizer in ["Memory", "MemoryWithOrigins"] else None, 331 AddFlag("-fsanitize-memory-track-origins") if sanitizer == "MemoryWithOrigins" else None, 332 333 AddFlag("-fsanitize=thread") if sanitizer == "Thread" else None, 334 AddFeature("tsan") if sanitizer == "Thread" else None, 335 336 AddFlag("-fsanitize=dataflow") if sanitizer == "DataFlow" else None, 337 AddFlag("-fsanitize=leaks") if sanitizer == "Leaks" else None, 338 339 AddFeature("sanitizer-new-delete") if sanitizer in ["Address", "HWAddress", "Memory", "MemoryWithOrigins", "Thread"] else None, 340 AddFeature("lsan") if sanitizer in ["Address", "HWAddress", "Leaks"] else None, 341 ] 342 ) 343 ), 344 Parameter( 345 name="enable_experimental", 346 choices=[True, False], 347 type=bool, 348 default=True, 349 help="Whether to enable tests for experimental C++ Library features.", 350 actions=lambda experimental: [ 351 # When linking in MSVC mode via the Clang driver, a -l<foo> 352 # maps to <foo>.lib, so we need to use -llibc++experimental here 353 # to make it link against the static libc++experimental.lib. 354 # We can't check for the feature 'msvc' in available_features 355 # as those features are added after processing parameters. 356 AddFeature("c++experimental"), 357 PrependLinkFlag(lambda cfg: "-llibc++experimental" if _isMSVC(cfg) else "-lc++experimental"), 358 AddCompileFlag("-D_LIBCPP_ENABLE_EXPERIMENTAL"), 359 ] 360 if experimental 361 else [ 362 AddFeature("libcpp-has-no-incomplete-pstl"), 363 AddFeature("libcpp-has-no-experimental-tzdb"), 364 AddFeature("libcpp-has-no-experimental-syncstream"), 365 ], 366 ), 367 # TODO: This can be improved once we use a version of GoogleBenchmark that supports the dry-run mode. 368 # See https://github.com/google/benchmark/issues/1827. 369 Parameter( 370 name="enable_benchmarks", 371 choices=["no", "run", "dry-run"], 372 type=str, 373 default="run", 374 help="Whether to run the benchmarks in the test suite, to only dry-run them or to disable them entirely.", 375 actions=lambda mode: [AddFeature(f"enable-benchmarks={mode}")], 376 ), 377 Parameter( 378 name="long_tests", 379 choices=[True, False], 380 type=bool, 381 default=True, 382 help="Whether to enable tests that take longer to run. This can be useful when running on a very slow device.", 383 actions=lambda enabled: [] if not enabled else [AddFeature("long_tests")], 384 ), 385 Parameter( 386 name="large_tests", 387 choices=[True, False], 388 type=bool, 389 default=True, 390 help="Whether to enable tests that use a lot of memory. This can be useful when running on a device with limited amounts of memory.", 391 actions=lambda enabled: [] if not enabled else [AddFeature("large_tests")], 392 ), 393 Parameter( 394 name="hardening_mode", 395 choices=["none", "fast", "extensive", "debug", "undefined"], 396 type=str, 397 default="undefined", 398 help="Whether to enable one of the hardening modes when compiling the test suite. This is only " 399 "meaningful when running the tests against libc++. By default, no hardening mode is specified " 400 "so the default hardening mode of the standard library will be used (if any).", 401 actions=lambda hardening_mode: filter( 402 None, 403 [ 404 AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE") if hardening_mode == "none" else None, 405 AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST") if hardening_mode == "fast" else None, 406 AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE") if hardening_mode == "extensive" else None, 407 AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG") if hardening_mode == "debug" else None, 408 AddFeature("libcpp-hardening-mode={}".format(hardening_mode)) if hardening_mode != "undefined" else None, 409 ], 410 ), 411 ), 412 Parameter( 413 name="additional_features", 414 type=list, 415 default=[], 416 help="A comma-delimited list of additional features that will be enabled when running the tests. " 417 "This should be used sparingly since specifying ad-hoc features manually is error-prone and " 418 "brittle in the long run as changes are made to the test suite.", 419 actions=lambda features: [AddFeature(f) for f in features], 420 ), 421 Parameter( 422 name="enable_transitive_includes", 423 choices=[True, False], 424 type=bool, 425 default=True, 426 help="Whether to enable backwards-compatibility transitive includes when running the tests. This " 427 "is provided to ensure that the trimmed-down version of libc++ does not bit-rot in between " 428 "points at which we bulk-remove transitive includes.", 429 actions=lambda enabled: [] if enabled else [ 430 AddFeature("transitive-includes-disabled"), 431 AddCompileFlag("-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES"), 432 ], 433 ), 434 Parameter( 435 name="executor", 436 type=str, 437 default=f"{shlex.quote(sys.executable)} {shlex.quote(str(Path(__file__).resolve().parent.parent.parent / 'run.py'))}", 438 help="Custom executor to use instead of the configured default.", 439 actions=lambda executor: [AddSubstitution("%{executor}", executor)], 440 ), 441 Parameter( 442 name='clang-tidy-executable', 443 type=str, 444 default=lambda cfg: getSuitableClangTidy(cfg), 445 help="Selects the clang-tidy executable to use.", 446 actions=lambda exe: [] if exe is None else [ 447 AddFeature('has-clang-tidy'), 448 AddSubstitution('%{clang-tidy}', exe), 449 ] 450 ), 451] 452# fmt: on 453