diff options
65 files changed, 4164 insertions, 3063 deletions
diff --git a/libcxx/benchmarks/lit.cfg.py b/libcxx/benchmarks/lit.cfg.py index 84857d5..7d222dd 100644 --- a/libcxx/benchmarks/lit.cfg.py +++ b/libcxx/benchmarks/lit.cfg.py @@ -3,21 +3,21 @@ import os import site -site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'utils')) +site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(__file__)), "utils")) from libcxx.test.googlebenchmark import GoogleBenchmark # Tell pylint that we know config and lit_config exist somewhere. -if 'PYLINT_IMPORT' in os.environ: +if "PYLINT_IMPORT" in os.environ: config = object() lit_config = object() # name: The name of this test suite. -config.name = 'libc++ benchmarks' +config.name = "libc++ benchmarks" config.suffixes = [] -config.test_exec_root = os.path.join(config.libcxx_obj_root, 'benchmarks') +config.test_exec_root = os.path.join(config.libcxx_obj_root, "benchmarks") config.test_source_root = config.test_exec_root -config.test_format = GoogleBenchmark(test_sub_dirs='.', - test_suffix='.libcxx.out', - benchmark_args=config.benchmark_args)
\ No newline at end of file +config.test_format = GoogleBenchmark( + test_sub_dirs=".", test_suffix=".libcxx.out", benchmark_args=config.benchmark_args +) diff --git a/libcxx/docs/conf.py b/libcxx/docs/conf.py index f680969..d24ec63 100644 --- a/libcxx/docs/conf.py +++ b/libcxx/docs/conf.py @@ -16,106 +16,106 @@ from datetime import date # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] +extensions = ["sphinx.ext.intersphinx", "sphinx.ext.todo"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'libc++' -copyright = u'2011-%d, LLVM Project' % date.today().year +project = "libc++" +copyright = "2011-%d, LLVM Project" % date.today().year # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '17.0' +version = "17.0" # The full version, including alpha/beta/rc tags. -release = '17.0' +release = "17.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -today_fmt = '%Y-%m-%d' +today_fmt = "%Y-%m-%d" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build', 'Helpers'] +exclude_patterns = ["_build", "Helpers"] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. show_authors = True # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'friendly' +pygments_style = "friendly" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'haiku' +html_theme = "haiku" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # "<project> v<release> documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -124,101 +124,95 @@ html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a <link> tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'libcxxdoc' +htmlhelp_basename = "libcxxdoc" # -- Options for LaTeX output -------------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('contents', 'libcxx.tex', u'libcxx Documentation', - u'LLVM project', 'manual'), + ("contents", "libcxx.tex", "libcxx Documentation", "LLVM project", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('contents', 'libc++', u'libc++ Documentation', - [u'LLVM project'], 1) -] +man_pages = [("contents", "libc++", "libc++ Documentation", ["LLVM project"], 1)] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ @@ -227,19 +221,25 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('contents', 'libc++', u'libc++ Documentation', - u'LLVM project', 'libc++', 'One line description of project.', - 'Miscellaneous'), + ( + "contents", + "libc++", + "libc++ Documentation", + "LLVM project", + "libc++", + "One line description of project.", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # FIXME: Define intersphinx configuration. diff --git a/libcxx/test/libcxx/experimental/lit.local.cfg b/libcxx/test/libcxx/experimental/lit.local.cfg index 5e2c632..ebfaa02 100644 --- a/libcxx/test/libcxx/experimental/lit.local.cfg +++ b/libcxx/test/libcxx/experimental/lit.local.cfg @@ -1,3 +1,3 @@ # Disable all of the experimental tests if the correct feature is not available. -if 'c++experimental' not in config.available_features: - config.unsupported = True +if "c++experimental" not in config.available_features: + config.unsupported = True diff --git a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.py b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.py index c64efa3..ddb58a8 100644 --- a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.py +++ b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.py @@ -1,10 +1,10 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """Commands used to automate testing gdb pretty printers. This script is part of a larger framework to test gdb pretty printers. It @@ -31,10 +31,8 @@ has_run_tests = False class CheckResult(gdb.Command): - def __init__(self): - super(CheckResult, self).__init__( - "print_and_compare", gdb.COMMAND_DATA) + super(CheckResult, self).__init__("print_and_compare", gdb.COMMAND_DATA) def invoke(self, arg, from_tty): global has_run_tests @@ -55,7 +53,7 @@ class CheckResult(gdb.Command): value_str = self._get_value_string(compare_frame, testcase_frame) # Ignore the convenience variable name and newline - value = value_str[value_str.find("= ") + 2:-1] + value = value_str[value_str.find("= ") + 2 : -1] gdb.newest_frame().select() expectation_val = compare_frame.read_var("expectation") check_literal = expectation_val.string(encoding="utf-8") @@ -66,16 +64,14 @@ class CheckResult(gdb.Command): if test_fails: global test_failures - print("FAIL: " + test_loc.symtab.filename + - ":" + str(test_loc.line)) + print("FAIL: " + test_loc.symtab.filename + ":" + str(test_loc.line)) print("GDB printed:") print(" " + repr(value)) print("Value should match:") print(" " + repr(check_literal)) test_failures += 1 else: - print("PASS: " + test_loc.symtab.filename + - ":" + str(test_loc.line)) + print("PASS: " + test_loc.symtab.filename + ":" + str(test_loc.line)) except RuntimeError as e: # At this point, lots of different things could be wrong, so don't try to diff --git a/libcxx/test/libcxx/input.output/file.streams/lit.local.cfg b/libcxx/test/libcxx/input.output/file.streams/lit.local.cfg index b89e35b..495f1cc 100644 --- a/libcxx/test/libcxx/input.output/file.streams/lit.local.cfg +++ b/libcxx/test/libcxx/input.output/file.streams/lit.local.cfg @@ -1,6 +1,7 @@ # Load the same local configuration as the corresponding one in libcxx/test/std import os -inLibcxx = os.path.join('libcxx', 'test', 'libcxx') -inStd = os.path.join('libcxx', 'test', 'std') + +inLibcxx = os.path.join("libcxx", "test", "libcxx") +inStd = os.path.join("libcxx", "test", "std") localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd) config.load_from_path(localConfig, lit_config) diff --git a/libcxx/test/libcxx/input.output/filesystems/lit.local.cfg b/libcxx/test/libcxx/input.output/filesystems/lit.local.cfg index 4eadb33..df91de1 100644 --- a/libcxx/test/libcxx/input.output/filesystems/lit.local.cfg +++ b/libcxx/test/libcxx/input.output/filesystems/lit.local.cfg @@ -1,4 +1,7 @@ # Load the same local configuration as the filesystem tests in libcxx/test/std import os -std_filesystem_tests = os.path.join(config.test_source_root, 'std', 'input.output', 'filesystems') -config.load_from_path(os.path.join(std_filesystem_tests, 'lit.local.cfg'), lit_config) + +std_filesystem_tests = os.path.join( + config.test_source_root, "std", "input.output", "filesystems" +) +config.load_from_path(os.path.join(std_filesystem_tests, "lit.local.cfg"), lit_config) diff --git a/libcxx/test/libcxx/input.output/iostream.format/lit.local.cfg b/libcxx/test/libcxx/input.output/iostream.format/lit.local.cfg index b89e35b..495f1cc 100644 --- a/libcxx/test/libcxx/input.output/iostream.format/lit.local.cfg +++ b/libcxx/test/libcxx/input.output/iostream.format/lit.local.cfg @@ -1,6 +1,7 @@ # Load the same local configuration as the corresponding one in libcxx/test/std import os -inLibcxx = os.path.join('libcxx', 'test', 'libcxx') -inStd = os.path.join('libcxx', 'test', 'std') + +inLibcxx = os.path.join("libcxx", "test", "libcxx") +inStd = os.path.join("libcxx", "test", "std") localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd) config.load_from_path(localConfig, lit_config) diff --git a/libcxx/test/libcxx/input.output/iostream.objects/lit.local.cfg b/libcxx/test/libcxx/input.output/iostream.objects/lit.local.cfg index b89e35b..495f1cc 100644 --- a/libcxx/test/libcxx/input.output/iostream.objects/lit.local.cfg +++ b/libcxx/test/libcxx/input.output/iostream.objects/lit.local.cfg @@ -1,6 +1,7 @@ # Load the same local configuration as the corresponding one in libcxx/test/std import os -inLibcxx = os.path.join('libcxx', 'test', 'libcxx') -inStd = os.path.join('libcxx', 'test', 'std') + +inLibcxx = os.path.join("libcxx", "test", "libcxx") +inStd = os.path.join("libcxx", "test", "std") localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd) config.load_from_path(localConfig, lit_config) diff --git a/libcxx/test/libcxx/input.output/iostreams.base/lit.local.cfg b/libcxx/test/libcxx/input.output/iostreams.base/lit.local.cfg index b89e35b..495f1cc 100644 --- a/libcxx/test/libcxx/input.output/iostreams.base/lit.local.cfg +++ b/libcxx/test/libcxx/input.output/iostreams.base/lit.local.cfg @@ -1,6 +1,7 @@ # Load the same local configuration as the corresponding one in libcxx/test/std import os -inLibcxx = os.path.join('libcxx', 'test', 'libcxx') -inStd = os.path.join('libcxx', 'test', 'std') + +inLibcxx = os.path.join("libcxx", "test", "libcxx") +inStd = os.path.join("libcxx", "test", "std") localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd) config.load_from_path(localConfig, lit_config) diff --git a/libcxx/test/libcxx/input.output/stream.buffers/lit.local.cfg b/libcxx/test/libcxx/input.output/stream.buffers/lit.local.cfg index b89e35b..495f1cc 100644 --- a/libcxx/test/libcxx/input.output/stream.buffers/lit.local.cfg +++ b/libcxx/test/libcxx/input.output/stream.buffers/lit.local.cfg @@ -1,6 +1,7 @@ # Load the same local configuration as the corresponding one in libcxx/test/std import os -inLibcxx = os.path.join('libcxx', 'test', 'libcxx') -inStd = os.path.join('libcxx', 'test', 'std') + +inLibcxx = os.path.join("libcxx", "test", "libcxx") +inStd = os.path.join("libcxx", "test", "std") localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd) config.load_from_path(localConfig, lit_config) diff --git a/libcxx/test/libcxx/input.output/string.streams/lit.local.cfg b/libcxx/test/libcxx/input.output/string.streams/lit.local.cfg index b89e35b..495f1cc 100644 --- a/libcxx/test/libcxx/input.output/string.streams/lit.local.cfg +++ b/libcxx/test/libcxx/input.output/string.streams/lit.local.cfg @@ -1,6 +1,7 @@ # Load the same local configuration as the corresponding one in libcxx/test/std import os -inLibcxx = os.path.join('libcxx', 'test', 'libcxx') -inStd = os.path.join('libcxx', 'test', 'std') + +inLibcxx = os.path.join("libcxx", "test", "libcxx") +inStd = os.path.join("libcxx", "test", "std") localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd) config.load_from_path(localConfig, lit_config) diff --git a/libcxx/test/libcxx/lint/lint_cmakelists.sh.py b/libcxx/test/libcxx/lint/lint_cmakelists.sh.py index 1a94b44b..417f9ac 100644 --- a/libcxx/test/libcxx/lint/lint_cmakelists.sh.py +++ b/libcxx/test/libcxx/lint/lint_cmakelists.sh.py @@ -6,25 +6,25 @@ import os -if __name__ == '__main__': +if __name__ == "__main__": libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__)) - libcxx = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, '../../..')) - cmakelists_name = os.path.join(libcxx, 'include/CMakeLists.txt') + libcxx = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, "../../..")) + cmakelists_name = os.path.join(libcxx, "include/CMakeLists.txt") assert os.path.isfile(cmakelists_name) - with open(cmakelists_name, 'r') as f: + with open(cmakelists_name, "r") as f: lines = f.readlines() - assert lines[0] == 'set(files\n' + assert lines[0] == "set(files\n" okay = True prevline = lines[1] for line in lines[2:]: - if (line == ' )\n'): + if line == " )\n": break - if (line < prevline): + if line < prevline: okay = False - print('LINES OUT OF ORDER in libcxx/include/CMakeLists.txt!') + print("LINES OUT OF ORDER in libcxx/include/CMakeLists.txt!") print(prevline) print(line) prevline = line diff --git a/libcxx/test/libcxx/lint/lint_headers.sh.py b/libcxx/test/libcxx/lint/lint_headers.sh.py index 173f98b..ab237c9 100644 --- a/libcxx/test/libcxx/lint/lint_headers.sh.py +++ b/libcxx/test/libcxx/lint/lint_headers.sh.py @@ -10,45 +10,52 @@ import re def exclude_from_consideration(path): return ( - path.endswith('.txt') or - path.endswith('.modulemap.in') or - os.path.basename(path) == '__config' or - os.path.basename(path) == '__config_site.in' or - os.path.basename(path) == 'libcxx.imp' or - os.path.basename(path).startswith('__pstl') or # TODO: Remove once PSTL integration is finished - not os.path.isfile(path) + path.endswith(".txt") + or path.endswith(".modulemap.in") + or os.path.basename(path) == "__config" + or os.path.basename(path) == "__config_site.in" + or os.path.basename(path) == "libcxx.imp" + or os.path.basename(path).startswith("__pstl") + or not os.path.isfile(path) # TODO: Remove once PSTL integration is finished ) def check_for_pragma_GCC_system_header(pretty_fname, lines): - if pretty_fname not in ['__undef_macros']: + if pretty_fname not in ["__undef_macros"]: for line in lines: - if re.match('# *pragma GCC system_header\n', line): + if re.match("# *pragma GCC system_header\n", line): return True - print('FAILED TO FIND # pragma GCC system_header in libcxx/include/%s' % pretty_fname) + print( + "FAILED TO FIND # pragma GCC system_header in libcxx/include/%s" + % pretty_fname + ) return False return True -if __name__ == '__main__': +if __name__ == "__main__": libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__)) - libcxx_include = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, '../../../include')) + libcxx_include = os.path.abspath( + os.path.join(libcxx_test_libcxx_lint, "../../../include") + ) assert os.path.isdir(libcxx_include) def pretty(path): - return path[len(libcxx_include) + 1:] + return path[len(libcxx_include) + 1 :] all_headers = [ - p for p in ( - glob.glob(os.path.join(libcxx_include, '*')) + - glob.glob(os.path.join(libcxx_include, '__*/*.h')) - ) if not exclude_from_consideration(p) + p + for p in ( + glob.glob(os.path.join(libcxx_include, "*")) + + glob.glob(os.path.join(libcxx_include, "__*/*.h")) + ) + if not exclude_from_consideration(p) ] okay = True for fname in all_headers: pretty_fname = pretty(fname) - with open(fname, 'r') as f: + with open(fname, "r") as f: lines = f.readlines() okay = check_for_pragma_GCC_system_header(pretty_fname, lines) and okay diff --git a/libcxx/test/libcxx/lint/lint_modulemap.sh.py b/libcxx/test/libcxx/lint/lint_modulemap.sh.py index 85d2c4b..9610929 100755 --- a/libcxx/test/libcxx/lint/lint_modulemap.sh.py +++ b/libcxx/test/libcxx/lint/lint_modulemap.sh.py @@ -7,39 +7,53 @@ import os import re -if __name__ == '__main__': +if __name__ == "__main__": libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__)) - libcxx = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, '../../..')) - modulemap_name = os.path.join(libcxx, 'include/module.modulemap.in') + libcxx = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, "../../..")) + modulemap_name = os.path.join(libcxx, "include/module.modulemap.in") assert os.path.isfile(modulemap_name) okay = True prevline = None - with open(modulemap_name, 'r') as f: + with open(modulemap_name, "r") as f: for line in f.readlines(): - if re.match(r'^\s*module.*[{]\s*private', line): + if re.match(r"^\s*module.*[{]\s*private", line): # Check that these lines are all of the expected format. # This incidentally checks for typos in the module name. - if re.match(r'^\s*module (\w+)\s+[{] private header "\1(.h)?"\s+export [*] [}]', line): + if re.match( + r'^\s*module (\w+)\s+[{] private header "\1(.h)?"\s+export [*] [}]', + line, + ): # It's a top-level private header, such as <__bit_reference>. pass - elif re.match(r'^\s*module (\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]', line): + elif re.match( + r'^\s*module (\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]', + line, + ): # It's a private submodule, such as <__utility/swap.h>. pass - elif re.match(r'^\s*module (\w+)_fwd\s+[{] private header "__fwd/\1[.]h" [}]', line): + elif re.match( + r'^\s*module (\w+)_fwd\s+[{] private header "__fwd/\1[.]h" [}]', + line, + ): # It's a private submodule with forward declarations, such as <__fwd/span.h>. pass - elif re.match(r'^\s*module (?:\w+_)*(\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]', line): + elif re.match( + r'^\s*module (?:\w+_)*(\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]', + line, + ): # It's a private pstl submodule, such as <__algorithm/pstl_backends/cpu_backend.h> pass else: okay = False - print("LINE DOESN'T MATCH REGEX in libcxx/include/module.modulemap.in!") + print( + "LINE DOESN'T MATCH REGEX in libcxx/include/module.modulemap.in!" + ) print(line) # Check that these lines are alphabetized. if (prevline is not None) and (line < prevline): okay = False - print('LINES OUT OF ORDER in libcxx/include/module.modulemap.in!') + print("LINES OUT OF ORDER in libcxx/include/module.modulemap.in!") print(prevline) print(line) prevline = line diff --git a/libcxx/test/libcxx/lit.local.cfg b/libcxx/test/libcxx/lit.local.cfg index f328db3..1473673 100644 --- a/libcxx/test/libcxx/lit.local.cfg +++ b/libcxx/test/libcxx/lit.local.cfg @@ -1,3 +1,4 @@ # The tests in this directory need to run Python import pipes, sys -config.substitutions.append(('%{python}', pipes.quote(sys.executable))) + +config.substitutions.append(("%{python}", pipes.quote(sys.executable))) diff --git a/libcxx/test/libcxx/localization/lit.local.cfg b/libcxx/test/libcxx/localization/lit.local.cfg index b89e35b..495f1cc 100644 --- a/libcxx/test/libcxx/localization/lit.local.cfg +++ b/libcxx/test/libcxx/localization/lit.local.cfg @@ -1,6 +1,7 @@ # Load the same local configuration as the corresponding one in libcxx/test/std import os -inLibcxx = os.path.join('libcxx', 'test', 'libcxx') -inStd = os.path.join('libcxx', 'test', 'std') + +inLibcxx = os.path.join("libcxx", "test", "libcxx") +inStd = os.path.join("libcxx", "test", "std") localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd) config.load_from_path(localConfig, lit_config) diff --git a/libcxx/test/libcxx/selftest/additional_compile_flags/lit.local.cfg b/libcxx/test/libcxx/selftest/additional_compile_flags/lit.local.cfg index 44618de..fdddd89 100644 --- a/libcxx/test/libcxx/selftest/additional_compile_flags/lit.local.cfg +++ b/libcxx/test/libcxx/selftest/additional_compile_flags/lit.local.cfg @@ -1,2 +1,2 @@ # Add a Lit feature so we can test conditional addition of compile flags. -config.available_features.add('some-defined-feature') +config.available_features.add("some-defined-feature") diff --git a/libcxx/test/libcxx/selftest/dsl/dsl.sh.py b/libcxx/test/libcxx/selftest/dsl/dsl.sh.py index 81fb60a..dfe290b 100644 --- a/libcxx/test/libcxx/selftest/dsl/dsl.sh.py +++ b/libcxx/test/libcxx/selftest/dsl/dsl.sh.py @@ -1,10 +1,10 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # Note: We prepend arguments with 'x' to avoid thinking there are too few # arguments in case an argument is an empty string. @@ -23,15 +23,17 @@ from os.path import dirname # Allow importing 'lit' and the 'libcxx' module. Make sure we put the lit # path first so we don't find any system-installed version. monorepoRoot = dirname(dirname(dirname(dirname(dirname(dirname(__file__)))))) -sys.path = [os.path.join(monorepoRoot, 'libcxx', 'utils'), - os.path.join(monorepoRoot, 'llvm', 'utils', 'lit')] + sys.path +sys.path = [ + os.path.join(monorepoRoot, "libcxx", "utils"), + os.path.join(monorepoRoot, "llvm", "utils", "lit"), +] + sys.path import libcxx.test.dsl as dsl import lit.LitConfig import lit.util # Steal some parameters from the config running this test so that we can # bootstrap our own TestingConfig. -args = list(map(lambda s: s[1:], sys.argv[1:8])) # Remove the leading 'x' +args = list(map(lambda s: s[1:], sys.argv[1:8])) # Remove the leading 'x' SOURCE_ROOT, EXEC_PATH, SUBSTITUTIONS = args sys.argv[1:8] = [] @@ -40,10 +42,12 @@ SUBSTITUTIONS = pickle.loads(base64.b64decode(SUBSTITUTIONS)) for s, sub in SUBSTITUTIONS: print("Substitution '{}' is '{}'".format(s, sub)) + class SetupConfigs(unittest.TestCase): """ Base class for the tests below -- it creates a fake TestingConfig. """ + def setUp(self): """ Create a fake TestingConfig that can be populated however we wish for @@ -51,7 +55,7 @@ class SetupConfigs(unittest.TestCase): minimum required substitutions. """ self.litConfig = lit.LitConfig.LitConfig( - progname='lit', + progname="lit", path=[], quiet=False, useValgrind=False, @@ -59,9 +63,10 @@ class SetupConfigs(unittest.TestCase): valgrindArgs=[], noExecute=False, debug=False, - isWindows=platform.system() == 'Windows', - order='smart', - params={}) + isWindows=platform.system() == "Windows", + order="smart", + params={}, + ) self.config = lit.TestingConfig.TestingConfig.fromdefaults(self.litConfig) self.config.environment = dict(os.environ) @@ -82,7 +87,7 @@ class SetupConfigs(unittest.TestCase): def findIndex(list, pred): """Finds the index of the first element satisfying 'pred' in a list, or - 'len(list)' if there is no such element.""" + 'len(list)' if there is no such element.""" index = 0 for x in list: if pred(x): @@ -96,23 +101,27 @@ class TestHasCompileFlag(SetupConfigs): """ Tests for libcxx.test.dsl.hasCompileFlag """ + def test_no_flag_should_work(self): - self.assertTrue(dsl.hasCompileFlag(self.config, '')) + self.assertTrue(dsl.hasCompileFlag(self.config, "")) def test_flag_exists(self): - self.assertTrue(dsl.hasCompileFlag(self.config, '-O1')) + self.assertTrue(dsl.hasCompileFlag(self.config, "-O1")) def test_nonexistent_flag(self): - self.assertFalse(dsl.hasCompileFlag(self.config, '-this_is_not_a_flag_any_compiler_has')) + self.assertFalse( + dsl.hasCompileFlag(self.config, "-this_is_not_a_flag_any_compiler_has") + ) def test_multiple_flags(self): - self.assertTrue(dsl.hasCompileFlag(self.config, '-O1 -Dhello')) + self.assertTrue(dsl.hasCompileFlag(self.config, "-O1 -Dhello")) class TestSourceBuilds(SetupConfigs): """ Tests for libcxx.test.dsl.sourceBuilds """ + def test_valid_program_builds(self): source = """int main(int, char**) { return 0; }""" self.assertTrue(dsl.sourceBuilds(self.config, source)) @@ -131,6 +140,7 @@ class TestProgramOutput(SetupConfigs): """ Tests for libcxx.test.dsl.programOutput """ + def test_valid_program_returns_output(self): source = """ #include <cstdio> @@ -156,14 +166,20 @@ class TestProgramOutput(SetupConfigs): source = """ int main(int, char**) { return 1; } """ - self.assertRaises(dsl.ConfigurationRuntimeError, lambda: dsl.programOutput(self.config, source)) + self.assertRaises( + dsl.ConfigurationRuntimeError, + lambda: dsl.programOutput(self.config, source), + ) def test_program_that_fails_to_compile_raises_compilation_error(self): # The program doesn't compile source = """ int main(int, char**) { this doesnt compile } """ - self.assertRaises(dsl.ConfigurationCompilationError, lambda: dsl.programOutput(self.config, source)) + self.assertRaises( + dsl.ConfigurationCompilationError, + lambda: dsl.programOutput(self.config, source), + ) def test_pass_arguments_to_program(self): source = """ @@ -191,14 +207,22 @@ class TestProgramOutput(SetupConfigs): return 0; } """ - compileFlagsIndex = findIndex(self.config.substitutions, lambda x: x[0] == '%{compile_flags}') + compileFlagsIndex = findIndex( + self.config.substitutions, lambda x: x[0] == "%{compile_flags}" + ) compileFlags = self.config.substitutions[compileFlagsIndex][1] - self.config.substitutions[compileFlagsIndex] = ('%{compile_flags}', compileFlags + ' -DMACRO=1') + self.config.substitutions[compileFlagsIndex] = ( + "%{compile_flags}", + compileFlags + " -DMACRO=1", + ) output1 = dsl.programOutput(self.config, source) self.assertEqual(output1, "MACRO=1\n") - self.config.substitutions[compileFlagsIndex] = ('%{compile_flags}', compileFlags + ' -DMACRO=2') + self.config.substitutions[compileFlagsIndex] = ( + "%{compile_flags}", + compileFlags + " -DMACRO=2", + ) output2 = dsl.programOutput(self.config, source) self.assertEqual(output2, "MACRO=2\n") @@ -220,6 +244,7 @@ class TestProgramSucceeds(SetupConfigs): """ Tests for libcxx.test.dsl.programSucceeds """ + def test_success(self): source = """ int main(int, char**) { return 0; } @@ -236,33 +261,47 @@ class TestProgramSucceeds(SetupConfigs): source = """ this does not compile """ - self.assertRaises(dsl.ConfigurationCompilationError, lambda: dsl.programSucceeds(self.config, source)) + self.assertRaises( + dsl.ConfigurationCompilationError, + lambda: dsl.programSucceeds(self.config, source), + ) + class TestHasLocale(SetupConfigs): """ Tests for libcxx.test.dsl.hasLocale """ + def test_doesnt_explode(self): # It's really hard to test that a system has a given locale, so at least # make sure we don't explode when we try to check it. try: - dsl.hasAnyLocale(self.config, ['en_US.UTF-8']) + dsl.hasAnyLocale(self.config, ["en_US.UTF-8"]) except subprocess.CalledProcessError: self.fail("checking for hasLocale should not explode") def test_nonexistent_locale(self): - self.assertFalse(dsl.hasAnyLocale(self.config, ['forsurethisisnotanexistinglocale'])) + self.assertFalse( + dsl.hasAnyLocale(self.config, ["forsurethisisnotanexistinglocale"]) + ) def test_localization_program_doesnt_compile(self): - compilerIndex = findIndex(self.config.substitutions, lambda x: x[0] == '%{cxx}') - self.config.substitutions[compilerIndex] = ('%{cxx}', 'this-is-certainly-not-a-valid-compiler!!') - self.assertRaises(dsl.ConfigurationCompilationError, lambda: dsl.hasAnyLocale(self.config, ['en_US.UTF-8'])) + compilerIndex = findIndex(self.config.substitutions, lambda x: x[0] == "%{cxx}") + self.config.substitutions[compilerIndex] = ( + "%{cxx}", + "this-is-certainly-not-a-valid-compiler!!", + ) + self.assertRaises( + dsl.ConfigurationCompilationError, + lambda: dsl.hasAnyLocale(self.config, ["en_US.UTF-8"]), + ) class TestCompilerMacros(SetupConfigs): """ Tests for libcxx.test.dsl.compilerMacros """ + def test_basic(self): macros = dsl.compilerMacros(self.config) self.assertIsInstance(macros, dict) @@ -273,28 +312,29 @@ class TestCompilerMacros(SetupConfigs): def test_no_flag(self): macros = dsl.compilerMacros(self.config) - self.assertIn('__cplusplus', macros.keys()) + self.assertIn("__cplusplus", macros.keys()) def test_empty_flag(self): - macros = dsl.compilerMacros(self.config, '') - self.assertIn('__cplusplus', macros.keys()) + macros = dsl.compilerMacros(self.config, "") + self.assertIn("__cplusplus", macros.keys()) def test_with_flag(self): - macros = dsl.compilerMacros(self.config, '-DFOO=3') - self.assertIn('__cplusplus', macros.keys()) - self.assertEqual(macros['FOO'], '3') + macros = dsl.compilerMacros(self.config, "-DFOO=3") + self.assertIn("__cplusplus", macros.keys()) + self.assertEqual(macros["FOO"], "3") def test_with_flags(self): - macros = dsl.compilerMacros(self.config, '-DFOO=3 -DBAR=hello') - self.assertIn('__cplusplus', macros.keys()) - self.assertEqual(macros['FOO'], '3') - self.assertEqual(macros['BAR'], 'hello') + macros = dsl.compilerMacros(self.config, "-DFOO=3 -DBAR=hello") + self.assertIn("__cplusplus", macros.keys()) + self.assertEqual(macros["FOO"], "3") + self.assertEqual(macros["BAR"], "hello") class TestFeatureTestMacros(SetupConfigs): """ Tests for libcxx.test.dsl.featureTestMacros """ + def test_basic(self): macros = dsl.featureTestMacros(self.config) self.assertIsInstance(macros, dict) @@ -308,21 +348,22 @@ class TestFeature(SetupConfigs): """ Tests for libcxx.test.dsl.Feature """ + def test_trivial(self): - feature = dsl.Feature(name='name') + feature = dsl.Feature(name="name") origSubstitutions = copy.deepcopy(self.config.substitutions) actions = feature.getActions(self.config) self.assertTrue(len(actions) == 1) for a in actions: a.applyTo(self.config) self.assertEqual(origSubstitutions, self.config.substitutions) - self.assertIn('name', self.config.available_features) + self.assertIn("name", self.config.available_features) def test_name_can_be_a_callable(self): - feature = dsl.Feature(name=lambda cfg: 'name') + feature = dsl.Feature(name=lambda cfg: "name") for a in feature.getActions(self.config): a.applyTo(self.config) - self.assertIn('name', self.config.available_features) + self.assertIn("name", self.config.available_features) def test_name_is_not_a_string_1(self): feature = dsl.Feature(name=None) @@ -335,159 +376,250 @@ class TestFeature(SetupConfigs): self.assertRaises(ValueError, lambda: feature.pretty(self.config)) def test_adding_action(self): - feature = dsl.Feature(name='name', actions=[dsl.AddCompileFlag('-std=c++03')]) - origLinkFlags = copy.deepcopy(self.getSubstitution('%{link_flags}')) + feature = dsl.Feature(name="name", actions=[dsl.AddCompileFlag("-std=c++03")]) + origLinkFlags = copy.deepcopy(self.getSubstitution("%{link_flags}")) for a in feature.getActions(self.config): a.applyTo(self.config) - self.assertIn('name', self.config.available_features) - self.assertIn('-std=c++03', self.getSubstitution('%{compile_flags}')) - self.assertEqual(origLinkFlags, self.getSubstitution('%{link_flags}')) + self.assertIn("name", self.config.available_features) + self.assertIn("-std=c++03", self.getSubstitution("%{compile_flags}")) + self.assertEqual(origLinkFlags, self.getSubstitution("%{link_flags}")) def test_actions_can_be_a_callable(self): - feature = dsl.Feature(name='name', - actions=lambda cfg: ( - self.assertIs(self.config, cfg), - [dsl.AddCompileFlag('-std=c++03')] - )[1]) + feature = dsl.Feature( + name="name", + actions=lambda cfg: ( + self.assertIs(self.config, cfg), + [dsl.AddCompileFlag("-std=c++03")], + )[1], + ) for a in feature.getActions(self.config): a.applyTo(self.config) - self.assertIn('-std=c++03', self.getSubstitution('%{compile_flags}')) + self.assertIn("-std=c++03", self.getSubstitution("%{compile_flags}")) def test_unsupported_feature(self): - feature = dsl.Feature(name='name', when=lambda _: False) + feature = dsl.Feature(name="name", when=lambda _: False) self.assertEqual(feature.getActions(self.config), []) def test_is_supported_gets_passed_the_config(self): - feature = dsl.Feature(name='name', when=lambda cfg: (self.assertIs(self.config, cfg), True)[1]) + feature = dsl.Feature( + name="name", when=lambda cfg: (self.assertIs(self.config, cfg), True)[1] + ) self.assertEqual(len(feature.getActions(self.config)), 1) def _throw(): raise ValueError() + class TestParameter(SetupConfigs): """ Tests for libcxx.test.dsl.Parameter """ + def test_empty_name_should_blow_up(self): - self.assertRaises(ValueError, lambda: dsl.Parameter(name='', choices=['c++03'], type=str, help='', actions=lambda _: [])) + self.assertRaises( + ValueError, + lambda: dsl.Parameter( + name="", choices=["c++03"], type=str, help="", actions=lambda _: [] + ), + ) def test_empty_choices_should_blow_up(self): - self.assertRaises(ValueError, lambda: dsl.Parameter(name='std', choices=[], type=str, help='', actions=lambda _: [])) + self.assertRaises( + ValueError, + lambda: dsl.Parameter( + name="std", choices=[], type=str, help="", actions=lambda _: [] + ), + ) def test_no_choices_is_ok(self): - param = dsl.Parameter(name='triple', type=str, help='', actions=lambda _: []) - self.assertEqual(param.name, 'triple') + param = dsl.Parameter(name="triple", type=str, help="", actions=lambda _: []) + self.assertEqual(param.name, "triple") def test_name_is_set_correctly(self): - param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', actions=lambda _: []) - self.assertEqual(param.name, 'std') + param = dsl.Parameter( + name="std", choices=["c++03"], type=str, help="", actions=lambda _: [] + ) + self.assertEqual(param.name, "std") def test_no_value_provided_and_no_default_value(self): - param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', actions=lambda _: []) - self.assertRaises(ValueError, lambda: param.getActions(self.config, self.litConfig.params)) + param = dsl.Parameter( + name="std", choices=["c++03"], type=str, help="", actions=lambda _: [] + ) + self.assertRaises( + ValueError, lambda: param.getActions(self.config, self.litConfig.params) + ) def test_no_value_provided_and_default_value(self): - param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', default='c++03', - actions=lambda std: [dsl.AddFeature(std)]) + param = dsl.Parameter( + name="std", + choices=["c++03"], + type=str, + help="", + default="c++03", + actions=lambda std: [dsl.AddFeature(std)], + ) for a in param.getActions(self.config, self.litConfig.params): a.applyTo(self.config) - self.assertIn('c++03', self.config.available_features) + self.assertIn("c++03", self.config.available_features) def test_value_provided_on_command_line_and_no_default_value(self): - self.litConfig.params['std'] = 'c++03' - param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', - actions=lambda std: [dsl.AddFeature(std)]) + self.litConfig.params["std"] = "c++03" + param = dsl.Parameter( + name="std", + choices=["c++03"], + type=str, + help="", + actions=lambda std: [dsl.AddFeature(std)], + ) for a in param.getActions(self.config, self.litConfig.params): a.applyTo(self.config) - self.assertIn('c++03', self.config.available_features) + self.assertIn("c++03", self.config.available_features) def test_value_provided_on_command_line_and_default_value(self): """The value provided on the command line should override the default value""" - self.litConfig.params['std'] = 'c++11' - param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, default='c++03', help='', - actions=lambda std: [dsl.AddFeature(std)]) + self.litConfig.params["std"] = "c++11" + param = dsl.Parameter( + name="std", + choices=["c++03", "c++11"], + type=str, + default="c++03", + help="", + actions=lambda std: [dsl.AddFeature(std)], + ) for a in param.getActions(self.config, self.litConfig.params): a.applyTo(self.config) - self.assertIn('c++11', self.config.available_features) - self.assertNotIn('c++03', self.config.available_features) + self.assertIn("c++11", self.config.available_features) + self.assertNotIn("c++03", self.config.available_features) def test_value_provided_in_config_and_default_value(self): """The value provided in the config should override the default value""" - self.config.std ='c++11' - param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, default='c++03', help='', - actions=lambda std: [dsl.AddFeature(std)]) + self.config.std = "c++11" + param = dsl.Parameter( + name="std", + choices=["c++03", "c++11"], + type=str, + default="c++03", + help="", + actions=lambda std: [dsl.AddFeature(std)], + ) for a in param.getActions(self.config, self.litConfig.params): a.applyTo(self.config) - self.assertIn('c++11', self.config.available_features) - self.assertNotIn('c++03', self.config.available_features) + self.assertIn("c++11", self.config.available_features) + self.assertNotIn("c++03", self.config.available_features) def test_value_provided_in_config_and_on_command_line(self): """The value on the command line should override the one in the config""" - self.config.std = 'c++11' - self.litConfig.params['std'] = 'c++03' - param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, help='', - actions=lambda std: [dsl.AddFeature(std)]) + self.config.std = "c++11" + self.litConfig.params["std"] = "c++03" + param = dsl.Parameter( + name="std", + choices=["c++03", "c++11"], + type=str, + help="", + actions=lambda std: [dsl.AddFeature(std)], + ) for a in param.getActions(self.config, self.litConfig.params): a.applyTo(self.config) - self.assertIn('c++03', self.config.available_features) - self.assertNotIn('c++11', self.config.available_features) + self.assertIn("c++03", self.config.available_features) + self.assertNotIn("c++11", self.config.available_features) def test_no_actions(self): - self.litConfig.params['std'] = 'c++03' - param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', - actions=lambda _: []) + self.litConfig.params["std"] = "c++03" + param = dsl.Parameter( + name="std", choices=["c++03"], type=str, help="", actions=lambda _: [] + ) actions = param.getActions(self.config, self.litConfig.params) self.assertEqual(actions, []) def test_boolean_value_parsed_from_trueish_string_parameter(self): - self.litConfig.params['enable_exceptions'] = "True" - param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='', - actions=lambda exceptions: [] if exceptions else _throw()) + self.litConfig.params["enable_exceptions"] = "True" + param = dsl.Parameter( + name="enable_exceptions", + choices=[True, False], + type=bool, + help="", + actions=lambda exceptions: [] if exceptions else _throw(), + ) self.assertEqual(param.getActions(self.config, self.litConfig.params), []) def test_boolean_value_from_true_boolean_parameter(self): - self.litConfig.params['enable_exceptions'] = True - param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='', - actions=lambda exceptions: [] if exceptions else _throw()) + self.litConfig.params["enable_exceptions"] = True + param = dsl.Parameter( + name="enable_exceptions", + choices=[True, False], + type=bool, + help="", + actions=lambda exceptions: [] if exceptions else _throw(), + ) self.assertEqual(param.getActions(self.config, self.litConfig.params), []) def test_boolean_value_parsed_from_falseish_string_parameter(self): - self.litConfig.params['enable_exceptions'] = "False" - param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='', - actions=lambda exceptions: [] if exceptions else [dsl.AddFeature("-fno-exceptions")]) + self.litConfig.params["enable_exceptions"] = "False" + param = dsl.Parameter( + name="enable_exceptions", + choices=[True, False], + type=bool, + help="", + actions=lambda exceptions: [] + if exceptions + else [dsl.AddFeature("-fno-exceptions")], + ) for a in param.getActions(self.config, self.litConfig.params): a.applyTo(self.config) - self.assertIn('-fno-exceptions', self.config.available_features) + self.assertIn("-fno-exceptions", self.config.available_features) def test_boolean_value_from_false_boolean_parameter(self): - self.litConfig.params['enable_exceptions'] = False - param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='', - actions=lambda exceptions: [] if exceptions else [dsl.AddFeature("-fno-exceptions")]) + self.litConfig.params["enable_exceptions"] = False + param = dsl.Parameter( + name="enable_exceptions", + choices=[True, False], + type=bool, + help="", + actions=lambda exceptions: [] + if exceptions + else [dsl.AddFeature("-fno-exceptions")], + ) for a in param.getActions(self.config, self.litConfig.params): a.applyTo(self.config) - self.assertIn('-fno-exceptions', self.config.available_features) + self.assertIn("-fno-exceptions", self.config.available_features) def test_list_parsed_from_comma_delimited_string_empty(self): - self.litConfig.params['additional_features'] = "" - param = dsl.Parameter(name='additional_features', type=list, help='', actions=lambda f: f) + self.litConfig.params["additional_features"] = "" + param = dsl.Parameter( + name="additional_features", type=list, help="", actions=lambda f: f + ) self.assertEqual(param.getActions(self.config, self.litConfig.params), []) def test_list_parsed_from_comma_delimited_string_1(self): - self.litConfig.params['additional_features'] = "feature1" - param = dsl.Parameter(name='additional_features', type=list, help='', actions=lambda f: f) - self.assertEqual(param.getActions(self.config, self.litConfig.params), ['feature1']) + self.litConfig.params["additional_features"] = "feature1" + param = dsl.Parameter( + name="additional_features", type=list, help="", actions=lambda f: f + ) + self.assertEqual( + param.getActions(self.config, self.litConfig.params), ["feature1"] + ) def test_list_parsed_from_comma_delimited_string_2(self): - self.litConfig.params['additional_features'] = "feature1,feature2" - param = dsl.Parameter(name='additional_features', type=list, help='', actions=lambda f: f) - self.assertEqual(param.getActions(self.config, self.litConfig.params), ['feature1', 'feature2']) + self.litConfig.params["additional_features"] = "feature1,feature2" + param = dsl.Parameter( + name="additional_features", type=list, help="", actions=lambda f: f + ) + self.assertEqual( + param.getActions(self.config, self.litConfig.params), + ["feature1", "feature2"], + ) def test_list_parsed_from_comma_delimited_string_3(self): - self.litConfig.params['additional_features'] = "feature1,feature2, feature3" - param = dsl.Parameter(name='additional_features', type=list, help='', actions=lambda f: f) - self.assertEqual(param.getActions(self.config, self.litConfig.params), ['feature1', 'feature2', 'feature3']) + self.litConfig.params["additional_features"] = "feature1,feature2, feature3" + param = dsl.Parameter( + name="additional_features", type=list, help="", actions=lambda f: f + ) + self.assertEqual( + param.getActions(self.config, self.litConfig.params), + ["feature1", "feature2", "feature3"], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main(verbosity=2) diff --git a/libcxx/test/libcxx/selftest/dsl/lit.local.cfg b/libcxx/test/libcxx/selftest/dsl/lit.local.cfg index ce4a323..352719b 100644 --- a/libcxx/test/libcxx/selftest/dsl/lit.local.cfg +++ b/libcxx/test/libcxx/selftest/dsl/lit.local.cfg @@ -9,6 +9,7 @@ # to pass it to the test, and we decode and unpickle the substitutions from # within the test. import base64, lit.util, pickle + base64Encode = lambda s: lit.util.to_string(base64.b64encode(lit.util.to_bytes(s))) escapedSubstitutions = base64Encode(pickle.dumps(config.substitutions)) -config.substitutions.append(('%{substitutions}', escapedSubstitutions)) +config.substitutions.append(("%{substitutions}", escapedSubstitutions)) diff --git a/libcxx/test/libcxx/transitive_includes_to_csv.py b/libcxx/test/libcxx/transitive_includes_to_csv.py index ad86ca7..97843ec 100755 --- a/libcxx/test/libcxx/transitive_includes_to_csv.py +++ b/libcxx/test/libcxx/transitive_includes_to_csv.py @@ -41,7 +41,8 @@ def parse_line(line: str) -> header: # literal level.) LIBCXX_HEADER_REGEX = r".*c\+\+(?:/|\\\\)v[0-9]+(?:/|\\\\)(.+)" -def is_libcxx_public_header(header : str) -> bool: + +def is_libcxx_public_header(header: str) -> bool: """ Returns whether a header is a C++ public header file. """ @@ -62,7 +63,7 @@ def is_libcxx_public_header(header : str) -> bool: return True -def is_libcxx_header(header : str) -> bool: +def is_libcxx_header(header: str) -> bool: """ Returns whether a header is a libc++ header, excluding the C-compatibility headers. """ @@ -73,7 +74,9 @@ def is_libcxx_header(header : str) -> bool: # Skip C compatibility headers (in particular, make sure not to skip libc++ detail headers). relative = match.group(1) - if relative.endswith(".h") and not (relative.startswith("__") or re.search(r"(/|\\\\)__", relative)): + if relative.endswith(".h") and not ( + relative.startswith("__") or re.search(r"(/|\\\\)__", relative) + ): return False return True @@ -130,7 +133,9 @@ def create_include_graph(path: pathlib.Path) -> List[str]: # Get actual filenames relative to libc++'s installation directory instead of full paths relative = lambda h: re.match(LIBCXX_HEADER_REGEX, h).group(1) - top_level = relative(next(h.name for h in headers if h.level == 1)) # There should be only one top-level header + top_level = relative( + next(h.name for h in headers if h.level == 1) + ) # There should be only one top-level header includes = [relative(h.name) for h in headers if h.level != 1] # Remove duplicates in all includes. diff --git a/libcxx/test/lit.cfg.py b/libcxx/test/lit.cfg.py index 647464a..ea4a9a7 100644 --- a/libcxx/test/lit.cfg.py +++ b/libcxx/test/lit.cfg.py @@ -7,4 +7,5 @@ lit_config.fatal( "You seem to be running Lit directly -- you should be running Lit through " "<build>/bin/llvm-lit, which will ensure that the right Lit configuration " - "file is used.") + "file is used." +) diff --git a/libcxx/test/std/depr/depr.ios.members/lit.local.cfg b/libcxx/test/std/depr/depr.ios.members/lit.local.cfg index 3d9bcf3..fd1206b 100644 --- a/libcxx/test/std/depr/depr.ios.members/lit.local.cfg +++ b/libcxx/test/std/depr/depr.ios.members/lit.local.cfg @@ -1,2 +1,2 @@ -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/depr/depr.str.strstreams/lit.local.cfg b/libcxx/test/std/depr/depr.str.strstreams/lit.local.cfg index 3d9bcf3..fd1206b 100644 --- a/libcxx/test/std/depr/depr.str.strstreams/lit.local.cfg +++ b/libcxx/test/std/depr/depr.str.strstreams/lit.local.cfg @@ -1,2 +1,2 @@ -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/experimental/lit.local.cfg b/libcxx/test/std/experimental/lit.local.cfg index 5e2c632..ebfaa02 100644 --- a/libcxx/test/std/experimental/lit.local.cfg +++ b/libcxx/test/std/experimental/lit.local.cfg @@ -1,3 +1,3 @@ # Disable all of the experimental tests if the correct feature is not available. -if 'c++experimental' not in config.available_features: - config.unsupported = True +if "c++experimental" not in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/file.streams/lit.local.cfg b/libcxx/test/std/input.output/file.streams/lit.local.cfg index c62247c..0abfd8b 100644 --- a/libcxx/test/std/input.output/file.streams/lit.local.cfg +++ b/libcxx/test/std/input.output/file.streams/lit.local.cfg @@ -1,6 +1,6 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True -if 'no-fstream' in config.available_features: - config.unsupported = True +if "no-fstream" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/filesystems/lit.local.cfg b/libcxx/test/std/input.output/filesystems/lit.local.cfg index c2195962..6091761 100644 --- a/libcxx/test/std/input.output/filesystems/lit.local.cfg +++ b/libcxx/test/std/input.output/filesystems/lit.local.cfg @@ -1,5 +1,5 @@ -if 'availability-filesystem-missing' in config.available_features: - config.unsupported = True +if "availability-filesystem-missing" in config.available_features: + config.unsupported = True -if 'no-filesystem' in config.available_features: +if "no-filesystem" in config.available_features: config.unsupported = True diff --git a/libcxx/test/std/input.output/input.output.general/lit.local.cfg b/libcxx/test/std/input.output/input.output.general/lit.local.cfg index 781b508..2cb1001 100644 --- a/libcxx/test/std/input.output/input.output.general/lit.local.cfg +++ b/libcxx/test/std/input.output/input.output.general/lit.local.cfg @@ -1,3 +1,3 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/iostream.format/lit.local.cfg b/libcxx/test/std/input.output/iostream.format/lit.local.cfg index 781b508..2cb1001 100644 --- a/libcxx/test/std/input.output/iostream.format/lit.local.cfg +++ b/libcxx/test/std/input.output/iostream.format/lit.local.cfg @@ -1,3 +1,3 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/iostream.forward/lit.local.cfg b/libcxx/test/std/input.output/iostream.forward/lit.local.cfg index 781b508..2cb1001 100644 --- a/libcxx/test/std/input.output/iostream.forward/lit.local.cfg +++ b/libcxx/test/std/input.output/iostream.forward/lit.local.cfg @@ -1,3 +1,3 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/iostream.objects/lit.local.cfg b/libcxx/test/std/input.output/iostream.objects/lit.local.cfg index 781b508..2cb1001 100644 --- a/libcxx/test/std/input.output/iostream.objects/lit.local.cfg +++ b/libcxx/test/std/input.output/iostream.objects/lit.local.cfg @@ -1,3 +1,3 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/iostreams.base/lit.local.cfg b/libcxx/test/std/input.output/iostreams.base/lit.local.cfg index 781b508..2cb1001 100644 --- a/libcxx/test/std/input.output/iostreams.base/lit.local.cfg +++ b/libcxx/test/std/input.output/iostreams.base/lit.local.cfg @@ -1,3 +1,3 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/iostreams.requirements/lit.local.cfg b/libcxx/test/std/input.output/iostreams.requirements/lit.local.cfg index 781b508..2cb1001 100644 --- a/libcxx/test/std/input.output/iostreams.requirements/lit.local.cfg +++ b/libcxx/test/std/input.output/iostreams.requirements/lit.local.cfg @@ -1,3 +1,3 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/stream.buffers/lit.local.cfg b/libcxx/test/std/input.output/stream.buffers/lit.local.cfg index 781b508..2cb1001 100644 --- a/libcxx/test/std/input.output/stream.buffers/lit.local.cfg +++ b/libcxx/test/std/input.output/stream.buffers/lit.local.cfg @@ -1,3 +1,3 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/input.output/string.streams/lit.local.cfg b/libcxx/test/std/input.output/string.streams/lit.local.cfg index 781b508..2cb1001 100644 --- a/libcxx/test/std/input.output/string.streams/lit.local.cfg +++ b/libcxx/test/std/input.output/string.streams/lit.local.cfg @@ -1,3 +1,3 @@ # All non-trivial uses of iostreams require localization support -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/iterators/stream.iterators/lit.local.cfg b/libcxx/test/std/iterators/stream.iterators/lit.local.cfg index 504efc6..b2119d9 100644 --- a/libcxx/test/std/iterators/stream.iterators/lit.local.cfg +++ b/libcxx/test/std/iterators/stream.iterators/lit.local.cfg @@ -1,3 +1,3 @@ # stream iterators rely on the streams library, which requires localization -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/localization/lit.local.cfg b/libcxx/test/std/localization/lit.local.cfg index de37401..d47f3e0 100644 --- a/libcxx/test/std/localization/lit.local.cfg +++ b/libcxx/test/std/localization/lit.local.cfg @@ -1,3 +1,3 @@ # <locale> tests are obviously not supported when localization support is disabled -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/re/lit.local.cfg b/libcxx/test/std/re/lit.local.cfg index 9626384..17db114 100644 --- a/libcxx/test/std/re/lit.local.cfg +++ b/libcxx/test/std/re/lit.local.cfg @@ -1,3 +1,3 @@ # Unfortunately, <regex> uses locales in regex_traits -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string.io/lit.local.cfg b/libcxx/test/std/strings/basic.string/string.nonmembers/string.io/lit.local.cfg index 7780409..42a86f7 100644 --- a/libcxx/test/std/strings/basic.string/string.nonmembers/string.io/lit.local.cfg +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string.io/lit.local.cfg @@ -1,3 +1,3 @@ # These std::string functions require iostreams, which requires localization -if 'no-localization' in config.available_features: - config.unsupported = True +if "no-localization" in config.available_features: + config.unsupported = True diff --git a/libcxx/utils/cat_files.py b/libcxx/utils/cat_files.py index ac4f386..77127cb 100755 --- a/libcxx/utils/cat_files.py +++ b/libcxx/utils/cat_files.py @@ -1,45 +1,51 @@ #!/usr/bin/env python -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 argparse import ArgumentParser import sys + def print_and_exit(msg): - sys.stderr.write(msg + '\n') + sys.stderr.write(msg + "\n") sys.exit(1) + def main(): - parser = ArgumentParser( - description="Concatenate two files into a single file") + parser = ArgumentParser(description="Concatenate two files into a single file") parser.add_argument( - '-o', '--output', dest='output', required=True, - help='The output file. stdout is used if not given', - type=str, action='store') + "-o", + "--output", + dest="output", + required=True, + help="The output file. stdout is used if not given", + type=str, + action="store", + ) parser.add_argument( - 'files', metavar='files', nargs='+', - help='The files to concatenate') + "files", metavar="files", nargs="+", help="The files to concatenate" + ) args = parser.parse_args() if len(args.files) < 2: - print_and_exit('fewer than 2 inputs provided') - data = '' + print_and_exit("fewer than 2 inputs provided") + data = "" for filename in args.files: - with open(filename, 'r') as f: + with open(filename, "r") as f: data += f.read() - if len(data) != 0 and data[-1] != '\n': - data += '\n' + if len(data) != 0 and data[-1] != "\n": + data += "\n" assert len(data) > 0 and "cannot cat empty files" - with open(args.output, 'w') as f: + with open(args.output, "w") as f: f.write(data) -if __name__ == '__main__': +if __name__ == "__main__": main() sys.exit(0) diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py index e62c367..251761a 100644 --- a/libcxx/utils/gdb/libcxx/printers.py +++ b/libcxx/utils/gdb/libcxx/printers.py @@ -1,10 +1,10 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """GDB pretty-printers for libc++. These should work for objects compiled with either the stable ABI or the unstable ABI. @@ -29,6 +29,7 @@ _long_int_type = gdb.lookup_type("unsigned long long") _libcpp_big_endian = False + def addr_as_long(addr): return int(addr.cast(_long_int_type)) @@ -97,10 +98,11 @@ def _size_field(node): # Some common substitutions on the types to reduce visual clutter (A user who # wants to see the actual details can always use print/r). _common_substitutions = [ - ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >", - "std::string"), - ("std::basic_string_view<char, std::char_traits<char> >", - "std::string_view"), + ( + "std::basic_string<char, std::char_traits<char>, std::allocator<char> >", + "std::string", + ), + ("std::basic_string_view<char, std::char_traits<char> >", "std::string_view"), ] @@ -116,8 +118,11 @@ def _prettify_typename(gdb_type): """ type_without_typedefs = gdb_type.strip_typedefs() - typename = type_without_typedefs.name or type_without_typedefs.tag or \ - str(type_without_typedefs) + typename = ( + type_without_typedefs.name + or type_without_typedefs.tag + or str(type_without_typedefs) + ) result = _remove_cxx_namespace(typename) for find_str, subst_str in _common_substitutions: result = re.sub(find_str, subst_str, result) @@ -247,18 +252,18 @@ class StdStringViewPrinter(object): """Print a std::string_view.""" def __init__(self, val): - self.val = val + self.val = val def display_hint(self): - return "string" + return "string" def to_string(self): # pylint: disable=g-bad-name - """GDB calls this to compute the pretty-printed form.""" + """GDB calls this to compute the pretty-printed form.""" - ptr = _data_field(self.val) - ptr = ptr.cast(ptr.type.target().strip_typedefs().pointer()) - size = _size_field(self.val) - return ptr.lazy_string(length=size) + ptr = _data_field(self.val) + ptr = ptr.cast(ptr.type.target().strip_typedefs().pointer()) + size = _size_field(self.val) + return ptr.lazy_string(length=size) class StdUniquePtrPrinter(object): @@ -273,9 +278,10 @@ class StdUniquePtrPrinter(object): typename = _remove_generics(_prettify_typename(self.val.type)) if not self.addr: return "%s is nullptr" % typename - return ("%s<%s> containing" % - (typename, - _remove_generics(_prettify_typename(self.pointee_type)))) + return "%s<%s> containing" % ( + typename, + _remove_generics(_prettify_typename(self.pointee_type)), + ) def __iter__(self): if self.addr: @@ -296,7 +302,8 @@ class StdSharedPointerPrinter(object): """Returns self as a string.""" typename = _remove_generics(_prettify_typename(self.val.type)) pointee_type = _remove_generics( - _prettify_typename(self.val.type.template_argument(0))) + _prettify_typename(self.val.type.template_argument(0)) + ) if not self.addr: return "%s is nullptr" % typename refcount = self.val["__cntrl_"] @@ -391,20 +398,24 @@ class StdVectorPrinter(object): self.typename += "<bool>" self.length = self.val["__size_"] bits_per_word = self.val["__bits_per_word"] - self.capacity = _value_of_pair_first( - self.val["__cap_alloc_"]) * bits_per_word - self.iterator = self._VectorBoolIterator( - begin, self.length, bits_per_word) + self.capacity = ( + _value_of_pair_first(self.val["__cap_alloc_"]) * bits_per_word + ) + self.iterator = self._VectorBoolIterator(begin, self.length, bits_per_word) else: end = self.val["__end_"] self.length = end - begin - self.capacity = _get_base_subobject( - self.val["__end_cap_"])["__value_"] - begin + self.capacity = ( + _get_base_subobject(self.val["__end_cap_"])["__value_"] - begin + ) self.iterator = self._VectorIterator(begin, end) def to_string(self): - return ("%s of length %d, capacity %d" % - (self.typename, self.length, self.capacity)) + return "%s of length %d, capacity %d" % ( + self.typename, + self.length, + self.capacity, + ) def children(self): return self.iterator @@ -424,8 +435,9 @@ class StdBitsetPrinter(object): if self.n_words == 1: self.values = [int(self.val["__first_"])] else: - self.values = [int(self.val["__first_"][index]) - for index in range(self.n_words)] + self.values = [ + int(self.val["__first_"][index]) for index in range(self.n_words) + ] def to_string(self): typename = _prettify_typename(self.val.type) @@ -454,8 +466,7 @@ class StdDequePrinter(object): self.start_ptr = self.val["__map_"]["__begin_"] self.first_block_start_index = int(self.val["__start_"]) self.node_type = self.start_ptr.type - self.block_size = self._calculate_block_size( - val.type.template_argument(0)) + self.block_size = self._calculate_block_size(val.type.template_argument(0)) def _calculate_block_size(self, element_type): """Calculates the number of elements in a full block.""" @@ -473,13 +484,13 @@ class StdDequePrinter(object): current_addr = self.start_ptr start_index = self.first_block_start_index while num_emitted < self.size: - end_index = min(start_index + self.size - - num_emitted, self.block_size) + end_index = min(start_index + self.size - num_emitted, self.block_size) for _, elem in self._bucket_it(current_addr, start_index, end_index): yield "", elem num_emitted += end_index - start_index - current_addr = gdb.Value(addr_as_long(current_addr) + _pointer_size) \ - .cast(self.node_type) + current_addr = gdb.Value(addr_as_long(current_addr) + _pointer_size).cast( + self.node_type + ) start_index = 0 def to_string(self): @@ -507,8 +518,10 @@ class StdListPrinter(object): self.size = int(_value_of_pair_first(size_alloc_field)) dummy_node = self.val["__end_"] self.nodetype = gdb.lookup_type( - re.sub("__list_node_base", "__list_node", - str(dummy_node.type.strip_typedefs()))).pointer() + re.sub( + "__list_node_base", "__list_node", str(dummy_node.type.strip_typedefs()) + ) + ).pointer() self.first_node = dummy_node["__next_"] def to_string(self): @@ -685,7 +698,8 @@ class StdMapPrinter(AbstractRBTreePrinter): def _init_cast_type(self, val_type): map_it_type = gdb.lookup_type( - str(val_type.strip_typedefs()) + "::iterator").strip_typedefs() + str(val_type.strip_typedefs()) + "::iterator" + ).strip_typedefs() tree_it_type = map_it_type.template_argument(0) node_ptr_type = tree_it_type.template_argument(1) return node_ptr_type @@ -703,7 +717,8 @@ class StdSetPrinter(AbstractRBTreePrinter): def _init_cast_type(self, val_type): set_it_type = gdb.lookup_type( - str(val_type.strip_typedefs()) + "::iterator").strip_typedefs() + str(val_type.strip_typedefs()) + "::iterator" + ).strip_typedefs() node_ptr_type = set_it_type.template_argument(1) return node_ptr_type @@ -730,8 +745,7 @@ class AbstractRBTreeIteratorPrinter(object): def _is_valid_node(self): if not self.util.parent(self.addr): return False - return self.util.is_left_child(self.addr) or \ - self.util.is_right_child(self.addr) + return self.util.is_left_child(self.addr) or self.util.is_right_child(self.addr) def to_string(self): if not self.addr: @@ -756,8 +770,7 @@ class MapIteratorPrinter(AbstractRBTreeIteratorPrinter): """Print a std::(multi)map iterator.""" def __init__(self, val): - self._initialize(val["__i_"], - _remove_generics(_prettify_typename(val.type))) + self._initialize(val["__i_"], _remove_generics(_prettify_typename(val.type))) def _get_node_value(self, node): return _cc_field(node) @@ -976,10 +989,12 @@ class LibcxxPrettyPrinter(object): # Don't attempt types known to be inside libstdcxx. typename = val.type.name or val.type.tag or str(val.type) match = re.match("^std::(__.*?)::", typename) - if match is not None and match.group(1) in ["__cxx1998", - "__debug", - "__7", - "__g"]: + if match is not None and match.group(1) in [ + "__cxx1998", + "__debug", + "__7", + "__g", + ]: return None # Handle any using declarations or other typedefs. @@ -1005,13 +1020,13 @@ def _register_libcxx_printers(event): # already generated as part of a larger data structure, and there is # no python api to get the endianness. Mixed-endianness debugging # rare enough that this workaround should be adequate. - _libcpp_big_endian = "big endian" in gdb.execute("show endian", - to_string=True) + _libcpp_big_endian = "big endian" in gdb.execute("show endian", to_string=True) if not getattr(progspace, _libcxx_printer_name, False): print("Loading libc++ pretty-printers.") gdb.printing.register_pretty_printer( - progspace, LibcxxPrettyPrinter(_libcxx_printer_name)) + progspace, LibcxxPrettyPrinter(_libcxx_printer_name) + ) setattr(progspace, _libcxx_printer_name, True) diff --git a/libcxx/utils/generate_abi_list.py b/libcxx/utils/generate_abi_list.py index 670300b..94e49dc 100755 --- a/libcxx/utils/generate_abi_list.py +++ b/libcxx/utils/generate_abi_list.py @@ -1,11 +1,11 @@ #!/usr/bin/env python -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## import argparse import io @@ -14,27 +14,38 @@ import libcxx.sym_check.util import pprint import sys + def OutputFile(file): if isinstance(file, io.IOBase): return file assert isinstance(file, str), "Got object {} which is not a str".format(file) - return open(file, 'w', newline='\n') + return open(file, "w", newline="\n") + def main(argv): parser = argparse.ArgumentParser( - description='Extract a list of symbols from a shared library.') - parser.add_argument('library', metavar='LIB', type=str, - help='The library to extract symbols from.') - parser.add_argument('-o', '--output', dest='output', type=OutputFile, default=sys.stdout, - help='The output file to write the symbols to. It is overwritten if it already exists. ' - 'If no file is specified, the results are written to standard output.') + description="Extract a list of symbols from a shared library." + ) + parser.add_argument( + "library", metavar="LIB", type=str, help="The library to extract symbols from." + ) + parser.add_argument( + "-o", + "--output", + dest="output", + type=OutputFile, + default=sys.stdout, + help="The output file to write the symbols to. It is overwritten if it already exists. " + "If no file is specified, the results are written to standard output.", + ) args = parser.parse_args(argv) symbols = libcxx.sym_check.extract.extract_symbols(args.library) symbols, _ = libcxx.sym_check.util.filter_stdlib_symbols(symbols) lines = [pprint.pformat(sym, width=99999) for sym in symbols] - args.output.writelines('\n'.join(sorted(lines))) + args.output.writelines("\n".join(sorted(lines))) + -if __name__ == '__main__': +if __name__ == "__main__": main(sys.argv[1:]) diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index ce02746..abc833d 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -4,30 +4,43 @@ import os from builtins import range from functools import reduce + def get_libcxx_paths(): - utils_path = os.path.dirname(os.path.abspath(__file__)) - script_name = os.path.basename(__file__) - assert os.path.exists(utils_path) - src_root = os.path.dirname(utils_path) - include_path = os.path.join(src_root, 'include') - assert os.path.exists(include_path) - docs_path = os.path.join(src_root, 'docs') - assert os.path.exists(docs_path) - macro_test_path = os.path.join(src_root, 'test', 'std', 'language.support', - 'support.limits', 'support.limits.general') - assert os.path.exists(macro_test_path) - assert os.path.exists(os.path.join(macro_test_path, 'version.version.compile.pass.cpp')) - return script_name, src_root, include_path, docs_path, macro_test_path + utils_path = os.path.dirname(os.path.abspath(__file__)) + script_name = os.path.basename(__file__) + assert os.path.exists(utils_path) + src_root = os.path.dirname(utils_path) + include_path = os.path.join(src_root, "include") + assert os.path.exists(include_path) + docs_path = os.path.join(src_root, "docs") + assert os.path.exists(docs_path) + macro_test_path = os.path.join( + src_root, + "test", + "std", + "language.support", + "support.limits", + "support.limits.general", + ) + assert os.path.exists(macro_test_path) + assert os.path.exists( + os.path.join(macro_test_path, "version.version.compile.pass.cpp") + ) + return script_name, src_root, include_path, docs_path, macro_test_path + script_name, source_root, include_path, docs_path, macro_test_path = get_libcxx_paths() + def has_header(h): - h_path = os.path.join(include_path, h) - return os.path.exists(h_path) + h_path = os.path.join(include_path, h) + return os.path.exists(h_path) + def add_version_header(tc): - tc["headers"].append("version") - return tc + tc["headers"].append("version") + return tc + # ================ ============================================================ # Field Description @@ -59,733 +72,972 @@ def add_version_header(tc): # you've fully implemented the feature, you should remove # this field. # ================ ============================================================ -feature_test_macros = [ add_version_header(x) for x in [ - { - "name": "__cpp_lib_adaptor_iterator_pair_constructor", - "values": { "c++23": 202106 }, - "headers": ["queue", "stack"], - }, { - "name": "__cpp_lib_addressof_constexpr", - "values": { "c++17": 201603 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_allocate_at_least", - "values": { "c++23": 202106 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_allocator_traits_is_always_equal", - "values": { "c++17": 201411 }, - "headers": ["deque", "forward_list", "list", "map", "memory", "scoped_allocator", "set", "string", "unordered_map", "unordered_set", "vector"], - }, { - "name": "__cpp_lib_any", - "values": { "c++17": 201606 }, - "headers": ["any"], - }, { - "name": "__cpp_lib_apply", - "values": { "c++17": 201603 }, - "headers": ["tuple"], - }, { - "name": "__cpp_lib_array_constexpr", - "values": { "c++17": 201603, "c++20": 201811 }, - "headers": ["array", "iterator"], - }, { - "name": "__cpp_lib_as_const", - "values": { "c++17": 201510 }, - "headers": ["utility"], - }, { - "name": "__cpp_lib_associative_heterogeneous_erasure", - "values": { "c++23": 202110 }, - "headers": ["map", "set", "unordered_map", "unordered_set"], - "unimplemented": True, - }, { - "name": "__cpp_lib_assume_aligned", - "values": { "c++20": 201811 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_atomic_flag_test", - "values": { "c++20": 201907 }, - "headers": ["atomic"], - }, { - "name": "__cpp_lib_atomic_float", - "values": { "c++20": 201711 }, - "headers": ["atomic"], - "unimplemented": True, - }, { - "name": "__cpp_lib_atomic_is_always_lock_free", - "values": { "c++17": 201603 }, - "headers": ["atomic"], - }, { - "name": "__cpp_lib_atomic_lock_free_type_aliases", - "values": { "c++20": 201907 }, - "headers": ["atomic"], - }, { - "name": "__cpp_lib_atomic_ref", - "values": { "c++20": 201806 }, - "headers": ["atomic"], - "unimplemented": True, - }, { - "name": "__cpp_lib_atomic_shared_ptr", - "values": { "c++20": 201711 }, - "headers": ["atomic"], - "unimplemented": True, - }, { - "name": "__cpp_lib_atomic_value_initialization", - "values": { "c++20": 201911 }, - "headers": ["atomic", "memory"], - }, { - "name": "__cpp_lib_atomic_wait", - "values": { "c++20": 201907 }, - "headers": ["atomic"], - "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", - "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", - }, { - "name": "__cpp_lib_barrier", - "values": { "c++20": 201907 }, - "headers": ["barrier"], - "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", - "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", - }, { - "name": "__cpp_lib_bind_back", - "values": { "c++23": 202202 }, - "headers": ["functional"], - "unimplemented": True, - }, { - "name": "__cpp_lib_bind_front", - "values": { "c++20": 201907 }, - "headers": ["functional"], - }, { - "name": "__cpp_lib_bit_cast", - "values": { "c++20": 201806 }, - "headers": ["bit"], - }, { - "name": "__cpp_lib_bitops", - "values": { "c++20": 201907 }, - "headers": ["bit"], - "unimplemented": True, - }, { - "name": "__cpp_lib_bool_constant", - "values": { "c++17": 201505 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_bounded_array_traits", - "values": { "c++20": 201902 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_boyer_moore_searcher", - "values": { "c++17": 201603 }, - "headers": ["functional"], - }, { - "name": "__cpp_lib_byte", - "values": { "c++17": 201603 }, - "headers": ["cstddef"], - }, { - "name": "__cpp_lib_byteswap", - "values": { "c++23": 202110 }, - "headers": ["bit"], - }, { - "name": "__cpp_lib_char8_t", - "values": { "c++20": 201907 }, - "headers": ["atomic", "filesystem", "istream", "limits", "locale", "ostream", "string", "string_view"], - "test_suite_guard": "defined(__cpp_char8_t)", - "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CHAR8_T)", - }, { - "name": "__cpp_lib_chrono", - "values": { "c++17": 201611 }, - "headers": ["chrono"], - }, { - "name": "__cpp_lib_chrono_udls", - "values": { "c++14": 201304 }, - "headers": ["chrono"], - }, { - "name": "__cpp_lib_clamp", - "values": { "c++17": 201603 }, - "headers": ["algorithm"], - }, { - "name": "__cpp_lib_complex_udls", - "values": { "c++14": 201309 }, - "headers": ["complex"], - }, { - "name": "__cpp_lib_concepts", - "values": { "c++20": 202002 }, - "headers": ["concepts"], - }, { - "name": "__cpp_lib_constexpr_algorithms", - "values": { "c++20": 201806 }, - "headers": ["algorithm", "utility"], - }, { - "name": "__cpp_lib_constexpr_bitset", - "values": { "c++23": 202207 }, - "headers": ["bitset"], - }, { - "name": "__cpp_lib_constexpr_charconv", - "values": { "c++23": 202207 }, - "headers": ["charconv"], - }, { - "name": "__cpp_lib_constexpr_cmath", - "values": { "c++23": 202202 }, - "headers": ["cmath", "cstdlib"], - "unimplemented": True, - }, { - "name": "__cpp_lib_constexpr_complex", - "values": { "c++20": 201711 }, - "headers": ["complex"], - }, { - "name": "__cpp_lib_constexpr_dynamic_alloc", - "values": { "c++20": 201907 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_constexpr_functional", - "values": { "c++20": 201907 }, - "headers": ["functional"], - }, { - "name": "__cpp_lib_constexpr_iterator", - "values": { "c++20": 201811 }, - "headers": ["iterator"], - }, { - "name": "__cpp_lib_constexpr_memory", - "values": { "c++20": 201811, "c++23": 202202 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_constexpr_numeric", - "values": { "c++20": 201911 }, - "headers": ["numeric"], - }, { - "name": "__cpp_lib_constexpr_string", - "values": { "c++20": 201907 }, - "headers": ["string"], - }, { - "name": "__cpp_lib_constexpr_string_view", - "values": { "c++20": 201811 }, - "headers": ["string_view"], - }, { - "name": "__cpp_lib_constexpr_tuple", - "values": { "c++20": 201811 }, - "headers": ["tuple"], - }, { - "name": "__cpp_lib_constexpr_typeinfo", - "values": { "c++23": 202106 }, - "headers": ["typeinfo"], - }, { - "name": "__cpp_lib_constexpr_utility", - "values": { "c++20": 201811 }, - "headers": ["utility"], - }, { - "name": "__cpp_lib_constexpr_vector", - "values": { "c++20": 201907 }, - "headers": ["vector"], - }, { - "name": "__cpp_lib_coroutine", - "values": { "c++20": 201902 }, - "headers": ["coroutine"], - }, { - "name": "__cpp_lib_destroying_delete", - "values": { "c++20": 201806 }, - "headers": ["new"], - "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", - "libcxx_guard": "_LIBCPP_STD_VER >= 20 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", - }, { - "name": "__cpp_lib_enable_shared_from_this", - "values": { "c++17": 201603 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_endian", - "values": { "c++20": 201907 }, - "headers": ["bit"], - }, { - "name": "__cpp_lib_erase_if", - "values": { "c++20": 202002 }, - "headers": ["deque", "forward_list", "list", "map", "set", "string", "unordered_map", "unordered_set", "vector"], - }, { - "name": "__cpp_lib_exchange_function", - "values": { "c++14": 201304 }, - "headers": ["utility"], - }, { - "name": "__cpp_lib_execution", - "values": { "c++17": 201603, "c++20": 201902 }, - "headers": ["execution"], - "unimplemented": True, - }, { - "name": "__cpp_lib_expected", - "values": { "c++23": 202211 }, - "headers": ["expected"], - }, { - "name": "__cpp_lib_filesystem", - "values": { "c++17": 201703 }, - "headers": ["filesystem"], - "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM)", - "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM)" - }, { - "name": "__cpp_lib_format", - "values": { - # "c++20": 201907 Not implemented P1361R2 Integration of chrono with text formatting - # "c++20": 202106 Fully implemented - # "c++20": 202110 Not implemented P2372R3 Fixing locale handling in chrono formatters - "c++20": 202106, - # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types - }, - "headers": ["format"], - "unimplemented": True, - }, { - "name": "__cpp_lib_format_ranges", - "values": { "c++23": 202207 }, - "headers": ["format"], - }, { - "name": "__cpp_lib_formatters", - "values": { "c++23": 202302 }, - "headers": ["stacktrace", "thread"], - "unimplemented": True, - }, { - "name": "__cpp_lib_forward_like", - "values": { "c++23": 202207 }, - "headers": ["utility"], - }, { - "name": "__cpp_lib_gcd_lcm", - "values": { "c++17": 201606 }, - "headers": ["numeric"], - }, { - "name": "__cpp_lib_generic_associative_lookup", - "values": { "c++14": 201304 }, - "headers": ["map", "set"], - }, { - "name": "__cpp_lib_generic_unordered_lookup", - "values": { "c++20": 201811 }, - "headers": ["unordered_map", "unordered_set"], - }, { - "name": "__cpp_lib_hardware_interference_size", - "values": { "c++17": 201703 }, - "test_suite_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)", - "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)", - "headers": ["new"], - }, { - "name": "__cpp_lib_has_unique_object_representations", - "values": { "c++17": 201606 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_hypot", - "values": { "c++17": 201603 }, - "headers": ["cmath"], - }, { - "name": "__cpp_lib_incomplete_container_elements", - "values": { "c++17": 201505 }, - "headers": ["forward_list", "list", "vector"], - }, { - "name": "__cpp_lib_int_pow2", - "values": { "c++20": 202002 }, - "headers": ["bit"], - }, { - "name": "__cpp_lib_integer_comparison_functions", - "values": { "c++20": 202002 }, - "headers": ["utility"], - }, { - "name": "__cpp_lib_integer_sequence", - "values": { "c++14": 201304 }, - "headers": ["utility"], - }, { - "name": "__cpp_lib_integral_constant_callable", - "values": { "c++14": 201304 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_interpolate", - "values": { "c++20": 201902 }, - "headers": ["cmath", "numeric"], - }, { - "name": "__cpp_lib_invoke", - "values": { "c++17": 201411 }, - "headers": ["functional"], - }, { - "name": "__cpp_lib_invoke_r", - "values": { "c++23": 202106 }, - "headers": ["functional"], - }, { - "name": "__cpp_lib_is_aggregate", - "values": { "c++17": 201703 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_is_constant_evaluated", - "values": { "c++20": 201811 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_is_final", - "values": { "c++14": 201402 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_is_invocable", - "values": { "c++17": 201703 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_is_layout_compatible", - "values": { "c++20": 201907 }, - "headers": ["type_traits"], - "unimplemented": True, - }, { - "name": "__cpp_lib_is_nothrow_convertible", - "values": { "c++20": 201806 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_is_null_pointer", - "values": { "c++14": 201309 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_is_pointer_interconvertible", - "values": { "c++20": 201907 }, - "headers": ["type_traits"], - "unimplemented": True, - }, { - "name": "__cpp_lib_is_scoped_enum", - "values": { "c++23": 202011 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_is_swappable", - "values": { "c++17": 201603 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_jthread", - "values": { "c++20": 201911 }, - "headers": ["stop_token", "thread"], - "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", - "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", - "unimplemented": True, - }, { - "name": "__cpp_lib_latch", - "values": { "c++20": 201907 }, - "headers": ["latch"], - "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", - "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", - }, { - "name": "__cpp_lib_launder", - "values": { "c++17": 201606 }, - "headers": ["new"], - }, { - "name": "__cpp_lib_list_remove_return_type", - "values": { "c++20": 201806 }, - "headers": ["forward_list", "list"], - }, { - "name": "__cpp_lib_logical_traits", - "values": { "c++17": 201510 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_make_from_tuple", - "values": { "c++17": 201606 }, - "headers": ["tuple"], - }, { - "name": "__cpp_lib_make_reverse_iterator", - "values": { "c++14": 201402 }, - "headers": ["iterator"], - }, { - "name": "__cpp_lib_make_unique", - "values": { "c++14": 201304 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_map_try_emplace", - "values": { "c++17": 201411 }, - "headers": ["map"], - }, { - "name": "__cpp_lib_math_constants", - "values": { "c++20": 201907 }, - "headers": ["numbers"], - }, { - "name": "__cpp_lib_math_special_functions", - "values": { "c++17": 201603 }, - "headers": ["cmath"], - "unimplemented": True, - }, { - "name": "__cpp_lib_mdspan", - "values": { "c++23": 202207 }, - "headers": ["mdspan"], - "unimplemented": True, - }, { - "name": "__cpp_lib_memory_resource", - "values": { "c++17": 201603 }, - "headers": ["memory_resource"], - }, { - "name": "__cpp_lib_move_iterator_concept", - "values": { "c++20": 202207 }, - "headers": ["iterator"], - }, { - "name": "__cpp_lib_move_only_function", - "values": { "c++23": 202110 }, - "headers": ["functional"], - "unimplemented": True, - }, { - "name": "__cpp_lib_node_extract", - "values": { "c++17": 201606 }, - "headers": ["map", "set", "unordered_map", "unordered_set"], - }, { - "name": "__cpp_lib_nonmember_container_access", - "values": { "c++17": 201411 }, - "headers": ["array", "deque", "forward_list", "iterator", "list", "map", "regex", "set", "string", "unordered_map", "unordered_set", "vector"], - }, { - "name": "__cpp_lib_not_fn", - "values": { "c++17": 201603 }, - "headers": ["functional"], - }, { - "name": "__cpp_lib_null_iterators", - "values": { "c++14": 201304 }, - "headers": ["iterator"], - }, { - "name": "__cpp_lib_optional", - "values": { "c++17": 201606, "c++23": 202110 }, - "headers": ["optional"], - }, { - "name": "__cpp_lib_out_ptr", - "values": { "c++23": 202106 }, - "headers": ["memory"], - "unimplemented": True, - }, { - "name": "__cpp_lib_parallel_algorithm", - "values": { "c++17": 201603 }, - "headers": ["algorithm", "numeric"], - "unimplemented": True, - }, { - "name": "__cpp_lib_polymorphic_allocator", - "values": { "c++20": 201902 }, - "headers": ["memory_resource"], - }, { - "name": "__cpp_lib_quoted_string_io", - "values": { "c++14": 201304 }, - "headers": ["iomanip"], - }, { - "name": "__cpp_lib_ranges", - "values": { "c++20": 202106 }, - "headers": ["algorithm", "functional", "iterator", "memory", "ranges"], - }, { - "name": "__cpp_lib_ranges_as_rvalue", - "values": { "c++23": 202207 }, - "headers": ["ranges"], - }, { - "name": "__cpp_lib_ranges_chunk", - "values": { "c++23": 202202 }, - "headers": ["ranges"], - "unimplemented": True, - }, { - "name": "__cpp_lib_ranges_chunk_by", - "values": { "c++23": 202202 }, - "headers": ["ranges"], - "unimplemented": True, - }, { - "name": "__cpp_lib_ranges_iota", - "values": { "c++23": 202202 }, - "headers": ["numeric"], - "unimplemented": True, - }, { - "name": "__cpp_lib_ranges_join_with", - "values": { "c++23": 202202 }, - "headers": ["ranges"], - "unimplemented": True, - }, { - "name": "__cpp_lib_ranges_slide", - "values": { "c++23": 202202 }, - "headers": ["ranges"], - "unimplemented": True, - }, { - "name": "__cpp_lib_ranges_starts_ends_with", - "values": { "c++23": 202106 }, - "headers": ["algorithm"], - "unimplemented": True, - }, { - "name": "__cpp_lib_ranges_to_container", - "values": { "c++23": 202202 }, - "headers": ["deque", "forward_list", "list", "map", "priority_queue", "queue", "set", "stack", "string", "unordered_map", "unordered_set", "vector"], - "unimplemented": True, - }, { - "name": "__cpp_lib_ranges_zip", - "values": { "c++23": 202110 }, - "headers": ["ranges", "tuple", "utility"], - "unimplemented": True, - }, { - "name": "__cpp_lib_raw_memory_algorithms", - "values": { "c++17": 201606 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_reference_from_temporary", - "values": { "c++23": 202202 }, - "headers": ["type_traits"], - "unimplemented": True, - }, { - "name": "__cpp_lib_remove_cvref", - "values": { "c++20": 201711 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_result_of_sfinae", - "values": { "c++14": 201210 }, - "headers": ["functional", "type_traits"], - }, { - "name": "__cpp_lib_robust_nonmodifying_seq_ops", - "values": { "c++14": 201304 }, - "headers": ["algorithm"], - }, { - "name": "__cpp_lib_sample", - "values": { "c++17": 201603 }, - "headers": ["algorithm"], - }, { - "name": "__cpp_lib_scoped_lock", - "values": { "c++17": 201703 }, - "headers": ["mutex"], - }, { - "name": "__cpp_lib_semaphore", - "values": { "c++20": 201907 }, - "headers": ["semaphore"], - "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", - "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", - }, { - "name": "__cpp_lib_shared_mutex", - "values": { "c++17": 201505 }, - "headers": ["shared_mutex"], - "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)", - "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)", - }, { - "name": "__cpp_lib_shared_ptr_arrays", - "values": { "c++17": 201611, "c++20": 201707 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_shared_ptr_weak_type", - "values": { "c++17": 201606 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_shared_timed_mutex", - "values": { "c++14": 201402 }, - "headers": ["shared_mutex"], - "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)", - "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)", - }, { - "name": "__cpp_lib_shift", - "values": { "c++20": 201806 }, - "headers": ["algorithm"], - }, { - "name": "__cpp_lib_smart_ptr_for_overwrite", - "values": { "c++20": 202002 }, - "headers": ["memory"], - "unimplemented": True, - }, { - "name": "__cpp_lib_source_location", - "values": { "c++20": 201907 }, - "headers": ["source_location"], - "test_suite_guard": "__has_builtin(__builtin_source_location) && !(defined(TEST_APPLE_CLANG_VER) && TEST_APPLE_CLANG_VER <= 1403)", - "libcxx_guard": "__has_builtin(__builtin_source_location) && !(defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER <= 1403)", - }, { - "name": "__cpp_lib_span", - "values": { "c++20": 202002 }, - "headers": ["span"], - }, { - "name": "__cpp_lib_spanstream", - "values": { "c++23": 202106 }, - "headers": ["spanstream"], - "unimplemented": True, - }, { - "name": "__cpp_lib_ssize", - "values": { "c++20": 201902 }, - "headers": ["iterator"], - }, { - "name": "__cpp_lib_stacktrace", - "values": { "c++23": 202011 }, - "headers": ["stacktrace"], - "unimplemented": True, - }, { - "name": "__cpp_lib_starts_ends_with", - "values": { "c++20": 201711 }, - "headers": ["string", "string_view"], - }, { - "name": "__cpp_lib_stdatomic_h", - "values": { "c++23": 202011 }, - "headers": ["stdatomic.h"], - }, { - "name": "__cpp_lib_string_contains", - "values": { "c++23": 202011 }, - "headers": ["string", "string_view"], - }, { - "name": "__cpp_lib_string_resize_and_overwrite", - "values": { "c++23": 202110 }, - "headers": ["string"], - }, { - "name": "__cpp_lib_string_udls", - "values": { "c++14": 201304 }, - "headers": ["string"], - }, { - "name": "__cpp_lib_string_view", - "values": { "c++17": 201606, "c++20": 201803 }, - "headers": ["string", "string_view"], - }, { - "name": "__cpp_lib_syncbuf", - "values": { "c++20": 201803 }, - "headers": ["syncstream"], - "unimplemented": True, - }, { - "name": "__cpp_lib_three_way_comparison", - "values": { "c++20": 201907 }, - "headers": ["compare"], - "unimplemented": True, - }, { - "name": "__cpp_lib_to_address", - "values": { "c++20": 201711 }, - "headers": ["memory"], - }, { - "name": "__cpp_lib_to_array", - "values": { "c++20": 201907 }, - "headers": ["array"], - }, { - "name": "__cpp_lib_to_chars", - "values": { "c++17": 201611 }, - "headers": ["charconv"], - "unimplemented": True, - }, { - "name": "__cpp_lib_to_underlying", - "values": { "c++23": 202102 }, - "headers": ["utility"], - }, { - "name": "__cpp_lib_transformation_trait_aliases", - "values": { "c++14": 201304 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_transparent_operators", - "values": { "c++14": 201210, "c++17": 201510 }, - "headers": ["functional", "memory"], - }, { - "name": "__cpp_lib_tuple_element_t", - "values": { "c++14": 201402 }, - "headers": ["tuple"], - }, { - "name": "__cpp_lib_tuples_by_type", - "values": { "c++14": 201304 }, - "headers": ["tuple", "utility"], - }, { - "name": "__cpp_lib_type_identity", - "values": { "c++20": 201806 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_type_trait_variable_templates", - "values": { "c++17": 201510 }, - "headers": ["type_traits"], - }, { - "name": "__cpp_lib_uncaught_exceptions", - "values": { "c++17": 201411 }, - "headers": ["exception"], - }, { - "name": "__cpp_lib_unordered_map_try_emplace", - "values": { "c++17": 201411 }, - "headers": ["unordered_map"], - }, { - "name": "__cpp_lib_unreachable", - "values": { "c++23": 202202 }, - "headers": ["utility"], - }, { - "name": "__cpp_lib_unwrap_ref", - "values": { "c++20": 201811 }, - "headers": ["functional"], - }, { - "name": "__cpp_lib_variant", - "values": { "c++17": 202102 }, - "headers": ["variant"], - }, { - "name": "__cpp_lib_void_t", - "values": { "c++17": 201411 }, - "headers": ["type_traits"], - } -]] +feature_test_macros = [ + add_version_header(x) + for x in [ + { + "name": "__cpp_lib_adaptor_iterator_pair_constructor", + "values": {"c++23": 202106}, + "headers": ["queue", "stack"], + }, + { + "name": "__cpp_lib_addressof_constexpr", + "values": {"c++17": 201603}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_allocate_at_least", + "values": {"c++23": 202106}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_allocator_traits_is_always_equal", + "values": {"c++17": 201411}, + "headers": [ + "deque", + "forward_list", + "list", + "map", + "memory", + "scoped_allocator", + "set", + "string", + "unordered_map", + "unordered_set", + "vector", + ], + }, + { + "name": "__cpp_lib_any", + "values": {"c++17": 201606}, + "headers": ["any"], + }, + { + "name": "__cpp_lib_apply", + "values": {"c++17": 201603}, + "headers": ["tuple"], + }, + { + "name": "__cpp_lib_array_constexpr", + "values": {"c++17": 201603, "c++20": 201811}, + "headers": ["array", "iterator"], + }, + { + "name": "__cpp_lib_as_const", + "values": {"c++17": 201510}, + "headers": ["utility"], + }, + { + "name": "__cpp_lib_associative_heterogeneous_erasure", + "values": {"c++23": 202110}, + "headers": ["map", "set", "unordered_map", "unordered_set"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_assume_aligned", + "values": {"c++20": 201811}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_atomic_flag_test", + "values": {"c++20": 201907}, + "headers": ["atomic"], + }, + { + "name": "__cpp_lib_atomic_float", + "values": {"c++20": 201711}, + "headers": ["atomic"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_atomic_is_always_lock_free", + "values": {"c++17": 201603}, + "headers": ["atomic"], + }, + { + "name": "__cpp_lib_atomic_lock_free_type_aliases", + "values": {"c++20": 201907}, + "headers": ["atomic"], + }, + { + "name": "__cpp_lib_atomic_ref", + "values": {"c++20": 201806}, + "headers": ["atomic"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_atomic_shared_ptr", + "values": {"c++20": 201711}, + "headers": ["atomic"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_atomic_value_initialization", + "values": {"c++20": 201911}, + "headers": ["atomic", "memory"], + }, + { + "name": "__cpp_lib_atomic_wait", + "values": {"c++20": 201907}, + "headers": ["atomic"], + "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", + "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", + }, + { + "name": "__cpp_lib_barrier", + "values": {"c++20": 201907}, + "headers": ["barrier"], + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", + }, + { + "name": "__cpp_lib_bind_back", + "values": {"c++23": 202202}, + "headers": ["functional"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_bind_front", + "values": {"c++20": 201907}, + "headers": ["functional"], + }, + { + "name": "__cpp_lib_bit_cast", + "values": {"c++20": 201806}, + "headers": ["bit"], + }, + { + "name": "__cpp_lib_bitops", + "values": {"c++20": 201907}, + "headers": ["bit"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_bool_constant", + "values": {"c++17": 201505}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_bounded_array_traits", + "values": {"c++20": 201902}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_boyer_moore_searcher", + "values": {"c++17": 201603}, + "headers": ["functional"], + }, + { + "name": "__cpp_lib_byte", + "values": {"c++17": 201603}, + "headers": ["cstddef"], + }, + { + "name": "__cpp_lib_byteswap", + "values": {"c++23": 202110}, + "headers": ["bit"], + }, + { + "name": "__cpp_lib_char8_t", + "values": {"c++20": 201907}, + "headers": [ + "atomic", + "filesystem", + "istream", + "limits", + "locale", + "ostream", + "string", + "string_view", + ], + "test_suite_guard": "defined(__cpp_char8_t)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_CHAR8_T)", + }, + { + "name": "__cpp_lib_chrono", + "values": {"c++17": 201611}, + "headers": ["chrono"], + }, + { + "name": "__cpp_lib_chrono_udls", + "values": {"c++14": 201304}, + "headers": ["chrono"], + }, + { + "name": "__cpp_lib_clamp", + "values": {"c++17": 201603}, + "headers": ["algorithm"], + }, + { + "name": "__cpp_lib_complex_udls", + "values": {"c++14": 201309}, + "headers": ["complex"], + }, + { + "name": "__cpp_lib_concepts", + "values": {"c++20": 202002}, + "headers": ["concepts"], + }, + { + "name": "__cpp_lib_constexpr_algorithms", + "values": {"c++20": 201806}, + "headers": ["algorithm", "utility"], + }, + { + "name": "__cpp_lib_constexpr_bitset", + "values": {"c++23": 202207}, + "headers": ["bitset"], + }, + { + "name": "__cpp_lib_constexpr_charconv", + "values": {"c++23": 202207}, + "headers": ["charconv"], + }, + { + "name": "__cpp_lib_constexpr_cmath", + "values": {"c++23": 202202}, + "headers": ["cmath", "cstdlib"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_constexpr_complex", + "values": {"c++20": 201711}, + "headers": ["complex"], + }, + { + "name": "__cpp_lib_constexpr_dynamic_alloc", + "values": {"c++20": 201907}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_constexpr_functional", + "values": {"c++20": 201907}, + "headers": ["functional"], + }, + { + "name": "__cpp_lib_constexpr_iterator", + "values": {"c++20": 201811}, + "headers": ["iterator"], + }, + { + "name": "__cpp_lib_constexpr_memory", + "values": {"c++20": 201811, "c++23": 202202}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_constexpr_numeric", + "values": {"c++20": 201911}, + "headers": ["numeric"], + }, + { + "name": "__cpp_lib_constexpr_string", + "values": {"c++20": 201907}, + "headers": ["string"], + }, + { + "name": "__cpp_lib_constexpr_string_view", + "values": {"c++20": 201811}, + "headers": ["string_view"], + }, + { + "name": "__cpp_lib_constexpr_tuple", + "values": {"c++20": 201811}, + "headers": ["tuple"], + }, + { + "name": "__cpp_lib_constexpr_typeinfo", + "values": {"c++23": 202106}, + "headers": ["typeinfo"], + }, + { + "name": "__cpp_lib_constexpr_utility", + "values": {"c++20": 201811}, + "headers": ["utility"], + }, + { + "name": "__cpp_lib_constexpr_vector", + "values": {"c++20": 201907}, + "headers": ["vector"], + }, + { + "name": "__cpp_lib_coroutine", + "values": {"c++20": 201902}, + "headers": ["coroutine"], + }, + { + "name": "__cpp_lib_destroying_delete", + "values": {"c++20": 201806}, + "headers": ["new"], + "test_suite_guard": "TEST_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", + "libcxx_guard": "_LIBCPP_STD_VER >= 20 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L", + }, + { + "name": "__cpp_lib_enable_shared_from_this", + "values": {"c++17": 201603}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_endian", + "values": {"c++20": 201907}, + "headers": ["bit"], + }, + { + "name": "__cpp_lib_erase_if", + "values": {"c++20": 202002}, + "headers": [ + "deque", + "forward_list", + "list", + "map", + "set", + "string", + "unordered_map", + "unordered_set", + "vector", + ], + }, + { + "name": "__cpp_lib_exchange_function", + "values": {"c++14": 201304}, + "headers": ["utility"], + }, + { + "name": "__cpp_lib_execution", + "values": {"c++17": 201603, "c++20": 201902}, + "headers": ["execution"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_expected", + "values": {"c++23": 202211}, + "headers": ["expected"], + }, + { + "name": "__cpp_lib_filesystem", + "values": {"c++17": 201703}, + "headers": ["filesystem"], + "test_suite_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM)", + "libcxx_guard": "!defined(_LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM)", + }, + { + "name": "__cpp_lib_format", + "values": { + # "c++20": 201907 Not implemented P1361R2 Integration of chrono with text formatting + # "c++20": 202106 Fully implemented + # "c++20": 202110 Not implemented P2372R3 Fixing locale handling in chrono formatters + "c++20": 202106, + # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types + }, + "headers": ["format"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_format_ranges", + "values": {"c++23": 202207}, + "headers": ["format"], + }, + { + "name": "__cpp_lib_formatters", + "values": {"c++23": 202302}, + "headers": ["stacktrace", "thread"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_forward_like", + "values": {"c++23": 202207}, + "headers": ["utility"], + }, + { + "name": "__cpp_lib_gcd_lcm", + "values": {"c++17": 201606}, + "headers": ["numeric"], + }, + { + "name": "__cpp_lib_generic_associative_lookup", + "values": {"c++14": 201304}, + "headers": ["map", "set"], + }, + { + "name": "__cpp_lib_generic_unordered_lookup", + "values": {"c++20": 201811}, + "headers": ["unordered_map", "unordered_set"], + }, + { + "name": "__cpp_lib_hardware_interference_size", + "values": {"c++17": 201703}, + "test_suite_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)", + "libcxx_guard": "defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)", + "headers": ["new"], + }, + { + "name": "__cpp_lib_has_unique_object_representations", + "values": {"c++17": 201606}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_hypot", + "values": {"c++17": 201603}, + "headers": ["cmath"], + }, + { + "name": "__cpp_lib_incomplete_container_elements", + "values": {"c++17": 201505}, + "headers": ["forward_list", "list", "vector"], + }, + { + "name": "__cpp_lib_int_pow2", + "values": {"c++20": 202002}, + "headers": ["bit"], + }, + { + "name": "__cpp_lib_integer_comparison_functions", + "values": {"c++20": 202002}, + "headers": ["utility"], + }, + { + "name": "__cpp_lib_integer_sequence", + "values": {"c++14": 201304}, + "headers": ["utility"], + }, + { + "name": "__cpp_lib_integral_constant_callable", + "values": {"c++14": 201304}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_interpolate", + "values": {"c++20": 201902}, + "headers": ["cmath", "numeric"], + }, + { + "name": "__cpp_lib_invoke", + "values": {"c++17": 201411}, + "headers": ["functional"], + }, + { + "name": "__cpp_lib_invoke_r", + "values": {"c++23": 202106}, + "headers": ["functional"], + }, + { + "name": "__cpp_lib_is_aggregate", + "values": {"c++17": 201703}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_is_constant_evaluated", + "values": {"c++20": 201811}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_is_final", + "values": {"c++14": 201402}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_is_invocable", + "values": {"c++17": 201703}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_is_layout_compatible", + "values": {"c++20": 201907}, + "headers": ["type_traits"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_is_nothrow_convertible", + "values": {"c++20": 201806}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_is_null_pointer", + "values": {"c++14": 201309}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_is_pointer_interconvertible", + "values": {"c++20": 201907}, + "headers": ["type_traits"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_is_scoped_enum", + "values": {"c++23": 202011}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_is_swappable", + "values": {"c++17": 201603}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_jthread", + "values": {"c++20": 201911}, + "headers": ["stop_token", "thread"], + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS)", + "unimplemented": True, + }, + { + "name": "__cpp_lib_latch", + "values": {"c++20": 201907}, + "headers": ["latch"], + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", + }, + { + "name": "__cpp_lib_launder", + "values": {"c++17": 201606}, + "headers": ["new"], + }, + { + "name": "__cpp_lib_list_remove_return_type", + "values": {"c++20": 201806}, + "headers": ["forward_list", "list"], + }, + { + "name": "__cpp_lib_logical_traits", + "values": {"c++17": 201510}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_make_from_tuple", + "values": {"c++17": 201606}, + "headers": ["tuple"], + }, + { + "name": "__cpp_lib_make_reverse_iterator", + "values": {"c++14": 201402}, + "headers": ["iterator"], + }, + { + "name": "__cpp_lib_make_unique", + "values": {"c++14": 201304}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_map_try_emplace", + "values": {"c++17": 201411}, + "headers": ["map"], + }, + { + "name": "__cpp_lib_math_constants", + "values": {"c++20": 201907}, + "headers": ["numbers"], + }, + { + "name": "__cpp_lib_math_special_functions", + "values": {"c++17": 201603}, + "headers": ["cmath"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_mdspan", + "values": {"c++23": 202207}, + "headers": ["mdspan"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_memory_resource", + "values": {"c++17": 201603}, + "headers": ["memory_resource"], + }, + { + "name": "__cpp_lib_move_iterator_concept", + "values": {"c++20": 202207}, + "headers": ["iterator"], + }, + { + "name": "__cpp_lib_move_only_function", + "values": {"c++23": 202110}, + "headers": ["functional"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_node_extract", + "values": {"c++17": 201606}, + "headers": ["map", "set", "unordered_map", "unordered_set"], + }, + { + "name": "__cpp_lib_nonmember_container_access", + "values": {"c++17": 201411}, + "headers": [ + "array", + "deque", + "forward_list", + "iterator", + "list", + "map", + "regex", + "set", + "string", + "unordered_map", + "unordered_set", + "vector", + ], + }, + { + "name": "__cpp_lib_not_fn", + "values": {"c++17": 201603}, + "headers": ["functional"], + }, + { + "name": "__cpp_lib_null_iterators", + "values": {"c++14": 201304}, + "headers": ["iterator"], + }, + { + "name": "__cpp_lib_optional", + "values": {"c++17": 201606, "c++23": 202110}, + "headers": ["optional"], + }, + { + "name": "__cpp_lib_out_ptr", + "values": {"c++23": 202106}, + "headers": ["memory"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_parallel_algorithm", + "values": {"c++17": 201603}, + "headers": ["algorithm", "numeric"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_polymorphic_allocator", + "values": {"c++20": 201902}, + "headers": ["memory_resource"], + }, + { + "name": "__cpp_lib_quoted_string_io", + "values": {"c++14": 201304}, + "headers": ["iomanip"], + }, + { + "name": "__cpp_lib_ranges", + "values": {"c++20": 202106}, + "headers": ["algorithm", "functional", "iterator", "memory", "ranges"], + }, + { + "name": "__cpp_lib_ranges_as_rvalue", + "values": {"c++23": 202207}, + "headers": ["ranges"], + }, + { + "name": "__cpp_lib_ranges_chunk", + "values": {"c++23": 202202}, + "headers": ["ranges"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_ranges_chunk_by", + "values": {"c++23": 202202}, + "headers": ["ranges"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_ranges_iota", + "values": {"c++23": 202202}, + "headers": ["numeric"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_ranges_join_with", + "values": {"c++23": 202202}, + "headers": ["ranges"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_ranges_slide", + "values": {"c++23": 202202}, + "headers": ["ranges"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_ranges_starts_ends_with", + "values": {"c++23": 202106}, + "headers": ["algorithm"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_ranges_to_container", + "values": {"c++23": 202202}, + "headers": [ + "deque", + "forward_list", + "list", + "map", + "priority_queue", + "queue", + "set", + "stack", + "string", + "unordered_map", + "unordered_set", + "vector", + ], + "unimplemented": True, + }, + { + "name": "__cpp_lib_ranges_zip", + "values": {"c++23": 202110}, + "headers": ["ranges", "tuple", "utility"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_raw_memory_algorithms", + "values": {"c++17": 201606}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_reference_from_temporary", + "values": {"c++23": 202202}, + "headers": ["type_traits"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_remove_cvref", + "values": {"c++20": 201711}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_result_of_sfinae", + "values": {"c++14": 201210}, + "headers": ["functional", "type_traits"], + }, + { + "name": "__cpp_lib_robust_nonmodifying_seq_ops", + "values": {"c++14": 201304}, + "headers": ["algorithm"], + }, + { + "name": "__cpp_lib_sample", + "values": {"c++17": 201603}, + "headers": ["algorithm"], + }, + { + "name": "__cpp_lib_scoped_lock", + "values": {"c++17": 201703}, + "headers": ["mutex"], + }, + { + "name": "__cpp_lib_semaphore", + "values": {"c++20": 201907}, + "headers": ["semaphore"], + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)", + }, + { + "name": "__cpp_lib_shared_mutex", + "values": {"c++17": 201505}, + "headers": ["shared_mutex"], + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)", + }, + { + "name": "__cpp_lib_shared_ptr_arrays", + "values": {"c++17": 201611, "c++20": 201707}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_shared_ptr_weak_type", + "values": {"c++17": 201606}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_shared_timed_mutex", + "values": {"c++14": 201402}, + "headers": ["shared_mutex"], + "test_suite_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)", + "libcxx_guard": "!defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SHARED_MUTEX)", + }, + { + "name": "__cpp_lib_shift", + "values": {"c++20": 201806}, + "headers": ["algorithm"], + }, + { + "name": "__cpp_lib_smart_ptr_for_overwrite", + "values": {"c++20": 202002}, + "headers": ["memory"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_source_location", + "values": {"c++20": 201907}, + "headers": ["source_location"], + "test_suite_guard": "__has_builtin(__builtin_source_location) && !(defined(TEST_APPLE_CLANG_VER) && TEST_APPLE_CLANG_VER <= 1403)", + "libcxx_guard": "__has_builtin(__builtin_source_location) && !(defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER <= 1403)", + }, + { + "name": "__cpp_lib_span", + "values": {"c++20": 202002}, + "headers": ["span"], + }, + { + "name": "__cpp_lib_spanstream", + "values": {"c++23": 202106}, + "headers": ["spanstream"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_ssize", + "values": {"c++20": 201902}, + "headers": ["iterator"], + }, + { + "name": "__cpp_lib_stacktrace", + "values": {"c++23": 202011}, + "headers": ["stacktrace"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_starts_ends_with", + "values": {"c++20": 201711}, + "headers": ["string", "string_view"], + }, + { + "name": "__cpp_lib_stdatomic_h", + "values": {"c++23": 202011}, + "headers": ["stdatomic.h"], + }, + { + "name": "__cpp_lib_string_contains", + "values": {"c++23": 202011}, + "headers": ["string", "string_view"], + }, + { + "name": "__cpp_lib_string_resize_and_overwrite", + "values": {"c++23": 202110}, + "headers": ["string"], + }, + { + "name": "__cpp_lib_string_udls", + "values": {"c++14": 201304}, + "headers": ["string"], + }, + { + "name": "__cpp_lib_string_view", + "values": {"c++17": 201606, "c++20": 201803}, + "headers": ["string", "string_view"], + }, + { + "name": "__cpp_lib_syncbuf", + "values": {"c++20": 201803}, + "headers": ["syncstream"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_three_way_comparison", + "values": {"c++20": 201907}, + "headers": ["compare"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_to_address", + "values": {"c++20": 201711}, + "headers": ["memory"], + }, + { + "name": "__cpp_lib_to_array", + "values": {"c++20": 201907}, + "headers": ["array"], + }, + { + "name": "__cpp_lib_to_chars", + "values": {"c++17": 201611}, + "headers": ["charconv"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_to_underlying", + "values": {"c++23": 202102}, + "headers": ["utility"], + }, + { + "name": "__cpp_lib_transformation_trait_aliases", + "values": {"c++14": 201304}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_transparent_operators", + "values": {"c++14": 201210, "c++17": 201510}, + "headers": ["functional", "memory"], + }, + { + "name": "__cpp_lib_tuple_element_t", + "values": {"c++14": 201402}, + "headers": ["tuple"], + }, + { + "name": "__cpp_lib_tuples_by_type", + "values": {"c++14": 201304}, + "headers": ["tuple", "utility"], + }, + { + "name": "__cpp_lib_type_identity", + "values": {"c++20": 201806}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_type_trait_variable_templates", + "values": {"c++17": 201510}, + "headers": ["type_traits"], + }, + { + "name": "__cpp_lib_uncaught_exceptions", + "values": {"c++17": 201411}, + "headers": ["exception"], + }, + { + "name": "__cpp_lib_unordered_map_try_emplace", + "values": {"c++17": 201411}, + "headers": ["unordered_map"], + }, + { + "name": "__cpp_lib_unreachable", + "values": {"c++23": 202202}, + "headers": ["utility"], + }, + { + "name": "__cpp_lib_unwrap_ref", + "values": {"c++20": 201811}, + "headers": ["functional"], + }, + { + "name": "__cpp_lib_variant", + "values": {"c++17": 202102}, + "headers": ["variant"], + }, + { + "name": "__cpp_lib_void_t", + "values": {"c++17": 201411}, + "headers": ["type_traits"], + }, + ] +] assert feature_test_macros == sorted(feature_test_macros, key=lambda tc: tc["name"]) assert all(tc["headers"] == sorted(tc["headers"]) for tc in feature_test_macros) -assert all(("libcxx_guard" in tc) == ("test_suite_guard" in tc) for tc in feature_test_macros) -assert all(all(key in ["name", "values", "headers", "libcxx_guard", "test_suite_guard", "unimplemented"] for key in tc.keys()) for tc in feature_test_macros) +assert all( + ("libcxx_guard" in tc) == ("test_suite_guard" in tc) for tc in feature_test_macros +) +assert all( + all( + key + in [ + "name", + "values", + "headers", + "libcxx_guard", + "test_suite_guard", + "unimplemented", + ] + for key in tc.keys() + ) + for tc in feature_test_macros +) # Map from each header to the Lit annotations that should be used for # tests that include that header. @@ -794,26 +1046,28 @@ assert all(all(key in ["name", "values", "headers", "libcxx_guard", "test_suite_ # <thread> should be marked as UNSUPPORTED, because including <thread> # is a hard error in that case. lit_markup = { - "barrier": ["UNSUPPORTED: no-threads"], - "filesystem": ["UNSUPPORTED: no-filesystem"], - "iomanip": ["UNSUPPORTED: no-localization"], - "ios": ["UNSUPPORTED: no-localization"], - "iostream": ["UNSUPPORTED: no-localization"], - "istream": ["UNSUPPORTED: no-localization"], - "latch": ["UNSUPPORTED: no-threads"], - "locale": ["UNSUPPORTED: no-localization"], - "mutex": ["UNSUPPORTED: no-threads"], - "ostream": ["UNSUPPORTED: no-localization"], - "regex": ["UNSUPPORTED: no-localization"], - "semaphore": ["UNSUPPORTED: no-threads"], - "shared_mutex": ["UNSUPPORTED: no-threads"], - "stdatomic.h": ["UNSUPPORTED: no-threads"], - "thread": ["UNSUPPORTED: no-threads"], + "barrier": ["UNSUPPORTED: no-threads"], + "filesystem": ["UNSUPPORTED: no-filesystem"], + "iomanip": ["UNSUPPORTED: no-localization"], + "ios": ["UNSUPPORTED: no-localization"], + "iostream": ["UNSUPPORTED: no-localization"], + "istream": ["UNSUPPORTED: no-localization"], + "latch": ["UNSUPPORTED: no-threads"], + "locale": ["UNSUPPORTED: no-localization"], + "mutex": ["UNSUPPORTED: no-threads"], + "ostream": ["UNSUPPORTED: no-localization"], + "regex": ["UNSUPPORTED: no-localization"], + "semaphore": ["UNSUPPORTED: no-threads"], + "shared_mutex": ["UNSUPPORTED: no-threads"], + "stdatomic.h": ["UNSUPPORTED: no-threads"], + "thread": ["UNSUPPORTED: no-threads"], } + def get_std_dialects(): - std_dialects = ['c++14', 'c++17', 'c++20', 'c++23', 'c++26'] - return list(std_dialects) + std_dialects = ["c++14", "c++17", "c++20", "c++23", "c++26"] + return list(std_dialects) + def get_first_std(d): for s in get_std_dialects(): @@ -821,128 +1075,147 @@ def get_first_std(d): return s return None + def get_last_std(d): - rev_dialects = get_std_dialects() - rev_dialects.reverse() - for s in rev_dialects: - if s in d.keys(): - return s - return None + rev_dialects = get_std_dialects() + rev_dialects.reverse() + for s in rev_dialects: + if s in d.keys(): + return s + return None + def get_std_before(d, std): - std_dialects = get_std_dialects() - candidates = std_dialects[0:std_dialects.index(std)] - candidates.reverse() - for cand in candidates: - if cand in d.keys(): - return cand - return None + std_dialects = get_std_dialects() + candidates = std_dialects[0 : std_dialects.index(std)] + candidates.reverse() + for cand in candidates: + if cand in d.keys(): + return cand + return None + def get_value_before(d, std): - new_std = get_std_before(d, std) - if new_std is None: - return None - return d[new_std] + new_std = get_std_before(d, std) + if new_std is None: + return None + return d[new_std] + def get_for_std(d, std): - # This catches the C++11 case for which there should be no defined feature - # test macros. - std_dialects = get_std_dialects() - if std not in std_dialects: + # This catches the C++11 case for which there should be no defined feature + # test macros. + std_dialects = get_std_dialects() + if std not in std_dialects: + return None + # Find the value for the newest C++ dialect between C++14 and std + std_list = list(std_dialects[0 : std_dialects.index(std) + 1]) + std_list.reverse() + for s in std_list: + if s in d.keys(): + return d[s] return None - # Find the value for the newest C++ dialect between C++14 and std - std_list = list(std_dialects[0:std_dialects.index(std)+1]) - std_list.reverse() - for s in std_list: - if s in d.keys(): - return d[s] - return None + def get_std_number(std): - return std.replace('c++', '') + return std.replace("c++", "") + """ Functions to produce the <version> header """ + def produce_macros_definition_for_std(std): - result = "" - indent = 55 - for tc in feature_test_macros: - if std not in tc["values"]: - continue - inner_indent = 1 - if 'test_suite_guard' in tc.keys(): - result += "# if %s\n" % tc["libcxx_guard"] - inner_indent += 2 - if get_value_before(tc["values"], std) is not None: - assert 'test_suite_guard' not in tc.keys() - result += "# undef %s\n" % tc["name"] - line = "#%sdefine %s" % ((" " * inner_indent), tc["name"]) - line += " " * (indent - len(line)) - line += " %sL" % tc["values"][std] - if 'unimplemented' in tc.keys(): - line = "// " + line - result += line - result += "\n" - if 'test_suite_guard' in tc.keys(): - result += "# endif\n" - return result.strip() + result = "" + indent = 55 + for tc in feature_test_macros: + if std not in tc["values"]: + continue + inner_indent = 1 + if "test_suite_guard" in tc.keys(): + result += "# if %s\n" % tc["libcxx_guard"] + inner_indent += 2 + if get_value_before(tc["values"], std) is not None: + assert "test_suite_guard" not in tc.keys() + result += "# undef %s\n" % tc["name"] + line = "#%sdefine %s" % ((" " * inner_indent), tc["name"]) + line += " " * (indent - len(line)) + line += " %sL" % tc["values"][std] + if "unimplemented" in tc.keys(): + line = "// " + line + result += line + result += "\n" + if "test_suite_guard" in tc.keys(): + result += "# endif\n" + return result.strip() + def produce_macros_definitions(): - macro_definition_template = """#if _LIBCPP_STD_VER >= {std_number} + macro_definition_template = """#if _LIBCPP_STD_VER >= {std_number} {macro_definition} #endif""" - macros_definitions = [] - for std in get_std_dialects(): - macros_definitions.append( - macro_definition_template.format(std_number=get_std_number(std), - macro_definition=produce_macros_definition_for_std(std))) + macros_definitions = [] + for std in get_std_dialects(): + macros_definitions.append( + macro_definition_template.format( + std_number=get_std_number(std), + macro_definition=produce_macros_definition_for_std(std), + ) + ) + + return "\n\n".join(macros_definitions) - return '\n\n'.join(macros_definitions) def chunks(l, n): - """Yield successive n-sized chunks from l.""" - for i in range(0, len(l), n): - yield l[i:i + n] + """Yield successive n-sized chunks from l.""" + for i in range(0, len(l), n): + yield l[i : i + n] + def produce_version_synopsis(): - indent = 56 - header_indent = 56 + len("20XXYYL ") - result = "" - def indent_to(s, val): - if len(s) >= val: - return s - s += " " * (val - len(s)) - return s - line = indent_to("Macro name", indent) + "Value" - line = indent_to(line, header_indent) + "Headers" - result += line + "\n" - for tc in feature_test_macros: - prev_defined_std = get_last_std(tc["values"]) - line = "{name: <{indent}}{value}L ".format(name=tc['name'], indent=indent, - value=tc["values"][prev_defined_std]) - headers = list(tc["headers"]) - headers.remove("version") - for chunk in chunks(headers, 3): - line = indent_to(line, header_indent) - chunk = ['<%s>' % header for header in chunk] - line += ' '.join(chunk) - result += line - result += "\n" - line = "" - while True: - prev_defined_std = get_std_before(tc["values"], prev_defined_std) - if prev_defined_std is None: - break - result += "%s%sL // %s\n" % (indent_to("", indent), tc["values"][prev_defined_std], - prev_defined_std.replace("c++", "C++")) - return result + indent = 56 + header_indent = 56 + len("20XXYYL ") + result = "" + + def indent_to(s, val): + if len(s) >= val: + return s + s += " " * (val - len(s)) + return s + + line = indent_to("Macro name", indent) + "Value" + line = indent_to(line, header_indent) + "Headers" + result += line + "\n" + for tc in feature_test_macros: + prev_defined_std = get_last_std(tc["values"]) + line = "{name: <{indent}}{value}L ".format( + name=tc["name"], indent=indent, value=tc["values"][prev_defined_std] + ) + headers = list(tc["headers"]) + headers.remove("version") + for chunk in chunks(headers, 3): + line = indent_to(line, header_indent) + chunk = ["<%s>" % header for header in chunk] + line += " ".join(chunk) + result += line + result += "\n" + line = "" + while True: + prev_defined_std = get_std_before(tc["values"], prev_defined_std) + if prev_defined_std is None: + break + result += "%s%sL // %s\n" % ( + indent_to("", indent), + tc["values"][prev_defined_std], + prev_defined_std.replace("c++", "C++"), + ) + return result def produce_version_header(): - template="""// -*- C++ -*- + template = """// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -977,12 +1250,13 @@ def produce_version_header(): #endif // _LIBCPP_VERSIONH """ - version_str = template.format( - synopsis=produce_version_synopsis().strip(), - cxx_macros=produce_macros_definitions()) - version_header_path = os.path.join(include_path, 'version') - with open(version_header_path, 'w', newline='\n') as f: - f.write(version_str) + version_str = template.format( + synopsis=produce_version_synopsis().strip(), + cxx_macros=produce_macros_definitions(), + ) + version_header_path = os.path.join(include_path, "version") + with open(version_header_path, "w", newline="\n") as f: + f.write(version_str) """ @@ -990,13 +1264,12 @@ def produce_version_header(): """ test_types = { - "undefined": """ + "undefined": """ # ifdef {name} # error "{name} should not be defined before {std_first}" # endif """, - - "test_suite_guard": """ + "test_suite_guard": """ # if {test_suite_guard} # ifndef {name} # error "{name} should be defined in {std}" @@ -1010,8 +1283,7 @@ test_types = { # endif # endif """, - - "unimplemented": """ + "unimplemented": """ # if !defined(_LIBCPP_VERSION) # ifndef {name} # error "{name} should be defined in {std}" @@ -1025,35 +1297,45 @@ test_types = { # endif # endif """, - - "defined": """ + "defined": """ # ifndef {name} # error "{name} should be defined in {std}" # endif # if {name} != {value} # error "{name} should have the value {value} in {std}" # endif -""" +""", } + def generate_std_test(test_list, std): - result = "" - for tc in test_list: - val = get_for_std(tc["values"], std) - if val is not None: - val = "%sL" % val - if val is None: - result += test_types["undefined"].format(name=tc["name"], std_first=get_first_std(tc["values"])) - elif 'unimplemented' in tc.keys(): - result += test_types["unimplemented"].format(name=tc["name"], value=val, std=std) - elif "test_suite_guard" in tc.keys(): - result += test_types["test_suite_guard"].format(name=tc["name"], value=val, std=std, test_suite_guard=tc["test_suite_guard"]) - else: - result += test_types["defined"].format(name=tc["name"], value=val, std=std) - return result.strip() + result = "" + for tc in test_list: + val = get_for_std(tc["values"], std) + if val is not None: + val = "%sL" % val + if val is None: + result += test_types["undefined"].format( + name=tc["name"], std_first=get_first_std(tc["values"]) + ) + elif "unimplemented" in tc.keys(): + result += test_types["unimplemented"].format( + name=tc["name"], value=val, std=std + ) + elif "test_suite_guard" in tc.keys(): + result += test_types["test_suite_guard"].format( + name=tc["name"], + value=val, + std=std, + test_suite_guard=tc["test_suite_guard"], + ) + else: + result += test_types["defined"].format(name=tc["name"], value=val, std=std) + return result.strip() + def generate_std_tests(test_list): - std_tests_template = """#if TEST_STD_VER < {first_std_number} + std_tests_template = """#if TEST_STD_VER < {first_std_number} {pre_std_test} @@ -1065,48 +1347,56 @@ def generate_std_tests(test_list): #endif // TEST_STD_VER > {penultimate_std_number}""" - std_dialects = get_std_dialects() + std_dialects = get_std_dialects() - other_std_tests = [] - for std in std_dialects[:-1]: - other_std_tests.append('#elif TEST_STD_VER == ' + get_std_number(std)) - other_std_tests.append(generate_std_test(test_list, std)) + other_std_tests = [] + for std in std_dialects[:-1]: + other_std_tests.append("#elif TEST_STD_VER == " + get_std_number(std)) + other_std_tests.append(generate_std_test(test_list, std)) - std_tests = std_tests_template.format(first_std_number=get_std_number(std_dialects[0]), - pre_std_test=generate_std_test(test_list, 'c++11'), - other_std_tests='\n\n'.join(other_std_tests), - penultimate_std_number=get_std_number(std_dialects[-2]), - last_std_test=generate_std_test(test_list, std_dialects[-1])) + std_tests = std_tests_template.format( + first_std_number=get_std_number(std_dialects[0]), + pre_std_test=generate_std_test(test_list, "c++11"), + other_std_tests="\n\n".join(other_std_tests), + penultimate_std_number=get_std_number(std_dialects[-2]), + last_std_test=generate_std_test(test_list, std_dialects[-1]), + ) + + return std_tests - return std_tests def generate_synopsis(test_list): max_name_len = max([len(tc["name"]) for tc in test_list]) indent = max_name_len + 8 + def mk_line(prefix, suffix): - return "{prefix: <{max_len}}{suffix}\n".format(prefix=prefix, suffix=suffix, - max_len=indent) + return "{prefix: <{max_len}}{suffix}\n".format( + prefix=prefix, suffix=suffix, max_len=indent + ) + result = "" result += mk_line("/* Constant", "Value") for tc in test_list: prefix = " %s" % tc["name"] for std in [s for s in get_std_dialects() if s in tc["values"].keys()]: - result += mk_line(prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++"))) + result += mk_line( + prefix, "%sL [%s]" % (tc["values"][std], std.replace("c++", "C++")) + ) prefix = "" result += "*/" return result + def produce_tests(): - headers = set([h for tc in feature_test_macros for h in tc["headers"]]) - for h in headers: - test_list = [tc for tc in feature_test_macros if h in tc["headers"]] - if not has_header(h): - for tc in test_list: - assert 'unimplemented' in tc.keys() - continue - markup = '\n'.join('// ' + tag for tag in lit_markup.get(h, [])) - test_body = \ -"""//===----------------------------------------------------------------------===// + headers = set([h for tc in feature_test_macros for h in tc["headers"]]) + for h in headers: + test_list = [tc for tc in feature_test_macros if h in tc["headers"]] + if not has_header(h): + for tc in test_list: + assert "unimplemented" in tc.keys() + continue + markup = "\n".join("// " + tag for tag in lit_markup.get(h, [])) + test_body = """//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -1130,75 +1420,87 @@ def produce_tests(): {cxx_tests} -""".format(script_name=script_name, - header=h, - markup=('\n{}\n'.format(markup) if markup else ''), - synopsis=generate_synopsis(test_list), - cxx_tests=generate_std_tests(test_list)) - test_name = "{header}.version.compile.pass.cpp".format(header=h) - out_path = os.path.join(macro_test_path, test_name) - with open(out_path, 'w', newline='\n') as f: - f.write(test_body) +""".format( + script_name=script_name, + header=h, + markup=("\n{}\n".format(markup) if markup else ""), + synopsis=generate_synopsis(test_list), + cxx_tests=generate_std_tests(test_list), + ) + test_name = "{header}.version.compile.pass.cpp".format(header=h) + out_path = os.path.join(macro_test_path, test_name) + with open(out_path, "w", newline="\n") as f: + f.write(test_body) + """ Produce documentation for the feature test macros """ + def make_widths(grid): - widths = [] - for i in range(0, len(grid[0])): - cell_width = 2 + max(reduce(lambda x,y: x+y, [[len(row[i])] for row in grid], [])) - widths += [cell_width] - return widths + widths = [] + for i in range(0, len(grid[0])): + cell_width = 2 + max( + reduce(lambda x, y: x + y, [[len(row[i])] for row in grid], []) + ) + widths += [cell_width] + return widths + def create_table(grid, indent): - indent_str = ' '*indent - col_widths = make_widths(grid) - result = [indent_str + add_divider(col_widths, 2)] - header_flag = 2 - for row_i in range(0, len(grid)): - row = grid[row_i] - line = indent_str + ' '.join([pad_cell(row[i], col_widths[i]) for i in range(0, len(row))]) - result.append(line.rstrip()) - if row_i == len(grid) - 1: - header_flag = 2 - if row[0].startswith('**'): - header_flag += 1 - separator = indent_str + add_divider(col_widths, header_flag) - result.append(separator.rstrip()) - header_flag = 0 - return '\n'.join(result) + indent_str = " " * indent + col_widths = make_widths(grid) + result = [indent_str + add_divider(col_widths, 2)] + header_flag = 2 + for row_i in range(0, len(grid)): + row = grid[row_i] + line = indent_str + " ".join( + [pad_cell(row[i], col_widths[i]) for i in range(0, len(row))] + ) + result.append(line.rstrip()) + if row_i == len(grid) - 1: + header_flag = 2 + if row[0].startswith("**"): + header_flag += 1 + separator = indent_str + add_divider(col_widths, header_flag) + result.append(separator.rstrip()) + header_flag = 0 + return "\n".join(result) + def add_divider(widths, header_flag): - if header_flag == 3: - return '='.join(['='*w for w in widths]) - if header_flag == 2: - return ' '.join(['='*w for w in widths]) - if header_flag == 1: - return '-'.join(['-'*w for w in widths]) - else: - return ' '.join(['-'*w for w in widths]) + if header_flag == 3: + return "=".join(["=" * w for w in widths]) + if header_flag == 2: + return " ".join(["=" * w for w in widths]) + if header_flag == 1: + return "-".join(["-" * w for w in widths]) + else: + return " ".join(["-" * w for w in widths]) + def pad_cell(s, length, left_align=True): - padding = ((length - len(s)) * ' ') - return s + padding + padding = (length - len(s)) * " " + return s + padding def get_status_table(): - table = [["Macro Name", "Value"]] - for std in get_std_dialects(): - table += [["**" + std.replace("c++", "C++ ") + "**", ""]] - for tc in feature_test_macros: - if std not in tc["values"].keys(): - continue - value = "``%sL``" % tc["values"][std] - if 'unimplemented' in tc.keys(): - value = '*unimplemented*' - table += [["``%s``" % tc["name"], value]] - return table + table = [["Macro Name", "Value"]] + for std in get_std_dialects(): + table += [["**" + std.replace("c++", "C++ ") + "**", ""]] + for tc in feature_test_macros: + if std not in tc["values"].keys(): + continue + value = "``%sL``" % tc["values"][std] + if "unimplemented" in tc.keys(): + value = "*unimplemented*" + table += [["``%s``" % tc["name"], value]] + return table + def produce_docs(): - doc_str = """.. _FeatureTestMacroTable: + doc_str = """.. _FeatureTestMacroTable: ========================== Feature Test Macro Support @@ -1223,17 +1525,20 @@ Status {status_tables} -""".format(status_tables=create_table(get_status_table(), 4)) +""".format( + status_tables=create_table(get_status_table(), 4) + ) + + table_doc_path = os.path.join(docs_path, "FeatureTestMacroTable.rst") + with open(table_doc_path, "w", newline="\n") as f: + f.write(doc_str) - table_doc_path = os.path.join(docs_path, 'FeatureTestMacroTable.rst') - with open(table_doc_path, 'w', newline='\n') as f: - f.write(doc_str) def main(): - produce_version_header() - produce_tests() - produce_docs() + produce_version_header() + produce_tests() + produce_docs() -if __name__ == '__main__': - main() +if __name__ == "__main__": + main() diff --git a/libcxx/utils/generate_header_inclusion_tests.py b/libcxx/utils/generate_header_inclusion_tests.py index 1262bcd..c5797c4 100755 --- a/libcxx/utils/generate_header_inclusion_tests.py +++ b/libcxx/utils/generate_header_inclusion_tests.py @@ -8,9 +8,11 @@ def get_libcxx_paths(): script_name = os.path.basename(__file__) assert os.path.exists(utils_path) src_root = os.path.dirname(utils_path) - test_path = os.path.join(src_root, 'test', 'libcxx', 'inclusions') + test_path = os.path.join(src_root, "test", "libcxx", "inclusions") assert os.path.exists(test_path) - assert os.path.exists(os.path.join(test_path, 'algorithm.inclusions.compile.pass.cpp')) + assert os.path.exists( + os.path.join(test_path, "algorithm.inclusions.compile.pass.cpp") + ) return script_name, src_root, test_path @@ -93,46 +95,46 @@ assert all(v == sorted(v) for k, v in mandatory_inclusions.items()) # <thread> should be marked as UNSUPPORTED, because including <thread> # is a hard error in that case. lit_markup = { - "barrier": ["UNSUPPORTED: no-threads"], - "filesystem": ["UNSUPPORTED: no-filesystem"], - "iomanip": ["UNSUPPORTED: no-localization"], - "ios": ["UNSUPPORTED: no-localization"], - "iostream": ["UNSUPPORTED: no-localization"], - "istream": ["UNSUPPORTED: no-localization"], - "latch": ["UNSUPPORTED: no-threads"], - "locale": ["UNSUPPORTED: no-localization"], - "mutex": ["UNSUPPORTED: no-threads"], - "ostream": ["UNSUPPORTED: no-localization"], - "regex": ["UNSUPPORTED: no-localization"], - "semaphore": ["UNSUPPORTED: no-threads"], - "shared_mutex": ["UNSUPPORTED: no-threads"], - "thread": ["UNSUPPORTED: no-threads"] + "barrier": ["UNSUPPORTED: no-threads"], + "filesystem": ["UNSUPPORTED: no-filesystem"], + "iomanip": ["UNSUPPORTED: no-localization"], + "ios": ["UNSUPPORTED: no-localization"], + "iostream": ["UNSUPPORTED: no-localization"], + "istream": ["UNSUPPORTED: no-localization"], + "latch": ["UNSUPPORTED: no-threads"], + "locale": ["UNSUPPORTED: no-localization"], + "mutex": ["UNSUPPORTED: no-threads"], + "ostream": ["UNSUPPORTED: no-localization"], + "regex": ["UNSUPPORTED: no-localization"], + "semaphore": ["UNSUPPORTED: no-threads"], + "shared_mutex": ["UNSUPPORTED: no-threads"], + "thread": ["UNSUPPORTED: no-threads"], } def get_std_ver_test(includee): v = new_in_version.get(includee, "03") if v == "03": - return '' + return "" versions = ["03", "11", "14", "17", "20"] - return 'TEST_STD_VER > {} && '.format(max(i for i in versions if i < v)) + return "TEST_STD_VER > {} && ".format(max(i for i in versions if i < v)) def get_unsupported_line(includee): v = new_in_version.get(includee, "03") return { "03": [], - "11": ['UNSUPPORTED: c++03'], - "14": ['UNSUPPORTED: c++03, c++11'], - "17": ['UNSUPPORTED: c++03, c++11, c++14'], - "20": ['UNSUPPORTED: c++03, c++11, c++14, c++17'], - "23": ['UNSUPPORTED: c++03, c++11, c++14, c++17, c++20'], - "26": ['UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23'], + "11": ["UNSUPPORTED: c++03"], + "14": ["UNSUPPORTED: c++03, c++11"], + "17": ["UNSUPPORTED: c++03, c++11, c++14"], + "20": ["UNSUPPORTED: c++03, c++11, c++14, c++17"], + "23": ["UNSUPPORTED: c++03, c++11, c++14, c++17, c++20"], + "26": ["UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23"], }[v] def get_libcpp_header_symbol(header_name): - return '_LIBCPP_' + header_name.upper().replace('.', '_') + return "_LIBCPP_" + header_name.upper().replace(".", "_") def get_includer_symbol_test(includer): @@ -157,7 +159,9 @@ def get_ifdef(includer, includee): """.strip().format( includee_test=get_std_ver_test(includee), symbol=symbol, - message="<{}> should include <{}> in C++{} and later".format(includer, includee, version) + message="<{}> should include <{}> in C++{} and later".format( + includer, includee, version + ), ) @@ -193,15 +197,19 @@ def produce_tests(): test_body = test_body_template.format( script_name=script_name, header=includer, - markup=('\n' + '\n'.join('// ' + m for m in markup_tags) + '\n') if markup_tags else '', + markup=("\n" + "\n".join("// " + m for m in markup_tags) + "\n") + if markup_tags + else "", test_includers_symbol=get_includer_symbol_test(includer), - test_per_includee='\n'.join(get_ifdef(includer, includee) for includee in includees), + test_per_includee="\n".join( + get_ifdef(includer, includee) for includee in includees + ), ) test_name = "{header}.inclusions.compile.pass.cpp".format(header=includer) out_path = os.path.join(test_path, test_name) - with open(out_path, 'w', newline='\n') as f: - f.write(test_body + '\n') + with open(out_path, "w", newline="\n") as f: + f.write(test_body + "\n") -if __name__ == '__main__': +if __name__ == "__main__": produce_tests() diff --git a/libcxx/utils/generate_header_tests.py b/libcxx/utils/generate_header_tests.py index f1664ad..905e7a4 100755 --- a/libcxx/utils/generate_header_tests.py +++ b/libcxx/utils/generate_header_tests.py @@ -16,12 +16,9 @@ header_restrictions = { "shared_mutex": "!defined(_LIBCPP_HAS_NO_THREADS)", "stdatomic.h": "__cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS)", "thread": "!defined(_LIBCPP_HAS_NO_THREADS)", - "filesystem": "!defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY)", - # TODO(LLVM-17): simplify this to __cplusplus >= 202002L "coroutine": "(defined(__cpp_impl_coroutine) && __cpp_impl_coroutine >= 201902L) || (defined(__cpp_coroutines) && __cpp_coroutines >= 201703L)", - "clocale": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)", "codecvt": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)", "fstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_FSTREAM)", @@ -36,12 +33,10 @@ header_restrictions = { "sstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)", "streambuf": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)", "strstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)", - "wctype.h": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)", "cwctype": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)", "cwchar": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)", "wchar.h": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)", - "experimental/algorithm": "__cplusplus >= 201103L", "experimental/deque": "__cplusplus >= 201103L", "experimental/forward_list": "__cplusplus >= 201103L", @@ -64,89 +59,133 @@ header_restrictions = { } private_headers_still_public_in_modules = [ - '__assert', '__config', - '__config_site.in', '__debug', '__hash_table', - '__threading_support', '__tree', '__undef_macros', '__verbose_abort' + "__assert", + "__config", + "__config_site.in", + "__debug", + "__hash_table", + "__threading_support", + "__tree", + "__undef_macros", + "__verbose_abort", ] + def find_script(file): """Finds the script used to generate a file inside the file itself. The script is delimited by - BEGIN-SCRIPT and END-SCRIPT markers. + BEGIN-SCRIPT and END-SCRIPT markers. """ - with open(file, 'r') as f: + with open(file, "r") as f: content = f.read() - match = re.search(r'^BEGIN-SCRIPT$(.+)^END-SCRIPT$', content, flags=re.MULTILINE | re.DOTALL) + match = re.search( + r"^BEGIN-SCRIPT$(.+)^END-SCRIPT$", content, flags=re.MULTILINE | re.DOTALL + ) if not match: - raise RuntimeError("Was unable to find a script delimited with BEGIN-SCRIPT/END-SCRIPT markers in {}".format(test_file)) + raise RuntimeError( + "Was unable to find a script delimited with BEGIN-SCRIPT/END-SCRIPT markers in {}".format( + test_file + ) + ) return match.group(1) + def execute_script(script, variables): """Executes the provided Mako template with the given variables available during the - evaluation of the script, and returns the result. + evaluation of the script, and returns the result. """ - code = compile(script, 'fake-filename', 'exec') + code = compile(script, "fake-filename", "exec") output = io.StringIO() with contextlib.redirect_stdout(output): exec(code, variables) output = output.getvalue() return output + def generate_new_file(file, new_content): """Generates the new content of the file by inserting the new content in-between - two '// GENERATED-MARKER' markers located in the file. + two '// GENERATED-MARKER' markers located in the file. """ - with open(file, 'r') as f: + with open(file, "r") as f: old_content = f.read() try: - before, begin_marker, _, end_marker, after = re.split(r'(// GENERATED-MARKER\n)', old_content, flags=re.MULTILINE | re.DOTALL) + before, begin_marker, _, end_marker, after = re.split( + r"(// GENERATED-MARKER\n)", old_content, flags=re.MULTILINE | re.DOTALL + ) except ValueError: - raise RuntimeError("Failed to split {} based on markers, please make sure the file has exactly two '// GENERATED-MARKER' occurrences".format(file)) + raise RuntimeError( + "Failed to split {} based on markers, please make sure the file has exactly two '// GENERATED-MARKER' occurrences".format( + file + ) + ) return before + begin_marker + new_content + end_marker + after + def produce(test_file, variables): script = find_script(test_file) result = execute_script(script, variables) new_content = generate_new_file(test_file, result) - with open(test_file, 'w', newline='\n') as f: + with open(test_file, "w", newline="\n") as f: f.write(new_content) + def is_header(file): """Returns whether the given file is a header (i.e. not a directory or the modulemap file).""" - return not file.is_dir() and not file.name == 'module.modulemap.in' and file.name != 'libcxx.imp' + return ( + not file.is_dir() + and not file.name == "module.modulemap.in" + and file.name != "libcxx.imp" + ) def main(): - monorepo_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) - include = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'include')) - test = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'test')) - assert(monorepo_root.exists()) - - toplevel_headers = sorted(str(p.relative_to(include)) for p in include.glob('[a-z]*') if is_header(p)) - experimental_headers = sorted(str(p.relative_to(include)) for p in include.glob('experimental/[a-z]*') if is_header(p)) - public_headers = toplevel_headers + experimental_headers - private_headers = sorted(str(p.relative_to(include)) for p in include.rglob('*') if is_header(p) and str(p.relative_to(include)).startswith('__') and not p.name.startswith('pstl')) + monorepo_root = pathlib.Path( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + ) + include = pathlib.Path(os.path.join(monorepo_root, "libcxx", "include")) + test = pathlib.Path(os.path.join(monorepo_root, "libcxx", "test")) + assert monorepo_root.exists() + + toplevel_headers = sorted( + str(p.relative_to(include)) for p in include.glob("[a-z]*") if is_header(p) + ) + experimental_headers = sorted( + str(p.relative_to(include)) + for p in include.glob("experimental/[a-z]*") + if is_header(p) + ) + public_headers = toplevel_headers + experimental_headers + private_headers = sorted( + str(p.relative_to(include)) + for p in include.rglob("*") + if is_header(p) + and str(p.relative_to(include)).startswith("__") + and not p.name.startswith("pstl") + ) variables = { - 'toplevel_headers': toplevel_headers, - 'experimental_headers': experimental_headers, - 'public_headers': public_headers, - 'private_headers': private_headers, - 'header_restrictions': header_restrictions, - 'private_headers_still_public_in_modules': private_headers_still_public_in_modules + "toplevel_headers": toplevel_headers, + "experimental_headers": experimental_headers, + "public_headers": public_headers, + "private_headers": private_headers, + "header_restrictions": header_restrictions, + "private_headers_still_public_in_modules": private_headers_still_public_in_modules, } - produce(test.joinpath('libcxx/assertions/headers_declare_verbose_abort.sh.cpp'), variables) - produce(test.joinpath('libcxx/clang_tidy.sh.cpp'), variables) - produce(test.joinpath('libcxx/double_include.sh.cpp'), variables) - produce(test.joinpath('libcxx/min_max_macros.compile.pass.cpp'), variables) - produce(test.joinpath('libcxx/modules_include.sh.cpp'), variables) - produce(test.joinpath('libcxx/nasty_macros.compile.pass.cpp'), variables) - produce(test.joinpath('libcxx/no_assert_include.compile.pass.cpp'), variables) - produce(test.joinpath('libcxx/private_headers.verify.cpp'), variables) - produce(test.joinpath('libcxx/transitive_includes.sh.cpp'), variables) - - -if __name__ == '__main__': + produce( + test.joinpath("libcxx/assertions/headers_declare_verbose_abort.sh.cpp"), + variables, + ) + produce(test.joinpath("libcxx/clang_tidy.sh.cpp"), variables) + produce(test.joinpath("libcxx/double_include.sh.cpp"), variables) + produce(test.joinpath("libcxx/min_max_macros.compile.pass.cpp"), variables) + produce(test.joinpath("libcxx/modules_include.sh.cpp"), variables) + produce(test.joinpath("libcxx/nasty_macros.compile.pass.cpp"), variables) + produce(test.joinpath("libcxx/no_assert_include.compile.pass.cpp"), variables) + produce(test.joinpath("libcxx/private_headers.verify.cpp"), variables) + produce(test.joinpath("libcxx/transitive_includes.sh.cpp"), variables) + + +if __name__ == "__main__": main() diff --git a/libcxx/utils/generate_iwyu_mapping.py b/libcxx/utils/generate_iwyu_mapping.py index f8377a9..621eacd 100644 --- a/libcxx/utils/generate_iwyu_mapping.py +++ b/libcxx/utils/generate_iwyu_mapping.py @@ -2,13 +2,17 @@ import os, pathlib, sys + def generate(private, public): return f'{{ include: [ "{private}", "private", "<{public}>", "public" ] }}' def panic(file): - print(f'========== {__file__} error ==========', file=sys.stderr) - print(f'\tFile \'{file}\' is a top-level detail header without a mapping', file=sys.stderr) + print(f"========== {__file__} error ==========", file=sys.stderr) + print( + f"\tFile '{file}' is a top-level detail header without a mapping", + file=sys.stderr, + ) sys.exit(1) @@ -18,50 +22,75 @@ def generate_map(include): c_headers = [] for i in include.iterdir(): - if i.is_dir() and i.name.startswith('__'): - detail_directories.append(f'{i.name}') + if i.is_dir() and i.name.startswith("__"): + detail_directories.append(f"{i.name}") continue - if i.name.startswith('__'): + if i.name.startswith("__"): detail_files.append(i.name) continue - if i.name.endswith('.h'): + if i.name.endswith(".h"): c_headers.append(i.name) result = [] - temporary_mappings = {'__locale_dir' : 'locale'} + temporary_mappings = {"__locale_dir": "locale"} for i in detail_directories: - public_header = temporary_mappings.get(i, i.lstrip('_')) + public_header = temporary_mappings.get(i, i.lstrip("_")) result.append(f'{generate(f"@<{i}/.*>", public_header)},') for i in detail_files: public = [] - if i == '__assert': continue - elif i == '__availability': continue - elif i == '__bit_reference': continue - elif i == '__bits': public = ['bits'] - elif i == '__config_site.in': continue - elif i == '__config': continue - elif i == '__debug': continue - elif i == '__errc': continue - elif i == '__hash_table': public = ['unordered_map', 'unordered_set'] - elif i == '__locale': public = ['locale'] - elif i == '__mbstate_t.h': continue - elif i == '__mutex_base': continue - elif i == '__node_handle': public = ['map', 'set', 'unordered_map', 'unordered_set'] - elif i == '__pstl_algorithm': continue - elif i == '__pstl_config_site.in': continue - elif i == '__pstl_execution': continue - elif i == '__pstl_memory': continue - elif i == '__pstl_numeric': continue - elif i == '__split_buffer': public = ['deque', 'vector'] - elif i == '__std_mbstate_t.h': continue - elif i == '__threading_support': public = ['atomic', 'mutex', 'semaphore', 'thread'] - elif i == '__tree': public = ['map', 'set'] - elif i == '__undef_macros': continue - elif i == '__verbose_abort': continue - else: panic(i) + if i == "__assert": + continue + elif i == "__availability": + continue + elif i == "__bit_reference": + continue + elif i == "__bits": + public = ["bits"] + elif i == "__config_site.in": + continue + elif i == "__config": + continue + elif i == "__debug": + continue + elif i == "__errc": + continue + elif i == "__hash_table": + public = ["unordered_map", "unordered_set"] + elif i == "__locale": + public = ["locale"] + elif i == "__mbstate_t.h": + continue + elif i == "__mutex_base": + continue + elif i == "__node_handle": + public = ["map", "set", "unordered_map", "unordered_set"] + elif i == "__pstl_algorithm": + continue + elif i == "__pstl_config_site.in": + continue + elif i == "__pstl_execution": + continue + elif i == "__pstl_memory": + continue + elif i == "__pstl_numeric": + continue + elif i == "__split_buffer": + public = ["deque", "vector"] + elif i == "__std_mbstate_t.h": + continue + elif i == "__threading_support": + public = ["atomic", "mutex", "semaphore", "thread"] + elif i == "__tree": + public = ["map", "set"] + elif i == "__undef_macros": + continue + elif i == "__verbose_abort": + continue + else: + panic(i) for p in public: result.append(f'{generate(f"<{i}>", p)},') @@ -69,16 +98,19 @@ def generate_map(include): result.sort() return result + def main(): - monorepo_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) - assert(monorepo_root.exists()) - include = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'include')) + monorepo_root = pathlib.Path( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + ) + assert monorepo_root.exists() + include = pathlib.Path(os.path.join(monorepo_root, "libcxx", "include")) mapping = generate_map(include) - data = '[\n ' + '\n '.join(mapping) + '\n]\n' - with open(f'{include}/libcxx.imp', 'w') as f: + data = "[\n " + "\n ".join(mapping) + "\n]\n" + with open(f"{include}/libcxx.imp", "w") as f: f.write(data) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/libcxx/utils/generate_width_estimation_table.py b/libcxx/utils/generate_width_estimation_table.py index 0f45d1f..8739cf6 100644 --- a/libcxx/utils/generate_width_estimation_table.py +++ b/libcxx/utils/generate_width_estimation_table.py @@ -326,10 +326,7 @@ def generate_data_tables() -> str: Generate Unicode data for [format.string.std]/12 """ east_asian_width_path = ( - Path(__file__).absolute().parent - / "data" - / "unicode" - / "EastAsianWidth.txt" + Path(__file__).absolute().parent / "data" / "unicode" / "EastAsianWidth.txt" ) properties = list() diff --git a/libcxx/utils/libcxx/__init__.py b/libcxx/utils/libcxx/__init__.py index d2e99ba..e83a441d 100644 --- a/libcxx/utils/libcxx/__init__.py +++ b/libcxx/utils/libcxx/__init__.py @@ -1,16 +1,16 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """libcxx python utilities""" -__author__ = 'Eric Fiselier' -__email__ = 'eric@efcs.ca' +__author__ = "Eric Fiselier" +__email__ = "eric@efcs.ca" __versioninfo__ = (0, 1, 0) -__version__ = ' '.join(str(v) for v in __versioninfo__) + 'dev' +__version__ = " ".join(str(v) for v in __versioninfo__) + "dev" __all__ = [] diff --git a/libcxx/utils/libcxx/sym_check/__init__.py b/libcxx/utils/libcxx/sym_check/__init__.py index 0766df2..bd02778 100644 --- a/libcxx/utils/libcxx/sym_check/__init__.py +++ b/libcxx/utils/libcxx/sym_check/__init__.py @@ -1,16 +1,16 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """libcxx abi symbol checker""" -__author__ = 'Eric Fiselier' -__email__ = 'eric@efcs.ca' +__author__ = "Eric Fiselier" +__email__ = "eric@efcs.ca" __versioninfo__ = (0, 1, 0) -__version__ = ' '.join(str(v) for v in __versioninfo__) + 'dev' +__version__ = " ".join(str(v) for v in __versioninfo__) + "dev" -__all__ = ['diff', 'extract', 'util'] +__all__ = ["diff", "extract", "util"] diff --git a/libcxx/utils/libcxx/sym_check/diff.py b/libcxx/utils/libcxx/sym_check/diff.py index cba93fa..008c6e9 100644 --- a/libcxx/utils/libcxx/sym_check/diff.py +++ b/libcxx/utils/libcxx/sym_check/diff.py @@ -1,11 +1,11 @@ # -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80: -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """ diff - A set of functions for diff-ing two symbol lists. """ @@ -14,15 +14,15 @@ from libcxx.sym_check import util def _symbol_difference(lhs, rhs): - lhs_names = set(((n['name'], n['type']) for n in lhs)) - rhs_names = set(((n['name'], n['type']) for n in rhs)) + lhs_names = set(((n["name"], n["type"]) for n in lhs)) + rhs_names = set(((n["name"], n["type"]) for n in rhs)) diff_names = lhs_names - rhs_names - return [n for n in lhs if (n['name'], n['type']) in diff_names] + return [n for n in lhs if (n["name"], n["type"]) in diff_names] def _find_by_key(sym_list, k): for sym in sym_list: - if sym['name'] == k: + if sym["name"] == k: return sym return None @@ -40,9 +40,8 @@ def changed_symbols(old, new): for old_sym in old: if old_sym in new: continue - new_sym = _find_by_key(new, old_sym['name']) - if (new_sym is not None and not new_sym in old - and old_sym != new_sym): + new_sym = _find_by_key(new, old_sym["name"]) + if new_sym is not None and not new_sym in old and old_sym != new_sym: changed += [(old_sym, new_sym)] return changed @@ -54,49 +53,51 @@ def diff(old, new): return added, removed, changed -def report_diff(added_syms, removed_syms, changed_syms, names_only=False, - demangle=True): +def report_diff( + added_syms, removed_syms, changed_syms, names_only=False, demangle=True +): def maybe_demangle(name): return util.demangle_symbol(name) if demangle else name - report = '' + report = "" for sym in added_syms: - report += 'Symbol added: %s\n' % maybe_demangle(sym['name']) + report += "Symbol added: %s\n" % maybe_demangle(sym["name"]) if not names_only: - report += ' %s\n\n' % sym + report += " %s\n\n" % sym if added_syms and names_only: - report += '\n' + report += "\n" for sym in removed_syms: - report += 'SYMBOL REMOVED: %s\n' % maybe_demangle(sym['name']) + report += "SYMBOL REMOVED: %s\n" % maybe_demangle(sym["name"]) if not names_only: - report += ' %s\n\n' % sym + report += " %s\n\n" % sym if removed_syms and names_only: - report += '\n' + report += "\n" if not names_only: for sym_pair in changed_syms: old_sym, new_sym = sym_pair - old_str = '\n OLD SYMBOL: %s' % old_sym - new_str = '\n NEW SYMBOL: %s' % new_sym - report += ('SYMBOL CHANGED: %s%s%s\n\n' % - (maybe_demangle(old_sym['name']), - old_str, new_str)) + old_str = "\n OLD SYMBOL: %s" % old_sym + new_str = "\n NEW SYMBOL: %s" % new_sym + report += "SYMBOL CHANGED: %s%s%s\n\n" % ( + maybe_demangle(old_sym["name"]), + old_str, + new_str, + ) added = bool(len(added_syms) != 0) abi_break = bool(len(removed_syms)) if not names_only: abi_break = abi_break or len(changed_syms) if added or abi_break: - report += 'Summary\n' - report += ' Added: %d\n' % len(added_syms) - report += ' Removed: %d\n' % len(removed_syms) + report += "Summary\n" + report += " Added: %d\n" % len(added_syms) + report += " Removed: %d\n" % len(removed_syms) if not names_only: - report += ' Changed: %d\n' % len(changed_syms) + report += " Changed: %d\n" % len(changed_syms) if not abi_break: - report += 'Symbols added.' + report += "Symbols added." else: - report += 'ABI BREAKAGE: SYMBOLS ADDED OR REMOVED!' + report += "ABI BREAKAGE: SYMBOLS ADDED OR REMOVED!" else: - report += 'Symbols match.' - is_different = abi_break or bool(len(added_syms)) \ - or bool(len(changed_syms)) + report += "Symbols match." + is_different = abi_break or bool(len(added_syms)) or bool(len(changed_syms)) return report, abi_break, is_different diff --git a/libcxx/utils/libcxx/sym_check/extract.py b/libcxx/utils/libcxx/sym_check/extract.py index dbf7ab1..abd4aba 100644 --- a/libcxx/utils/libcxx/sym_check/extract.py +++ b/libcxx/utils/libcxx/sym_check/extract.py @@ -1,11 +1,11 @@ # -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80: -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """ extract - A set of function that extract symbol lists from shared libraries. """ @@ -18,7 +18,8 @@ import sys from libcxx.sym_check import util -extract_ignore_names = ['_init', '_fini'] +extract_ignore_names = ["_init", "_fini"] + class NMExtractor(object): """ @@ -30,7 +31,7 @@ class NMExtractor(object): """ Search for the nm executable and return the path. """ - return shutil.which('nm') + return shutil.which("nm") def __init__(self, static_lib): """ @@ -43,11 +44,10 @@ class NMExtractor(object): print("ERROR: Could not find nm") sys.exit(1) self.static_lib = static_lib - self.flags = ['-P', '-g'] - if sys.platform.startswith('aix'): + self.flags = ["-P", "-g"] + if sys.platform.startswith("aix"): # AIX nm demangles symbols by default, so suppress that. - self.flags.append('-C') - + self.flags.append("-C") def extract(self, lib): """ @@ -56,8 +56,7 @@ class NMExtractor(object): """ cmd = [self.nm_exe] + self.flags + [lib] out = subprocess.check_output(cmd).decode() - fmt_syms = (self._extract_sym(l) - for l in out.splitlines() if l.strip()) + fmt_syms = (self._extract_sym(l) for l in out.splitlines() if l.strip()) # Cast symbol to string. final_syms = (repr(s) for s in fmt_syms if self._want_sym(s)) # Make unique and sort strings. @@ -71,15 +70,15 @@ class NMExtractor(object): if len(bits) < 2: return None new_sym = { - 'name': bits[0], - 'type': bits[1], - 'is_defined': (bits[1].lower() != 'u') + "name": bits[0], + "type": bits[1], + "is_defined": (bits[1].lower() != "u"), } - new_sym['name'] = new_sym['name'].replace('@@', '@') + new_sym["name"] = new_sym["name"].replace("@@", "@") new_sym = self._transform_sym_type(new_sym) # NM types which we want to save the size for. - if new_sym['type'] == 'OBJECT' and len(bits) > 3: - new_sym['size'] = int(bits[3], 16) + if new_sym["type"] == "OBJECT" and len(bits) > 3: + new_sym["size"] = int(bits[3], 16) return new_sym @staticmethod @@ -89,11 +88,14 @@ class NMExtractor(object): """ if sym is None or len(sym) < 2: return False - if sym['name'] in extract_ignore_names: + if sym["name"] in extract_ignore_names: return False - bad_types = ['t', 'b', 'r', 'd', 'w'] - return (sym['type'] not in bad_types - and sym['name'] not in ['__bss_start', '_end', '_edata']) + bad_types = ["t", "b", "r", "d", "w"] + return sym["type"] not in bad_types and sym["name"] not in [ + "__bss_start", + "_end", + "_edata", + ] @staticmethod def _transform_sym_type(sym): @@ -101,14 +103,15 @@ class NMExtractor(object): Map the nm single letter output for type to either FUNC or OBJECT. If the type is not recognized it is left unchanged. """ - func_types = ['T', 'W'] - obj_types = ['B', 'D', 'R', 'V', 'S'] - if sym['type'] in func_types: - sym['type'] = 'FUNC' - elif sym['type'] in obj_types: - sym['type'] = 'OBJECT' + func_types = ["T", "W"] + obj_types = ["B", "D", "R", "V", "S"] + if sym["type"] in func_types: + sym["type"] = "FUNC" + elif sym["type"] in obj_types: + sym["type"] = "OBJECT" return sym + class ReadElfExtractor(object): """ ReadElfExtractor - Extract symbol lists from libraries using readelf. @@ -119,7 +122,7 @@ class ReadElfExtractor(object): """ Search for the readelf executable and return the path. """ - return shutil.which('readelf') + return shutil.which("readelf") def __init__(self, static_lib): """ @@ -133,7 +136,7 @@ class ReadElfExtractor(object): sys.exit(1) # TODO: Support readelf for reading symbols from archives assert not static_lib and "RealElf does not yet support static libs" - self.flags = ['--wide', '--symbols'] + self.flags = ["--wide", "--symbols"] def extract(self, lib): """ @@ -155,18 +158,18 @@ class ReadElfExtractor(object): if len(parts) == 7: continue new_sym = { - 'name': parts[7], - 'size': int(parts[2]), - 'type': parts[3], - 'is_defined': (parts[6] != 'UND') + "name": parts[7], + "size": int(parts[2]), + "type": parts[3], + "is_defined": (parts[6] != "UND"), } - assert new_sym['type'] in ['OBJECT', 'FUNC', 'NOTYPE', 'TLS'] - if new_sym['name'] in extract_ignore_names: + assert new_sym["type"] in ["OBJECT", "FUNC", "NOTYPE", "TLS"] + if new_sym["name"] in extract_ignore_names: continue - if new_sym['type'] == 'NOTYPE': + if new_sym["type"] == "NOTYPE": continue - if new_sym['type'] == 'FUNC': - del new_sym['size'] + if new_sym["type"] == "FUNC": + del new_sym["size"] new_syms += [new_sym] return new_syms @@ -190,98 +193,100 @@ class ReadElfExtractor(object): end = len(lines) return lines[start:end] + class AIXDumpExtractor(object): - """ - AIXDumpExtractor - Extract symbol lists from libraries using AIX dump. - """ + """ + AIXDumpExtractor - Extract symbol lists from libraries using AIX dump. + """ - @staticmethod - def find_tool(): - """ - Search for the dump executable and return the path. - """ - return shutil.which('dump') + @staticmethod + def find_tool(): + """ + Search for the dump executable and return the path. + """ + return shutil.which("dump") - def __init__(self, static_lib): - """ - Initialize the dump executable and flags that will be used to - extract symbols from shared libraries. - """ - # TODO: Support dump for reading symbols from static libraries - assert not static_lib and "static libs not yet supported with dump" - self.tool = self.find_tool() - if self.tool is None: - print("ERROR: Could not find dump") - sys.exit(1) - self.flags = ['-n', '-v'] - object_mode = environ.get('OBJECT_MODE') - if object_mode == '32': - self.flags += ['-X32'] - elif object_mode == '64': - self.flags += ['-X64'] - else: - self.flags += ['-X32_64'] + def __init__(self, static_lib): + """ + Initialize the dump executable and flags that will be used to + extract symbols from shared libraries. + """ + # TODO: Support dump for reading symbols from static libraries + assert not static_lib and "static libs not yet supported with dump" + self.tool = self.find_tool() + if self.tool is None: + print("ERROR: Could not find dump") + sys.exit(1) + self.flags = ["-n", "-v"] + object_mode = environ.get("OBJECT_MODE") + if object_mode == "32": + self.flags += ["-X32"] + elif object_mode == "64": + self.flags += ["-X64"] + else: + self.flags += ["-X32_64"] - def extract(self, lib): - """ - Extract symbols from a library and return the results as a dict of - parsed symbols. - """ - cmd = [self.tool] + self.flags + [lib] - out = subprocess.check_output(cmd).decode() - loader_syms = self.get_loader_symbol_table(out) - return self.process_syms(loader_syms) + def extract(self, lib): + """ + Extract symbols from a library and return the results as a dict of + parsed symbols. + """ + cmd = [self.tool] + self.flags + [lib] + out = subprocess.check_output(cmd).decode() + loader_syms = self.get_loader_symbol_table(out) + return self.process_syms(loader_syms) - def process_syms(self, sym_list): - new_syms = [] - for s in sym_list: - parts = s.split() - if not parts: - continue - assert len(parts) == 8 or len(parts) == 7 - if len(parts) == 7: - continue - new_sym = { - 'name': parts[7], - 'type': 'FUNC' if parts[4] == 'DS' else 'OBJECT', - 'is_defined': (parts[5] != 'EXTref'), - 'storage_mapping_class': parts[4], - 'import_export': parts[3] - } - if new_sym['name'] in extract_ignore_names: - continue - new_syms += [new_sym] - return new_syms + def process_syms(self, sym_list): + new_syms = [] + for s in sym_list: + parts = s.split() + if not parts: + continue + assert len(parts) == 8 or len(parts) == 7 + if len(parts) == 7: + continue + new_sym = { + "name": parts[7], + "type": "FUNC" if parts[4] == "DS" else "OBJECT", + "is_defined": (parts[5] != "EXTref"), + "storage_mapping_class": parts[4], + "import_export": parts[3], + } + if new_sym["name"] in extract_ignore_names: + continue + new_syms += [new_sym] + return new_syms - def get_loader_symbol_table(self, out): - lines = out.splitlines() - return filter(lambda n: re.match(r'^\[[0-9]+\]', n), lines) + def get_loader_symbol_table(self, out): + lines = out.splitlines() + return filter(lambda n: re.match(r"^\[[0-9]+\]", n), lines) - @staticmethod - def is_shared_lib(lib): - """ - Check for the shared object flag in XCOFF headers of the input file or - library archive. - """ - dump = AIXDumpExtractor.find_tool() - if dump is None: - print("ERROR: Could not find dump") - sys.exit(1) - cmd = [dump, '-X32_64', '-ov', lib] - out = subprocess.check_output(cmd).decode() - return out.find("SHROBJ") != -1 + @staticmethod + def is_shared_lib(lib): + """ + Check for the shared object flag in XCOFF headers of the input file or + library archive. + """ + dump = AIXDumpExtractor.find_tool() + if dump is None: + print("ERROR: Could not find dump") + sys.exit(1) + cmd = [dump, "-X32_64", "-ov", lib] + out = subprocess.check_output(cmd).decode() + return out.find("SHROBJ") != -1 def is_static_library(lib_file): - """ - Determine if a given library is static or shared. - """ - if sys.platform.startswith('aix'): - # An AIX library could be both, but for simplicity assume it isn't. - return not AIXDumpExtractor.is_shared_lib(lib_file) - else: - _, ext = os.path.splitext(lib_file) - return ext == '.a' + """ + Determine if a given library is static or shared. + """ + if sys.platform.startswith("aix"): + # An AIX library could be both, but for simplicity assume it isn't. + return not AIXDumpExtractor.is_shared_lib(lib_file) + else: + _, ext = os.path.splitext(lib_file) + return ext == ".a" + def extract_symbols(lib_file, static_lib=None): """ @@ -291,7 +296,7 @@ def extract_symbols(lib_file, static_lib=None): """ if static_lib is None: static_lib = is_static_library(lib_file) - if sys.platform.startswith('aix'): + if sys.platform.startswith("aix"): extractor = AIXDumpExtractor(static_lib=static_lib) elif ReadElfExtractor.find_tool() and not static_lib: extractor = ReadElfExtractor(static_lib=static_lib) diff --git a/libcxx/utils/libcxx/sym_check/match.py b/libcxx/utils/libcxx/sym_check/match.py index 636e3ab..39cc0f8 100644 --- a/libcxx/utils/libcxx/sym_check/match.py +++ b/libcxx/utils/libcxx/sym_check/match.py @@ -1,11 +1,11 @@ # -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80: -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """ match - A set of functions for matching symbols in a list to a list of regexs """ @@ -14,19 +14,19 @@ import re def find_and_report_matching(symbol_list, regex_list): - report = '' + report = "" found_count = 0 for regex_str in regex_list: report += 'Matching regex "%s":\n' % regex_str matching_list = find_matching_symbols(symbol_list, regex_str) if not matching_list: - report += ' No matches found\n\n' + report += " No matches found\n\n" continue # else found_count += len(matching_list) for m in matching_list: - report += ' MATCHES: %s\n' % m['name'] - report += '\n' + report += " MATCHES: %s\n" % m["name"] + report += "\n" return found_count, report @@ -34,6 +34,6 @@ def find_matching_symbols(symbol_list, regex_str): regex = re.compile(regex_str) matching_list = [] for s in symbol_list: - if regex.match(s['name']): + if regex.match(s["name"]): matching_list += [s] return matching_list diff --git a/libcxx/utils/libcxx/sym_check/util.py b/libcxx/utils/libcxx/sym_check/util.py index 897f992..fc7ba42 100644 --- a/libcxx/utils/libcxx/sym_check/util.py +++ b/libcxx/utils/libcxx/sym_check/util.py @@ -1,10 +1,10 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 pprint import pformat import ast @@ -26,16 +26,16 @@ def read_syms_from_file(filename): """ Read a list of symbols in from a file. """ - with open(filename, 'r') as f: + with open(filename, "r") as f: data = f.read() return read_syms_from_list(data.splitlines()) def read_exclusions(filename): - with open(filename, 'r') as f: + with open(filename, "r") as f: data = f.read() lines = [l.strip() for l in data.splitlines() if l.strip()] - lines = [l for l in lines if not l.startswith('#')] + lines = [l for l in lines if not l.startswith("#")] return lines @@ -43,24 +43,24 @@ def write_syms(sym_list, out=None, names_only=False, filter=None): """ Write a list of symbols to the file named by out. """ - out_str = '' + out_str = "" out_list = sym_list - out_list.sort(key=lambda x: x['name']) + out_list.sort(key=lambda x: x["name"]) if filter is not None: out_list = filter(out_list) if names_only: - out_list = [sym['name'] for sym in out_list] + out_list = [sym["name"] for sym in out_list] for sym in out_list: # Use pformat for consistent ordering of keys. - out_str += pformat(sym, width=100000) + '\n' + out_str += pformat(sym, width=100000) + "\n" if out is None: sys.stdout.write(out_str) else: - with open(out, 'w') as f: + with open(out, "w") as f: f.write(out_str) -_cppfilt_exe = shutil.which('c++filt') +_cppfilt_exe = shutil.which("c++filt") def demangle_symbol(symbol): @@ -73,35 +73,37 @@ def demangle_symbol(symbol): def is_elf(filename): - with open(filename, 'rb') as f: + with open(filename, "rb") as f: magic_bytes = f.read(4) - return magic_bytes == b'\x7fELF' + return magic_bytes == b"\x7fELF" def is_mach_o(filename): - with open(filename, 'rb') as f: + with open(filename, "rb") as f: magic_bytes = f.read(4) return magic_bytes in [ - b'\xfe\xed\xfa\xce', # MH_MAGIC - b'\xce\xfa\xed\xfe', # MH_CIGAM - b'\xfe\xed\xfa\xcf', # MH_MAGIC_64 - b'\xcf\xfa\xed\xfe', # MH_CIGAM_64 - b'\xca\xfe\xba\xbe', # FAT_MAGIC - b'\xbe\xba\xfe\xca' # FAT_CIGAM + b"\xfe\xed\xfa\xce", # MH_MAGIC + b"\xce\xfa\xed\xfe", # MH_CIGAM + b"\xfe\xed\xfa\xcf", # MH_MAGIC_64 + b"\xcf\xfa\xed\xfe", # MH_CIGAM_64 + b"\xca\xfe\xba\xbe", # FAT_MAGIC + b"\xbe\xba\xfe\xca", # FAT_CIGAM ] + def is_xcoff_or_big_ar(filename): - with open(filename, 'rb') as f: + with open(filename, "rb") as f: magic_bytes = f.read(7) - return magic_bytes[:4] in [ - b'\x01DF', # XCOFF32 - b'\x01F7' # XCOFF64 - ] or magic_bytes == b'<bigaf>' + return ( + magic_bytes[:4] in [b"\x01DF", b"\x01F7"] # XCOFF32 # XCOFF64 + or magic_bytes == b"<bigaf>" + ) + def is_library_file(filename): - if sys.platform == 'darwin': + if sys.platform == "darwin": return is_mach_o(filename) - elif sys.platform.startswith('aix'): + elif sys.platform.startswith("aix"): return is_xcoff_or_big_ar(filename) else: return is_elf(filename) @@ -109,169 +111,167 @@ def is_library_file(filename): def extract_or_load(filename): import libcxx.sym_check.extract + if is_library_file(filename): return libcxx.sym_check.extract.extract_symbols(filename) return read_syms_from_file(filename) + def adjust_mangled_name(name): - if not name.startswith('__Z'): + if not name.startswith("__Z"): return name return name[1:] -new_delete_std_symbols = [ - '_Znam', - '_Znwm', - '_ZdaPv', - '_ZdaPvm', - '_ZdlPv', - '_ZdlPvm' -] + +new_delete_std_symbols = ["_Znam", "_Znwm", "_ZdaPv", "_ZdaPvm", "_ZdlPv", "_ZdlPvm"] cxxabi_symbols = [ - '___dynamic_cast', - '___gxx_personality_v0', - '_ZTIDi', - '_ZTIDn', - '_ZTIDs', - '_ZTIPDi', - '_ZTIPDn', - '_ZTIPDs', - '_ZTIPKDi', - '_ZTIPKDn', - '_ZTIPKDs', - '_ZTIPKa', - '_ZTIPKb', - '_ZTIPKc', - '_ZTIPKd', - '_ZTIPKe', - '_ZTIPKf', - '_ZTIPKh', - '_ZTIPKi', - '_ZTIPKj', - '_ZTIPKl', - '_ZTIPKm', - '_ZTIPKs', - '_ZTIPKt', - '_ZTIPKv', - '_ZTIPKw', - '_ZTIPKx', - '_ZTIPKy', - '_ZTIPa', - '_ZTIPb', - '_ZTIPc', - '_ZTIPd', - '_ZTIPe', - '_ZTIPf', - '_ZTIPh', - '_ZTIPi', - '_ZTIPj', - '_ZTIPl', - '_ZTIPm', - '_ZTIPs', - '_ZTIPt', - '_ZTIPv', - '_ZTIPw', - '_ZTIPx', - '_ZTIPy', - '_ZTIa', - '_ZTIb', - '_ZTIc', - '_ZTId', - '_ZTIe', - '_ZTIf', - '_ZTIh', - '_ZTIi', - '_ZTIj', - '_ZTIl', - '_ZTIm', - '_ZTIs', - '_ZTIt', - '_ZTIv', - '_ZTIw', - '_ZTIx', - '_ZTIy', - '_ZTSDi', - '_ZTSDn', - '_ZTSDs', - '_ZTSPDi', - '_ZTSPDn', - '_ZTSPDs', - '_ZTSPKDi', - '_ZTSPKDn', - '_ZTSPKDs', - '_ZTSPKa', - '_ZTSPKb', - '_ZTSPKc', - '_ZTSPKd', - '_ZTSPKe', - '_ZTSPKf', - '_ZTSPKh', - '_ZTSPKi', - '_ZTSPKj', - '_ZTSPKl', - '_ZTSPKm', - '_ZTSPKs', - '_ZTSPKt', - '_ZTSPKv', - '_ZTSPKw', - '_ZTSPKx', - '_ZTSPKy', - '_ZTSPa', - '_ZTSPb', - '_ZTSPc', - '_ZTSPd', - '_ZTSPe', - '_ZTSPf', - '_ZTSPh', - '_ZTSPi', - '_ZTSPj', - '_ZTSPl', - '_ZTSPm', - '_ZTSPs', - '_ZTSPt', - '_ZTSPv', - '_ZTSPw', - '_ZTSPx', - '_ZTSPy', - '_ZTSa', - '_ZTSb', - '_ZTSc', - '_ZTSd', - '_ZTSe', - '_ZTSf', - '_ZTSh', - '_ZTSi', - '_ZTSj', - '_ZTSl', - '_ZTSm', - '_ZTSs', - '_ZTSt', - '_ZTSv', - '_ZTSw', - '_ZTSx', - '_ZTSy' + "___dynamic_cast", + "___gxx_personality_v0", + "_ZTIDi", + "_ZTIDn", + "_ZTIDs", + "_ZTIPDi", + "_ZTIPDn", + "_ZTIPDs", + "_ZTIPKDi", + "_ZTIPKDn", + "_ZTIPKDs", + "_ZTIPKa", + "_ZTIPKb", + "_ZTIPKc", + "_ZTIPKd", + "_ZTIPKe", + "_ZTIPKf", + "_ZTIPKh", + "_ZTIPKi", + "_ZTIPKj", + "_ZTIPKl", + "_ZTIPKm", + "_ZTIPKs", + "_ZTIPKt", + "_ZTIPKv", + "_ZTIPKw", + "_ZTIPKx", + "_ZTIPKy", + "_ZTIPa", + "_ZTIPb", + "_ZTIPc", + "_ZTIPd", + "_ZTIPe", + "_ZTIPf", + "_ZTIPh", + "_ZTIPi", + "_ZTIPj", + "_ZTIPl", + "_ZTIPm", + "_ZTIPs", + "_ZTIPt", + "_ZTIPv", + "_ZTIPw", + "_ZTIPx", + "_ZTIPy", + "_ZTIa", + "_ZTIb", + "_ZTIc", + "_ZTId", + "_ZTIe", + "_ZTIf", + "_ZTIh", + "_ZTIi", + "_ZTIj", + "_ZTIl", + "_ZTIm", + "_ZTIs", + "_ZTIt", + "_ZTIv", + "_ZTIw", + "_ZTIx", + "_ZTIy", + "_ZTSDi", + "_ZTSDn", + "_ZTSDs", + "_ZTSPDi", + "_ZTSPDn", + "_ZTSPDs", + "_ZTSPKDi", + "_ZTSPKDn", + "_ZTSPKDs", + "_ZTSPKa", + "_ZTSPKb", + "_ZTSPKc", + "_ZTSPKd", + "_ZTSPKe", + "_ZTSPKf", + "_ZTSPKh", + "_ZTSPKi", + "_ZTSPKj", + "_ZTSPKl", + "_ZTSPKm", + "_ZTSPKs", + "_ZTSPKt", + "_ZTSPKv", + "_ZTSPKw", + "_ZTSPKx", + "_ZTSPKy", + "_ZTSPa", + "_ZTSPb", + "_ZTSPc", + "_ZTSPd", + "_ZTSPe", + "_ZTSPf", + "_ZTSPh", + "_ZTSPi", + "_ZTSPj", + "_ZTSPl", + "_ZTSPm", + "_ZTSPs", + "_ZTSPt", + "_ZTSPv", + "_ZTSPw", + "_ZTSPx", + "_ZTSPy", + "_ZTSa", + "_ZTSb", + "_ZTSc", + "_ZTSd", + "_ZTSe", + "_ZTSf", + "_ZTSh", + "_ZTSi", + "_ZTSj", + "_ZTSl", + "_ZTSm", + "_ZTSs", + "_ZTSt", + "_ZTSv", + "_ZTSw", + "_ZTSx", + "_ZTSy", ] + def is_stdlib_symbol_name(name, sym): name = adjust_mangled_name(name) if re.search("@GLIBC|@GCC", name): # Only when symbol is defined do we consider it ours - return sym['is_defined'] - if re.search('(St[0-9])|(__cxa)|(__cxxabi)', name): + return sym["is_defined"] + if re.search("(St[0-9])|(__cxa)|(__cxxabi)", name): return True if name in new_delete_std_symbols: return True if name in cxxabi_symbols: return True - if name.startswith('_Z'): + if name.startswith("_Z"): return True return False + def filter_stdlib_symbols(syms): stdlib_symbols = [] other_symbols = [] for s in syms: - canon_name = adjust_mangled_name(s['name']) + canon_name = adjust_mangled_name(s["name"]) if not is_stdlib_symbol_name(canon_name, s): other_symbols += [s] else: diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py index 253f8e8..292c9ca 100644 --- a/libcxx/utils/libcxx/test/config.py +++ b/libcxx/utils/libcxx/test/config.py @@ -1,49 +1,55 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## import os def _getSubstitution(substitution, config): - for (orig, replacement) in config.substitutions: - if orig == substitution: - return replacement - raise ValueError('Substitution {} is not in the config.'.format(substitution)) + for (orig, replacement) in config.substitutions: + if orig == substitution: + return replacement + raise ValueError("Substitution {} is not in the config.".format(substitution)) + def configure(parameters, features, config, lit_config): - note = lambda s: lit_config.note("({}) {}".format(config.name, s)) - config.environment = dict(os.environ) - - # Apply the actions supplied by parameters to the configuration first, since - # parameters are things that we request explicitly and which might influence - # what features are implicitly made available next. - for param in parameters: - actions = param.getActions(config, lit_config.params) - for action in actions: - action.applyTo(config) - if lit_config.debug: - note("Applied '{}' as a result of parameter '{}'".format( - action.pretty(config, lit_config.params), - param.pretty(config, lit_config.params))) - - # Then, apply the automatically-detected features. - for feature in features: - actions = feature.getActions(config) - for action in actions: - action.applyTo(config) - if lit_config.debug: - note("Applied '{}' as a result of implicitly detected feature '{}'".format( - action.pretty(config, lit_config.params), - feature.pretty(config))) - - # Print the basic substitutions - for sub in ('%{cxx}', '%{flags}', '%{compile_flags}', '%{link_flags}', '%{exec}'): - note("Using {} substitution: '{}'".format(sub, _getSubstitution(sub, config))) - - # Print all available features - note("All available features: {}".format(', '.join(config.available_features))) + note = lambda s: lit_config.note("({}) {}".format(config.name, s)) + config.environment = dict(os.environ) + + # Apply the actions supplied by parameters to the configuration first, since + # parameters are things that we request explicitly and which might influence + # what features are implicitly made available next. + for param in parameters: + actions = param.getActions(config, lit_config.params) + for action in actions: + action.applyTo(config) + if lit_config.debug: + note( + "Applied '{}' as a result of parameter '{}'".format( + action.pretty(config, lit_config.params), + param.pretty(config, lit_config.params), + ) + ) + + # Then, apply the automatically-detected features. + for feature in features: + actions = feature.getActions(config) + for action in actions: + action.applyTo(config) + if lit_config.debug: + note( + "Applied '{}' as a result of implicitly detected feature '{}'".format( + action.pretty(config, lit_config.params), feature.pretty(config) + ) + ) + + # Print the basic substitutions + for sub in ("%{cxx}", "%{flags}", "%{compile_flags}", "%{link_flags}", "%{exec}"): + note("Using {} substitution: '{}'".format(sub, _getSubstitution(sub, config))) + + # Print all available features + note("All available features: {}".format(", ".join(config.available_features))) diff --git a/libcxx/utils/libcxx/test/dsl.py b/libcxx/utils/libcxx/test/dsl.py index d127337..66cf817 100644 --- a/libcxx/utils/libcxx/test/dsl.py +++ b/libcxx/utils/libcxx/test/dsl.py @@ -1,10 +1,10 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## import os import pickle @@ -21,211 +21,252 @@ import lit.Test import lit.TestRunner import lit.util + class ConfigurationError(Exception): - pass + pass + class ConfigurationCompilationError(ConfigurationError): - pass + pass + class ConfigurationRuntimeError(ConfigurationError): - pass + pass + def _memoizeExpensiveOperation(extractCacheKey): - """ - Allows memoizing a very expensive operation. - - We pickle the cache key to make sure we store an immutable representation - of it. If we stored an object and the object was referenced elsewhere, it - could be changed from under our feet, which would break the cache. - - We also store the cache for a given function persistently across invocations - of Lit. This dramatically speeds up the configuration of the test suite when - invoking Lit repeatedly, which is important for developer workflow. However, - with the current implementation that does not synchronize updates to the - persistent cache, this also means that one should not call a memoized - operation from multiple threads. This should normally not be a problem - since Lit configuration is single-threaded. - """ - def decorator(function): - def f(config, *args, **kwargs): - cacheRoot = os.path.join(config.test_exec_root, '__config_cache__') - persistentCache = os.path.join(cacheRoot, function.__name__) - if not os.path.exists(cacheRoot): - os.makedirs(cacheRoot) - - cache = {} - # Load a cache from a previous Lit invocation if there is one. - if os.path.exists(persistentCache): - with open(persistentCache, 'rb') as cacheFile: - cache = pickle.load(cacheFile) - - cacheKey = pickle.dumps(extractCacheKey(config, *args, **kwargs)) - if cacheKey not in cache: - cache[cacheKey] = function(config, *args, **kwargs) - # Update the persistent cache so it knows about the new key - with open(persistentCache, 'wb') as cacheFile: - pickle.dump(cache, cacheFile) - return cache[cacheKey] - return f - return decorator + """ + Allows memoizing a very expensive operation. + + We pickle the cache key to make sure we store an immutable representation + of it. If we stored an object and the object was referenced elsewhere, it + could be changed from under our feet, which would break the cache. + + We also store the cache for a given function persistently across invocations + of Lit. This dramatically speeds up the configuration of the test suite when + invoking Lit repeatedly, which is important for developer workflow. However, + with the current implementation that does not synchronize updates to the + persistent cache, this also means that one should not call a memoized + operation from multiple threads. This should normally not be a problem + since Lit configuration is single-threaded. + """ + + def decorator(function): + def f(config, *args, **kwargs): + cacheRoot = os.path.join(config.test_exec_root, "__config_cache__") + persistentCache = os.path.join(cacheRoot, function.__name__) + if not os.path.exists(cacheRoot): + os.makedirs(cacheRoot) + + cache = {} + # Load a cache from a previous Lit invocation if there is one. + if os.path.exists(persistentCache): + with open(persistentCache, "rb") as cacheFile: + cache = pickle.load(cacheFile) + + cacheKey = pickle.dumps(extractCacheKey(config, *args, **kwargs)) + if cacheKey not in cache: + cache[cacheKey] = function(config, *args, **kwargs) + # Update the persistent cache so it knows about the new key + with open(persistentCache, "wb") as cacheFile: + pickle.dump(cache, cacheFile) + return cache[cacheKey] + + return f + + return decorator + def _executeWithFakeConfig(test, commands): - """ - Returns (stdout, stderr, exitCode, timeoutInfo, parsedCommands) - """ - litConfig = lit.LitConfig.LitConfig( - progname='lit', - path=[], - quiet=False, - useValgrind=False, - valgrindLeakCheck=False, - valgrindArgs=[], - noExecute=False, - debug=False, - isWindows=platform.system() == 'Windows', - order='smart', - params={}) - return libcxx.test.format._executeScriptInternal(test, litConfig, commands) + """ + Returns (stdout, stderr, exitCode, timeoutInfo, parsedCommands) + """ + litConfig = lit.LitConfig.LitConfig( + progname="lit", + path=[], + quiet=False, + useValgrind=False, + valgrindLeakCheck=False, + valgrindArgs=[], + noExecute=False, + debug=False, + isWindows=platform.system() == "Windows", + order="smart", + params={}, + ) + return libcxx.test.format._executeScriptInternal(test, litConfig, commands) + def _makeConfigTest(config): - # Make sure the support directories exist, which is needed to create - # the temporary file %t below. - sourceRoot = os.path.join(config.test_exec_root, '__config_src__') - execRoot = os.path.join(config.test_exec_root, '__config_exec__') - for supportDir in (sourceRoot, execRoot): - if not os.path.exists(supportDir): - os.makedirs(supportDir) - - # Create a dummy test suite and single dummy test inside it. As part of - # the Lit configuration, automatically do the equivalent of 'mkdir %T' - # and 'rm -r %T' to avoid cluttering the build directory. - suite = lit.Test.TestSuite('__config__', sourceRoot, execRoot, config) - tmp = tempfile.NamedTemporaryFile(dir=sourceRoot, delete=False, suffix='.cpp') - tmp.close() - pathInSuite = [os.path.relpath(tmp.name, sourceRoot)] - class TestWrapper(lit.Test.Test): - def __enter__(self): - testDir, _ = libcxx.test.format._getTempPaths(self) - os.makedirs(testDir) - return self - def __exit__(self, *args): - testDir, _ = libcxx.test.format._getTempPaths(self) - shutil.rmtree(testDir) - os.remove(tmp.name) - return TestWrapper(suite, pathInSuite, config) + # Make sure the support directories exist, which is needed to create + # the temporary file %t below. + sourceRoot = os.path.join(config.test_exec_root, "__config_src__") + execRoot = os.path.join(config.test_exec_root, "__config_exec__") + for supportDir in (sourceRoot, execRoot): + if not os.path.exists(supportDir): + os.makedirs(supportDir) + + # Create a dummy test suite and single dummy test inside it. As part of + # the Lit configuration, automatically do the equivalent of 'mkdir %T' + # and 'rm -r %T' to avoid cluttering the build directory. + suite = lit.Test.TestSuite("__config__", sourceRoot, execRoot, config) + tmp = tempfile.NamedTemporaryFile(dir=sourceRoot, delete=False, suffix=".cpp") + tmp.close() + pathInSuite = [os.path.relpath(tmp.name, sourceRoot)] + + class TestWrapper(lit.Test.Test): + def __enter__(self): + testDir, _ = libcxx.test.format._getTempPaths(self) + os.makedirs(testDir) + return self + + def __exit__(self, *args): + testDir, _ = libcxx.test.format._getTempPaths(self) + shutil.rmtree(testDir) + os.remove(tmp.name) + + return TestWrapper(suite, pathInSuite, config) + @_memoizeExpensiveOperation(lambda c, s, f=[]: (c.substitutions, c.environment, s, f)) def sourceBuilds(config, source, additionalFlags=[]): - """ - Return whether the program in the given string builds successfully. - - This is done by compiling and linking a program that consists of the given - source with the %{cxx} substitution, and seeing whether that succeeds. If - any additional flags are passed, they are appended to the compiler invocation. - """ - with _makeConfigTest(config) as test: - with open(test.getSourcePath(), 'w') as sourceFile: - sourceFile.write(source) - _, _, exitCode, _, _ = _executeWithFakeConfig(test, ['%{{build}} {}'.format(' '.join(additionalFlags))]) - return exitCode == 0 + """ + Return whether the program in the given string builds successfully. -@_memoizeExpensiveOperation(lambda c, p, args=None: (c.substitutions, c.environment, p, args)) + This is done by compiling and linking a program that consists of the given + source with the %{cxx} substitution, and seeing whether that succeeds. If + any additional flags are passed, they are appended to the compiler invocation. + """ + with _makeConfigTest(config) as test: + with open(test.getSourcePath(), "w") as sourceFile: + sourceFile.write(source) + _, _, exitCode, _, _ = _executeWithFakeConfig( + test, ["%{{build}} {}".format(" ".join(additionalFlags))] + ) + return exitCode == 0 + + +@_memoizeExpensiveOperation( + lambda c, p, args=None: (c.substitutions, c.environment, p, args) +) def programOutput(config, program, args=None): - """ - Compiles a program for the test target, run it on the test target and return - the output. + """ + Compiles a program for the test target, run it on the test target and return + the output. - Note that execution of the program is done through the %{exec} substitution, - which means that the program may be run on a remote host depending on what - %{exec} does. - """ - if args is None: - args = [] - with _makeConfigTest(config) as test: - with open(test.getSourcePath(), 'w') as source: - source.write(program) - _, err, exitCode, _, buildcmd = _executeWithFakeConfig(test, ['%{build}']) - if exitCode != 0: - raise ConfigurationCompilationError("Failed to build program, cmd:\n{}\nstderr is:\n{}".format(buildcmd, err)) - - out, err, exitCode, _, runcmd = _executeWithFakeConfig(test, ["%{{run}} {}".format(' '.join(args))]) - if exitCode != 0: - raise ConfigurationRuntimeError("Failed to run program, cmd:\n{}\nstderr is:\n{}".format(runcmd, err)) - - actualOut = re.search("# command output:\n(.+)\n$", out, flags=re.DOTALL) - actualOut = actualOut.group(1) if actualOut else "" - return actualOut - -@_memoizeExpensiveOperation(lambda c, p, args=None: (c.substitutions, c.environment, p, args)) + Note that execution of the program is done through the %{exec} substitution, + which means that the program may be run on a remote host depending on what + %{exec} does. + """ + if args is None: + args = [] + with _makeConfigTest(config) as test: + with open(test.getSourcePath(), "w") as source: + source.write(program) + _, err, exitCode, _, buildcmd = _executeWithFakeConfig(test, ["%{build}"]) + if exitCode != 0: + raise ConfigurationCompilationError( + "Failed to build program, cmd:\n{}\nstderr is:\n{}".format( + buildcmd, err + ) + ) + + out, err, exitCode, _, runcmd = _executeWithFakeConfig( + test, ["%{{run}} {}".format(" ".join(args))] + ) + if exitCode != 0: + raise ConfigurationRuntimeError( + "Failed to run program, cmd:\n{}\nstderr is:\n{}".format(runcmd, err) + ) + + actualOut = re.search("# command output:\n(.+)\n$", out, flags=re.DOTALL) + actualOut = actualOut.group(1) if actualOut else "" + return actualOut + + +@_memoizeExpensiveOperation( + lambda c, p, args=None: (c.substitutions, c.environment, p, args) +) def programSucceeds(config, program, args=None): - """ - Compiles a program for the test target, run it on the test target and return - whether it completed successfully. + """ + Compiles a program for the test target, run it on the test target and return + whether it completed successfully. + + Note that execution of the program is done through the %{exec} substitution, + which means that the program may be run on a remote host depending on what + %{exec} does. + """ + try: + programOutput(config, program, args) + except ConfigurationRuntimeError: + return False + return True - Note that execution of the program is done through the %{exec} substitution, - which means that the program may be run on a remote host depending on what - %{exec} does. - """ - try: - programOutput(config, program, args) - except ConfigurationRuntimeError: - return False - return True @_memoizeExpensiveOperation(lambda c, f: (c.substitutions, c.environment, f)) def hasCompileFlag(config, flag): - """ - Return whether the compiler in the configuration supports a given compiler flag. + """ + Return whether the compiler in the configuration supports a given compiler flag. + + This is done by executing the %{cxx} substitution with the given flag and + checking whether that succeeds. + """ + with _makeConfigTest(config) as test: + out, err, exitCode, timeoutInfo, _ = _executeWithFakeConfig( + test, + [ + "%{{cxx}} -xc++ {} -Werror -fsyntax-only %{{flags}} %{{compile_flags}} {}".format( + os.devnull, flag + ) + ], + ) + return exitCode == 0 - This is done by executing the %{cxx} substitution with the given flag and - checking whether that succeeds. - """ - with _makeConfigTest(config) as test: - out, err, exitCode, timeoutInfo, _ = _executeWithFakeConfig(test, [ - "%{{cxx}} -xc++ {} -Werror -fsyntax-only %{{flags}} %{{compile_flags}} {}".format(os.devnull, flag) - ]) - return exitCode == 0 @_memoizeExpensiveOperation(lambda c, s: (c.substitutions, c.environment, s)) def runScriptExitCode(config, script): - """ - Runs the given script as a Lit test, and returns the exit code of the execution. + """ + Runs the given script as a Lit test, and returns the exit code of the execution. + + The script must be a list of commands, each of which being something that + could appear on the right-hand-side of a `RUN:` keyword. + """ + with _makeConfigTest(config) as test: + _, _, exitCode, _, _ = _executeWithFakeConfig(test, script) + return exitCode - The script must be a list of commands, each of which being something that - could appear on the right-hand-side of a `RUN:` keyword. - """ - with _makeConfigTest(config) as test: - _, _, exitCode, _, _ = _executeWithFakeConfig(test, script) - return exitCode @_memoizeExpensiveOperation(lambda c, s: (c.substitutions, c.environment, s)) def commandOutput(config, command): - """ - Runs the given script as a Lit test, and returns the output. - If the exit code isn't 0 an exception is raised. + """ + Runs the given script as a Lit test, and returns the output. + If the exit code isn't 0 an exception is raised. + + The script must be a list of commands, each of which being something that + could appear on the right-hand-side of a `RUN:` keyword. + """ + with _makeConfigTest(config) as test: + out, err, exitCode, _, cmd = _executeWithFakeConfig(test, command) + if exitCode != 0: + raise ConfigurationRuntimeError( + "Failed to run command: {}\nstderr is:\n{}".format(cmd, err) + ) + return out - The script must be a list of commands, each of which being something that - could appear on the right-hand-side of a `RUN:` keyword. - """ - with _makeConfigTest(config) as test: - out, err, exitCode, _, cmd = _executeWithFakeConfig(test, command) - if exitCode != 0: - raise ConfigurationRuntimeError("Failed to run command: {}\nstderr is:\n{}".format(cmd, err)) - return out @_memoizeExpensiveOperation(lambda c, l: (c.substitutions, c.environment, l)) def hasAnyLocale(config, locales): - """ - Return whether the runtime execution environment supports a given locale. - Different systems may use different names for a locale, so this function checks - whether any of the passed locale names is supported by setlocale() and returns - true if one of them works. - - This is done by executing a program that tries to set the given locale using - %{exec} -- this means that the command may be executed on a remote host - depending on the %{exec} substitution. - """ - program = """ + """ + Return whether the runtime execution environment supports a given locale. + Different systems may use different names for a locale, so this function checks + whether any of the passed locale names is supported by setlocale() and returns + true if one of them works. + + This is done by executing a program that tries to set the given locale using + %{exec} -- this means that the command may be executed on a remote host + depending on the %{exec} substitution. + """ + program = """ #include <stddef.h> #if defined(_LIBCPP_HAS_NO_LOCALIZATION) int main(int, char**) { return 1; } @@ -241,460 +282,532 @@ def hasAnyLocale(config, locales): } #endif """ - return programSucceeds(config, program, args=[pipes.quote(l) for l in locales]) + return programSucceeds(config, program, args=[pipes.quote(l) for l in locales]) -@_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. +@_memoizeExpensiveOperation(lambda c, flags="": (c.substitutions, c.environment, flags)) +def compilerMacros(config, flags=""): + """ + Return a dictionary of predefined compiler macros. - 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(""" + 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_site>) # include <__config_site> #endif - """) - 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(cmd, err)) - parsedMacros = dict() - defines = (l.strip() for l in unparsedOutput.split('\n') if l.startswith('#define ')) - for line in defines: - line = line[len('#define '):] - macro, _, value = line.partition(' ') - parsedMacros[macro] = value - return parsedMacros - -def featureTestMacros(config, flags=''): - """ - Return a dictionary of feature test macros. + """ + ) + 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( + cmd, err + ) + ) + parsedMacros = dict() + defines = ( + l.strip() for l in unparsedOutput.split("\n") if l.startswith("#define ") + ) + for line in defines: + line = line[len("#define ") :] + macro, _, value = line.partition(" ") + parsedMacros[macro] = value + return parsedMacros + + +def featureTestMacros(config, flags=""): + """ + Return a dictionary of feature test macros. + + The keys are strings representing feature test macros, and the values are + integers representing the value of the macro. + """ + allMacros = compilerMacros(config, flags) + return { + m: int(v.rstrip("LlUu")) + for (m, v) in allMacros.items() + if m.startswith("__cpp_") + } - The keys are strings representing feature test macros, and the values are - integers representing the value of the macro. - """ - allMacros = compilerMacros(config, flags) - return {m: int(v.rstrip('LlUu')) for (m, v) in allMacros.items() if m.startswith('__cpp_')} def _appendToSubstitution(substitutions, key, value): - return [(k, v + ' ' + value) if k == key else (k, v) for (k, v) in substitutions] + return [(k, v + " " + value) if k == key else (k, v) for (k, v) in substitutions] + def _prependToSubstitution(substitutions, key, value): - return [(k, value + ' ' + v) if k == key else (k, v) for (k, v) in substitutions] + return [(k, value + " " + v) if k == key else (k, v) for (k, v) in substitutions] class ConfigAction(object): - """ - This class represents an action that can be performed on a Lit TestingConfig - object. + """ + This class represents an action that can be performed on a Lit TestingConfig + object. - Examples of such actions are adding or modifying substitutions, Lit features, - etc. This class only provides the interface of such actions, and it is meant - to be subclassed appropriately to create new actions. - """ - def applyTo(self, config): + Examples of such actions are adding or modifying substitutions, Lit features, + etc. This class only provides the interface of such actions, and it is meant + to be subclassed appropriately to create new actions. """ - Applies the action to the given configuration. - This should modify the configuration object in place, and return nothing. + def applyTo(self, config): + """ + Applies the action to the given configuration. - If applying the action to the configuration would yield an invalid - configuration, and it is possible to diagnose it here, this method - should produce an error. For example, it should be an error to modify - a substitution in a way that we know for sure is invalid (e.g. adding - a compiler flag when we know the compiler doesn't support it). Failure - to do so early may lead to difficult-to-diagnose issues down the road. - """ - pass + This should modify the configuration object in place, and return nothing. - def pretty(self, config, litParams): - """ - Returns a short and human-readable string describing what this action does. + If applying the action to the configuration would yield an invalid + configuration, and it is possible to diagnose it here, this method + should produce an error. For example, it should be an error to modify + a substitution in a way that we know for sure is invalid (e.g. adding + a compiler flag when we know the compiler doesn't support it). Failure + to do so early may lead to difficult-to-diagnose issues down the road. + """ + pass - This is used for logging purposes when running the test suite, so it should - be kept concise. - """ - pass + def pretty(self, config, litParams): + """ + Returns a short and human-readable string describing what this action does. + + This is used for logging purposes when running the test suite, so it should + be kept concise. + """ + pass class AddFeature(ConfigAction): - """ - This action defines the given Lit feature when running the test suite. + """ + This action defines the given Lit feature when running the test suite. - The name of the feature can be a string or a callable, in which case it is - called with the configuration to produce the feature name (as a string). - """ - def __init__(self, name): - self._name = name + The name of the feature can be a string or a callable, in which case it is + called with the configuration to produce the feature name (as a string). + """ - def _getName(self, config): - name = self._name(config) if callable(self._name) else self._name - if not isinstance(name, str): - raise ValueError("Lit feature did not resolve to a string (got {})".format(name)) - return name + def __init__(self, name): + self._name = name - def applyTo(self, config): - config.available_features.add(self._getName(config)) + def _getName(self, config): + name = self._name(config) if callable(self._name) else self._name + if not isinstance(name, str): + raise ValueError( + "Lit feature did not resolve to a string (got {})".format(name) + ) + return name - def pretty(self, config, litParams): - return 'add Lit feature {}'.format(self._getName(config)) + def applyTo(self, config): + config.available_features.add(self._getName(config)) + + def pretty(self, config, litParams): + return "add Lit feature {}".format(self._getName(config)) class AddFlag(ConfigAction): - """ - This action adds the given flag to the %{flags} substitution. + """ + This action adds the given flag to the %{flags} substitution. - The flag can be a string or a callable, in which case it is called with the - configuration to produce the actual flag (as a string). - """ - def __init__(self, flag): - self._getFlag = lambda config: flag(config) if callable(flag) else flag + The flag can be a string or a callable, in which case it is called with the + configuration to produce the actual flag (as a string). + """ - def applyTo(self, config): - flag = self._getFlag(config) - assert hasCompileFlag(config, flag), "Trying to enable flag {}, which is not supported".format(flag) - config.substitutions = _appendToSubstitution(config.substitutions, '%{flags}', flag) + def __init__(self, flag): + self._getFlag = lambda config: flag(config) if callable(flag) else flag - def pretty(self, config, litParams): - return 'add {} to %{{flags}}'.format(self._getFlag(config)) + def applyTo(self, config): + flag = self._getFlag(config) + assert hasCompileFlag( + config, flag + ), "Trying to enable flag {}, which is not supported".format(flag) + config.substitutions = _appendToSubstitution( + config.substitutions, "%{flags}", flag + ) + + def pretty(self, config, litParams): + return "add {} to %{{flags}}".format(self._getFlag(config)) class AddFlagIfSupported(ConfigAction): - """ - This action adds the given flag to the %{flags} substitution, only if - the compiler supports the flag. + """ + This action adds the given flag to the %{flags} substitution, only if + the compiler supports the flag. - The flag can be a string or a callable, in which case it is called with the - configuration to produce the actual flag (as a string). - """ - def __init__(self, flag): - self._getFlag = lambda config: flag(config) if callable(flag) else flag + The flag can be a string or a callable, in which case it is called with the + configuration to produce the actual flag (as a string). + """ + + def __init__(self, flag): + self._getFlag = lambda config: flag(config) if callable(flag) else flag - def applyTo(self, config): - flag = self._getFlag(config) - if hasCompileFlag(config, flag): - config.substitutions = _appendToSubstitution(config.substitutions, '%{flags}', flag) + def applyTo(self, config): + flag = self._getFlag(config) + if hasCompileFlag(config, flag): + config.substitutions = _appendToSubstitution( + config.substitutions, "%{flags}", flag + ) - def pretty(self, config, litParams): - return 'add {} to %{{flags}}'.format(self._getFlag(config)) + def pretty(self, config, litParams): + return "add {} to %{{flags}}".format(self._getFlag(config)) class AddCompileFlag(ConfigAction): - """ - This action adds the given flag to the %{compile_flags} substitution. + """ + This action adds the given flag to the %{compile_flags} substitution. - The flag can be a string or a callable, in which case it is called with the - configuration to produce the actual flag (as a string). - """ - def __init__(self, flag): - self._getFlag = lambda config: flag(config) if callable(flag) else flag + The flag can be a string or a callable, in which case it is called with the + configuration to produce the actual flag (as a string). + """ + + def __init__(self, flag): + self._getFlag = lambda config: flag(config) if callable(flag) else flag - def applyTo(self, config): - flag = self._getFlag(config) - assert hasCompileFlag(config, flag), "Trying to enable compile flag {}, which is not supported".format(flag) - config.substitutions = _appendToSubstitution(config.substitutions, '%{compile_flags}', flag) + def applyTo(self, config): + flag = self._getFlag(config) + assert hasCompileFlag( + config, flag + ), "Trying to enable compile flag {}, which is not supported".format(flag) + config.substitutions = _appendToSubstitution( + config.substitutions, "%{compile_flags}", flag + ) - def pretty(self, config, litParams): - return 'add {} to %{{compile_flags}}'.format(self._getFlag(config)) + def pretty(self, config, litParams): + return "add {} to %{{compile_flags}}".format(self._getFlag(config)) class AddLinkFlag(ConfigAction): - """ - This action appends the given flag to the %{link_flags} substitution. + """ + This action appends the given flag to the %{link_flags} substitution. - The flag can be a string or a callable, in which case it is called with the - configuration to produce the actual flag (as a string). - """ - def __init__(self, flag): - self._getFlag = lambda config: flag(config) if callable(flag) else flag + The flag can be a string or a callable, in which case it is called with the + configuration to produce the actual flag (as a string). + """ - def applyTo(self, config): - flag = self._getFlag(config) - assert hasCompileFlag(config, flag), "Trying to enable link flag {}, which is not supported".format(flag) - config.substitutions = _appendToSubstitution(config.substitutions, '%{link_flags}', flag) + def __init__(self, flag): + self._getFlag = lambda config: flag(config) if callable(flag) else flag - def pretty(self, config, litParams): - return 'append {} to %{{link_flags}}'.format(self._getFlag(config)) + def applyTo(self, config): + flag = self._getFlag(config) + assert hasCompileFlag( + config, flag + ), "Trying to enable link flag {}, which is not supported".format(flag) + config.substitutions = _appendToSubstitution( + config.substitutions, "%{link_flags}", flag + ) + + def pretty(self, config, litParams): + return "append {} to %{{link_flags}}".format(self._getFlag(config)) class PrependLinkFlag(ConfigAction): - """ - This action prepends the given flag to the %{link_flags} substitution. + """ + This action prepends the given flag to the %{link_flags} substitution. - The flag can be a string or a callable, in which case it is called with the - configuration to produce the actual flag (as a string). - """ - def __init__(self, flag): - self._getFlag = lambda config: flag(config) if callable(flag) else flag + The flag can be a string or a callable, in which case it is called with the + configuration to produce the actual flag (as a string). + """ - def applyTo(self, config): - flag = self._getFlag(config) - assert hasCompileFlag(config, flag), "Trying to enable link flag {}, which is not supported".format(flag) - config.substitutions = _prependToSubstitution(config.substitutions, '%{link_flags}', flag) + def __init__(self, flag): + self._getFlag = lambda config: flag(config) if callable(flag) else flag - def pretty(self, config, litParams): - return 'prepend {} to %{{link_flags}}'.format(self._getFlag(config)) + def applyTo(self, config): + flag = self._getFlag(config) + assert hasCompileFlag( + config, flag + ), "Trying to enable link flag {}, which is not supported".format(flag) + config.substitutions = _prependToSubstitution( + config.substitutions, "%{link_flags}", flag + ) + + def pretty(self, config, litParams): + return "prepend {} to %{{link_flags}}".format(self._getFlag(config)) class AddOptionalWarningFlag(ConfigAction): - """ - This action adds the given warning flag to the %{compile_flags} substitution, - if it is supported by the compiler. + """ + This action adds the given warning flag to the %{compile_flags} substitution, + if it is supported by the compiler. - The flag can be a string or a callable, in which case it is called with the - configuration to produce the actual flag (as a string). - """ - def __init__(self, flag): - self._getFlag = lambda config: flag(config) if callable(flag) else flag + The flag can be a string or a callable, in which case it is called with the + configuration to produce the actual flag (as a string). + """ - def applyTo(self, config): - flag = self._getFlag(config) - # Use -Werror to make sure we see an error about the flag being unsupported. - if hasCompileFlag(config, '-Werror ' + flag): - config.substitutions = _appendToSubstitution(config.substitutions, '%{compile_flags}', flag) + def __init__(self, flag): + self._getFlag = lambda config: flag(config) if callable(flag) else flag - def pretty(self, config, litParams): - return 'add {} to %{{compile_flags}}'.format(self._getFlag(config)) + def applyTo(self, config): + flag = self._getFlag(config) + # Use -Werror to make sure we see an error about the flag being unsupported. + if hasCompileFlag(config, "-Werror " + flag): + config.substitutions = _appendToSubstitution( + config.substitutions, "%{compile_flags}", flag + ) + def pretty(self, config, litParams): + return "add {} to %{{compile_flags}}".format(self._getFlag(config)) -class AddSubstitution(ConfigAction): - """ - This action adds the given substitution to the Lit configuration. - The substitution can be a string or a callable, in which case it is called - with the configuration to produce the actual substitution (as a string). - """ - def __init__(self, key, substitution): - self._key = key - self._getSub = lambda config: substitution(config) if callable(substitution) else substitution +class AddSubstitution(ConfigAction): + """ + This action adds the given substitution to the Lit configuration. - def applyTo(self, config): - key = self._key - sub = self._getSub(config) - config.substitutions.append((key, sub)) + The substitution can be a string or a callable, in which case it is called + with the configuration to produce the actual substitution (as a string). + """ - def pretty(self, config, litParams): - return 'add substitution {} = {}'.format(self._key, self._getSub(config)) + def __init__(self, key, substitution): + self._key = key + self._getSub = ( + lambda config: substitution(config) + if callable(substitution) + else substitution + ) + def applyTo(self, config): + key = self._key + sub = self._getSub(config) + config.substitutions.append((key, sub)) -class Feature(object): - """ - Represents a Lit available feature that is enabled whenever it is supported. + def pretty(self, config, litParams): + return "add substitution {} = {}".format(self._key, self._getSub(config)) - A feature like this informs the test suite about a capability of the compiler, - platform, etc. Unlike Parameters, it does not make sense to explicitly - control whether a Feature is enabled -- it should be enabled whenever it - is supported. - """ - def __init__(self, name, actions=None, when=lambda _: True): - """ - Create a Lit feature for consumption by a test suite. - - - name - The name of the feature. This is what will end up in Lit's available - features if the feature is enabled. This can be either a string or a - callable, in which case it is passed the TestingConfig and should - generate a string representing the name of the feature. - - - actions - An optional list of ConfigActions to apply when the feature is supported. - An AddFeature action is always created regardless of any actions supplied - here -- these actions are meant to perform more than setting a corresponding - Lit feature (e.g. adding compiler flags). If 'actions' is a callable, it - is called with the current configuration object to generate the actual - list of actions. - - - when - A callable that gets passed a TestingConfig and should return a - boolean representing whether the feature is supported in that - configuration. For example, this can use `hasCompileFlag` to - check whether the compiler supports the flag that the feature - represents. If omitted, the feature will always be considered - supported. - """ - self._name = name - self._actions = [] if actions is None else actions - self._isSupported = when - - def _getName(self, config): - name = self._name(config) if callable(self._name) else self._name - if not isinstance(name, str): - raise ValueError("Feature did not resolve to a name that's a string, got {}".format(name)) - return name - - def getActions(self, config): - """ - Return the list of actions associated to this feature. - - If the feature is not supported, an empty list is returned. - If the feature is supported, an `AddFeature` action is automatically added - to the returned list of actions, in addition to any actions provided on - construction. - """ - if not self._isSupported(config): - return [] - else: - actions = self._actions(config) if callable(self._actions) else self._actions - return [AddFeature(self._getName(config))] + actions - def pretty(self, config): - """ - Returns the Feature's name. +class Feature(object): """ - return self._getName(config) - - -def _str_to_bool(s): - """ - Convert a string value to a boolean. - - True values are "y", "yes", "t", "true", "on" and "1", regardless of capitalization. - False values are "n", "no", "f", "false", "off" and "0", regardless of capitalization. - """ - trueVals = ["y", "yes", "t", "true", "on", "1"] - falseVals = ["n", "no", "f", "false", "off", "0"] - lower = s.lower() - if lower in trueVals: - return True - elif lower in falseVals: - return False - else: - raise ValueError("Got string '{}', which isn't a valid boolean".format(s)) - -def _parse_parameter(s, type): - if type is bool and isinstance(s, str): - return _str_to_bool(s) - elif type is list and isinstance(s, str): - return [x.strip() for x in s.split(',') if x.strip()] - return type(s) + Represents a Lit available feature that is enabled whenever it is supported. + A feature like this informs the test suite about a capability of the compiler, + platform, etc. Unlike Parameters, it does not make sense to explicitly + control whether a Feature is enabled -- it should be enabled whenever it + is supported. + """ -class Parameter(object): - """ - Represents a parameter of a Lit test suite. - - Parameters are used to customize the behavior of test suites in a user - controllable way. There are two ways of setting the value of a Parameter. - The first one is to pass `--param <KEY>=<VALUE>` when running Lit (or - equivalently to set `litConfig.params[KEY] = VALUE` somewhere in the - Lit configuration files. This method will set the parameter globally for - all test suites being run. - - The second method is to set `config.KEY = VALUE` somewhere in the Lit - configuration files, which sets the parameter only for the test suite(s) - that use that `config` object. - - Parameters can have multiple possible values, and they can have a default - value when left unspecified. They can also have any number of ConfigActions - associated to them, in which case the actions will be performed on the - TestingConfig if the parameter is enabled. Depending on the actions - associated to a Parameter, it may be an error to enable the Parameter - if some actions are not supported in the given configuration. For example, - trying to set the compilation standard to C++23 when `-std=c++23` is not - supported by the compiler would be an error. - """ - def __init__(self, name, type, help, actions, choices=None, default=None): - """ - Create a Lit parameter to customize the behavior of a test suite. - - - name - The name of the parameter that can be used to set it on the command-line. - On the command-line, the parameter can be set using `--param <name>=<value>` - when running Lit. This must be non-empty. - - - choices - An optional non-empty set of possible values for this parameter. If provided, - this must be anything that can be iterated. It is an error if the parameter - is given a value that is not in that set, whether explicitly or through a - default value. - - - type - A callable that can be used to parse the value of the parameter given - on the command-line. As a special case, using the type `bool` also - allows parsing strings with boolean-like contents, and the type `list` - will parse a string delimited by commas into a list of the substrings. - - - help - A string explaining the parameter, for documentation purposes. - TODO: We should be able to surface those from the Lit command-line. - - - actions - A callable that gets passed the parsed value of the parameter (either - the one passed on the command-line or the default one), and that returns - a list of ConfigAction to perform given the value of the parameter. - All the ConfigAction must be supported in the given configuration. - - - default - An optional default value to use for the parameter when no value is - provided on the command-line. If the default value is a callable, it - is called with the TestingConfig and should return the default value - for the parameter. Whether the default value is computed or specified - directly, it must be in the 'choices' provided for that Parameter. - """ - self._name = name - if len(self._name) == 0: - raise ValueError("Parameter name must not be the empty string") - - if choices is not None: - self._choices = list(choices) # should be finite - if len(self._choices) == 0: - raise ValueError("Parameter '{}' must be given at least one possible value".format(self._name)) - else: - self._choices = None + def __init__(self, name, actions=None, when=lambda _: True): + """ + Create a Lit feature for consumption by a test suite. + + - name + The name of the feature. This is what will end up in Lit's available + features if the feature is enabled. This can be either a string or a + callable, in which case it is passed the TestingConfig and should + generate a string representing the name of the feature. + + - actions + An optional list of ConfigActions to apply when the feature is supported. + An AddFeature action is always created regardless of any actions supplied + here -- these actions are meant to perform more than setting a corresponding + Lit feature (e.g. adding compiler flags). If 'actions' is a callable, it + is called with the current configuration object to generate the actual + list of actions. + + - when + A callable that gets passed a TestingConfig and should return a + boolean representing whether the feature is supported in that + configuration. For example, this can use `hasCompileFlag` to + check whether the compiler supports the flag that the feature + represents. If omitted, the feature will always be considered + supported. + """ + self._name = name + self._actions = [] if actions is None else actions + self._isSupported = when + + def _getName(self, config): + name = self._name(config) if callable(self._name) else self._name + if not isinstance(name, str): + raise ValueError( + "Feature did not resolve to a name that's a string, got {}".format(name) + ) + return name + + def getActions(self, config): + """ + Return the list of actions associated to this feature. + + If the feature is not supported, an empty list is returned. + If the feature is supported, an `AddFeature` action is automatically added + to the returned list of actions, in addition to any actions provided on + construction. + """ + if not self._isSupported(config): + return [] + else: + actions = ( + self._actions(config) if callable(self._actions) else self._actions + ) + return [AddFeature(self._getName(config))] + actions + + def pretty(self, config): + """ + Returns the Feature's name. + """ + return self._getName(config) - self._parse = lambda x: _parse_parameter(x, type) - self._help = help - self._actions = actions - self._default = default - def _getValue(self, config, litParams): - """ - Return the value of the parameter given the configuration objects. +def _str_to_bool(s): """ - param = getattr(config, self.name, None) - param = litParams.get(self.name, param) - if param is None and self._default is None: - raise ValueError("Parameter {} doesn't have a default value, but it was not specified in the Lit parameters or in the Lit config".format(self.name)) - getDefault = lambda: self._default(config) if callable(self._default) else self._default + Convert a string value to a boolean. - if param is not None: - (pretty, value) = (param, self._parse(param)) + True values are "y", "yes", "t", "true", "on" and "1", regardless of capitalization. + False values are "n", "no", "f", "false", "off" and "0", regardless of capitalization. + """ + trueVals = ["y", "yes", "t", "true", "on", "1"] + falseVals = ["n", "no", "f", "false", "off", "0"] + lower = s.lower() + if lower in trueVals: + return True + elif lower in falseVals: + return False else: - value = getDefault() - pretty = '{} (default)'.format(value) + raise ValueError("Got string '{}', which isn't a valid boolean".format(s)) - if self._choices and value not in self._choices: - raise ValueError("Got value '{}' for parameter '{}', which is not in the provided set of possible choices: {}".format(value, self.name, self._choices)) - return (pretty, value) - @property - def name(self): - """ - Return the name of the parameter. +def _parse_parameter(s, type): + if type is bool and isinstance(s, str): + return _str_to_bool(s) + elif type is list and isinstance(s, str): + return [x.strip() for x in s.split(",") if x.strip()] + return type(s) - This is the name that can be used to set the parameter on the command-line - when running Lit. - """ - return self._name - def getActions(self, config, litParams): +class Parameter(object): """ - Return the list of actions associated to this value of the parameter. + Represents a parameter of a Lit test suite. + + Parameters are used to customize the behavior of test suites in a user + controllable way. There are two ways of setting the value of a Parameter. + The first one is to pass `--param <KEY>=<VALUE>` when running Lit (or + equivalently to set `litConfig.params[KEY] = VALUE` somewhere in the + Lit configuration files. This method will set the parameter globally for + all test suites being run. + + The second method is to set `config.KEY = VALUE` somewhere in the Lit + configuration files, which sets the parameter only for the test suite(s) + that use that `config` object. + + Parameters can have multiple possible values, and they can have a default + value when left unspecified. They can also have any number of ConfigActions + associated to them, in which case the actions will be performed on the + TestingConfig if the parameter is enabled. Depending on the actions + associated to a Parameter, it may be an error to enable the Parameter + if some actions are not supported in the given configuration. For example, + trying to set the compilation standard to C++23 when `-std=c++23` is not + supported by the compiler would be an error. """ - (_, parameterValue) = self._getValue(config, litParams) - return self._actions(parameterValue) - def pretty(self, config, litParams): - """ - Return a pretty representation of the parameter's name and value. - """ - (prettyParameterValue, _) = self._getValue(config, litParams) - return "{}={}".format(self.name, prettyParameterValue) + def __init__(self, name, type, help, actions, choices=None, default=None): + """ + Create a Lit parameter to customize the behavior of a test suite. + + - name + The name of the parameter that can be used to set it on the command-line. + On the command-line, the parameter can be set using `--param <name>=<value>` + when running Lit. This must be non-empty. + + - choices + An optional non-empty set of possible values for this parameter. If provided, + this must be anything that can be iterated. It is an error if the parameter + is given a value that is not in that set, whether explicitly or through a + default value. + + - type + A callable that can be used to parse the value of the parameter given + on the command-line. As a special case, using the type `bool` also + allows parsing strings with boolean-like contents, and the type `list` + will parse a string delimited by commas into a list of the substrings. + + - help + A string explaining the parameter, for documentation purposes. + TODO: We should be able to surface those from the Lit command-line. + + - actions + A callable that gets passed the parsed value of the parameter (either + the one passed on the command-line or the default one), and that returns + a list of ConfigAction to perform given the value of the parameter. + All the ConfigAction must be supported in the given configuration. + + - default + An optional default value to use for the parameter when no value is + provided on the command-line. If the default value is a callable, it + is called with the TestingConfig and should return the default value + for the parameter. Whether the default value is computed or specified + directly, it must be in the 'choices' provided for that Parameter. + """ + self._name = name + if len(self._name) == 0: + raise ValueError("Parameter name must not be the empty string") + + if choices is not None: + self._choices = list(choices) # should be finite + if len(self._choices) == 0: + raise ValueError( + "Parameter '{}' must be given at least one possible value".format( + self._name + ) + ) + else: + self._choices = None + + self._parse = lambda x: _parse_parameter(x, type) + self._help = help + self._actions = actions + self._default = default + + def _getValue(self, config, litParams): + """ + Return the value of the parameter given the configuration objects. + """ + param = getattr(config, self.name, None) + param = litParams.get(self.name, param) + if param is None and self._default is None: + raise ValueError( + "Parameter {} doesn't have a default value, but it was not specified in the Lit parameters or in the Lit config".format( + self.name + ) + ) + getDefault = ( + lambda: self._default(config) if callable(self._default) else self._default + ) + + if param is not None: + (pretty, value) = (param, self._parse(param)) + else: + value = getDefault() + pretty = "{} (default)".format(value) + + if self._choices and value not in self._choices: + raise ValueError( + "Got value '{}' for parameter '{}', which is not in the provided set of possible choices: {}".format( + value, self.name, self._choices + ) + ) + return (pretty, value) + + @property + def name(self): + """ + Return the name of the parameter. + + This is the name that can be used to set the parameter on the command-line + when running Lit. + """ + return self._name + + def getActions(self, config, litParams): + """ + Return the list of actions associated to this value of the parameter. + """ + (_, parameterValue) = self._getValue(config, litParams) + return self._actions(parameterValue) + + def pretty(self, config, litParams): + """ + Return a pretty representation of the parameter's name and value. + """ + (prettyParameterValue, _) = self._getValue(config, litParams) + return "{}={}".format(self.name, prettyParameterValue) diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py index a55d242..b4478b5 100644 --- a/libcxx/utils/libcxx/test/features.py +++ b/libcxx/utils/libcxx/test/features.py @@ -1,10 +1,10 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 * from lit.BooleanExpression import BooleanExpression @@ -13,107 +13,176 @@ import shutil import subprocess import sys -_isClang = lambda cfg: '__clang__' in compilerMacros(cfg) and '__apple_build_version__' not in compilerMacros(cfg) -_isAppleClang = lambda cfg: '__apple_build_version__' in compilerMacros(cfg) -_isGCC = lambda cfg: '__GNUC__' in compilerMacros(cfg) and '__clang__' not in compilerMacros(cfg) -_isMSVC = lambda cfg: '_MSC_VER' in compilerMacros(cfg) -_msvcVersion = lambda cfg: (int(compilerMacros(cfg)['_MSC_VER']) // 100, int(compilerMacros(cfg)['_MSC_VER']) % 100) +_isClang = lambda cfg: "__clang__" in compilerMacros( + cfg +) and "__apple_build_version__" not in compilerMacros(cfg) +_isAppleClang = lambda cfg: "__apple_build_version__" in compilerMacros(cfg) +_isGCC = lambda cfg: "__GNUC__" in compilerMacros( + cfg +) and "__clang__" not in compilerMacros(cfg) +_isMSVC = lambda cfg: "_MSC_VER" in compilerMacros(cfg) +_msvcVersion = lambda cfg: ( + int(compilerMacros(cfg)["_MSC_VER"]) // 100, + int(compilerMacros(cfg)["_MSC_VER"]) % 100, +) -def _getSuitableClangTidy(cfg): - try: - # If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests. - if runScriptExitCode(cfg, ['stat %{test-tools}/clang_tidy_checks/libcxx-tidy.plugin']) != 0: - return None - - # TODO This should be the last stable release. - # LLVM RELEASE bump to latest stable version - if runScriptExitCode(cfg, ['clang-tidy-16 --version']) == 0: - return 'clang-tidy-16' - # LLVM RELEASE bump version - if int(re.search('[0-9]+', commandOutput(cfg, ['clang-tidy --version'])).group()) >= 16: - return 'clang-tidy' +def _getSuitableClangTidy(cfg): + try: + # If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests. + if ( + runScriptExitCode( + cfg, ["stat %{test-tools}/clang_tidy_checks/libcxx-tidy.plugin"] + ) + != 0 + ): + return None + + # TODO This should be the last stable release. + # LLVM RELEASE bump to latest stable version + if runScriptExitCode(cfg, ["clang-tidy-16 --version"]) == 0: + return "clang-tidy-16" + + # LLVM RELEASE bump version + if ( + int( + re.search( + "[0-9]+", commandOutput(cfg, ["clang-tidy --version"]) + ).group() + ) + >= 16 + ): + return "clang-tidy" + + except ConfigurationRuntimeError: + return None - except ConfigurationRuntimeError: - return None DEFAULT_FEATURES = [ - Feature(name='thread-safety', - when=lambda cfg: hasCompileFlag(cfg, '-Werror=thread-safety'), - actions=[AddCompileFlag('-Werror=thread-safety')]), - - Feature(name='diagnose-if-support', - when=lambda cfg: hasCompileFlag(cfg, '-Wuser-defined-warnings'), - actions=[AddCompileFlag('-Wuser-defined-warnings')]), - - # Tests to validate whether the compiler has a way to set the maximum number - # of steps during constant evaluation. Since the flag differs per compiler - # store the "valid" flag as a feature. This allows passing the proper compile - # flag to the compiler: - # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12345678 - # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=12345678 - Feature(name='has-fconstexpr-steps', - when=lambda cfg: hasCompileFlag(cfg, '-fconstexpr-steps=1')), - - Feature(name='has-fconstexpr-ops-limit', - when=lambda cfg: hasCompileFlag(cfg, '-fconstexpr-ops-limit=1')), - - Feature(name='has-fblocks', when=lambda cfg: hasCompileFlag(cfg, '-fblocks')), - Feature(name='-fsized-deallocation', when=lambda cfg: hasCompileFlag(cfg, '-fsized-deallocation')), - Feature(name='-faligned-allocation', when=lambda cfg: hasCompileFlag(cfg, '-faligned-allocation')), - Feature(name='fdelayed-template-parsing', when=lambda cfg: hasCompileFlag(cfg, '-fdelayed-template-parsing')), - Feature(name='libcpp-no-coroutines', when=lambda cfg: featureTestMacros(cfg).get('__cpp_impl_coroutine', 0) < 201902), - Feature(name='has-fobjc-arc', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc') and - sys.platform.lower().strip() == 'darwin'), # TODO: this doesn't handle cross-compiling to Apple platforms. - Feature(name='objective-c++', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc')), - Feature(name='verify-support', when=lambda cfg: hasCompileFlag(cfg, '-Xclang -verify-ignore-unexpected')), - - Feature(name='non-lockfree-atomics', - when=lambda cfg: sourceBuilds(cfg, """ + Feature( + name="thread-safety", + when=lambda cfg: hasCompileFlag(cfg, "-Werror=thread-safety"), + actions=[AddCompileFlag("-Werror=thread-safety")], + ), + Feature( + name="diagnose-if-support", + when=lambda cfg: hasCompileFlag(cfg, "-Wuser-defined-warnings"), + actions=[AddCompileFlag("-Wuser-defined-warnings")], + ), + # Tests to validate whether the compiler has a way to set the maximum number + # of steps during constant evaluation. Since the flag differs per compiler + # store the "valid" flag as a feature. This allows passing the proper compile + # flag to the compiler: + # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12345678 + # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=12345678 + Feature( + name="has-fconstexpr-steps", + when=lambda cfg: hasCompileFlag(cfg, "-fconstexpr-steps=1"), + ), + Feature( + name="has-fconstexpr-ops-limit", + when=lambda cfg: hasCompileFlag(cfg, "-fconstexpr-ops-limit=1"), + ), + Feature(name="has-fblocks", when=lambda cfg: hasCompileFlag(cfg, "-fblocks")), + Feature( + name="-fsized-deallocation", + when=lambda cfg: hasCompileFlag(cfg, "-fsized-deallocation"), + ), + Feature( + name="-faligned-allocation", + when=lambda cfg: hasCompileFlag(cfg, "-faligned-allocation"), + ), + Feature( + name="fdelayed-template-parsing", + when=lambda cfg: hasCompileFlag(cfg, "-fdelayed-template-parsing"), + ), + Feature( + name="libcpp-no-coroutines", + when=lambda cfg: featureTestMacros(cfg).get("__cpp_impl_coroutine", 0) < 201902, + ), + Feature( + name="has-fobjc-arc", + when=lambda cfg: hasCompileFlag(cfg, "-xobjective-c++ -fobjc-arc") + and sys.platform.lower().strip() == "darwin", + ), # TODO: this doesn't handle cross-compiling to Apple platforms. + Feature( + name="objective-c++", + when=lambda cfg: hasCompileFlag(cfg, "-xobjective-c++ -fobjc-arc"), + ), + Feature( + name="verify-support", + when=lambda cfg: hasCompileFlag(cfg, "-Xclang -verify-ignore-unexpected"), + ), + Feature( + name="non-lockfree-atomics", + when=lambda cfg: sourceBuilds( + cfg, + """ #include <atomic> struct Large { int storage[100]; }; std::atomic<Large> x; int main(int, char**) { (void)x.load(); return 0; } - """)), - # TODO: Remove this feature once compiler-rt includes __atomic_is_lockfree() - # on all supported platforms. - Feature(name='is-lockfree-runtime-function', - when=lambda cfg: sourceBuilds(cfg, """ + """, + ), + ), + # TODO: Remove this feature once compiler-rt includes __atomic_is_lockfree() + # on all supported platforms. + Feature( + name="is-lockfree-runtime-function", + when=lambda cfg: sourceBuilds( + cfg, + """ #include <atomic> struct Large { int storage[100]; }; std::atomic<Large> x; int main(int, char**) { return x.is_lock_free(); } - """)), - - # Some tests rely on creating shared libraries which link in the C++ Standard Library. In some - # cases, this doesn't work (e.g. if the library was built as a static archive and wasn't compiled - # as position independent). This feature informs the test suite of whether it's possible to create - # a shared library in a shell test by using the '-shared' compiler flag. - # - # Note: To implement this check properly, we need to make sure that we use something inside the - # compiled library, not only in the headers. It should be safe to assume that all implementations - # define `operator new` in the compiled library. - Feature(name='cant-build-shared-library', - when=lambda cfg: not sourceBuilds(cfg, """ + """, + ), + ), + # Some tests rely on creating shared libraries which link in the C++ Standard Library. In some + # cases, this doesn't work (e.g. if the library was built as a static archive and wasn't compiled + # as position independent). This feature informs the test suite of whether it's possible to create + # a shared library in a shell test by using the '-shared' compiler flag. + # + # Note: To implement this check properly, we need to make sure that we use something inside the + # compiled library, not only in the headers. It should be safe to assume that all implementations + # define `operator new` in the compiled library. + Feature( + name="cant-build-shared-library", + when=lambda cfg: not sourceBuilds( + cfg, + """ void f() { new int(3); } - """, ['-shared'])), - - # 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(name='win32-broken-utf8-wchar-ctype', - when=lambda cfg: not '_LIBCPP_HAS_NO_LOCALIZATION' in compilerMacros(cfg) and '_WIN32' in compilerMacros(cfg) and not programSucceeds(cfg, """ + """, + ["-shared"], + ), + ), + # 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( + name="win32-broken-utf8-wchar-ctype", + when=lambda cfg: not "_LIBCPP_HAS_NO_LOCALIZATION" in compilerMacros(cfg) + and "_WIN32" in compilerMacros(cfg) + and not programSucceeds( + cfg, + """ #include <locale.h> #include <wctype.h> int main(int, char**) { setlocale(LC_ALL, "en_US.UTF-8"); return towlower(L'\\xDA') != L'\\xFA'; } - """)), - - # Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.19041.0). - # https://developercommunity.visualstudio.com/t/printf-formatting-with-g-outputs-too/1660837 - Feature(name='win32-broken-printf-g-precision', - when=lambda cfg: '_WIN32' in compilerMacros(cfg) and not programSucceeds(cfg, """ + """, + ), + ), + # Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.19041.0). + # https://developercommunity.visualstudio.com/t/printf-formatting-with-g-outputs-too/1660837 + Feature( + name="win32-broken-printf-g-precision", + when=lambda cfg: "_WIN32" in compilerMacros(cfg) + and not programSucceeds( + cfg, + """ #include <stdio.h> #include <string.h> int main(int, char**) { @@ -121,70 +190,126 @@ DEFAULT_FEATURES = [ snprintf(buf, sizeof(buf), "%#.*g", 0, 0.0); return strcmp(buf, "0."); } - """)), - - # Check for Glibc < 2.27, where the ru_RU.UTF-8 locale had - # mon_decimal_point == ".", which our tests don't handle. - Feature(name='glibc-old-ru_RU-decimal-point', - when=lambda cfg: not '_LIBCPP_HAS_NO_LOCALIZATION' in compilerMacros(cfg) and not programSucceeds(cfg, """ + """, + ), + ), + # Check for Glibc < 2.27, where the ru_RU.UTF-8 locale had + # mon_decimal_point == ".", which our tests don't handle. + Feature( + name="glibc-old-ru_RU-decimal-point", + when=lambda cfg: not "_LIBCPP_HAS_NO_LOCALIZATION" in compilerMacros(cfg) + and not programSucceeds( + cfg, + """ #include <locale.h> #include <string.h> int main(int, char**) { setlocale(LC_ALL, "ru_RU.UTF-8"); return strcmp(localeconv()->mon_decimal_point, ","); } - """)), - - Feature(name='has-unix-headers', - when=lambda cfg: sourceBuilds(cfg, """ + """, + ), + ), + Feature( + name="has-unix-headers", + when=lambda cfg: sourceBuilds( + cfg, + """ #include <unistd.h> #include <sys/wait.h> int main(int, char**) { return 0; } - """)), - - # Whether Bash can run on the executor. - # This is not always the case, for example when running on embedded systems. - # - # For the corner case of bash existing, but it being missing in the path - # set in %{exec} as "--env PATH=one-single-dir", the executor does find - # and executes bash, but bash then can't find any other common shell - # utilities. Test executing "bash -c 'bash --version'" to see if bash - # manages to find binaries to execute. - Feature(name='executor-has-no-bash', - when=lambda cfg: runScriptExitCode(cfg, ['%{exec} bash -c \'bash --version\'']) != 0), - Feature(name='has-clang-tidy', - when=lambda cfg: _getSuitableClangTidy(cfg) is not None, - actions=[AddSubstitution('%{clang-tidy}', lambda cfg: _getSuitableClangTidy(cfg))]), - - Feature(name='apple-clang', when=_isAppleClang), - Feature(name=lambda cfg: 'apple-clang-{__clang_major__}'.format(**compilerMacros(cfg)), when=_isAppleClang), - Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)), when=_isAppleClang), - Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isAppleClang), - - Feature(name='clang', when=_isClang), - Feature(name=lambda cfg: 'clang-{__clang_major__}'.format(**compilerMacros(cfg)), when=_isClang), - Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)), when=_isClang), - Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isClang), - - # Note: Due to a GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104760), we must disable deprecation warnings - # on GCC or spurious diagnostics are issued. - # - # TODO: - # - Enable -Wplacement-new with GCC. - # - Enable -Wclass-memaccess with GCC. - Feature(name='gcc', when=_isGCC, - actions=[AddCompileFlag('-D_LIBCPP_DISABLE_DEPRECATION_WARNINGS'), - AddCompileFlag('-Wno-placement-new'), - AddCompileFlag('-Wno-class-memaccess')]), - Feature(name=lambda cfg: 'gcc-{__GNUC__}'.format(**compilerMacros(cfg)), when=_isGCC), - Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}'.format(**compilerMacros(cfg)), when=_isGCC), - Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}'.format(**compilerMacros(cfg)), when=_isGCC), - - Feature(name='msvc', when=_isMSVC), - Feature(name=lambda cfg: 'msvc-{}'.format(*_msvcVersion(cfg)), when=_isMSVC), - Feature(name=lambda cfg: 'msvc-{}.{}'.format(*_msvcVersion(cfg)), when=_isMSVC), + """, + ), + ), + # Whether Bash can run on the executor. + # This is not always the case, for example when running on embedded systems. + # + # For the corner case of bash existing, but it being missing in the path + # set in %{exec} as "--env PATH=one-single-dir", the executor does find + # and executes bash, but bash then can't find any other common shell + # utilities. Test executing "bash -c 'bash --version'" to see if bash + # manages to find binaries to execute. + Feature( + name="executor-has-no-bash", + when=lambda cfg: runScriptExitCode(cfg, ["%{exec} bash -c 'bash --version'"]) + != 0, + ), + Feature( + name="has-clang-tidy", + when=lambda cfg: _getSuitableClangTidy(cfg) is not None, + actions=[ + AddSubstitution("%{clang-tidy}", lambda cfg: _getSuitableClangTidy(cfg)) + ], + ), + Feature(name="apple-clang", when=_isAppleClang), + Feature( + name=lambda cfg: "apple-clang-{__clang_major__}".format(**compilerMacros(cfg)), + when=_isAppleClang, + ), + Feature( + name=lambda cfg: "apple-clang-{__clang_major__}.{__clang_minor__}".format( + **compilerMacros(cfg) + ), + when=_isAppleClang, + ), + Feature( + name=lambda cfg: "apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format( + **compilerMacros(cfg) + ), + when=_isAppleClang, + ), + Feature(name="clang", when=_isClang), + Feature( + name=lambda cfg: "clang-{__clang_major__}".format(**compilerMacros(cfg)), + when=_isClang, + ), + Feature( + name=lambda cfg: "clang-{__clang_major__}.{__clang_minor__}".format( + **compilerMacros(cfg) + ), + when=_isClang, + ), + Feature( + name=lambda cfg: "clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format( + **compilerMacros(cfg) + ), + when=_isClang, + ), + # Note: Due to a GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104760), we must disable deprecation warnings + # on GCC or spurious diagnostics are issued. + # + # TODO: + # - Enable -Wplacement-new with GCC. + # - Enable -Wclass-memaccess with GCC. + Feature( + name="gcc", + when=_isGCC, + actions=[ + AddCompileFlag("-D_LIBCPP_DISABLE_DEPRECATION_WARNINGS"), + AddCompileFlag("-Wno-placement-new"), + AddCompileFlag("-Wno-class-memaccess"), + ], + ), + Feature( + name=lambda cfg: "gcc-{__GNUC__}".format(**compilerMacros(cfg)), when=_isGCC + ), + Feature( + name=lambda cfg: "gcc-{__GNUC__}.{__GNUC_MINOR__}".format( + **compilerMacros(cfg) + ), + when=_isGCC, + ), + Feature( + name=lambda cfg: "gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}".format( + **compilerMacros(cfg) + ), + when=_isGCC, + ), + Feature(name="msvc", when=_isMSVC), + Feature(name=lambda cfg: "msvc-{}".format(*_msvcVersion(cfg)), when=_isMSVC), + Feature(name=lambda cfg: "msvc-{}.{}".format(*_msvcVersion(cfg)), when=_isMSVC), ] # Deduce and add the test features that that are implied by the #defines in @@ -198,54 +323,70 @@ DEFAULT_FEATURES = [ # Note that features that are more strongly tied to libc++ are named libcpp-foo, # while features that are more general in nature are not prefixed with 'libcpp-'. macros = { - '_LIBCPP_HAS_NO_MONOTONIC_CLOCK': 'no-monotonic-clock', - '_LIBCPP_HAS_NO_THREADS': 'no-threads', - '_LIBCPP_HAS_THREAD_API_EXTERNAL': 'libcpp-has-thread-api-external', - '_LIBCPP_HAS_THREAD_API_PTHREAD': 'libcpp-has-thread-api-pthread', - '_LIBCPP_NO_VCRUNTIME': 'libcpp-no-vcruntime', - '_LIBCPP_ABI_VERSION': 'libcpp-abi-version', - '_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY': 'no-filesystem', - '_LIBCPP_HAS_NO_RANDOM_DEVICE': 'no-random-device', - '_LIBCPP_HAS_NO_LOCALIZATION': 'no-localization', - '_LIBCPP_HAS_NO_FSTREAM': 'no-fstream', - '_LIBCPP_HAS_NO_WIDE_CHARACTERS': 'no-wide-characters', - '_LIBCPP_HAS_NO_UNICODE': 'libcpp-has-no-unicode', - '_LIBCPP_ENABLE_DEBUG_MODE': 'libcpp-has-debug-mode', + "_LIBCPP_HAS_NO_MONOTONIC_CLOCK": "no-monotonic-clock", + "_LIBCPP_HAS_NO_THREADS": "no-threads", + "_LIBCPP_HAS_THREAD_API_EXTERNAL": "libcpp-has-thread-api-external", + "_LIBCPP_HAS_THREAD_API_PTHREAD": "libcpp-has-thread-api-pthread", + "_LIBCPP_NO_VCRUNTIME": "libcpp-no-vcruntime", + "_LIBCPP_ABI_VERSION": "libcpp-abi-version", + "_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY": "no-filesystem", + "_LIBCPP_HAS_NO_RANDOM_DEVICE": "no-random-device", + "_LIBCPP_HAS_NO_LOCALIZATION": "no-localization", + "_LIBCPP_HAS_NO_FSTREAM": "no-fstream", + "_LIBCPP_HAS_NO_WIDE_CHARACTERS": "no-wide-characters", + "_LIBCPP_HAS_NO_UNICODE": "libcpp-has-no-unicode", + "_LIBCPP_ENABLE_DEBUG_MODE": "libcpp-has-debug-mode", } for macro, feature in macros.items(): - DEFAULT_FEATURES.append( - Feature(name=lambda cfg, m=macro, f=feature: f + ('={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''), - when=lambda cfg, m=macro: m in compilerMacros(cfg)) - ) + DEFAULT_FEATURES.append( + Feature( + name=lambda cfg, m=macro, f=feature: f + + ("={}".format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ""), + when=lambda cfg, m=macro: m in compilerMacros(cfg), + ) + ) # Mapping from canonical locale names (used in the tests) to possible locale # names on various systems. Each locale is considered supported if any of the # alternative names is supported. locales = { - 'en_US.UTF-8': ['en_US.UTF-8', 'en_US.utf8', 'English_United States.1252'], - 'fr_FR.UTF-8': ['fr_FR.UTF-8', 'fr_FR.utf8', 'French_France.1252'], - 'ja_JP.UTF-8': ['ja_JP.UTF-8', 'ja_JP.utf8', 'Japanese_Japan.923'], - 'ru_RU.UTF-8': ['ru_RU.UTF-8', 'ru_RU.utf8', 'Russian_Russia.1251'], - 'zh_CN.UTF-8': ['zh_CN.UTF-8', 'zh_CN.utf8', 'Chinese_China.936'], - 'fr_CA.ISO8859-1': ['fr_CA.ISO8859-1', 'French_Canada.1252'], - 'cs_CZ.ISO8859-2': ['cs_CZ.ISO8859-2', 'Czech_Czech Republic.1250'] + "en_US.UTF-8": ["en_US.UTF-8", "en_US.utf8", "English_United States.1252"], + "fr_FR.UTF-8": ["fr_FR.UTF-8", "fr_FR.utf8", "French_France.1252"], + "ja_JP.UTF-8": ["ja_JP.UTF-8", "ja_JP.utf8", "Japanese_Japan.923"], + "ru_RU.UTF-8": ["ru_RU.UTF-8", "ru_RU.utf8", "Russian_Russia.1251"], + "zh_CN.UTF-8": ["zh_CN.UTF-8", "zh_CN.utf8", "Chinese_China.936"], + "fr_CA.ISO8859-1": ["fr_CA.ISO8859-1", "French_Canada.1252"], + "cs_CZ.ISO8859-2": ["cs_CZ.ISO8859-2", "Czech_Czech Republic.1250"], } for locale, alts in locales.items(): - # Note: Using alts directly in the lambda body here will bind it to the value at the - # end of the loop. Assigning it to a default argument works around this issue. - DEFAULT_FEATURES.append(Feature(name='locale.{}'.format(locale), - when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts))) + # Note: Using alts directly in the lambda body here will bind it to the value at the + # end of the loop. Assigning it to a default argument works around this issue. + DEFAULT_FEATURES.append( + Feature( + name="locale.{}".format(locale), + when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts), + ) + ) # Add features representing the target platform name: darwin, linux, windows, etc... DEFAULT_FEATURES += [ - Feature(name='darwin', when=lambda cfg: '__APPLE__' in compilerMacros(cfg)), - Feature(name='windows', when=lambda cfg: '_WIN32' in compilerMacros(cfg)), - Feature(name='windows-dll', when=lambda cfg: '_WIN32' in compilerMacros(cfg) and sourceBuilds(cfg, """ + Feature(name="darwin", when=lambda cfg: "__APPLE__" in compilerMacros(cfg)), + Feature(name="windows", when=lambda cfg: "_WIN32" in compilerMacros(cfg)), + Feature( + name="windows-dll", + when=lambda cfg: "_WIN32" in compilerMacros(cfg) + and sourceBuilds( + cfg, + """ #include <iostream> int main(int, char**) { return 0; } - """) and programSucceeds(cfg, """ + """, + ) + and programSucceeds( + cfg, + """ #include <iostream> #include <windows.h> #include <winnt.h> @@ -272,57 +413,76 @@ DEFAULT_FEATURES += [ // loaded from a DLL. return 0; } - """), actions=[AddCompileFlag('-DTEST_WINDOWS_DLL')]), - Feature(name='linux', when=lambda cfg: '__linux__' in compilerMacros(cfg)), - Feature(name='netbsd', when=lambda cfg: '__NetBSD__' in compilerMacros(cfg)), - Feature(name='freebsd', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg)), - Feature(name='LIBCXX-FREEBSD-FIXME', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg)), + """, + ), + actions=[AddCompileFlag("-DTEST_WINDOWS_DLL")], + ), + Feature(name="linux", when=lambda cfg: "__linux__" in compilerMacros(cfg)), + Feature(name="netbsd", when=lambda cfg: "__NetBSD__" in compilerMacros(cfg)), + Feature(name="freebsd", when=lambda cfg: "__FreeBSD__" in compilerMacros(cfg)), + Feature( + name="LIBCXX-FREEBSD-FIXME", + when=lambda cfg: "__FreeBSD__" in compilerMacros(cfg), + ), ] # Add features representing the build host platform name. # The build host could differ from the target platform for cross-compilation. DEFAULT_FEATURES += [ - Feature(name='buildhost={}'.format(sys.platform.lower().strip())), - # sys.platform can often be represented by a "sub-system", such as 'win32', 'cygwin', 'mingw', freebsd13 & etc. - # We define a consolidated feature on a few platforms. - Feature(name='buildhost=windows', when=lambda cfg: platform.system().lower().startswith('windows')), - Feature(name='buildhost=freebsd', when=lambda cfg: platform.system().lower().startswith('freebsd')), - Feature(name='buildhost=aix', when=lambda cfg: platform.system().lower().startswith('aix')) + Feature(name="buildhost={}".format(sys.platform.lower().strip())), + # sys.platform can often be represented by a "sub-system", such as 'win32', 'cygwin', 'mingw', freebsd13 & etc. + # We define a consolidated feature on a few platforms. + Feature( + name="buildhost=windows", + when=lambda cfg: platform.system().lower().startswith("windows"), + ), + Feature( + name="buildhost=freebsd", + when=lambda cfg: platform.system().lower().startswith("freebsd"), + ), + Feature( + name="buildhost=aix", + when=lambda cfg: platform.system().lower().startswith("aix"), + ), ] # Detect whether GDB is on the system, has Python scripting and supports # adding breakpoint commands. If so add a substitution to access it. def check_gdb(cfg): - gdb_path = shutil.which('gdb') - if gdb_path is None: - return False - - # Check that we can set breakpoint commands, which was added in 8.3. - # Using the quit command here means that gdb itself exits, not just - # the "python <...>" command. - test_src = """\ + gdb_path = shutil.which("gdb") + if gdb_path is None: + return False + + # Check that we can set breakpoint commands, which was added in 8.3. + # Using the quit command here means that gdb itself exits, not just + # the "python <...>" command. + test_src = """\ try: gdb.Breakpoint(\"main\").commands=\"foo\" except AttributeError: gdb.execute(\"quit 1\") gdb.execute(\"quit\")""" - try: - stdout = subprocess.check_output( - [gdb_path, "-ex", "python " + test_src, "--batch"], - stderr=subprocess.DEVNULL, universal_newlines=True) - except subprocess.CalledProcessError: - # We can't set breakpoint commands - return False + try: + stdout = subprocess.check_output( + [gdb_path, "-ex", "python " + test_src, "--batch"], + stderr=subprocess.DEVNULL, + universal_newlines=True, + ) + except subprocess.CalledProcessError: + # We can't set breakpoint commands + return False + + # Check we actually ran the Python + return not "Python scripting is not supported" in stdout - # Check we actually ran the Python - return not "Python scripting is not supported" in stdout DEFAULT_FEATURES += [ - Feature(name='host-has-gdb-with-python', - when=check_gdb, - actions=[AddSubstitution('%{gdb}', lambda cfg: shutil.which('gdb'))] - ) + Feature( + name="host-has-gdb-with-python", + when=check_gdb, + actions=[AddSubstitution("%{gdb}", lambda cfg: shutil.which("gdb"))], + ) ] # Define features for back-deployment testing. @@ -339,56 +499,105 @@ DEFAULT_FEATURES += [ # be achieved by creating a `.verify.cpp` test that checks for the right errors, and # mark that test as requiring `stdlib=<vendor>-libc++ && target=<target>`. DEFAULT_FEATURES += [ - # Tests that require std::to_chars(floating-point) in the built library - Feature(name='availability-fp_to_chars-missing', - 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)), - - # Tests that require https://wg21.link/P0482 support in the built library - Feature(name='availability-char8_t_support-missing', - 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)), - - # Tests that require __libcpp_verbose_abort support in the built library - Feature(name='availability-verbose_abort-missing', - 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)), - - # Tests that require std::bad_variant_access in the built library - Feature(name='availability-bad_variant_access-missing', - when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)), - - # Tests that require std::bad_optional_access in the built library - Feature(name='availability-bad_optional_access-missing', - when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)), - - # Tests that require std::bad_any_cast in the built library - Feature(name='availability-bad_any_cast-missing', - when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)), - - # Tests that require std::pmr support in the built library - Feature(name='availability-pmr-missing', - 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)), - - # Tests that require std::filesystem support in the built library - Feature(name='availability-filesystem-missing', - when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14)(.0)?}}', cfg.available_features)), - - # Tests that require the C++20 synchronization library (P1135R6 implemented by https://llvm.org/D68480) in the built library - Feature(name='availability-synchronization_library-missing', - when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14|15)(.0)?}}', cfg.available_features)), - - # Tests that require support for std::shared_mutex and std::shared_timed_mutex in the built library - Feature(name='availability-shared_mutex-missing', - when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11)(.0)?}}', cfg.available_features)), - - # Tests that require support for aligned allocation in the built library. This is about `operator new(..., std::align_val_t, ...)` specifically, - # not other forms of aligned allocation. - Feature(name='availability-aligned_allocation-missing', - when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)), - - # Tests that require 64-bit architecture - Feature(name='32-bit-pointer', - when=lambda cfg: sourceBuilds(cfg, """ + # Tests that require std::to_chars(floating-point) in the built library + Feature( + name="availability-fp_to_chars-missing", + 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, + ), + ), + # Tests that require https://wg21.link/P0482 support in the built library + Feature( + name="availability-char8_t_support-missing", + 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, + ), + ), + # Tests that require __libcpp_verbose_abort support in the built library + Feature( + name="availability-verbose_abort-missing", + 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, + ), + ), + # Tests that require std::bad_variant_access in the built library + Feature( + name="availability-bad_variant_access-missing", + when=lambda cfg: BooleanExpression.evaluate( + "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}", + cfg.available_features, + ), + ), + # Tests that require std::bad_optional_access in the built library + Feature( + name="availability-bad_optional_access-missing", + when=lambda cfg: BooleanExpression.evaluate( + "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}", + cfg.available_features, + ), + ), + # Tests that require std::bad_any_cast in the built library + Feature( + name="availability-bad_any_cast-missing", + when=lambda cfg: BooleanExpression.evaluate( + "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}", + cfg.available_features, + ), + ), + # Tests that require std::pmr support in the built library + Feature( + name="availability-pmr-missing", + 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, + ), + ), + # Tests that require std::filesystem support in the built library + Feature( + name="availability-filesystem-missing", + when=lambda cfg: BooleanExpression.evaluate( + "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14)(.0)?}}", + cfg.available_features, + ), + ), + # Tests that require the C++20 synchronization library (P1135R6 implemented by https://llvm.org/D68480) in the built library + Feature( + name="availability-synchronization_library-missing", + when=lambda cfg: BooleanExpression.evaluate( + "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14|15)(.0)?}}", + cfg.available_features, + ), + ), + # Tests that require support for std::shared_mutex and std::shared_timed_mutex in the built library + Feature( + name="availability-shared_mutex-missing", + when=lambda cfg: BooleanExpression.evaluate( + "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11)(.0)?}}", + cfg.available_features, + ), + ), + # Tests that require support for aligned allocation in the built library. This is about `operator new(..., std::align_val_t, ...)` specifically, + # not other forms of aligned allocation. + Feature( + name="availability-aligned_allocation-missing", + when=lambda cfg: BooleanExpression.evaluate( + "stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}", + cfg.available_features, + ), + ), + # Tests that require 64-bit architecture + Feature( + name="32-bit-pointer", + when=lambda cfg: sourceBuilds( + cfg, + """ int main(int, char**) { static_assert(sizeof(void *) == 4); } - """)), + """, + ), + ), ] diff --git a/libcxx/utils/libcxx/test/format.py b/libcxx/utils/libcxx/test/format.py index 2543923..6827b1b7 100644 --- a/libcxx/utils/libcxx/test/format.py +++ b/libcxx/utils/libcxx/test/format.py @@ -1,10 +1,10 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## import lit import lit.formats @@ -13,6 +13,7 @@ import pipes import re import shutil + def _getTempPaths(test): """ Return the values to use for the %T and %t substitutions, respectively. @@ -22,40 +23,45 @@ def _getTempPaths(test): """ tmpDir, _ = lit.TestRunner.getTempPaths(test) _, testName = os.path.split(test.getExecPath()) - tmpDir = os.path.join(tmpDir, testName + '.dir') - tmpBase = os.path.join(tmpDir, 't') + tmpDir = os.path.join(tmpDir, testName + ".dir") + tmpBase = os.path.join(tmpDir, "t") return tmpDir, tmpBase + def _checkBaseSubstitutions(substitutions): substitutions = [s for (s, _) in substitutions] - for s in ['%{cxx}', '%{compile_flags}', '%{link_flags}', '%{flags}', '%{exec}']: + for s in ["%{cxx}", "%{compile_flags}", "%{link_flags}", "%{flags}", "%{exec}"]: assert s in substitutions, "Required substitution {} was not provided".format(s) + def _executeScriptInternal(test, litConfig, commands): - """ - Returns (stdout, stderr, exitCode, timeoutInfo, parsedCommands) - - TODO: This really should be easier to access from Lit itself - """ - parsedCommands = parseScript(test, preamble=commands) - - _, tmpBase = _getTempPaths(test) - execDir = os.path.dirname(test.getExecPath()) - res = lit.TestRunner.executeScriptInternal(test, litConfig, tmpBase, parsedCommands, execDir) - if isinstance(res, lit.Test.Result): # Handle failure to parse the Lit test - res = ('', res.output, 127, None) - (out, err, exitCode, timeoutInfo) = res - - # TODO: As a temporary workaround until https://reviews.llvm.org/D81892 lands, manually - # split any stderr output that is included in stdout. It shouldn't be there, but - # the Lit internal shell conflates stderr and stdout. - conflatedErrorOutput = re.search("(# command stderr:.+$)", out, flags=re.DOTALL) - if conflatedErrorOutput: - conflatedErrorOutput = conflatedErrorOutput.group(0) - out = out[:-len(conflatedErrorOutput)] - err += conflatedErrorOutput - - return (out, err, exitCode, timeoutInfo, parsedCommands) + """ + Returns (stdout, stderr, exitCode, timeoutInfo, parsedCommands) + + TODO: This really should be easier to access from Lit itself + """ + parsedCommands = parseScript(test, preamble=commands) + + _, tmpBase = _getTempPaths(test) + execDir = os.path.dirname(test.getExecPath()) + res = lit.TestRunner.executeScriptInternal( + test, litConfig, tmpBase, parsedCommands, execDir + ) + if isinstance(res, lit.Test.Result): # Handle failure to parse the Lit test + res = ("", res.output, 127, None) + (out, err, exitCode, timeoutInfo) = res + + # TODO: As a temporary workaround until https://reviews.llvm.org/D81892 lands, manually + # split any stderr output that is included in stdout. It shouldn't be there, but + # the Lit internal shell conflates stderr and stdout. + conflatedErrorOutput = re.search("(# command stderr:.+$)", out, flags=re.DOTALL) + if conflatedErrorOutput: + conflatedErrorOutput = conflatedErrorOutput.group(0) + out = out[: -len(conflatedErrorOutput)] + err += conflatedErrorOutput + + return (out, err, exitCode, timeoutInfo, parsedCommands) + def parseScript(test, preamble): """ @@ -78,32 +84,41 @@ def parseScript(test, preamble): # Check base substitutions and add the %{build} and %{run} convenience substitutions _checkBaseSubstitutions(substitutions) - substitutions.append(('%{build}', '%{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe')) - substitutions.append(('%{run}', '%{exec} %t.exe')) + substitutions.append( + ("%{build}", "%{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe") + ) + substitutions.append(("%{run}", "%{exec} %t.exe")) # Parse the test file, including custom directives additionalCompileFlags = [] fileDependencies = [] parsers = [ - lit.TestRunner.IntegratedTestKeywordParser('FILE_DEPENDENCIES:', - lit.TestRunner.ParserKind.LIST, - initial_value=fileDependencies), - lit.TestRunner.IntegratedTestKeywordParser('ADDITIONAL_COMPILE_FLAGS:', - lit.TestRunner.ParserKind.LIST, - initial_value=additionalCompileFlags) + lit.TestRunner.IntegratedTestKeywordParser( + "FILE_DEPENDENCIES:", + lit.TestRunner.ParserKind.LIST, + initial_value=fileDependencies, + ), + lit.TestRunner.IntegratedTestKeywordParser( + "ADDITIONAL_COMPILE_FLAGS:", + lit.TestRunner.ParserKind.LIST, + initial_value=additionalCompileFlags, + ), ] # Add conditional parsers for ADDITIONAL_COMPILE_FLAGS. This should be replaced by first # class support for conditional keywords in Lit, which would allow evaluating arbitrary # Lit boolean expressions instead. for feature in test.config.available_features: - parser = lit.TestRunner.IntegratedTestKeywordParser('ADDITIONAL_COMPILE_FLAGS({}):'.format(feature), - lit.TestRunner.ParserKind.LIST, - initial_value=additionalCompileFlags) + parser = lit.TestRunner.IntegratedTestKeywordParser( + "ADDITIONAL_COMPILE_FLAGS({}):".format(feature), + lit.TestRunner.ParserKind.LIST, + initial_value=additionalCompileFlags, + ) parsers.append(parser) - scriptInTest = lit.TestRunner.parseIntegratedTestScript(test, additional_parsers=parsers, - require_script=not preamble) + scriptInTest = lit.TestRunner.parseIntegratedTestScript( + test, additional_parsers=parsers, require_script=not preamble + ) if isinstance(scriptInTest, lit.Test.Result): return scriptInTest @@ -113,17 +128,22 @@ def parseScript(test, preamble): # that file to the execution directory. Execute the copy from %S to allow # relative paths from the test directory. for dep in fileDependencies: - script += ['%dbg(SETUP) cd %S && cp {} %T'.format(dep)] + script += ["%dbg(SETUP) cd %S && cp {} %T".format(dep)] script += preamble script += scriptInTest # Add compile flags specified with ADDITIONAL_COMPILE_FLAGS. - substitutions = [(s, x + ' ' + ' '.join(additionalCompileFlags)) if s == '%{compile_flags}' - else (s, x) for (s, x) in substitutions] + substitutions = [ + (s, x + " " + " ".join(additionalCompileFlags)) + if s == "%{compile_flags}" + else (s, x) + for (s, x) in substitutions + ] # Perform substitutions in the script itself. - script = lit.TestRunner.applySubstitutions(script, substitutions, - recursion_limit=test.config.recursiveExpansionLimit) + script = lit.TestRunner.applySubstitutions( + script, substitutions, recursion_limit=test.config.recursiveExpansionLimit + ) return script @@ -213,80 +233,100 @@ class CxxStandardLibraryTest(lit.formats.TestFormat): Equivalent to `%{exec} %t.exe`. This is intended to be used in conjunction with the %{build} substitution. """ + def getTestsInDirectory(self, testSuite, pathInSuite, litConfig, localConfig): - SUPPORTED_SUFFIXES = ['[.]pass[.]cpp$', '[.]pass[.]mm$', - '[.]compile[.]pass[.]cpp$', '[.]compile[.]pass[.]mm$', - '[.]compile[.]fail[.]cpp$', - '[.]link[.]pass[.]cpp$', '[.]link[.]pass[.]mm$', - '[.]link[.]fail[.]cpp$', - '[.]sh[.][^.]+$', - '[.]verify[.]cpp$', - '[.]fail[.]cpp$'] + SUPPORTED_SUFFIXES = [ + "[.]pass[.]cpp$", + "[.]pass[.]mm$", + "[.]compile[.]pass[.]cpp$", + "[.]compile[.]pass[.]mm$", + "[.]compile[.]fail[.]cpp$", + "[.]link[.]pass[.]cpp$", + "[.]link[.]pass[.]mm$", + "[.]link[.]fail[.]cpp$", + "[.]sh[.][^.]+$", + "[.]verify[.]cpp$", + "[.]fail[.]cpp$", + ] sourcePath = testSuite.getSourcePath(pathInSuite) for filename in os.listdir(sourcePath): # Ignore dot files and excluded tests. - if filename.startswith('.') or filename in localConfig.excludes: + if filename.startswith(".") or filename in localConfig.excludes: continue filepath = os.path.join(sourcePath, filename) if not os.path.isdir(filepath): if any([re.search(ext, filename) for ext in SUPPORTED_SUFFIXES]): - yield lit.Test.Test(testSuite, pathInSuite + (filename,), localConfig) + yield lit.Test.Test( + testSuite, pathInSuite + (filename,), localConfig + ) def execute(self, test, litConfig): - VERIFY_FLAGS = '-Xclang -verify -Xclang -verify-ignore-unexpected=note -ferror-limit=0' - supportsVerify = 'verify-support' in test.config.available_features + VERIFY_FLAGS = ( + "-Xclang -verify -Xclang -verify-ignore-unexpected=note -ferror-limit=0" + ) + supportsVerify = "verify-support" in test.config.available_features filename = test.path_in_suite[-1] - if re.search('[.]sh[.][^.]+$', filename): - steps = [ ] # The steps are already in the script + if re.search("[.]sh[.][^.]+$", filename): + steps = [] # The steps are already in the script return self._executeShTest(test, litConfig, steps) - elif filename.endswith('.compile.pass.cpp') or filename.endswith('.compile.pass.mm'): + elif filename.endswith(".compile.pass.cpp") or filename.endswith( + ".compile.pass.mm" + ): steps = [ "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} -fsyntax-only" ] return self._executeShTest(test, litConfig, steps) - elif filename.endswith('.compile.fail.cpp'): + elif filename.endswith(".compile.fail.cpp"): steps = [ "%dbg(COMPILED WITH) ! %{cxx} %s %{flags} %{compile_flags} -fsyntax-only" ] return self._executeShTest(test, litConfig, steps) - elif filename.endswith('.link.pass.cpp') or filename.endswith('.link.pass.mm'): + elif filename.endswith(".link.pass.cpp") or filename.endswith(".link.pass.mm"): steps = [ "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe" ] return self._executeShTest(test, litConfig, steps) - elif filename.endswith('.link.fail.cpp'): + elif filename.endswith(".link.fail.cpp"): steps = [ "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} -c -o %t.o", - "%dbg(LINKED WITH) ! %{cxx} %t.o %{flags} %{link_flags} -o %t.exe" + "%dbg(LINKED WITH) ! %{cxx} %t.o %{flags} %{link_flags} -o %t.exe", ] return self._executeShTest(test, litConfig, steps) - elif filename.endswith('.verify.cpp'): + elif filename.endswith(".verify.cpp"): if not supportsVerify: - return lit.Test.Result(lit.Test.UNSUPPORTED, - "Test {} requires support for Clang-verify, which isn't supported by the compiler".format(test.getFullName())) + return lit.Test.Result( + lit.Test.UNSUPPORTED, + "Test {} requires support for Clang-verify, which isn't supported by the compiler".format( + test.getFullName() + ), + ) steps = [ # Note: Use -Wno-error to make sure all diagnostics are not treated as errors, # which doesn't make sense for clang-verify tests. - "%dbg(COMPILED WITH) %{{cxx}} %s %{{flags}} %{{compile_flags}} -fsyntax-only -Wno-error {}".format(VERIFY_FLAGS) + "%dbg(COMPILED WITH) %{{cxx}} %s %{{flags}} %{{compile_flags}} -fsyntax-only -Wno-error {}".format( + VERIFY_FLAGS + ) ] return self._executeShTest(test, litConfig, steps) # Make sure to check these ones last, since they will match other # suffixes above too. - elif filename.endswith('.pass.cpp') or filename.endswith('.pass.mm'): + elif filename.endswith(".pass.cpp") or filename.endswith(".pass.mm"): steps = [ "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe", - "%dbg(EXECUTED AS) %{exec} %t.exe" + "%dbg(EXECUTED AS) %{exec} %t.exe", ] return self._executeShTest(test, litConfig, steps) # This is like a .verify.cpp test when clang-verify is supported, # otherwise it's like a .compile.fail.cpp test. This is only provided # for backwards compatibility with the test suite. - elif filename.endswith('.fail.cpp'): + elif filename.endswith(".fail.cpp"): if supportsVerify: steps = [ - "%dbg(COMPILED WITH) %{{cxx}} %s %{{flags}} %{{compile_flags}} -fsyntax-only -Wno-error {}".format(VERIFY_FLAGS) + "%dbg(COMPILED WITH) %{{cxx}} %s %{{flags}} %{{compile_flags}} -fsyntax-only -Wno-error {}".format( + VERIFY_FLAGS + ) ] else: steps = [ @@ -294,19 +334,25 @@ class CxxStandardLibraryTest(lit.formats.TestFormat): ] return self._executeShTest(test, litConfig, steps) else: - return lit.Test.Result(lit.Test.UNRESOLVED, "Unknown test suffix for '{}'".format(filename)) + return lit.Test.Result( + lit.Test.UNRESOLVED, "Unknown test suffix for '{}'".format(filename) + ) def _executeShTest(self, test, litConfig, steps): if test.config.unsupported: - return lit.Test.Result(lit.Test.UNSUPPORTED, 'Test is unsupported') + return lit.Test.Result(lit.Test.UNSUPPORTED, "Test is unsupported") script = parseScript(test, steps) if isinstance(script, lit.Test.Result): return script if litConfig.noExecute: - return lit.Test.Result(lit.Test.XFAIL if test.isExpectedToFail() else lit.Test.PASS) + return lit.Test.Result( + lit.Test.XFAIL if test.isExpectedToFail() else lit.Test.PASS + ) else: _, tmpBase = _getTempPaths(test) useExternalSh = False - return lit.TestRunner._runShTest(test, litConfig, useExternalSh, script, tmpBase) + return lit.TestRunner._runShTest( + test, litConfig, useExternalSh, script, tmpBase + ) diff --git a/libcxx/utils/libcxx/test/googlebenchmark.py b/libcxx/utils/libcxx/test/googlebenchmark.py index d6960a7..d260484 100644 --- a/libcxx/utils/libcxx/test/googlebenchmark.py +++ b/libcxx/utils/libcxx/test/googlebenchmark.py @@ -8,20 +8,21 @@ import lit.TestRunner import lit.util from lit.formats.base import TestFormat -kIsWindows = sys.platform in ['win32', 'cygwin'] +kIsWindows = sys.platform in ["win32", "cygwin"] + class GoogleBenchmark(TestFormat): def __init__(self, test_sub_dirs, test_suffix, benchmark_args=[]): self.benchmark_args = list(benchmark_args) - self.test_sub_dirs = os.path.normcase(str(test_sub_dirs)).split(';') + self.test_sub_dirs = os.path.normcase(str(test_sub_dirs)).split(";") # On Windows, assume tests will also end in '.exe'. exe_suffix = str(test_suffix) if kIsWindows: - exe_suffix += '.exe' + exe_suffix += ".exe" # Also check for .py files for testing purposes. - self.test_suffixes = {exe_suffix, test_suffix + '.py'} + self.test_suffixes = {exe_suffix, test_suffix + ".py"} def getBenchmarkTests(self, path, litConfig, localConfig): """getBenchmarkTests(path) - [name] @@ -36,14 +37,14 @@ class GoogleBenchmark(TestFormat): # TODO: allow splitting tests according to the "benchmark family" so # the output for a single family of tests all belongs to the same test # target. - list_test_cmd = [path, '--benchmark_list_tests'] + list_test_cmd = [path, "--benchmark_list_tests"] try: - output = subprocess.check_output(list_test_cmd, - env=localConfig.environment) + output = subprocess.check_output(list_test_cmd, env=localConfig.environment) except subprocess.CalledProcessError as exc: litConfig.warning( "unable to discover google-benchmarks in %r: %s. Process output: %s" - % (path, sys.exc_info()[1], exc.output)) + % (path, sys.exc_info()[1], exc.output) + ) raise StopIteration nested_tests = [] @@ -53,69 +54,72 @@ class GoogleBenchmark(TestFormat): continue index = 0 - while ln[index*2:index*2+2] == ' ': + while ln[index * 2 : index * 2 + 2] == " ": index += 1 while len(nested_tests) > index: nested_tests.pop() - ln = ln[index*2:] - if ln.endswith('.'): + ln = ln[index * 2 :] + if ln.endswith("."): nested_tests.append(ln) - elif any([name.startswith('DISABLED_') - for name in nested_tests + [ln]]): + elif any([name.startswith("DISABLED_") for name in nested_tests + [ln]]): # Gtest will internally skip these tests. No need to launch a # child process for it. continue else: - yield ''.join(nested_tests) + ln + yield "".join(nested_tests) + ln - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): + def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig): source_path = testSuite.getSourcePath(path_in_suite) for subdir in self.test_sub_dirs: dir_path = os.path.join(source_path, subdir) if not os.path.isdir(dir_path): continue - for fn in lit.util.listdir_files(dir_path, - suffixes=self.test_suffixes): + for fn in lit.util.listdir_files(dir_path, suffixes=self.test_suffixes): # Discover the tests in this executable. execpath = os.path.join(source_path, subdir, fn) testnames = self.getBenchmarkTests(execpath, litConfig, localConfig) for testname in testnames: testPath = path_in_suite + (subdir, fn, testname) - yield lit.Test.Test(testSuite, testPath, localConfig, - file_path=execpath) + yield lit.Test.Test( + testSuite, testPath, localConfig, file_path=execpath + ) def execute(self, test, litConfig): - testPath,testName = os.path.split(test.getSourcePath()) + testPath, testName = os.path.split(test.getSourcePath()) while not os.path.exists(testPath): # Handle GTest parametrized and typed tests, whose name includes # some '/'s. testPath, namePrefix = os.path.split(testPath) - testName = namePrefix + '/' + testName + testName = namePrefix + "/" + testName - cmd = [testPath, '--benchmark_filter=%s$' % testName ] + self.benchmark_args + cmd = [testPath, "--benchmark_filter=%s$" % testName] + self.benchmark_args if litConfig.noExecute: - return lit.Test.PASS, '' + return lit.Test.PASS, "" try: out, err, exitCode = lit.util.executeCommand( - cmd, env=test.config.environment, - timeout=litConfig.maxIndividualTestTime) + cmd, + env=test.config.environment, + timeout=litConfig.maxIndividualTestTime, + ) except lit.util.ExecuteCommandTimeoutException: - return (lit.Test.TIMEOUT, - 'Reached timeout of {} seconds'.format( - litConfig.maxIndividualTestTime) - ) + return ( + lit.Test.TIMEOUT, + "Reached timeout of {} seconds".format(litConfig.maxIndividualTestTime), + ) if exitCode: - return lit.Test.FAIL, ('exit code: %d\n' % exitCode) + out + err + return lit.Test.FAIL, ("exit code: %d\n" % exitCode) + out + err passing_test_line = testName if passing_test_line not in out: - msg = ('Unable to find %r in google benchmark output:\n\n%s%s' % - (passing_test_line, out, err)) + msg = "Unable to find %r in google benchmark output:\n\n%s%s" % ( + passing_test_line, + out, + err, + ) return lit.Test.UNRESOLVED, msg return lit.Test.PASS, err + out diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py index aa42157..052a187 100644 --- a/libcxx/utils/libcxx/test/params.py +++ b/libcxx/utils/libcxx/test/params.py @@ -1,126 +1,158 @@ -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 * from libcxx.test.features import _isMSVC import re _warningFlags = [ - '-Werror', - '-Wall', - '-Wctad-maybe-unsupported', - '-Wextra', - '-Wshadow', - '-Wundef', - '-Wunused-template', - '-Wno-unused-command-line-argument', - '-Wno-attributes', - '-Wno-pessimizing-move', - '-Wno-c++11-extensions', - '-Wno-noexcept-type', - '-Wno-aligned-allocation-unavailable', - '-Wno-atomic-alignment', - - # GCC warns about places where we might want to add sized allocation/deallocation - # functions, but we know better what we're doing/testing in the test suite. - '-Wno-sized-deallocation', - - # Turn off warnings about user-defined literals with reserved suffixes. Those are - # just noise since we are testing the Standard Library itself. - '-Wno-literal-suffix', # GCC - '-Wno-user-defined-literals', # Clang - - # GCC warns about this when TEST_IS_CONSTANT_EVALUATED is used on a non-constexpr - # function. (This mostely happens in C++11 mode.) - # TODO(mordante) investigate a solution for this issue. - '-Wno-tautological-compare', - - # -Wstringop-overread and -Wstringop-overflow seem to be a bit buggy currently - '-Wno-stringop-overread', - '-Wno-stringop-overflow', - - # 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. - '-Wsign-compare', - '-Wunused-variable', - '-Wunused-parameter', - '-Wunreachable-code', - '-Wno-unused-local-typedef', + "-Werror", + "-Wall", + "-Wctad-maybe-unsupported", + "-Wextra", + "-Wshadow", + "-Wundef", + "-Wunused-template", + "-Wno-unused-command-line-argument", + "-Wno-attributes", + "-Wno-pessimizing-move", + "-Wno-c++11-extensions", + "-Wno-noexcept-type", + "-Wno-aligned-allocation-unavailable", + "-Wno-atomic-alignment", + # GCC warns about places where we might want to add sized allocation/deallocation + # functions, but we know better what we're doing/testing in the test suite. + "-Wno-sized-deallocation", + # Turn off warnings about user-defined literals with reserved suffixes. Those are + # just noise since we are testing the Standard Library itself. + "-Wno-literal-suffix", # GCC + "-Wno-user-defined-literals", # Clang + # GCC warns about this when TEST_IS_CONSTANT_EVALUATED is used on a non-constexpr + # function. (This mostely happens in C++11 mode.) + # TODO(mordante) investigate a solution for this issue. + "-Wno-tautological-compare", + # -Wstringop-overread and -Wstringop-overflow seem to be a bit buggy currently + "-Wno-stringop-overread", + "-Wno-stringop-overflow", + # 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. + "-Wsign-compare", + "-Wunused-variable", + "-Wunused-parameter", + "-Wunreachable-code", + "-Wno-unused-local-typedef", ] -_allStandards = ['c++03', 'c++11', 'c++14', 'c++17', 'c++20', 'c++23', 'c++26'] -def getStdFlag(cfg, std): - fallbacks = { - 'c++11': 'c++0x', - 'c++14': 'c++1y', - 'c++17': 'c++1z', - 'c++20': 'c++2a', - 'c++23': 'c++2b', - } - # TODO(LLVM-17) Remove this clang-tidy-16 work-around - if std == 'c++23': - std = 'c++2b' - if hasCompileFlag(cfg, '-std='+std): - return '-std='+std - if std in fallbacks and hasCompileFlag(cfg, '-std='+fallbacks[std]): - return '-std='+fallbacks[std] - return None +_allStandards = ["c++03", "c++11", "c++14", "c++17", "c++20", "c++23", "c++26"] -DEFAULT_PARAMETERS = [ - Parameter(name='target_triple', type=str, - help="The target triple to compile the test suite for. This must be " - "compatible with the target that the tests will be run on.", - actions=lambda triple: filter(None, [ - AddFeature('target={}'.format(triple)), - AddFlagIfSupported('--target={}'.format(triple)), - AddSubstitution('%{triple}', triple) - ])), - Parameter(name='std', choices=_allStandards, type=str, - help="The version of the standard to compile the test suite with.", - default=lambda cfg: next(s for s in reversed(_allStandards) if getStdFlag(cfg, s)), - actions=lambda std: [ - AddFeature(std), - AddSubstitution('%{cxx_std}', re.sub('\+','x', std)), - AddCompileFlag(lambda cfg: getStdFlag(cfg, std)), - ]), - - Parameter(name='enable_modules', choices=[True, False], type=bool, default=False, - help="Whether to build the test suite with Clang modules enabled.", - actions=lambda modules: [ - AddFeature('modules-build'), - AddCompileFlag('-fmodules'), - AddCompileFlag('-fcxx-modules'), # AppleClang disregards -fmodules entirely when compiling C++. This enables modules for C++. - ] if modules else []), - - Parameter(name='enable_modules_lsv', choices=[True, False], type=bool, default=False, - help="Whether to enable Local Submodule Visibility in the Modules build.", - actions=lambda lsv: [ - AddCompileFlag('-Xclang -fmodules-local-submodule-visibility'), - ] if lsv else []), - - Parameter(name='enable_exceptions', choices=[True, False], type=bool, default=True, - help="Whether to enable exceptions when compiling the test suite.", - actions=lambda exceptions: [] if exceptions else [ - AddFeature('no-exceptions'), - AddCompileFlag('-fno-exceptions') - ]), +def getStdFlag(cfg, std): + fallbacks = { + "c++11": "c++0x", + "c++14": "c++1y", + "c++17": "c++1z", + "c++20": "c++2a", + "c++23": "c++2b", + } + # TODO(LLVM-17) Remove this clang-tidy-16 work-around + if std == "c++23": + std = "c++2b" + if hasCompileFlag(cfg, "-std=" + std): + return "-std=" + std + if std in fallbacks and hasCompileFlag(cfg, "-std=" + fallbacks[std]): + return "-std=" + fallbacks[std] + return None - Parameter(name='enable_rtti', choices=[True, False], type=bool, default=True, - help="Whether to enable RTTI when compiling the test suite.", - actions=lambda rtti: [] if rtti else [ - AddFeature('no-rtti'), - AddCompileFlag('-fno-rtti') - ]), - Parameter(name='stdlib', choices=['llvm-libc++', 'apple-libc++', 'libstdc++', 'msvc'], type=str, default='llvm-libc++', - help="""The C++ Standard Library implementation being tested. +DEFAULT_PARAMETERS = [ + Parameter( + name="target_triple", + type=str, + help="The target triple to compile the test suite for. This must be " + "compatible with the target that the tests will be run on.", + actions=lambda triple: filter( + None, + [ + AddFeature("target={}".format(triple)), + AddFlagIfSupported("--target={}".format(triple)), + AddSubstitution("%{triple}", triple), + ], + ), + ), + Parameter( + name="std", + choices=_allStandards, + type=str, + help="The version of the standard to compile the test suite with.", + default=lambda cfg: next( + s for s in reversed(_allStandards) if getStdFlag(cfg, s) + ), + actions=lambda std: [ + AddFeature(std), + AddSubstitution("%{cxx_std}", re.sub("\+", "x", std)), + AddCompileFlag(lambda cfg: getStdFlag(cfg, std)), + ], + ), + Parameter( + name="enable_modules", + choices=[True, False], + type=bool, + default=False, + help="Whether to build the test suite with Clang modules enabled.", + actions=lambda modules: [ + AddFeature("modules-build"), + AddCompileFlag("-fmodules"), + AddCompileFlag( + "-fcxx-modules" + ), # AppleClang disregards -fmodules entirely when compiling C++. This enables modules for C++. + ] + if modules + else [], + ), + Parameter( + name="enable_modules_lsv", + choices=[True, False], + type=bool, + default=False, + help="Whether to enable Local Submodule Visibility in the Modules build.", + actions=lambda lsv: [ + AddCompileFlag("-Xclang -fmodules-local-submodule-visibility"), + ] + if lsv + else [], + ), + Parameter( + name="enable_exceptions", + choices=[True, False], + type=bool, + default=True, + help="Whether to enable exceptions when compiling the test suite.", + actions=lambda exceptions: [] + if exceptions + else [AddFeature("no-exceptions"), AddCompileFlag("-fno-exceptions")], + ), + Parameter( + name="enable_rtti", + choices=[True, False], + type=bool, + default=True, + help="Whether to enable RTTI when compiling the test suite.", + actions=lambda rtti: [] + if rtti + else [AddFeature("no-rtti"), AddCompileFlag("-fno-rtti")], + ), + Parameter( + name="stdlib", + choices=["llvm-libc++", "apple-libc++", "libstdc++", "msvc"], + type=str, + default="llvm-libc++", + help="""The C++ Standard Library implementation being tested. Note that this parameter can also be used to encode different 'flavors' of the same standard library, such as libc++ as shipped by a different vendor, if it has different @@ -134,88 +166,148 @@ DEFAULT_PARAMETERS = [ - libstdc++: The GNU C++ library typically shipped with GCC. - msvc: The Microsoft implementation of the C++ Standard Library. """, - actions=lambda stdlib: filter(None, [ - AddFeature('stdlib={}'.format(stdlib)), - # Also add an umbrella feature 'stdlib=libc++' for all flavors of libc++, to simplify - # the test suite. - AddFeature('stdlib=libc++') if re.match('.+-libc\+\+', stdlib) else None - ])), - - Parameter(name='enable_warnings', choices=[True, False], type=bool, default=True, - help="Whether to enable warnings when compiling the test suite.", - actions=lambda warnings: [] if not warnings else - [AddOptionalWarningFlag(w) for w in _warningFlags] + - [AddCompileFlag('-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER')] + actions=lambda stdlib: filter( + None, + [ + AddFeature("stdlib={}".format(stdlib)), + # Also add an umbrella feature 'stdlib=libc++' for all flavors of libc++, to simplify + # the test suite. + AddFeature("stdlib=libc++") + if re.match(".+-libc\+\+", stdlib) + else None, + ], + ), + ), + Parameter( + name="enable_warnings", + choices=[True, False], + type=bool, + default=True, + help="Whether to enable warnings when compiling the test suite.", + actions=lambda warnings: [] + if not warnings + else [AddOptionalWarningFlag(w) for w in _warningFlags] + + [AddCompileFlag("-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER")], + ), + Parameter( + name="use_sanitizer", + choices=[ + "", + "Address", + "HWAddress", + "Undefined", + "Memory", + "MemoryWithOrigins", + "Thread", + "DataFlow", + "Leaks", + ], + type=str, + default="", + help="An optional sanitizer to enable when building and running the test suite.", + actions=lambda sanitizer: filter( + None, + [ + AddFlag("-g -fno-omit-frame-pointer") if sanitizer else None, + AddFlag( + "-fsanitize=undefined -fno-sanitize=float-divide-by-zero -fno-sanitize-recover=all" + ) + if sanitizer == "Undefined" + else None, + AddFeature("ubsan") if sanitizer == "Undefined" else None, + AddFlag("-fsanitize=address") if sanitizer == "Address" else None, + AddFeature("asan") if sanitizer == "Address" else None, + AddFlag("-fsanitize=hwaddress") if sanitizer == "HWAddress" else None, + AddFeature("hwasan") if sanitizer == "HWAddress" else None, + AddFlag("-fsanitize=memory") + if sanitizer in ["Memory", "MemoryWithOrigins"] + else None, + AddFeature("msan") + if sanitizer in ["Memory", "MemoryWithOrigins"] + else None, + AddFlag("-fsanitize-memory-track-origins") + if sanitizer == "MemoryWithOrigins" + else None, + AddFlag("-fsanitize=thread") if sanitizer == "Thread" else None, + AddFeature("tsan") if sanitizer == "Thread" else None, + AddFlag("-fsanitize=dataflow") if sanitizer == "DataFlow" else None, + AddFlag("-fsanitize=leaks") if sanitizer == "Leaks" else None, + AddFeature("sanitizer-new-delete") + if sanitizer + in ["Address", "HWAddress", "Memory", "MemoryWithOrigins", "Thread"] + else None, + ], + ), + ), + Parameter( + name="enable_experimental", + choices=[True, False], + type=bool, + default=True, + help="Whether to enable tests for experimental C++ Library features.", + actions=lambda experimental: [ + # When linking in MSVC mode via the Clang driver, a -l<foo> + # maps to <foo>.lib, so we need to use -llibc++experimental here + # to make it link against the static libc++experimental.lib. + # We can't check for the feature 'msvc' in available_features + # as those features are added after processing parameters. + AddFeature("c++experimental"), + PrependLinkFlag( + lambda cfg: "-llibc++experimental" + if _isMSVC(cfg) + else "-lc++experimental" ), - - Parameter(name='use_sanitizer', choices=['', 'Address', 'HWAddress', 'Undefined', 'Memory', 'MemoryWithOrigins', 'Thread', 'DataFlow', 'Leaks'], type=str, default='', - help="An optional sanitizer to enable when building and running the test suite.", - actions=lambda sanitizer: filter(None, [ - AddFlag('-g -fno-omit-frame-pointer') if sanitizer else None, - - AddFlag('-fsanitize=undefined -fno-sanitize=float-divide-by-zero -fno-sanitize-recover=all') if sanitizer == 'Undefined' else None, - AddFeature('ubsan') if sanitizer == 'Undefined' else None, - - AddFlag('-fsanitize=address') if sanitizer == 'Address' else None, - AddFeature('asan') if sanitizer == 'Address' else None, - - AddFlag('-fsanitize=hwaddress') if sanitizer == 'HWAddress' else None, - AddFeature('hwasan') if sanitizer == 'HWAddress' else None, - - AddFlag('-fsanitize=memory') if sanitizer in ['Memory', 'MemoryWithOrigins'] else None, - AddFeature('msan') if sanitizer in ['Memory', 'MemoryWithOrigins'] else None, - AddFlag('-fsanitize-memory-track-origins') if sanitizer == 'MemoryWithOrigins' else None, - - AddFlag('-fsanitize=thread') if sanitizer == 'Thread' else None, - AddFeature('tsan') if sanitizer == 'Thread' else None, - - AddFlag('-fsanitize=dataflow') if sanitizer == 'DataFlow' else None, - AddFlag('-fsanitize=leaks') if sanitizer == 'Leaks' else None, - - AddFeature('sanitizer-new-delete') if sanitizer in ['Address', 'HWAddress', 'Memory', 'MemoryWithOrigins', 'Thread'] else None, - ])), - - Parameter(name='enable_experimental', choices=[True, False], type=bool, default=True, - help="Whether to enable tests for experimental C++ Library features.", - actions=lambda experimental: [ - # When linking in MSVC mode via the Clang driver, a -l<foo> - # maps to <foo>.lib, so we need to use -llibc++experimental here - # to make it link against the static libc++experimental.lib. - # We can't check for the feature 'msvc' in available_features - # as those features are added after processing parameters. - AddFeature('c++experimental'), - PrependLinkFlag(lambda cfg: '-llibc++experimental' if _isMSVC(cfg) else '-lc++experimental'), - AddCompileFlag('-D_LIBCPP_ENABLE_EXPERIMENTAL'), - ] if experimental else [ - AddFeature('libcpp-has-no-incomplete-pstl'), - ]), - - Parameter(name='long_tests', choices=[True, False], type=bool, default=True, - help="Whether to enable tests that take longer to run. This can be useful when running on a very slow device.", - actions=lambda enabled: [] if not enabled else [ - AddFeature('long_tests') - ]), - - Parameter(name='enable_assertions', choices=[True, False], type=bool, default=False, - help="Whether to enable assertions when compiling the test suite. This is only meaningful when " - "running the tests against libc++.", - actions=lambda assertions: [ - AddCompileFlag('-D_LIBCPP_ENABLE_ASSERTIONS=1'), - AddFeature('libcpp-has-assertions') - ] if assertions else []), - - Parameter(name='additional_features', type=list, default=[], - help="A comma-delimited list of additional features that will be enabled when running the tests. " - "This should be used sparingly since specifying ad-hoc features manually is error-prone and " - "brittle in the long run as changes are made to the test suite.", - actions=lambda features: [AddFeature(f) for f in features]), - - Parameter(name='enable_transitive_includes', choices=[True, False], type=bool, default=True, - help="Whether to enable backwards-compatibility transitive includes when running the tests. This " - "is provided to ensure that the trimmed-down version of libc++ does not bit-rot in between " - "points at which we bulk-remove transitive includes.", - actions=lambda enabled: [] if enabled else [ - AddFeature('transitive-includes-disabled'), - AddCompileFlag('-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES') - ]), + AddCompileFlag("-D_LIBCPP_ENABLE_EXPERIMENTAL"), + ] + if experimental + else [ + AddFeature("libcpp-has-no-incomplete-pstl"), + ], + ), + Parameter( + name="long_tests", + choices=[True, False], + type=bool, + default=True, + help="Whether to enable tests that take longer to run. This can be useful when running on a very slow device.", + actions=lambda enabled: [] if not enabled else [AddFeature("long_tests")], + ), + Parameter( + name="enable_assertions", + choices=[True, False], + type=bool, + default=False, + help="Whether to enable assertions when compiling the test suite. This is only meaningful when " + "running the tests against libc++.", + actions=lambda assertions: [ + AddCompileFlag("-D_LIBCPP_ENABLE_ASSERTIONS=1"), + AddFeature("libcpp-has-assertions"), + ] + if assertions + else [], + ), + Parameter( + name="additional_features", + type=list, + default=[], + help="A comma-delimited list of additional features that will be enabled when running the tests. " + "This should be used sparingly since specifying ad-hoc features manually is error-prone and " + "brittle in the long run as changes are made to the test suite.", + actions=lambda features: [AddFeature(f) for f in features], + ), + Parameter( + name="enable_transitive_includes", + choices=[True, False], + type=bool, + default=True, + help="Whether to enable backwards-compatibility transitive includes when running the tests. This " + "is provided to ensure that the trimmed-down version of libc++ does not bit-rot in between " + "points at which we bulk-remove transitive includes.", + actions=lambda enabled: [] + if enabled + else [ + AddFeature("transitive-includes-disabled"), + AddCompileFlag("-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES"), + ], + ), ] diff --git a/libcxx/utils/run.py b/libcxx/utils/run.py index 347a013..32961d7 100755 --- a/libcxx/utils/run.py +++ b/libcxx/utils/run.py @@ -1,11 +1,11 @@ #!/usr/bin/env python -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """run.py is a utility for running a program. @@ -21,10 +21,12 @@ import subprocess def main(): parser = argparse.ArgumentParser() - parser.add_argument('--execdir', type=str, required=True) - parser.add_argument('--codesign_identity', type=str, required=False, default=None) - parser.add_argument('--env', type=str, nargs='*', required=False, default=[]) - parser.add_argument('--prepend_env', type=str, nargs='*', required=False, default=[]) + parser.add_argument("--execdir", type=str, required=True) + parser.add_argument("--codesign_identity", type=str, required=False, default=None) + parser.add_argument("--env", type=str, nargs="*", required=False, default=[]) + parser.add_argument( + "--prepend_env", type=str, nargs="*", required=False, default=[] + ) parser.add_argument("command", nargs=argparse.ONE_OR_MORE) args = parser.parse_args() commandLine = args.command @@ -35,35 +37,37 @@ def main(): # below. This allows us to do custom processing like codesigning test-executables. # It's also possible for there to be no such executable, for example in the case # of a .sh.cpp test. - isTestExe = lambda exe: exe.endswith('.tmp.exe') and os.path.exists(exe) + isTestExe = lambda exe: exe.endswith(".tmp.exe") and os.path.exists(exe) # Do any necessary codesigning of test-executables found in the command line. if args.codesign_identity: for exe in filter(isTestExe, commandLine): - subprocess.check_call(['xcrun', 'codesign', '-f', '-s', args.codesign_identity, exe], env={}) + subprocess.check_call( + ["xcrun", "codesign", "-f", "-s", args.codesign_identity, exe], env={} + ) # Extract environment variables into a dictionary - env = {k : v for (k, v) in map(lambda s: s.split('=', 1), args.env)} + env = {k: v for (k, v) in map(lambda s: s.split("=", 1), args.env)} # Set environment variables where we prepend the given value to the # existing environment variable. - for (k, v) in map(lambda s: s.split('=', 1), args.prepend_env): + for (k, v) in map(lambda s: s.split("=", 1), args.prepend_env): if k in os.environ: v = v + os.pathsep + os.environ[k] env[k] = v - if platform.system() == 'Windows': + if platform.system() == "Windows": # Pass some extra variables through on Windows: # COMSPEC is needed for running subprocesses via std::system(). - if 'COMSPEC' in os.environ: - env['COMSPEC'] = os.environ.get('COMSPEC') + if "COMSPEC" in os.environ: + env["COMSPEC"] = os.environ.get("COMSPEC") # TEMP is needed for placing temp files in a sensible directory. - if 'TEMP' in os.environ: - env['TEMP'] = os.environ.get('TEMP') + if "TEMP" in os.environ: + env["TEMP"] = os.environ.get("TEMP") # Run the command line with the given environment in the execution directory. return subprocess.call(commandLine, cwd=args.execdir, env=env, shell=False) -if __name__ == '__main__': +if __name__ == "__main__": exit(main()) diff --git a/libcxx/utils/ssh.py b/libcxx/utils/ssh.py index a5f17d6..dad98c1 100755 --- a/libcxx/utils/ssh.py +++ b/libcxx/utils/ssh.py @@ -1,11 +1,11 @@ #!/usr/bin/env python -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """ Runs an executable on a remote host. @@ -25,37 +25,43 @@ import tempfile from shlex import quote as cmd_quote + def ssh(args, command): - cmd = ['ssh', '-oBatchMode=yes'] + cmd = ["ssh", "-oBatchMode=yes"] if args.extra_ssh_args is not None: cmd.extend(shlex.split(args.extra_ssh_args)) return cmd + [args.host, command] def scp(args, src, dst): - cmd = ['scp', '-q', '-oBatchMode=yes'] + cmd = ["scp", "-q", "-oBatchMode=yes"] if args.extra_scp_args is not None: cmd.extend(shlex.split(args.extra_scp_args)) - return cmd + [src, '{}:{}'.format(args.host, dst)] + return cmd + [src, "{}:{}".format(args.host, dst)] def main(): parser = argparse.ArgumentParser() - parser.add_argument('--host', type=str, required=True) - parser.add_argument('--execdir', type=str, required=True) - parser.add_argument('--tempdir', type=str, required=False, default='/tmp') - parser.add_argument('--extra-ssh-args', type=str, required=False) - parser.add_argument('--extra-scp-args', type=str, required=False) - parser.add_argument('--codesign_identity', type=str, required=False, default=None) - parser.add_argument('--env', type=str, nargs='*', required=False, default=[]) - parser.add_argument('--prepend_env', type=str, nargs='*', required=False, default=[]) + parser.add_argument("--host", type=str, required=True) + parser.add_argument("--execdir", type=str, required=True) + parser.add_argument("--tempdir", type=str, required=False, default="/tmp") + parser.add_argument("--extra-ssh-args", type=str, required=False) + parser.add_argument("--extra-scp-args", type=str, required=False) + parser.add_argument("--codesign_identity", type=str, required=False, default=None) + parser.add_argument("--env", type=str, nargs="*", required=False, default=[]) + parser.add_argument( + "--prepend_env", type=str, nargs="*", required=False, default=[] + ) parser.add_argument("command", nargs=argparse.ONE_OR_MORE) args = parser.parse_args() commandLine = args.command # Create a temporary directory where the test will be run. # That is effectively the value of %T on the remote host. - tmp = subprocess.check_output(ssh(args, 'mktemp -d {}/libcxx.XXXXXXXXXX'.format(args.tempdir)), universal_newlines=True).strip() + tmp = subprocess.check_output( + ssh(args, "mktemp -d {}/libcxx.XXXXXXXXXX".format(args.tempdir)), + universal_newlines=True, + ).strip() # HACK: # If an argument is a file that ends in `.tmp.exe`, assume it is the name @@ -64,20 +70,23 @@ def main(): # and changing their path when running on the remote host. It's also possible # for there to be no such executable, for example in the case of a .sh.cpp # test. - isTestExe = lambda exe: exe.endswith('.tmp.exe') and os.path.exists(exe) + isTestExe = lambda exe: exe.endswith(".tmp.exe") and os.path.exists(exe) pathOnRemote = lambda file: posixpath.join(tmp, os.path.basename(file)) try: # Do any necessary codesigning of test-executables found in the command line. if args.codesign_identity: for exe in filter(isTestExe, commandLine): - subprocess.check_call(['xcrun', 'codesign', '-f', '-s', args.codesign_identity, exe], env={}) + subprocess.check_call( + ["xcrun", "codesign", "-f", "-s", args.codesign_identity, exe], + env={}, + ) # tar up the execution directory (which contains everything that's needed # to run the test), and copy the tarball over to the remote host. try: - tmpTar = tempfile.NamedTemporaryFile(suffix='.tar', delete=False) - with tarfile.open(fileobj=tmpTar, mode='w') as tarball: + tmpTar = tempfile.NamedTemporaryFile(suffix=".tar", delete=False) + with tarfile.open(fileobj=tmpTar, mode="w") as tarball: tarball.add(args.execdir, arcname=os.path.basename(args.execdir)) # Make sure we close the file before we scp it, because accessing @@ -93,22 +102,22 @@ def main(): # Untar the dependencies in the temporary directory and remove the tarball. remoteCommands = [ - 'tar -xf {} -C {} --strip-components 1'.format(remoteTarball, tmp), - 'rm {}'.format(remoteTarball) + "tar -xf {} -C {} --strip-components 1".format(remoteTarball, tmp), + "rm {}".format(remoteTarball), ] # Make sure all test-executables in the remote command line have 'execute' # permissions on the remote host. The host that compiled the test-executable # might not have a notion of 'executable' permissions. for exe in map(pathOnRemote, filter(isTestExe, commandLine)): - remoteCommands.append('chmod +x {}'.format(exe)) + remoteCommands.append("chmod +x {}".format(exe)) # Execute the command through SSH in the temporary directory, with the # correct environment. We tweak the command line to run it on the remote # host by transforming the path of test-executables to their path in the # temporary directory on the remote host. commandLine = (pathOnRemote(x) if isTestExe(x) else x for x in commandLine) - remoteCommands.append('cd {}'.format(tmp)) + remoteCommands.append("cd {}".format(tmp)) if args.prepend_env: # We can't sensibly know the original value of the env vars @@ -117,17 +126,17 @@ def main(): if args.env: env = list(map(cmd_quote, args.env)) - remoteCommands.append('export {}'.format(' '.join(args.env))) + remoteCommands.append("export {}".format(" ".join(args.env))) remoteCommands.append(subprocess.list2cmdline(commandLine)) # Finally, SSH to the remote host and execute all the commands. - rc = subprocess.call(ssh(args, ' && '.join(remoteCommands))) + rc = subprocess.call(ssh(args, " && ".join(remoteCommands))) return rc finally: # Make sure the temporary directory is removed when we're done. - subprocess.check_call(ssh(args, 'rm -r {}'.format(tmp))) + subprocess.check_call(ssh(args, "rm -r {}".format(tmp))) -if __name__ == '__main__': +if __name__ == "__main__": exit(main()) diff --git a/libcxx/utils/sym_diff.py b/libcxx/utils/sym_diff.py index 6bd1b57..8eaf8b7 100755 --- a/libcxx/utils/sym_diff.py +++ b/libcxx/utils/sym_diff.py @@ -1,11 +1,11 @@ #!/usr/bin/env python -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## # # 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 # -#===----------------------------------------------------------------------===## +# ===----------------------------------------------------------------------===## """ sym_diff - Compare two symbol lists and output the differences. """ @@ -17,34 +17,60 @@ from libcxx.sym_check import diff, util def main(): parser = ArgumentParser( - description='Extract a list of symbols from a shared library.') + description="Extract a list of symbols from a shared library." + ) parser.add_argument( - '--names-only', dest='names_only', - help='Only print symbol names', - action='store_true', default=False) + "--names-only", + dest="names_only", + help="Only print symbol names", + action="store_true", + default=False, + ) parser.add_argument( - '--removed-only', dest='removed_only', - help='Only print removed symbols', - action='store_true', default=False) - parser.add_argument('--only-stdlib-symbols', dest='only_stdlib', - help="Filter all symbols not related to the stdlib", - action='store_true', default=False) - parser.add_argument('--strict', dest='strict', - help="Exit with a non-zero status if any symbols " - "differ", - action='store_true', default=False) + "--removed-only", + dest="removed_only", + help="Only print removed symbols", + action="store_true", + default=False, + ) parser.add_argument( - '-o', '--output', dest='output', - help='The output file. stdout is used if not given', - type=str, action='store', default=None) + "--only-stdlib-symbols", + dest="only_stdlib", + help="Filter all symbols not related to the stdlib", + action="store_true", + default=False, + ) parser.add_argument( - '--demangle', dest='demangle', action='store_true', default=False) + "--strict", + dest="strict", + help="Exit with a non-zero status if any symbols " "differ", + action="store_true", + default=False, + ) parser.add_argument( - 'old_syms', metavar='old-syms', type=str, - help='The file containing the old symbol list or a library') + "-o", + "--output", + dest="output", + help="The output file. stdout is used if not given", + type=str, + action="store", + default=None, + ) parser.add_argument( - 'new_syms', metavar='new-syms', type=str, - help='The file containing the new symbol list or a library') + "--demangle", dest="demangle", action="store_true", default=False + ) + parser.add_argument( + "old_syms", + metavar="old-syms", + type=str, + help="The file containing the old symbol list or a library", + ) + parser.add_argument( + "new_syms", + metavar="new-syms", + type=str, + help="The file containing the new symbol list or a library", + ) args = parser.parse_args() old_syms_list = util.extract_or_load(args.old_syms) @@ -58,15 +84,16 @@ def main(): if args.removed_only: added = {} report, is_break, is_different = diff.report_diff( - added, removed, changed, names_only=args.names_only, - demangle=args.demangle) + added, removed, changed, names_only=args.names_only, demangle=args.demangle + ) if args.output is None: print(report) else: - with open(args.output, 'w') as f: - f.write(report + '\n') + with open(args.output, "w") as f: + f.write(report + "\n") exit_code = 1 if is_break or (args.strict and is_different) else 0 sys.exit(exit_code) -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/libcxxabi/test/lit.cfg.py b/libcxxabi/test/lit.cfg.py index 647464a..ea4a9a7 100644 --- a/libcxxabi/test/lit.cfg.py +++ b/libcxxabi/test/lit.cfg.py @@ -7,4 +7,5 @@ lit_config.fatal( "You seem to be running Lit directly -- you should be running Lit through " "<build>/bin/llvm-lit, which will ensure that the right Lit configuration " - "file is used.") + "file is used." +) diff --git a/libcxxabi/test/native/arm-linux-eabi/lit.local.cfg b/libcxxabi/test/native/arm-linux-eabi/lit.local.cfg index d12eb20..fd6b8ad 100644 --- a/libcxxabi/test/native/arm-linux-eabi/lit.local.cfg +++ b/libcxxabi/test/native/arm-linux-eabi/lit.local.cfg @@ -1,6 +1,9 @@ def is_arm_linux_eabi(triple): - return ('arm' in triple) and ('linux' in triple) and ('eabi' in triple) + return ("arm" in triple) and ("linux" in triple) and ("eabi" in triple) -is_native = hasattr(config.root, 'target_triple') and (config.root.host_triple == config.root.target_triple) + +is_native = hasattr(config.root, "target_triple") and ( + config.root.host_triple == config.root.target_triple +) if not is_native or not is_arm_linux_eabi(config.root.host_triple): config.unsupported = True diff --git a/libunwind/docs/conf.py b/libunwind/docs/conf.py index 307ece60..29f9c24 100644 --- a/libunwind/docs/conf.py +++ b/libunwind/docs/conf.py @@ -16,106 +16,106 @@ from datetime import date # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] +extensions = ["sphinx.ext.intersphinx", "sphinx.ext.todo"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'libunwind' -copyright = u'2011-%d, LLVM Project' % date.today().year +project = "libunwind" +copyright = "2011-%d, LLVM Project" % date.today().year # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '17.0' +version = "17.0" # The full version, including alpha/beta/rc tags. -release = '17.0' +release = "17.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -today_fmt = '%Y-%m-%d' +today_fmt = "%Y-%m-%d" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. show_authors = True # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'friendly' +pygments_style = "friendly" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'haiku' +html_theme = "haiku" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # "<project> v<release> documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -124,101 +124,95 @@ html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a <link> tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'libunwinddoc' +htmlhelp_basename = "libunwinddoc" # -- Options for LaTeX output -------------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('contents', 'libunwind.tex', u'libunwind Documentation', - u'LLVM project', 'manual'), + ("contents", "libunwind.tex", "libunwind Documentation", "LLVM project", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('contents', 'libunwind', u'libunwind Documentation', - [u'LLVM project'], 1) -] +man_pages = [("contents", "libunwind", "libunwind Documentation", ["LLVM project"], 1)] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ @@ -227,19 +221,25 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('contents', 'libunwind', u'libunwind Documentation', - u'LLVM project', 'libunwind', 'LLVM Unwinder', - 'Miscellaneous'), + ( + "contents", + "libunwind", + "libunwind Documentation", + "LLVM project", + "libunwind", + "LLVM Unwinder", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # FIXME: Define intersphinx configuration. diff --git a/libunwind/test/lit.cfg.py b/libunwind/test/lit.cfg.py index 647464a..ea4a9a7 100644 --- a/libunwind/test/lit.cfg.py +++ b/libunwind/test/lit.cfg.py @@ -7,4 +7,5 @@ lit_config.fatal( "You seem to be running Lit directly -- you should be running Lit through " "<build>/bin/llvm-lit, which will ensure that the right Lit configuration " - "file is used.") + "file is used." +) |