[compiler-rt][cmake] Fix clang-cl warnings introduced in ae4c643bcdf2
[llvm-project.git] / libcxx / utils / generate_header_inclusion_tests.py
blob00f6b0aa8765317a913f14401cde6cde773d604b
1 #!/usr/bin/env python
3 import os
6 def get_libcxx_paths():
7 utils_path = os.path.dirname(os.path.abspath(__file__))
8 script_name = os.path.basename(__file__)
9 assert os.path.exists(utils_path)
10 src_root = os.path.dirname(utils_path)
11 test_path = os.path.join(src_root, 'test', 'libcxx', 'inclusions')
12 assert os.path.exists(test_path)
13 assert os.path.exists(os.path.join(test_path, 'algorithm.inclusions.compile.pass.cpp'))
14 return script_name, src_root, test_path
17 script_name, source_root, test_path = get_libcxx_paths()
20 # This table was produced manually, by grepping the TeX source of the Standard's
21 # library clauses for the string "#include". Each header's synopsis contains
22 # explicit "#include" directives for its mandatory inclusions.
23 # For example, [algorithm.syn] contains "#include <initializer_list>".
25 mandatory_inclusions = {
26 "algorithm": ["initializer_list"],
27 "array": ["compare", "initializer_list"],
28 "bitset": ["iosfwd", "string"],
29 "chrono": ["compare"],
30 "cinttypes": ["cstdint"],
31 "complex.h": ["complex"],
32 "coroutine": ["compare"],
33 "deque": ["compare", "initializer_list"],
34 "filesystem": ["compare"],
35 "forward_list": ["compare", "initializer_list"],
36 "ios": ["iosfwd"],
37 "iostream": ["ios", "istream", "ostream", "streambuf"],
38 "iterator": ["compare", "concepts"],
39 "list": ["compare", "initializer_list"],
40 "map": ["compare", "initializer_list"],
41 "memory": ["compare"],
42 "optional": ["compare"],
43 "queue": ["compare", "initializer_list"],
44 "random": ["initializer_list"],
45 "ranges": ["compare", "initializer_list", "iterator"],
46 "regex": ["compare", "initializer_list"],
47 "set": ["compare", "initializer_list"],
48 "stack": ["compare", "initializer_list"],
49 "string_view": ["compare"],
50 "string": ["compare", "initializer_list"],
51 # TODO "syncstream": ["ostream"],
52 "system_error": ["compare"],
53 "tgmath.h": ["cmath", "complex"],
54 "thread": ["compare"],
55 "tuple": ["compare"],
56 "typeindex": ["compare"],
57 "unordered_map": ["compare", "initializer_list"],
58 "unordered_set": ["compare", "initializer_list"],
59 "utility": ["compare", "initializer_list"],
60 "valarray": ["initializer_list"],
61 "variant": ["compare"],
62 "vector": ["compare", "initializer_list"],
65 new_in_version = {
66 "chrono": "11",
67 "compare": "20",
68 "concepts": "20",
69 "coroutine": "20",
70 "filesystem": "17",
71 "initializer_list": "11",
72 "optional": "17",
73 "ranges": "20",
74 "string_view": "17",
75 "syncstream": "20",
76 "system_error": "11",
77 "thread": "11",
78 "tuple": "11",
79 "unordered_map": "11",
80 "unordered_set": "11",
81 "variant": "17",
84 assert all(v == sorted(v) for k, v in mandatory_inclusions.items())
86 # Map from each header to the Lit annotations that should be used for
87 # tests that include that header.
89 # For example, when threads are not supported, any test that includes
90 # <thread> should be marked as UNSUPPORTED, because including <thread>
91 # is a hard error in that case.
92 lit_markup = {
93 "barrier": ["UNSUPPORTED: libcpp-has-no-threads"],
94 "filesystem": ["UNSUPPORTED: libcpp-has-no-filesystem-library"],
95 "format": ["UNSUPPORTED: libcpp-has-no-incomplete-format"],
96 "iomanip": ["UNSUPPORTED: libcpp-has-no-localization"],
97 "ios": ["UNSUPPORTED: libcpp-has-no-localization"],
98 "iostream": ["UNSUPPORTED: libcpp-has-no-localization"],
99 "istream": ["UNSUPPORTED: libcpp-has-no-localization"],
100 "latch": ["UNSUPPORTED: libcpp-has-no-threads"],
101 "locale": ["UNSUPPORTED: libcpp-has-no-localization"],
102 "mutex": ["UNSUPPORTED: libcpp-has-no-threads"],
103 "ostream": ["UNSUPPORTED: libcpp-has-no-localization"],
104 "ranges": ["UNSUPPORTED: libcpp-has-no-incomplete-ranges"],
105 "regex": ["UNSUPPORTED: libcpp-has-no-localization"],
106 "semaphore": ["UNSUPPORTED: libcpp-has-no-threads"],
107 "shared_mutex": ["UNSUPPORTED: libcpp-has-no-threads"],
108 "thread": ["UNSUPPORTED: libcpp-has-no-threads"]
112 def get_std_ver_test(includee):
113 v = new_in_version.get(includee, "03")
114 if v == "03":
115 return ''
116 versions = ["03", "11", "14", "17", "20"]
117 return 'TEST_STD_VER > {} && '.format(max(i for i in versions if i < v))
120 def get_unsupported_line(includee):
121 v = new_in_version.get(includee, "03")
122 return {
123 "03": [],
124 "11": ['UNSUPPORTED: c++03'],
125 "14": ['UNSUPPORTED: c++03, c++11'],
126 "17": ['UNSUPPORTED: c++03, c++11, c++14'],
127 "20": ['UNSUPPORTED: c++03, c++11, c++14, c++17'],
128 "2b": ['UNSUPPORTED: c++03, c++11, c++14, c++17, c++20'],
129 }[v]
132 def get_libcpp_header_symbol(header_name):
133 return '_LIBCPP_' + header_name.upper().replace('.', '_')
136 def get_includer_symbol_test(includer):
137 symbol = get_libcpp_header_symbol(includer)
138 return """
139 #if !defined({symbol})
140 # error "{message}"
141 #endif
142 """.strip().format(
143 symbol=symbol,
144 message="<{}> was expected to define {}".format(includer, symbol),
148 def get_ifdef(includer, includee):
149 version = max(new_in_version.get(h, "03") for h in [includer, includee])
150 symbol = get_libcpp_header_symbol(includee)
151 return """
152 #if {includee_test}!defined({symbol})
153 # error "{message}"
154 #endif
155 """.strip().format(
156 includee_test=get_std_ver_test(includee),
157 symbol=symbol,
158 message="<{}> should include <{}> in C++{} and later".format(includer, includee, version)
162 test_body_template = """
163 //===----------------------------------------------------------------------===//
165 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
166 // See https://llvm.org/LICENSE.txt for license information.
167 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
169 //===----------------------------------------------------------------------===//
171 // WARNING: This test was generated by {script_name}
172 // and should not be edited manually.
174 // clang-format off
175 {markup}
176 // <{header}>
178 // Test that <{header}> includes all the other headers it's supposed to.
180 #include <{header}>
181 #include "test_macros.h"
183 {test_includers_symbol}
184 {test_per_includee}
185 """.strip()
188 def produce_tests():
189 for includer, includees in mandatory_inclusions.items():
190 markup_tags = get_unsupported_line(includer) + lit_markup.get(includer, [])
191 test_body = test_body_template.format(
192 script_name=script_name,
193 header=includer,
194 markup=('\n' + '\n'.join('// ' + m for m in markup_tags) + '\n') if markup_tags else '',
195 test_includers_symbol=get_includer_symbol_test(includer),
196 test_per_includee='\n'.join(get_ifdef(includer, includee) for includee in includees),
198 test_name = "{header}.inclusions.compile.pass.cpp".format(header=includer)
199 out_path = os.path.join(test_path, test_name)
200 with open(out_path, 'w', newline='\n') as f:
201 f.write(test_body + '\n')
204 if __name__ == '__main__':
205 produce_tests()