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