1# ===----------------------------------------------------------------------===## 2# 3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4# See https://llvm.org/LICENSE.txt for license information. 5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6# 7# ===----------------------------------------------------------------------===## 8 9# Test that we don't remove transitive includes of public C++ headers in the library accidentally. 10# When we remove a transitive public include, clients tend to break because they don't always 11# properly include what they use. Note that we don't check which system (C) headers are 12# included transitively, because that is too unstable across platforms, and hence difficult 13# to test for. 14# 15# This is not meant to block libc++ from removing unused transitive includes 16# forever, however we do try to group removals for a couple of releases 17# to avoid breaking users at every release. 18 19# RUN: %{python} %s %{libcxx-dir}/utils 20 21# block Lit from interpreting a RUN/XFAIL/etc inside the generation script 22# END. 23 24import sys 25sys.path.append(sys.argv[1]) 26from libcxx.header_information import lit_header_restrictions, public_headers 27 28import re 29 30# To re-generate the list of expected headers, temporarily set this to True, and run this test. 31# Note that this needs to be done for all supported language versions of libc++: 32# for std in c++03 c++11 c++14 c++17 c++20 c++23 c++26; do <build>/bin/llvm-lit --param std=$std libcxx/test/libcxx/transitive_includes.gen.py; done 33regenerate_expected_results = False 34 35if regenerate_expected_results: 36 print( 37 f"""\ 38//--- generate-transitive-includes.sh.cpp 39// RUN: mkdir %t 40""" 41 ) 42 43 all_traces = [] 44 for header in sorted(public_headers): 45 if header.is_C_compatibility() or header.is_internal(): 46 continue 47 48 normalized_header = re.sub("/", "_", str(header)) 49 print( 50 f"""\ 51// RUN: echo "#include <{header}>" | %{{cxx}} -xc++ - %{{flags}} %{{compile_flags}} --trace-includes -fshow-skipped-includes --preprocess > /dev/null 2> %t/trace-includes.{normalized_header}.txt 52""" 53 ) 54 all_traces.append(f"%t/trace-includes.{normalized_header}.txt") 55 56 print( 57 f"""\ 58// RUN: %{{python}} %{{libcxx-dir}}/test/libcxx/transitive_includes/to_csv.py {' '.join(all_traces)} > %{{libcxx-dir}}/test/libcxx/transitive_includes/%{{cxx_std}}.csv 59""" 60 ) 61 62else: 63 for header in public_headers: 64 if header.is_C_compatibility() or header.is_internal(): 65 continue 66 67 # Escape slashes for the awk command below 68 escaped_header = str(header).replace("/", "\\/") 69 70 print( 71 f"""\ 72//--- {header}.sh.cpp 73{lit_header_restrictions.get(header, '')} 74 75// TODO: Fix this test to make it work with localization or wide characters disabled 76// UNSUPPORTED: no-localization, no-wide-characters, no-threads, no-filesystem, libcpp-has-no-experimental-tzdb 77 78// When built with modules, this test doesn't work because --trace-includes doesn't 79// report the stack of includes correctly. 80// UNSUPPORTED: clang-modules-build 81 82// This test uses --trace-includes, which is not supported by GCC. 83// UNSUPPORTED: gcc 84 85// This test is not supported when we remove the transitive includes provided for backwards 86// compatibility. When we bulk-remove them, we'll adjust the includes that are expected by 87// this test instead. 88// UNSUPPORTED: transitive-includes-disabled 89 90// TODO: Figure out why <stdatomic.h> doesn't work on FreeBSD 91// UNSUPPORTED: LIBCXX-FREEBSD-FIXME 92 93// RUN: mkdir %t 94// RUN: %{{cxx}} %s %{{flags}} %{{compile_flags}} --trace-includes -fshow-skipped-includes --preprocess > /dev/null 2> %t/trace-includes.txt 95// RUN: %{{python}} %{{libcxx-dir}}/test/libcxx/transitive_includes/to_csv.py %t/trace-includes.txt > %t/actual_transitive_includes.csv 96// RUN: cat %{{libcxx-dir}}/test/libcxx/transitive_includes/%{{cxx_std}}.csv | awk '/^{escaped_header} / {{ print }}' > %t/expected_transitive_includes.csv 97// RUN: diff -w %t/expected_transitive_includes.csv %t/actual_transitive_includes.csv 98#include <{header}> 99""" 100 ) 101