forked from OSchip/llvm-project
204 lines
6.7 KiB
Python
Executable File
204 lines
6.7 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import os
|
|
|
|
|
|
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)
|
|
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'))
|
|
return script_name, src_root, test_path
|
|
|
|
|
|
script_name, source_root, test_path = get_libcxx_paths()
|
|
|
|
|
|
# This table was produced manually, by grepping the TeX source of the Standard's
|
|
# library clauses for the string "#include". Each header's synopsis contains
|
|
# explicit "#include" directives for its mandatory inclusions.
|
|
# For example, [algorithm.syn] contains "#include <initializer_list>".
|
|
#
|
|
mandatory_inclusions = {
|
|
"algorithm": ["initializer_list"],
|
|
"array": ["compare", "initializer_list"],
|
|
"bitset": ["iosfwd", "string"],
|
|
"chrono": ["compare"],
|
|
"cinttypes": ["cstdint"],
|
|
"complex.h": ["complex"],
|
|
# TODO "coroutine": ["compare"],
|
|
"deque": ["compare", "initializer_list"],
|
|
"filesystem": ["compare"],
|
|
"forward_list": ["compare", "initializer_list"],
|
|
"ios": ["iosfwd"],
|
|
"iostream": ["ios", "istream", "ostream", "streambuf"],
|
|
"iterator": ["compare", "concepts"],
|
|
"list": ["compare", "initializer_list"],
|
|
"map": ["compare", "initializer_list"],
|
|
"memory": ["compare"],
|
|
"optional": ["compare"],
|
|
"queue": ["compare", "initializer_list"],
|
|
"random": ["initializer_list"],
|
|
"ranges": ["compare", "initializer_list", "iterator"],
|
|
"regex": ["compare", "initializer_list"],
|
|
"set": ["compare", "initializer_list"],
|
|
"stack": ["compare", "initializer_list"],
|
|
"string": ["compare", "initializer_list"],
|
|
"string_view": ["compare"],
|
|
# TODO "syncstream": ["ostream"],
|
|
"system_error": ["compare"],
|
|
"tgmath.h": ["cmath", "complex"],
|
|
"thread": ["compare"],
|
|
"tuple": ["compare"],
|
|
"typeindex": ["compare"],
|
|
"unordered_map": ["compare", "initializer_list"],
|
|
"unordered_set": ["compare", "initializer_list"],
|
|
"utility": ["compare", "initializer_list"],
|
|
"valarray": ["initializer_list"],
|
|
"variant": ["compare"],
|
|
"vector": ["compare", "initializer_list"],
|
|
}
|
|
|
|
new_in_version = {
|
|
"chrono": "11",
|
|
"compare": "20",
|
|
"concepts": "20",
|
|
"coroutine": "20",
|
|
"filesystem": "17",
|
|
"initializer_list": "11",
|
|
"optional": "17",
|
|
"system_error": "11",
|
|
"thread": "11",
|
|
"tuple": "11",
|
|
"unordered_map": "11",
|
|
"unordered_set": "11",
|
|
"string_view": "17",
|
|
"ranges": "20",
|
|
"syncstream": "20",
|
|
"variant": "17",
|
|
}
|
|
|
|
assert all(v == sorted(v) for k, v in mandatory_inclusions.items())
|
|
|
|
# Map from each header to the Lit annotations that should be used for
|
|
# tests that include that header.
|
|
#
|
|
# For example, when threads are not supported, any test
|
|
# that includes <thread> should be marked as UNSUPPORTED, because including
|
|
# <thread> is a hard error in that case.
|
|
lit_markup = {
|
|
"atomic": ["UNSUPPORTED: libcpp-has-no-threads"],
|
|
"barrier": ["UNSUPPORTED: libcpp-has-no-threads"],
|
|
"filesystem": ["UNSUPPORTED: libcpp-has-no-filesystem-library"],
|
|
"iomanip": ["UNSUPPORTED: libcpp-has-no-localization"],
|
|
"istream": ["UNSUPPORTED: libcpp-has-no-localization"],
|
|
"ios": ["UNSUPPORTED: libcpp-has-no-localization"],
|
|
"iostream": ["UNSUPPORTED: libcpp-has-no-localization"],
|
|
"latch": ["UNSUPPORTED: libcpp-has-no-threads"],
|
|
"locale": ["UNSUPPORTED: libcpp-has-no-localization"],
|
|
"ostream": ["UNSUPPORTED: libcpp-has-no-localization"],
|
|
"regex": ["UNSUPPORTED: libcpp-has-no-localization"],
|
|
"semaphore": ["UNSUPPORTED: libcpp-has-no-threads"],
|
|
"shared_mutex": ["UNSUPPORTED: libcpp-has-no-threads"],
|
|
"thread": ["UNSUPPORTED: libcpp-has-no-threads"],
|
|
}
|
|
|
|
|
|
def get_std_ver_test(includee):
|
|
v = new_in_version.get(includee, "03")
|
|
if v == "03":
|
|
return ''
|
|
versions = ["03", "11", "14", "17", "20"]
|
|
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'],
|
|
"2b": ['UNSUPPORTED: c++03, c++11, c++14, c++17, c++20'],
|
|
}[v]
|
|
|
|
|
|
def get_libcpp_header_symbol(header_name):
|
|
return '_LIBCPP_' + header_name.upper().replace('.', '_')
|
|
|
|
|
|
def get_includer_symbol_test(includer):
|
|
symbol = get_libcpp_header_symbol(includer)
|
|
return """
|
|
#if !defined({symbol})
|
|
# error "{message}"
|
|
#endif
|
|
""".strip().format(
|
|
symbol=symbol,
|
|
message="<{}> was expected to define {}".format(includer, symbol),
|
|
)
|
|
|
|
|
|
def get_ifdef(includer, includee):
|
|
version = max(new_in_version.get(h, "03") for h in [includer, includee])
|
|
symbol = get_libcpp_header_symbol(includee)
|
|
return """
|
|
#if {includee_test}!defined({symbol})
|
|
# error "{message}"
|
|
#endif
|
|
""".strip().format(
|
|
includee_test=get_std_ver_test(includee),
|
|
symbol=symbol,
|
|
message="<{}> should include <{}> in C++{} and later".format(includer, includee, version)
|
|
)
|
|
|
|
|
|
test_body_template = """
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// WARNING: This test was generated by {script_name}
|
|
// and should not be edited manually.
|
|
//
|
|
// clang-format off
|
|
{markup}
|
|
// <{header}>
|
|
|
|
// Test that <{header}> includes all the other headers it's supposed to.
|
|
|
|
#include <{header}>
|
|
#include "test_macros.h"
|
|
|
|
{test_includers_symbol}
|
|
{test_per_includee}
|
|
""".strip()
|
|
|
|
|
|
def produce_tests():
|
|
for includer, includees in mandatory_inclusions.items():
|
|
markup_tags = get_unsupported_line(includer) + lit_markup.get(includer, [])
|
|
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 '',
|
|
test_includers_symbol=get_includer_symbol_test(includer),
|
|
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')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
produce_tests()
|