[libcxx-commits] [libcxx] c4ca3a2 - [libc++] Simplify transitive includes test and fix a bug

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 3 13:09:23 PDT 2022


Author: Louis Dionne
Date: 2022-10-03T16:09:07-04:00
New Revision: c4ca3a2c4b00033c393f694c1d92d28ff55c69cd

URL: https://github.com/llvm/llvm-project/commit/c4ca3a2c4b00033c393f694c1d92d28ff55c69cd
DIFF: https://github.com/llvm/llvm-project/commit/c4ca3a2c4b00033c393f694c1d92d28ff55c69cd.diff

LOG: [libc++] Simplify transitive includes test and fix a bug

This patch incorporates the "sanitize" step of the transitive includes
test into the CSV generator itself. In doing so, it removes complexity
in the test but also fixes a bug where we would filter out <__mutex>
from the output, leading to an incorrect list of includes for the
<shared_mutex> header.

Differential Revision: https://reviews.llvm.org/D134830

Added: 
    

Modified: 
    libcxx/test/libcxx/transitive_includes.sh.cpp
    libcxx/test/libcxx/transitive_includes/cxx14.csv
    libcxx/test/libcxx/transitive_includes/cxx17.csv
    libcxx/test/libcxx/transitive_includes/cxx20.csv
    libcxx/test/libcxx/transitive_includes/cxx2b.csv
    libcxx/test/libcxx/transitive_includes_to_csv.py

Removed: 
    libcxx/test/libcxx/transitive_includes.sanitize.py


################################################################################
diff  --git a/libcxx/test/libcxx/transitive_includes.sanitize.py b/libcxx/test/libcxx/transitive_includes.sanitize.py
deleted file mode 100755
index f528f8f95907e..0000000000000
--- a/libcxx/test/libcxx/transitive_includes.sanitize.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env python
-# ===----------------------------------------------------------------------===##
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-# ===----------------------------------------------------------------------===##
-
-# This script reads lines from standard input and looks for the names of public
-# C++ headers. Specifically, it looks for lines of the form 'c++/v1/header'
-# where 'header' is the name of a public C++ header, excluding C compatibility
-# headers. (Note it keeps the libc++ implementation detail .h files.)
-
-# Note --trace-includes removes duplicates of included headers unless they are
-# part of a cycle.
-
-# The input looks like
-# . ${build_dir}/include/c++/v1/algorithm
-# .. ${build_dir}/include/c++/v1/__assert
-# ... ${build_dir}/include/c++/v1/__config
-# .... ${build_dir}/include/c++/v1/__config_site
-# .... /usr/include/features.h
-# ..... /usr/include/stdc-predef.h
-# ..... /usr/include/x86_64-linux-gnu/sys/cdefs.h
-# ...... /usr/include/x86_64-linux-gnu/bits/wordsize.h
-# <snip>
-# .... ${build_dir}/include/c++/v1/version
-# .... ${build_dir}/include/c++/v1/stddef.h
-# ..... /usr/lib/llvm-15/lib/clang/15.0.0/include/stddef.h
-# ...... /usr/lib/llvm-15/lib/clang/15.0.0/include/__stddef_max_align_t.h
-# ... ${build_dir}/include/c++/v1/type_traits
-# <more>
-
-
-# The filtered output will be like:
-# type_traits
-# . algorithm
-# ... cstddef
-# .... __type_traits/enable_if.h
-# .... __type_traits/integral_constant.h
-# .... __type_traits/is_integral.h
-# ..... __type_traits/remove_cv.h
-# ...... __type_traits/remove_const.h
-# ...... __type_traits/remove_volatile.h
-# .... version
-
-import re
-import sys
-
-headers = []
-for line in sys.stdin.readlines():
-    # On Windows, the path separators can either be forward slash or backslash.
-    # If it is a backslash, Clang prints it escaped as two consecutive
-    # backslashes, and they need to be escaped in the RE. (Use a raw string for
-    # the pattern to avoid needing another level of escaping on the Python string
-    # literal level.)
-    match = re.match(r"(\.+).*c\+\+(?:/|\\\\)v[0-9]+(?:/|\\\\)(.+)", line)
-    if not match:
-        continue
-
-    header = match.group(2)
-    # Skip C headers, but accept libc++ detail headers.
-    if header.startswith("__"):
-        if not header.endswith(".h"):
-            continue
-    elif header.endswith(".h"):
-        continue
-
-    print(f"{match.group(1)} {match.group(2)}")

diff  --git a/libcxx/test/libcxx/transitive_includes.sh.cpp b/libcxx/test/libcxx/transitive_includes.sh.cpp
index 56724094f2b1e..c23e24df9396b 100644
--- a/libcxx/test/libcxx/transitive_includes.sh.cpp
+++ b/libcxx/test/libcxx/transitive_includes.sh.cpp
@@ -63,10 +63,7 @@ for i, header in enumerate(public_headers):
     continue
 
   normalized_header = re.sub('/', '_', header)
-  trace_includes = "%{{cxx}} %s %{{flags}} %{{compile_flags}} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_{} 2>&1".format(i)
-
-  print(f"// {RUN}: {trace_includes} | %{{python}} %S/transitive_includes.sanitize.py > %t/header.{normalized_header}")
-
+  print(f"// {RUN}: %{{cxx}} %s %{{flags}} %{{compile_flags}} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_{i} 2> %t/header.{normalized_header}")
   print(f"#if defined(TEST_{i})")
   print(f"#include <{header}>")
   print("#endif")
@@ -83,479 +80,479 @@ END-SCRIPT
 // DO NOT MANUALLY EDIT ANYTHING BETWEEN THE MARKERS BELOW
 // GENERATED-MARKER
 // RUN: mkdir %t
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_0 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.algorithm
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_0 2> %t/header.algorithm
 #if defined(TEST_0)
 #include <algorithm>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_1 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.any
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_1 2> %t/header.any
 #if defined(TEST_1)
 #include <any>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_2 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.array
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_2 2> %t/header.array
 #if defined(TEST_2)
 #include <array>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_3 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.atomic
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_3 2> %t/header.atomic
 #if defined(TEST_3)
 #include <atomic>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_4 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.barrier
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_4 2> %t/header.barrier
 #if defined(TEST_4)
 #include <barrier>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_5 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.bit
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_5 2> %t/header.bit
 #if defined(TEST_5)
 #include <bit>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_6 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.bitset
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_6 2> %t/header.bitset
 #if defined(TEST_6)
 #include <bitset>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_7 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cassert
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_7 2> %t/header.cassert
 #if defined(TEST_7)
 #include <cassert>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_8 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ccomplex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_8 2> %t/header.ccomplex
 #if defined(TEST_8)
 #include <ccomplex>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_9 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cctype
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_9 2> %t/header.cctype
 #if defined(TEST_9)
 #include <cctype>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_10 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cerrno
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_10 2> %t/header.cerrno
 #if defined(TEST_10)
 #include <cerrno>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_11 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cfenv
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_11 2> %t/header.cfenv
 #if defined(TEST_11)
 #include <cfenv>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_12 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cfloat
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_12 2> %t/header.cfloat
 #if defined(TEST_12)
 #include <cfloat>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_13 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.charconv
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_13 2> %t/header.charconv
 #if defined(TEST_13)
 #include <charconv>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_14 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.chrono
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_14 2> %t/header.chrono
 #if defined(TEST_14)
 #include <chrono>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_15 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cinttypes
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_15 2> %t/header.cinttypes
 #if defined(TEST_15)
 #include <cinttypes>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_16 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ciso646
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_16 2> %t/header.ciso646
 #if defined(TEST_16)
 #include <ciso646>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_17 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.climits
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_17 2> %t/header.climits
 #if defined(TEST_17)
 #include <climits>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_18 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.clocale
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_18 2> %t/header.clocale
 #if defined(TEST_18)
 #include <clocale>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_19 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cmath
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_19 2> %t/header.cmath
 #if defined(TEST_19)
 #include <cmath>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_20 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.codecvt
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_20 2> %t/header.codecvt
 #if defined(TEST_20)
 #include <codecvt>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_21 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.compare
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_21 2> %t/header.compare
 #if defined(TEST_21)
 #include <compare>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_22 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.complex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_22 2> %t/header.complex
 #if defined(TEST_22)
 #include <complex>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_24 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.concepts
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_24 2> %t/header.concepts
 #if defined(TEST_24)
 #include <concepts>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_25 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.condition_variable
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_25 2> %t/header.condition_variable
 #if defined(TEST_25)
 #include <condition_variable>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_26 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.coroutine
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_26 2> %t/header.coroutine
 #if defined(TEST_26)
 #include <coroutine>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_27 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.csetjmp
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_27 2> %t/header.csetjmp
 #if defined(TEST_27)
 #include <csetjmp>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_28 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.csignal
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_28 2> %t/header.csignal
 #if defined(TEST_28)
 #include <csignal>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_29 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cstdarg
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_29 2> %t/header.cstdarg
 #if defined(TEST_29)
 #include <cstdarg>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_30 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cstdbool
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_30 2> %t/header.cstdbool
 #if defined(TEST_30)
 #include <cstdbool>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_31 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cstddef
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_31 2> %t/header.cstddef
 #if defined(TEST_31)
 #include <cstddef>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_32 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cstdint
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_32 2> %t/header.cstdint
 #if defined(TEST_32)
 #include <cstdint>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_33 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cstdio
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_33 2> %t/header.cstdio
 #if defined(TEST_33)
 #include <cstdio>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_34 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cstdlib
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_34 2> %t/header.cstdlib
 #if defined(TEST_34)
 #include <cstdlib>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_35 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cstring
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_35 2> %t/header.cstring
 #if defined(TEST_35)
 #include <cstring>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_36 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ctgmath
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_36 2> %t/header.ctgmath
 #if defined(TEST_36)
 #include <ctgmath>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_37 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ctime
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_37 2> %t/header.ctime
 #if defined(TEST_37)
 #include <ctime>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_39 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cuchar
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_39 2> %t/header.cuchar
 #if defined(TEST_39)
 #include <cuchar>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_40 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cwchar
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_40 2> %t/header.cwchar
 #if defined(TEST_40)
 #include <cwchar>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_41 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.cwctype
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_41 2> %t/header.cwctype
 #if defined(TEST_41)
 #include <cwctype>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_42 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.deque
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_42 2> %t/header.deque
 #if defined(TEST_42)
 #include <deque>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_44 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.exception
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_44 2> %t/header.exception
 #if defined(TEST_44)
 #include <exception>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_45 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.execution
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_45 2> %t/header.execution
 #if defined(TEST_45)
 #include <execution>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_47 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.filesystem
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_47 2> %t/header.filesystem
 #if defined(TEST_47)
 #include <filesystem>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_49 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.format
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_49 2> %t/header.format
 #if defined(TEST_49)
 #include <format>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_50 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.forward_list
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_50 2> %t/header.forward_list
 #if defined(TEST_50)
 #include <forward_list>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_51 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.fstream
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_51 2> %t/header.fstream
 #if defined(TEST_51)
 #include <fstream>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_52 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.functional
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_52 2> %t/header.functional
 #if defined(TEST_52)
 #include <functional>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_53 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.future
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_53 2> %t/header.future
 #if defined(TEST_53)
 #include <future>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_54 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.initializer_list
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_54 2> %t/header.initializer_list
 #if defined(TEST_54)
 #include <initializer_list>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_56 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.iomanip
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_56 2> %t/header.iomanip
 #if defined(TEST_56)
 #include <iomanip>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_57 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ios
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_57 2> %t/header.ios
 #if defined(TEST_57)
 #include <ios>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_58 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.iosfwd
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_58 2> %t/header.iosfwd
 #if defined(TEST_58)
 #include <iosfwd>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_59 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.iostream
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_59 2> %t/header.iostream
 #if defined(TEST_59)
 #include <iostream>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_60 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.istream
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_60 2> %t/header.istream
 #if defined(TEST_60)
 #include <istream>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_61 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.iterator
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_61 2> %t/header.iterator
 #if defined(TEST_61)
 #include <iterator>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_62 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.latch
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_62 2> %t/header.latch
 #if defined(TEST_62)
 #include <latch>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_63 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.limits
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_63 2> %t/header.limits
 #if defined(TEST_63)
 #include <limits>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_65 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.list
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_65 2> %t/header.list
 #if defined(TEST_65)
 #include <list>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_66 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.locale
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_66 2> %t/header.locale
 #if defined(TEST_66)
 #include <locale>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_68 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.map
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_68 2> %t/header.map
 #if defined(TEST_68)
 #include <map>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_70 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.memory
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_70 2> %t/header.memory
 #if defined(TEST_70)
 #include <memory>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_71 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.mutex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_71 2> %t/header.mutex
 #if defined(TEST_71)
 #include <mutex>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_72 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.new
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_72 2> %t/header.new
 #if defined(TEST_72)
 #include <new>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_73 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.numbers
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_73 2> %t/header.numbers
 #if defined(TEST_73)
 #include <numbers>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_74 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.numeric
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_74 2> %t/header.numeric
 #if defined(TEST_74)
 #include <numeric>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_75 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.optional
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_75 2> %t/header.optional
 #if defined(TEST_75)
 #include <optional>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_76 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ostream
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_76 2> %t/header.ostream
 #if defined(TEST_76)
 #include <ostream>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_77 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.queue
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_77 2> %t/header.queue
 #if defined(TEST_77)
 #include <queue>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_78 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.random
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_78 2> %t/header.random
 #if defined(TEST_78)
 #include <random>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_79 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ranges
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_79 2> %t/header.ranges
 #if defined(TEST_79)
 #include <ranges>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_80 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ratio
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_80 2> %t/header.ratio
 #if defined(TEST_80)
 #include <ratio>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_81 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.regex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_81 2> %t/header.regex
 #if defined(TEST_81)
 #include <regex>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_82 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.scoped_allocator
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_82 2> %t/header.scoped_allocator
 #if defined(TEST_82)
 #include <scoped_allocator>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_83 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.semaphore
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_83 2> %t/header.semaphore
 #if defined(TEST_83)
 #include <semaphore>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_84 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.set
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_84 2> %t/header.set
 #if defined(TEST_84)
 #include <set>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_86 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.shared_mutex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_86 2> %t/header.shared_mutex
 #if defined(TEST_86)
 #include <shared_mutex>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_87 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.span
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_87 2> %t/header.span
 #if defined(TEST_87)
 #include <span>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_88 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.sstream
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_88 2> %t/header.sstream
 #if defined(TEST_88)
 #include <sstream>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_89 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.stack
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_89 2> %t/header.stack
 #if defined(TEST_89)
 #include <stack>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_93 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.stdexcept
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_93 2> %t/header.stdexcept
 #if defined(TEST_93)
 #include <stdexcept>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_97 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.streambuf
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_97 2> %t/header.streambuf
 #if defined(TEST_97)
 #include <streambuf>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_98 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.string
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_98 2> %t/header.string
 #if defined(TEST_98)
 #include <string>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_100 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.string_view
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_100 2> %t/header.string_view
 #if defined(TEST_100)
 #include <string_view>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_101 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.strstream
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_101 2> %t/header.strstream
 #if defined(TEST_101)
 #include <strstream>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_102 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.system_error
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_102 2> %t/header.system_error
 #if defined(TEST_102)
 #include <system_error>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_104 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.thread
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_104 2> %t/header.thread
 #if defined(TEST_104)
 #include <thread>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_105 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.tuple
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_105 2> %t/header.tuple
 #if defined(TEST_105)
 #include <tuple>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_106 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.type_traits
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_106 2> %t/header.type_traits
 #if defined(TEST_106)
 #include <type_traits>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_107 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.typeindex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_107 2> %t/header.typeindex
 #if defined(TEST_107)
 #include <typeindex>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_108 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.typeinfo
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_108 2> %t/header.typeinfo
 #if defined(TEST_108)
 #include <typeinfo>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_110 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.unordered_map
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_110 2> %t/header.unordered_map
 #if defined(TEST_110)
 #include <unordered_map>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_111 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.unordered_set
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_111 2> %t/header.unordered_set
 #if defined(TEST_111)
 #include <unordered_set>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_112 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.utility
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_112 2> %t/header.utility
 #if defined(TEST_112)
 #include <utility>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_113 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.valarray
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_113 2> %t/header.valarray
 #if defined(TEST_113)
 #include <valarray>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_114 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.variant
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_114 2> %t/header.variant
 #if defined(TEST_114)
 #include <variant>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_115 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.vector
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_115 2> %t/header.vector
 #if defined(TEST_115)
 #include <vector>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_116 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.version
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_116 2> %t/header.version
 #if defined(TEST_116)
 #include <version>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_119 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_algorithm
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_119 2> %t/header.experimental_algorithm
 #if defined(TEST_119)
 #include <experimental/algorithm>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_120 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_coroutine
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_120 2> %t/header.experimental_coroutine
 #if defined(TEST_120)
 #include <experimental/coroutine>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_121 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_deque
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_121 2> %t/header.experimental_deque
 #if defined(TEST_121)
 #include <experimental/deque>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_122 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_forward_list
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_122 2> %t/header.experimental_forward_list
 #if defined(TEST_122)
 #include <experimental/forward_list>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_123 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_functional
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_123 2> %t/header.experimental_functional
 #if defined(TEST_123)
 #include <experimental/functional>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_124 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_iterator
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_124 2> %t/header.experimental_iterator
 #if defined(TEST_124)
 #include <experimental/iterator>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_125 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_list
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_125 2> %t/header.experimental_list
 #if defined(TEST_125)
 #include <experimental/list>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_126 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_map
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_126 2> %t/header.experimental_map
 #if defined(TEST_126)
 #include <experimental/map>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_127 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_memory_resource
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_127 2> %t/header.experimental_memory_resource
 #if defined(TEST_127)
 #include <experimental/memory_resource>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_128 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_propagate_const
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_128 2> %t/header.experimental_propagate_const
 #if defined(TEST_128)
 #include <experimental/propagate_const>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_129 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_regex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_129 2> %t/header.experimental_regex
 #if defined(TEST_129)
 #include <experimental/regex>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_130 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_set
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_130 2> %t/header.experimental_set
 #if defined(TEST_130)
 #include <experimental/set>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_131 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_simd
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_131 2> %t/header.experimental_simd
 #if defined(TEST_131)
 #include <experimental/simd>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_132 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_string
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_132 2> %t/header.experimental_string
 #if defined(TEST_132)
 #include <experimental/string>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_133 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_type_traits
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_133 2> %t/header.experimental_type_traits
 #if defined(TEST_133)
 #include <experimental/type_traits>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_134 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_unordered_map
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_134 2> %t/header.experimental_unordered_map
 #if defined(TEST_134)
 #include <experimental/unordered_map>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_135 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_unordered_set
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_135 2> %t/header.experimental_unordered_set
 #if defined(TEST_135)
 #include <experimental/unordered_set>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_136 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_utility
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_136 2> %t/header.experimental_utility
 #if defined(TEST_136)
 #include <experimental/utility>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_137 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.experimental_vector
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_137 2> %t/header.experimental_vector
 #if defined(TEST_137)
 #include <experimental/vector>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_138 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ext_hash_map
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_138 2> %t/header.ext_hash_map
 #if defined(TEST_138)
 #include <ext/hash_map>
 #endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_139 2>&1 | %{python} %S/transitive_includes.sanitize.py > %t/header.ext_hash_set
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes -fsyntax-only -DTEST_139 2> %t/header.ext_hash_set
 #if defined(TEST_139)
 #include <ext/hash_set>
 #endif

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 69a11ec96b84a..5a9fe6a000fba 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -716,6 +716,12 @@ set optional
 set stdexcept
 set type_traits
 set version
+shared_mutex ctime
+shared_mutex iosfwd
+shared_mutex limits
+shared_mutex ratio
+shared_mutex system_error
+shared_mutex type_traits
 shared_mutex version
 span array
 span concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 69a11ec96b84a..5a9fe6a000fba 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -716,6 +716,12 @@ set optional
 set stdexcept
 set type_traits
 set version
+shared_mutex ctime
+shared_mutex iosfwd
+shared_mutex limits
+shared_mutex ratio
+shared_mutex system_error
+shared_mutex type_traits
 shared_mutex version
 span array
 span concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index d5ad19904ed70..346e40b24eb57 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -726,6 +726,12 @@ set optional
 set stdexcept
 set type_traits
 set version
+shared_mutex ctime
+shared_mutex iosfwd
+shared_mutex limits
+shared_mutex ratio
+shared_mutex system_error
+shared_mutex type_traits
 shared_mutex version
 span array
 span concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx2b.csv b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
index a17bc208b654d..e1e57466a6833 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
@@ -621,6 +621,12 @@ set optional
 set stdexcept
 set type_traits
 set version
+shared_mutex ctime
+shared_mutex iosfwd
+shared_mutex limits
+shared_mutex ratio
+shared_mutex system_error
+shared_mutex type_traits
 shared_mutex version
 span array
 span concepts

diff  --git a/libcxx/test/libcxx/transitive_includes_to_csv.py b/libcxx/test/libcxx/transitive_includes_to_csv.py
index 42ac69fad5234..ad86ca79a06e5 100755
--- a/libcxx/test/libcxx/transitive_includes_to_csv.py
+++ b/libcxx/test/libcxx/transitive_includes_to_csv.py
@@ -10,9 +10,9 @@
 from dataclasses import dataclass, field
 from typing import List  # Needed for python 3.8 compatibility.
 import argparse
+import pathlib
 import re
 import sys
-import pathlib
 
 
 @dataclass
@@ -22,6 +22,9 @@ class header:
 
 
 def parse_line(line: str) -> header:
+    """
+    Parse an output line from --trace-include into a `header`.
+    """
     match = re.match(r"(\.+) (.+)", line)
     if not match:
         sys.exit(f"Line {line} contains invalid data.")
@@ -31,59 +34,117 @@ def parse_line(line: str) -> header:
     return header(match.group(2), len(match.group(1)))
 
 
-# Generates the list of transitive includes of a header.
-#
-# The input contains two kinds of headers
-# * Standard headers  (algorithm, string, format, etc)
-# * Detail headers (__algorithm/copy.h, __algorithm/copy_n.h, etc)
-# The output contains the transitive includes of the Standard header being
-# processed. The detail headers are omitted from the output, but their
-# transitive includes are parsed and added, if they are a Standard header.
-#
-# This effectively generates the dependency graph of a Standard header.
+# On Windows, the path separators can either be forward slash or backslash.
+# If it is a backslash, Clang prints it escaped as two consecutive
+# backslashes, and they need to be escaped in the RE. (Use a raw string for
+# the pattern to avoid needing another level of escaping on the Python string
+# literal level.)
+LIBCXX_HEADER_REGEX = r".*c\+\+(?:/|\\\\)v[0-9]+(?:/|\\\\)(.+)"
+
+def is_libcxx_public_header(header : str) -> bool:
+    """
+    Returns whether a header is a C++ public header file.
+    """
+    # Only keep files in the c++/vN directory.
+    match = re.match(LIBCXX_HEADER_REGEX, header)
+    if not match:
+        return False
+
+    # Skip C compatibility headers.
+    if header.endswith(".h"):
+        return False
+
+    # Skip all other detail headers (headers starting with __ or in a subdirectory starting with __).
+    relative = match.group(1)
+    if relative.startswith("__") or re.search(r"(/|\\\\)__", relative):
+        return False
+
+    return True
+
+
+def is_libcxx_header(header : str) -> bool:
+    """
+    Returns whether a header is a libc++ header, excluding the C-compatibility headers.
+    """
+    # Only keep files in the c++/vN directory.
+    match = re.match(LIBCXX_HEADER_REGEX, header)
+    if not match:
+        return False
+
+    # Skip C compatibility headers (in particular, make sure not to skip libc++ detail headers).
+    relative = match.group(1)
+    if relative.endswith(".h") and not (relative.startswith("__") or re.search(r"(/|\\\\)__", relative)):
+        return False
+
+    return True
+
+
 def parse_file(file: pathlib.Path) -> List[str]:
+    """
+    Parse a file containing --trace-include output to generate a list of the top-level C++ includes
+    contained in it.
+
+    This effectively generates the dependency graph of C++ Standard Library headers of the header
+    whose --trace-include it is. In order to get the expected result of --trace-include, the
+    -fshow-skipped-includes flag also needs to be passed.
+    """
     result = list()
     with file.open(encoding="utf-8") as f:
-        level = 999
-
-        # The first line contains the Standard header being processed.
-        # The transitive includes of this Standard header should be processed.
-        header = parse_line(f.readline())
-        assert header.level == 1
-        result.append(header.name)
-
         for line in f.readlines():
             header = parse_line(line)
 
-            # Skip deeper nested headers for Standard headers.
+            # Skip non-libc++ headers
+            if not is_libcxx_header(header.name):
+                continue
+
+            # Include top-level headers in the output. There's usually exactly one,
+            # except if the compiler is passed a file with `-include`. Top-level
+            # headers are transparent, in the sense that we want to go look at
+            # transitive includes underneath.
+            if header.level == 1:
+                level = 999
+                result.append(header)
+                continue
+
+            # Skip libc++ headers included transitively.
             if header.level > level:
                 continue
 
-            # Process deeper nested headers for detail headers.
-            if header.name.startswith("__") or header.name.__contains__("/__"):
+            # Detail headers are transparent too: we attribute all includes of public libc++
+            # headers under a detail header to the last public libc++ header that included it.
+            if header.name.startswith("__") or re.search(r"(/|\\\\)__", header.name):
                 level = 999
                 continue
 
-            # Add the Standard header.
+            # Add the non-detail libc++ header to the list.
             level = header.level
-            result.append(header.name)
-
+            result.append(header)
     return result
 
 
 def create_include_graph(path: pathlib.Path) -> List[str]:
     result = list()
     for file in sorted(path.glob("header.*")):
-        includes = parse_file(file)
-        if len(includes) > 1:
-            result.append(includes)
+        headers = parse_file(file)
+
+        # Get actual filenames relative to libc++'s installation directory instead of full paths
+        relative = lambda h: re.match(LIBCXX_HEADER_REGEX, h).group(1)
+
+        top_level = relative(next(h.name for h in headers if h.level == 1)) # There should be only one top-level header
+        includes = [relative(h.name) for h in headers if h.level != 1]
+
+        # Remove duplicates in all includes.
+        includes = list(set(includes))
+
+        if len(includes) != 0:
+            result.append([top_level] + includes)
     return result
 
 
 def print_csv(graph: List[str]) -> None:
     for includes in graph:
         header = includes[0]
-        for include in sorted(set(includes[1:])):
+        for include in sorted(includes[1:]):
             if header == include:
                 sys.exit(f"Cycle detected: header {header} includes itself.")
             print(f"{header} {include}")


        


More information about the libcxx-commits mailing list