diff options
Diffstat (limited to 'test/libcxx/test/config.py')
-rw-r--r-- | test/libcxx/test/config.py | 216 |
1 files changed, 173 insertions, 43 deletions
diff --git a/test/libcxx/test/config.py b/test/libcxx/test/config.py index 593f9805447d..4551845104d2 100644 --- a/test/libcxx/test/config.py +++ b/test/libcxx/test/config.py @@ -13,6 +13,7 @@ import platform import pkgutil import re import shlex +import shutil import sys import lit.Test # pylint: disable=import-error,no-name-in-module @@ -57,6 +58,7 @@ class Configuration(object): self.lit_config = lit_config self.config = config self.cxx = None + self.cxx_stdlib_under_test = None self.project_obj_root = None self.libcxx_src_root = None self.libcxx_obj_root = None @@ -82,6 +84,10 @@ class Configuration(object): conf = self.get_lit_conf(name) if conf is None: return default + if isinstance(conf, bool): + return conf + if not isinstance(conf, str): + raise TypeError('expected bool or string') if conf.lower() in ('1', 'true'): return True if conf.lower() in ('', '0', 'false'): @@ -96,6 +102,7 @@ class Configuration(object): self.configure_triple() self.configure_src_root() self.configure_obj_root() + self.configure_cxx_stdlib_under_test() self.configure_cxx_library_root() self.configure_use_system_cxx_lib() self.configure_use_clang_verify() @@ -111,6 +118,7 @@ class Configuration(object): self.configure_warnings() self.configure_sanitizer() self.configure_coverage() + self.configure_modules() self.configure_substitutions() self.configure_features() @@ -118,8 +126,13 @@ class Configuration(object): # Print the final compile and link flags. self.lit_config.note('Using compiler: %s' % self.cxx.path) self.lit_config.note('Using flags: %s' % self.cxx.flags) + if self.cxx.use_modules: + self.lit_config.note('Using modules flags: %s' % + self.cxx.modules_flags) self.lit_config.note('Using compile flags: %s' % self.cxx.compile_flags) + if len(self.cxx.warning_flags): + self.lit_config.note('Using warnings: %s' % self.cxx.warning_flags) self.lit_config.note('Using link flags: %s' % self.cxx.link_flags) # Print as list to prevent "set([...])" from being printed. self.lit_config.note('Using available_features: %s' % @@ -177,6 +190,7 @@ class Configuration(object): assert self.cxx.version is not None maj_v, min_v, _ = self.cxx.version self.config.available_features.add(cxx_type) + self.config.available_features.add('%s-%s' % (cxx_type, maj_v)) self.config.available_features.add('%s-%s.%s' % ( cxx_type, maj_v, min_v)) @@ -212,14 +226,34 @@ class Configuration(object): self.lit_config.note( "inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib) + def configure_cxx_stdlib_under_test(self): + self.cxx_stdlib_under_test = self.get_lit_conf( + 'cxx_stdlib_under_test', 'libc++') + if self.cxx_stdlib_under_test not in \ + ['libc++', 'libstdc++', 'cxx_default']: + self.lit_config.fatal( + 'unsupported value for "cxx_stdlib_under_test": %s' + % self.cxx_stdlib_under_test) + self.config.available_features.add(self.cxx_stdlib_under_test) + if self.cxx_stdlib_under_test == 'libstdc++': + self.config.available_features.add('libstdc++') + # Manually enable the experimental and filesystem tests for libstdc++ + # if the options aren't present. + # FIXME this is a hack. + if self.get_lit_conf('enable_experimental') is None: + self.config.enable_experimental = 'true' + if self.get_lit_conf('enable_filesystem') is None: + self.config.enable_filesystem = 'true' + def configure_use_clang_verify(self): '''If set, run clang with -verify on failing tests.''' self.use_clang_verify = self.get_lit_bool('use_clang_verify') if self.use_clang_verify is None: # NOTE: We do not test for the -verify flag directly because # -verify will always exit with non-zero on an empty file. - self.use_clang_verify = self.cxx.hasCompileFlag( - ['-Xclang', '-verify-ignore-unexpected']) + self.use_clang_verify = self.cxx.isVerifySupported() + if self.use_clang_verify: + self.config.available_features.add('verify-support') self.lit_config.note( "inferred use_clang_verify as: %r" % self.use_clang_verify) @@ -267,6 +301,7 @@ class Configuration(object): # XFAIL markers for tests that are known to fail with versions of # libc++ as were shipped with a particular triple. if self.use_system_cxx_lib: + self.config.available_features.add('with_system_cxx_lib') self.config.available_features.add( 'with_system_cxx_lib=%s' % self.config.target_triple) @@ -290,9 +325,19 @@ class Configuration(object): if self.cxx.hasCompileFlag('-fsized-deallocation'): self.config.available_features.add('fsized-deallocation') + if self.cxx.hasCompileFlag('-faligned-allocation'): + self.config.available_features.add('-faligned-allocation') + else: + # FIXME remove this once more than just clang-4.0 support + # C++17 aligned allocation. + self.config.available_features.add('no-aligned-allocation') + if self.get_lit_bool('has_libatomic', False): self.config.available_features.add('libatomic') + if '__cpp_if_constexpr' not in self.cxx.dumpMacros(): + self.config.available_features.add('libcpp-no-if-constexpr') + def configure_compile_flags(self): no_default_flags = self.get_lit_bool('no_default_flags', False) if not no_default_flags: @@ -324,9 +369,8 @@ class Configuration(object): 'Failed to infer a supported language dialect from one of %r' % possible_stds) self.cxx.compile_flags += ['-std={0}'.format(std)] - self.config.available_features.add(std) + self.config.available_features.add(std.replace('gnu++', 'c++')) # Configure include paths - self.cxx.compile_flags += ['-nostdinc++'] self.configure_compile_flags_header_includes() self.target_info.add_cxx_compile_flags(self.cxx.compile_flags) # Configure feature flags. @@ -345,18 +389,32 @@ class Configuration(object): if gcc_toolchain: self.cxx.flags += ['-gcc-toolchain', gcc_toolchain] if self.use_target: - self.cxx.flags += ['-target', self.config.target_triple] + if not self.cxx.addFlagIfSupported( + ['-target', self.config.target_triple]): + self.lit_config.warning('use_target is true but -target is '\ + 'not supported by the compiler') def configure_compile_flags_header_includes(self): support_path = os.path.join(self.libcxx_src_root, 'test/support') - self.cxx.compile_flags += ['-include', os.path.join(support_path, 'nasty_macros.hpp')] + if self.cxx_stdlib_under_test != 'libstdc++': + self.cxx.compile_flags += [ + '-include', os.path.join(support_path, 'nasty_macros.hpp')] self.configure_config_site_header() - libcxx_headers = self.get_lit_conf( - 'libcxx_headers', os.path.join(self.libcxx_src_root, 'include')) - if not os.path.isdir(libcxx_headers): - self.lit_config.fatal("libcxx_headers='%s' is not a directory." - % libcxx_headers) - self.cxx.compile_flags += ['-I' + libcxx_headers] + cxx_headers = self.get_lit_conf('cxx_headers') + if cxx_headers == '' or (cxx_headers is None + and self.cxx_stdlib_under_test != 'libc++'): + self.lit_config.note('using the system cxx headers') + return + self.cxx.compile_flags += ['-nostdinc++'] + if cxx_headers is None: + cxx_headers = os.path.join(self.libcxx_src_root, 'include') + if not os.path.isdir(cxx_headers): + self.lit_config.fatal("cxx_headers='%s' is not a directory." + % cxx_headers) + self.cxx.compile_flags += ['-I' + cxx_headers] + cxxabi_headers = os.path.join(self.libcxx_obj_root, 'include', 'c++-build') + if os.path.isdir(cxxabi_headers): + self.cxx.compile_flags += ['-I' + cxxabi_headers] def configure_config_site_header(self): # Check for a possible __config_site in the build directory. We @@ -446,7 +504,7 @@ class Configuration(object): assert os.path.isdir(static_env) self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_STATIC_TEST_ROOT="%s"' % static_env] - dynamic_env = os.path.join(self.libcxx_obj_root, 'test', + dynamic_env = os.path.join(self.config.test_exec_root, 'filesystem', 'Output', 'dynamic_env') dynamic_env = os.path.realpath(dynamic_env) if not os.path.isdir(dynamic_env): @@ -465,16 +523,29 @@ class Configuration(object): def configure_link_flags(self): no_default_flags = self.get_lit_bool('no_default_flags', False) if not no_default_flags: - self.cxx.link_flags += ['-nodefaultlibs'] - # Configure library path self.configure_link_flags_cxx_library_path() self.configure_link_flags_abi_library_path() # Configure libraries - self.configure_link_flags_cxx_library() - self.configure_link_flags_abi_library() - self.configure_extra_library_flags() + if self.cxx_stdlib_under_test == 'libc++': + self.cxx.link_flags += ['-nodefaultlibs'] + self.configure_link_flags_cxx_library() + self.configure_link_flags_abi_library() + self.configure_extra_library_flags() + elif self.cxx_stdlib_under_test == 'libstdc++': + enable_fs = self.get_lit_bool('enable_filesystem', + default=False) + if enable_fs: + self.config.available_features.add('c++experimental') + self.cxx.link_flags += ['-lstdc++fs'] + self.cxx.link_flags += ['-lm', '-pthread'] + elif self.cxx_stdlib_under_test == 'cxx_default': + self.cxx.link_flags += ['-pthread'] + else: + self.lit_config.fatal( + 'unsupported value for "use_stdlib_type": %s' + % use_stdlib_type) link_flags_str = self.get_lit_conf('link_flags', '') self.cxx.link_flags += shlex.split(link_flags_str) @@ -508,6 +579,10 @@ class Configuration(object): self.cxx.link_flags += [abs_path] else: self.cxx.link_flags += ['-lc++'] + # This needs to come after -lc++ as we want its unresolved thread-api symbols + # to be picked up from this one. + if self.get_lit_bool('libcxx_external_thread_api', default=False): + self.cxx.link_flags += ['-lc++external_threads'] def configure_link_flags_abi_library(self): cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi') @@ -567,23 +642,34 @@ class Configuration(object): self.cxx.compile_flags += ['-D_LIBCPP_DEBUG=%s' % debug_level] def configure_warnings(self): - enable_warnings = self.get_lit_bool('enable_warnings', False) + # Turn on warnings by default for Clang based compilers when C++ >= 11 + default_enable_warnings = self.cxx.type in ['clang', 'apple-clang'] \ + and len(self.config.available_features.intersection( + ['c++11', 'c++14', 'c++1z'])) != 0 + enable_warnings = self.get_lit_bool('enable_warnings', + default_enable_warnings) if enable_warnings: - self.cxx.compile_flags += [ + self.cxx.useWarnings(True) + self.cxx.warning_flags += [ '-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER', '-Wall', '-Wextra', '-Werror' ] + self.cxx.addWarningFlagIfSupported('-Wshadow') self.cxx.addWarningFlagIfSupported('-Wno-unused-command-line-argument') self.cxx.addWarningFlagIfSupported('-Wno-attributes') self.cxx.addWarningFlagIfSupported('-Wno-pessimizing-move') self.cxx.addWarningFlagIfSupported('-Wno-c++11-extensions') self.cxx.addWarningFlagIfSupported('-Wno-user-defined-literals') - # TODO(EricWF) Remove the unused warnings once the test suite - # compiles clean with them. + # These warnings should be enabled in order to support the MSVC + # team using the test suite; They enable the warnings below and + # expect the test suite to be clean. + self.cxx.addWarningFlagIfSupported('-Wsign-compare') + self.cxx.addWarningFlagIfSupported('-Wunused-variable') + self.cxx.addWarningFlagIfSupported('-Wunused-parameter') + self.cxx.addWarningFlagIfSupported('-Wunreachable-code') + # FIXME: Enable the two warnings below. + self.cxx.addWarningFlagIfSupported('-Wno-conversion') self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef') - self.cxx.addWarningFlagIfSupported('-Wno-unused-variable') - self.cxx.addWarningFlagIfSupported('-Wno-unused-parameter') - self.cxx.addWarningFlagIfSupported('-Wno-sign-compare') std = self.get_lit_conf('std', None) if std in ['c++98', 'c++03']: # The '#define static_assert' provided by libc++ in C++03 mode @@ -604,9 +690,17 @@ class Configuration(object): os.pathsep + symbolizer_search_paths) llvm_symbolizer = lit.util.which('llvm-symbolizer', symbolizer_search_paths) + + def add_ubsan(): + self.cxx.flags += ['-fsanitize=undefined', + '-fno-sanitize=vptr,function,float-divide-by-zero', + '-fno-sanitize-recover=all'] + self.env['UBSAN_OPTIONS'] = 'print_stacktrace=1' + self.config.available_features.add('ubsan') + # Setup the sanitizer compile flags self.cxx.flags += ['-g', '-fno-omit-frame-pointer'] - if san == 'Address': + if san == 'Address' or san == 'Address;Undefined' or san == 'Undefined;Address': self.cxx.flags += ['-fsanitize=address'] if llvm_symbolizer is not None: self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer @@ -615,6 +709,9 @@ class Configuration(object): self.env['ASAN_OPTIONS'] = 'detect_odr_violation=0' self.config.available_features.add('asan') self.config.available_features.add('sanitizer-new-delete') + self.cxx.compile_flags += ['-O1'] + if san == 'Address;Undefined' or san == 'Undefined;Address': + add_ubsan() elif san == 'Memory' or san == 'MemoryWithOrigins': self.cxx.flags += ['-fsanitize=memory'] if san == 'MemoryWithOrigins': @@ -624,16 +721,10 @@ class Configuration(object): self.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer self.config.available_features.add('msan') self.config.available_features.add('sanitizer-new-delete') + self.cxx.compile_flags += ['-O1'] elif san == 'Undefined': - blacklist = os.path.join(self.libcxx_src_root, - 'test/ubsan_blacklist.txt') - self.cxx.flags += ['-fsanitize=undefined', - '-fno-sanitize=vptr,function,float-divide-by-zero', - '-fno-sanitize-recover=all', - '-fsanitize-blacklist=' + blacklist] - self.cxx.compile_flags += ['-O3'] - self.env['UBSAN_OPTIONS'] = 'print_stacktrace=1' - self.config.available_features.add('ubsan') + add_ubsan() + self.cxx.compile_flags += ['-O2'] elif san == 'Thread': self.cxx.flags += ['-fsanitize=thread'] self.config.available_features.add('tsan') @@ -652,9 +743,36 @@ class Configuration(object): self.cxx.flags += ['-g', '--coverage'] self.cxx.compile_flags += ['-O0'] + def configure_modules(self): + modules_flags = ['-fmodules'] + if platform.system() != 'Darwin': + modules_flags += ['-Xclang', '-fmodules-local-submodule-visibility'] + supports_modules = self.cxx.hasCompileFlag(modules_flags) + enable_modules_default = supports_modules and \ + os.environ.get('LIBCXX_USE_MODULES') is not None + enable_modules = self.get_lit_bool('enable_modules', + enable_modules_default) + if enable_modules and not supports_modules: + self.lit_config.fatal( + '-fmodules is enabled but not supported by the compiler') + if not supports_modules: + return + self.config.available_features.add('modules-support') + module_cache = os.path.join(self.config.test_exec_root, + 'modules.cache') + module_cache = os.path.realpath(module_cache) + if os.path.isdir(module_cache): + shutil.rmtree(module_cache) + os.makedirs(module_cache) + self.cxx.modules_flags = modules_flags + \ + ['-fmodules-cache-path=' + module_cache] + if enable_modules: + self.config.available_features.add('-fmodules') + self.cxx.useModules() + def configure_substitutions(self): sub = self.config.substitutions - # Configure compiler substitions + # Configure compiler substitutions sub.append(('%cxx', self.cxx.path)) # Configure flags substitutions flags_str = ' '.join(self.cxx.flags) @@ -665,13 +783,23 @@ class Configuration(object): sub.append(('%compile_flags', compile_flags_str)) sub.append(('%link_flags', link_flags_str)) sub.append(('%all_flags', all_flags)) + if self.cxx.isVerifySupported(): + verify_str = ' ' + ' '.join(self.cxx.verify_flags) + ' ' + sub.append(('%verify', verify_str)) # Add compile and link shortcuts compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str - + compile_flags_str) - link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str + + ' ' + compile_flags_str) + link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str + ' ' + link_flags_str) assert type(link_str) is str build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags + if self.cxx.use_modules: + sub.append(('%compile_module', compile_str)) + sub.append(('%build_module', build_str)) + elif self.cxx.modules_flags is not None: + modules_str = ' '.join(self.cxx.modules_flags) + ' ' + sub.append(('%compile_module', compile_str + ' ' + modules_str)) + sub.append(('%build_module', build_str + ' ' + modules_str)) sub.append(('%compile', compile_str)) sub.append(('%link', link_str)) sub.append(('%build', build_str)) @@ -686,18 +814,20 @@ class Configuration(object): sub.append(('%exec', exec_str)) # Configure run shortcut sub.append(('%run', exec_str + ' %t.exe')) - # Configure not program substitions + # Configure not program substitutions not_py = os.path.join(self.libcxx_src_root, 'utils', 'not', 'not.py') - not_str = '%s %s' % (sys.executable, not_py) - sub.append(('not', not_str)) + not_str = '%s %s ' % (sys.executable, not_py) + sub.append(('not ', not_str)) def configure_triple(self): # Get or infer the target triple. self.config.target_triple = self.get_lit_conf('target_triple') - self.use_target = bool(self.config.target_triple) + self.use_target = self.get_lit_bool('use_target', False) + if self.use_target and self.config.target_triple: + self.lit_config.warning('use_target is true but no triple is specified') # If no target triple was given, try to infer it from the compiler # under test. - if not self.use_target: + if not self.config.target_triple: target_triple = self.cxx.getTriple() # Drop sub-major version components from the triple, because the # current XFAIL handling expects exact matches for feature checks. |