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