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 getSpeedOptimizationFlag(cfg): 92 if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg): 93 return "-O3" 94 elif _isMSVC(cfg): 95 return "/O2" 96 else: 97 raise RuntimeError( 98 "Can't figure out what compiler is used in the configuration" 99 ) 100 101 102def getSizeOptimizationFlag(cfg): 103 if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg): 104 return "-Os" 105 elif _isMSVC(cfg): 106 return "/O1" 107 else: 108 raise RuntimeError( 109 "Can't figure out what compiler is used in the configuration" 110 ) 111 112 113def testClangTidy(cfg, version, executable): 114 try: 115 if version in commandOutput(cfg, [f"{executable} --version"]): 116 return executable 117 except ConfigurationRuntimeError: 118 return None 119 120 121def getSuitableClangTidy(cfg): 122 # If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests. 123 if ( 124 runScriptExitCode( 125 cfg, ["stat %{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin"] 126 ) 127 != 0 128 ): 129 return None 130 131 version = "{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format( 132 **compilerMacros(cfg) 133 ) 134 exe = testClangTidy( 135 cfg, version, "clang-tidy-{__clang_major__}".format(**compilerMacros(cfg)) 136 ) 137 138 if not exe: 139 exe = testClangTidy(cfg, version, "clang-tidy") 140 141 return exe 142 143 144# fmt: off 145DEFAULT_PARAMETERS = [ 146 Parameter( 147 name="target_triple", 148 type=str, 149 help="The target triple to compile the test suite for. This must be " 150 "compatible with the target that the tests will be run on.", 151 actions=lambda triple: filter( 152 None, 153 [ 154 AddFeature("target={}".format(triple)), 155 AddFlagIfSupported("--target={}".format(triple)), 156 AddSubstitution("%{triple}", triple), 157 ], 158 ), 159 ), 160 Parameter( 161 name="std", 162 choices=_allStandards, 163 type=str, 164 help="The version of the standard to compile the test suite with.", 165 default=lambda cfg: next( 166 s for s in reversed(_allStandards) if getStdFlag(cfg, s) 167 ), 168 actions=lambda std: [ 169 AddFeature(std), 170 AddSubstitution("%{cxx_std}", re.sub(r"\+", "x", std)), 171 AddCompileFlag(lambda cfg: getStdFlag(cfg, std)), 172 ], 173 ), 174 Parameter( 175 name="optimization", 176 choices=["none", "speed", "size"], 177 type=str, 178 help="The optimization level to use when compiling the test suite.", 179 default="none", 180 actions=lambda opt: filter(None, [ 181 AddCompileFlag(lambda cfg: getSpeedOptimizationFlag(cfg)) if opt == "speed" else None, 182 AddCompileFlag(lambda cfg: getSizeOptimizationFlag(cfg)) if opt == "size" else None, 183 AddFeature(f'optimization={opt}'), 184 ]), 185 ), 186 Parameter( 187 name="enable_modules", 188 choices=["none", "clang", "clang-lsv"], 189 type=str, 190 help="Whether to build the test suite with modules enabled. " 191 "Select `clang` for Clang modules, and 'clang-lsv' for Clang modules with Local Submodule Visibility.", 192 default="none", 193 actions=lambda modules: filter(None, [ 194 AddFeature("clang-modules-build") if modules in ("clang", "clang-lsv") else None, 195 196 # Note: AppleClang disregards -fmodules entirely when compiling C++, so we also pass -fcxx-modules 197 # to enable modules for C++. 198 AddCompileFlag("-fmodules -fcxx-modules") if modules in ("clang", "clang-lsv") else None, 199 200 # Note: We use a custom modules cache path to make sure that we don't reuse 201 # the default one, which can be shared across CI builds with different 202 # configurations. 203 AddCompileFlag(lambda cfg: f"-fmodules-cache-path={cfg.test_exec_root}/ModuleCache") if modules in ("clang", "clang-lsv") else None, 204 205 AddCompileFlag("-Xclang -fmodules-local-submodule-visibility") if modules == "clang-lsv" else None, 206 ]) 207 ), 208 Parameter( 209 name="enable_exceptions", 210 choices=[True, False], 211 type=bool, 212 default=True, 213 help="Whether to enable exceptions when compiling the test suite.", 214 actions=lambda exceptions: [] if exceptions else [ 215 AddFeature("no-exceptions"), 216 AddCompileFlag("-fno-exceptions") 217 ], 218 ), 219 Parameter( 220 name="enable_rtti", 221 choices=[True, False], 222 type=bool, 223 default=True, 224 help="Whether to enable RTTI when compiling the test suite.", 225 actions=lambda rtti: [] if rtti else [ 226 AddFeature("no-rtti"), 227 AddCompileFlag("-fno-rtti") 228 ], 229 ), 230 Parameter( 231 name="stdlib", 232 choices=["llvm-libc++", "apple-libc++", "libstdc++", "msvc"], 233 type=str, 234 default="llvm-libc++", 235 help="""The C++ Standard Library implementation being tested. 236 237 Note that this parameter can also be used to encode different 'flavors' of the same 238 standard library, such as libc++ as shipped by a different vendor, if it has different 239 properties worth testing. 240 241 The Standard libraries currently supported are: 242 - llvm-libc++: The 'upstream' libc++ as shipped with LLVM. 243 - apple-libc++: libc++ as shipped by Apple. This is basically like the LLVM one, but 244 there are a few differences like installation paths, the use of 245 universal dylibs and the existence of availability markup. 246 - libstdc++: The GNU C++ library typically shipped with GCC. 247 - msvc: The Microsoft implementation of the C++ Standard Library. 248 """, 249 actions=lambda stdlib: filter( 250 None, 251 [ 252 AddFeature("stdlib={}".format(stdlib)), 253 # Also add an umbrella feature 'stdlib=libc++' for all flavors of libc++, to simplify 254 # the test suite. 255 AddFeature("stdlib=libc++") if re.match(r".+-libc\+\+", stdlib) else None, 256 ], 257 ), 258 ), 259 Parameter( 260 name="enable_warnings", 261 choices=[True, False], 262 type=bool, 263 default=True, 264 help="Whether to enable warnings when compiling the test suite.", 265 actions=lambda warnings: [] if not warnings else 266 [AddOptionalWarningFlag(w) for w in _warningFlags] + 267 [AddCompileFlag("-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER")], 268 ), 269 Parameter( 270 name="use_sanitizer", 271 choices=[ 272 "", 273 "Address", 274 "HWAddress", 275 "Undefined", 276 "Memory", 277 "MemoryWithOrigins", 278 "Thread", 279 "DataFlow", 280 "Leaks", 281 ], 282 type=str, 283 default="", 284 help="An optional sanitizer to enable when building and running the test suite.", 285 actions=lambda sanitizer: filter( 286 None, 287 [ 288 AddFlag("-g -fno-omit-frame-pointer") if sanitizer else None, 289 290 AddFlag("-fsanitize=undefined -fno-sanitize=float-divide-by-zero -fno-sanitize-recover=all") if sanitizer == "Undefined" else None, 291 AddFeature("ubsan") if sanitizer == "Undefined" else None, 292 293 AddFlag("-fsanitize=address") if sanitizer == "Address" else None, 294 AddFeature("asan") if sanitizer == "Address" else None, 295 296 AddFlag("-fsanitize=hwaddress") if sanitizer == "HWAddress" else None, 297 AddFeature("hwasan") if sanitizer == "HWAddress" else None, 298 299 AddFlag("-fsanitize=memory") if sanitizer in ["Memory", "MemoryWithOrigins"] else None, 300 AddFeature("msan") if sanitizer in ["Memory", "MemoryWithOrigins"] else None, 301 AddFlag("-fsanitize-memory-track-origins") if sanitizer == "MemoryWithOrigins" else None, 302 303 AddFlag("-fsanitize=thread") if sanitizer == "Thread" else None, 304 AddFeature("tsan") if sanitizer == "Thread" else None, 305 306 AddFlag("-fsanitize=dataflow") if sanitizer == "DataFlow" else None, 307 AddFlag("-fsanitize=leaks") if sanitizer == "Leaks" else None, 308 309 AddFeature("sanitizer-new-delete") if sanitizer in ["Address", "HWAddress", "Memory", "MemoryWithOrigins", "Thread"] else None, 310 AddFeature("lsan") if sanitizer in ["Address", "HWAddress", "Leaks"] else None, 311 ] 312 ) 313 ), 314 Parameter( 315 name="enable_experimental", 316 choices=[True, False], 317 type=bool, 318 default=True, 319 help="Whether to enable tests for experimental C++ Library features.", 320 actions=lambda experimental: [ 321 # When linking in MSVC mode via the Clang driver, a -l<foo> 322 # maps to <foo>.lib, so we need to use -llibc++experimental here 323 # to make it link against the static libc++experimental.lib. 324 # We can't check for the feature 'msvc' in available_features 325 # as those features are added after processing parameters. 326 AddFeature("c++experimental"), 327 PrependLinkFlag(lambda cfg: "-llibc++experimental" if _isMSVC(cfg) else "-lc++experimental"), 328 AddCompileFlag("-D_LIBCPP_ENABLE_EXPERIMENTAL"), 329 ] 330 if experimental 331 else [ 332 AddFeature("libcpp-has-no-incomplete-pstl"), 333 AddFeature("libcpp-has-no-experimental-stop_token"), 334 AddFeature("libcpp-has-no-incomplete-tzdb"), 335 AddFeature("libcpp-has-no-experimental-syncstream"), 336 ], 337 ), 338 Parameter( 339 name="long_tests", 340 choices=[True, False], 341 type=bool, 342 default=True, 343 help="Whether to enable tests that take longer to run. This can be useful when running on a very slow device.", 344 actions=lambda enabled: [] if not enabled else [AddFeature("long_tests")], 345 ), 346 Parameter( 347 name="large_tests", 348 choices=[True, False], 349 type=bool, 350 default=True, 351 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.", 352 actions=lambda enabled: [] if not enabled else [AddFeature("large_tests")], 353 ), 354 Parameter( 355 name="hardening_mode", 356 choices=["none", "fast", "extensive", "debug"], 357 type=str, 358 default="none", 359 help="Whether to enable one of the hardening modes when compiling the test suite. This is only " 360 "meaningful when running the tests against libc++.", 361 actions=lambda hardening_mode: filter( 362 None, 363 [ 364 AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE") if hardening_mode == "none" else None, 365 AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST") if hardening_mode == "fast" else None, 366 AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE") if hardening_mode == "extensive" else None, 367 AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG") if hardening_mode == "debug" else None, 368 AddFeature("libcpp-hardening-mode={}".format(hardening_mode)), 369 ], 370 ), 371 ), 372 Parameter( 373 name="additional_features", 374 type=list, 375 default=[], 376 help="A comma-delimited list of additional features that will be enabled when running the tests. " 377 "This should be used sparingly since specifying ad-hoc features manually is error-prone and " 378 "brittle in the long run as changes are made to the test suite.", 379 actions=lambda features: [AddFeature(f) for f in features], 380 ), 381 Parameter( 382 name="enable_transitive_includes", 383 choices=[True, False], 384 type=bool, 385 default=True, 386 help="Whether to enable backwards-compatibility transitive includes when running the tests. This " 387 "is provided to ensure that the trimmed-down version of libc++ does not bit-rot in between " 388 "points at which we bulk-remove transitive includes.", 389 actions=lambda enabled: [] if enabled else [ 390 AddFeature("transitive-includes-disabled"), 391 AddCompileFlag("-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES"), 392 ], 393 ), 394 Parameter( 395 name="executor", 396 type=str, 397 default=f"{shlex.quote(sys.executable)} {shlex.quote(str(Path(__file__).resolve().parent.parent.parent / 'run.py'))}", 398 help="Custom executor to use instead of the configured default.", 399 actions=lambda executor: [AddSubstitution("%{executor}", executor)], 400 ), 401 Parameter( 402 name='clang-tidy-executable', 403 type=str, 404 default=lambda cfg: getSuitableClangTidy(cfg), 405 help="Selects the clang-tidy executable to use.", 406 actions=lambda exe: [] if exe is None else [ 407 AddFeature('has-clang-tidy'), 408 AddSubstitution('%{clang-tidy}', exe), 409 ] 410 ), 411] 412# fmt: on 413