Guard <riscv_vector.h> by target in the implicit toolchain probe

The implicit toolchain probe includes every system header that the
runtime and vendored sources spell, under __has_include. clang ships
<riscv_vector.h> for every target, and through clang 18 including it
without the RISC-V vector extension is an #error. Since the vendored
zlib's adler32_simd.c spells it, the probe failed with clang 18, which
disabled the native cache and program sharding: a sanitized dev build
then compiled the whole program as one translation unit.

The probe now includes <riscv_vector.h> only where __riscv_vector is
defined, and the probe's header test covers it and a riscv64 target.
This commit is contained in:
Chris Tate
2026-10-26 17:58:37 -05:00
parent 3c83fcb89c
commit f003bb4d68
2 changed files with 18 additions and 8 deletions
@@ -630,20 +630,27 @@ test.skipIf(clangExecutable === undefined)(
async () => {
// clang ships its x86 intrinsic headers (<emmintrin.h>, ...) for every
// target, so __has_include finds them on arm64, where including them is
// an #error, and the same holds for the ARM headers on x86. The probe
// must guard them by target. Only the compiler's own freestanding
// headers are visible here, so the result does not depend on the host's
// C library.
// an #error, and the same holds for the ARM headers on x86 and for
// <riscv_vector.h> (zlib's RVV code) outside RISC-V with the vector
// extension. The probe must guard them by target. Only the compiler's own
// freestanding headers are visible here, so the result does not depend on
// the host's C library.
const includes = (await implicitDependencyProbeIncludes(runtimeSrcDir())).filter(
(include) =>
include !== "<intrin.h>" && /intrin\.h>$|^<cpuid\.h>$|^<arm_(neon|acle)\.h>$/.test(include),
include !== "<intrin.h>" &&
/intrin\.h>$|^<cpuid\.h>$|^<arm_(neon|acle)\.h>$|^<riscv_vector\.h>$/.test(include),
);
expect(includes).toContain("<emmintrin.h>");
expect(includes).toContain("<riscv_vector.h>");
const resourceDir = execFileSync(clangExecutable!, ["-print-resource-dir"], {
encoding: "utf8",
}).trim();
const source = includes.map(implicitDependencyIncludeDirective).join("");
for (const target of ["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"]) {
for (const target of [
"aarch64-unknown-linux-gnu",
"riscv64-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
]) {
const result = spawnSync(
clangExecutable!,
[
@@ -207,7 +207,8 @@ function x86OnlyHeader(include: string): boolean {
/** One guarded line of the implicit-toolchain probe source: the header is
* included only when the compiler can find it and it belongs to the target
* being probed. */
* being probed. clang ships <riscv_vector.h> for every target, and through
* clang 18 including it without the RISC-V vector extension is an #error. */
export function implicitDependencyIncludeDirective(include: string): string {
const targetCondition = x86OnlyHeader(include)
? " && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))"
@@ -215,7 +216,9 @@ export function implicitDependencyIncludeDirective(include: string): string {
? " && defined(_WIN32)"
: include === "<arm64_neon.h>" || include === "<arm_acle.h>" || include === "<arm_neon.h>"
? " && (defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64))"
: "";
: include === "<riscv_vector.h>"
? " && defined(__riscv_vector)"
: "";
return `#if __has_include(${include})${targetCondition}\n#include ${include}\n#endif\n`;
}