• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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