[clang] [clang] Skip host default include paths for GPU triples (PR #192821)
Yaxun Liu via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 18 20:13:36 PDT 2026
https://github.com/yxsamliu created https://github.com/llvm/llvm-project/pull/192821
GPU compiles are freestanding. They should not search the host system's
`/usr/include` or `/usr/local/include` by default.
A concrete example is
clang --target=amdgcn-amd-amdhsa -ffreestanding -nogpulib -c foo.c
If `foo.c` contains `#include <string.h>`, Clang should not read the host
header `/usr/include/string.h`. That header belongs to the host libc, not
to the GPU target. On current `main`, however, GPU triples still fall
through to the generic default-include logic, so host include paths are
added and builds can fail on host-only headers such as
`bits/libc-header-start.h`.
Fix this in two parts:
1. In `InitHeaderSearch`, treat all GPU triples (`triple.isGPU()`) like
other targets whose include paths are managed by the driver, and skip
the generic host default-include fallback.
2. In the AMDGPU and NVPTX toolchains, add clang's resource-directory
builtin headers explicitly (`stddef.h`, `float.h`, `stdint.h`, ...).
These are still needed, but they should come from clang's builtin
header directory, not from the host libc.
Add a lit test that checks the printed include search list for GPU
triples and verifies that `/usr/include` and `/usr/local/include` are
not present.
Related: PR #177665.
>From ec53b32b33c3c5931542bed77f25272c1eb512e9 Mon Sep 17 00:00:00 2001
From: "Yaxun (Sam) Liu" <yaxun.liu at amd.com>
Date: Fri, 17 Apr 2026 13:33:56 -0400
Subject: [PATCH] [clang] Skip host default include paths for GPU triples
GPU compiles are freestanding. They should not search the host system's
`/usr/include` or `/usr/local/include` by default.
A concrete example is
clang --target=amdgcn-amd-amdhsa -ffreestanding -nogpulib -c foo.c
If `foo.c` contains `#include <string.h>`, Clang should not read the host
header `/usr/include/string.h`. That header belongs to the host libc, not
to the GPU target. On current `main`, however, GPU triples still fall
through to the generic default-include logic, so host include paths are
added and builds can fail on host-only headers such as
`bits/libc-header-start.h`.
Fix this in two parts:
1. In `InitHeaderSearch`, treat all GPU triples (`triple.isGPU()`) like
other targets whose include paths are managed by the driver, and skip
the generic host default-include fallback.
2. In the AMDGPU and NVPTX toolchains, add clang's resource-directory
builtin headers explicitly (`stddef.h`, `float.h`, `stdint.h`, ...).
These are still needed, but they should come from clang's builtin
header directory, not from the host libc.
Add a lit test that checks the printed include search list for GPU
triples and verifies that `/usr/include` and `/usr/local/include` are
not present.
Related: PR #177665.
---
clang/lib/Driver/ToolChains/AMDGPU.cpp | 17 +++++++++++++++--
clang/lib/Driver/ToolChains/Cuda.cpp | 17 +++++++++++++++--
clang/lib/Lex/InitHeaderSearch.cpp | 10 ++++++++++
.../gpu-targets-no-host-default-includes.c | 19 +++++++++++++++++++
4 files changed, 59 insertions(+), 4 deletions(-)
create mode 100644 clang/test/Preprocessor/gpu-targets-no-host-default-includes.c
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index ff4c781d51348..e229635745dc9 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -879,8 +879,21 @@ void AMDGPUToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
void AMDGPUToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc) ||
- DriverArgs.hasArg(options::OPT_nostdlibinc))
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ // Add clang's builtin headers (`stddef.h`, `float.h`, `stdint.h`, ...).
+ // These are compiler-provided headers, not host libc headers.
+ //
+ // Example: an amdgcn compile may still need `float.h`, but it should come
+ // from clang's resource directory, not from the host system's `/usr/include`.
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> ResourceDirInclude(getDriver().ResourceDir);
+ llvm::sys::path::append(ResourceDirInclude, "include");
+ addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
// Add multilib variant include paths in priority order.
diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp
index dcde82cdf4d85..7c248e3c433f9 100644
--- a/clang/lib/Driver/ToolChains/Cuda.cpp
+++ b/clang/lib/Driver/ToolChains/Cuda.cpp
@@ -790,8 +790,21 @@ void NVPTXToolChain::addClangTargetOptions(
void NVPTXToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc) ||
- DriverArgs.hasArg(options::OPT_nostdlibinc))
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ // Add clang's builtin headers (`stddef.h`, `float.h`, `stdint.h`, ...).
+ // These are compiler-provided headers, not host libc headers.
+ //
+ // Example: an nvptx compile may still need `float.h`, but it should come
+ // from clang's resource directory, not from the host system's `/usr/include`.
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> ResourceDirInclude(getDriver().ResourceDir);
+ llvm::sys::path::append(ResourceDirInclude, "include");
+ addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
// Add multilib variant include paths in priority order.
diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp
index e894086b66e76..7204602dc5514 100644
--- a/clang/lib/Lex/InitHeaderSearch.cpp
+++ b/clang/lib/Lex/InitHeaderSearch.cpp
@@ -210,6 +210,16 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
const llvm::Triple &triple) {
+ // GPU targets are freestanding, so they should not search the host system's
+ // `/usr/include` or `/usr/local/include`.
+ //
+ // Example: `clang --target=amdgcn-amd-amdhsa -ffreestanding -nogpulib`
+ // compiling a file with `#include <string.h>` should not read the host
+ // glibc header `/usr/include/string.h`. GPU toolchains add their own include
+ // paths explicitly, so skip the generic host fallback here.
+ if (triple.isGPU())
+ return false;
+
switch (triple.getOS()) {
case llvm::Triple::AIX:
case llvm::Triple::DragonFly:
diff --git a/clang/test/Preprocessor/gpu-targets-no-host-default-includes.c b/clang/test/Preprocessor/gpu-targets-no-host-default-includes.c
new file mode 100644
index 0000000000000..952c4b98c0fe9
--- /dev/null
+++ b/clang/test/Preprocessor/gpu-targets-no-host-default-includes.c
@@ -0,0 +1,19 @@
+// Check that GPU targets do not get the host system's default C include
+// paths (e.g. /usr/include, /usr/local/include) appended to the search list.
+// GPU toolchains are freestanding and manage their own include paths.
+//
+// Use `-v -E` on the source with `-nogpulib` to print the toolchain's
+// include search list and verify the host paths are absent.
+
+// RUN: %clang --target=amdgcn-amd-amdhsa -nogpulib -v -E -x c %s \
+// RUN: -o /dev/null 2>&1 | FileCheck %s
+
+// RUN: %clang --target=amdgcn--amdhsa -nogpulib -v -E -x c %s \
+// RUN: -o /dev/null 2>&1 | FileCheck %s
+
+// RUN: %clang --target=nvptx64-nvidia-cuda -nogpulib -nogpuinc -v -E -x c %s \
+// RUN: -o /dev/null 2>&1 | FileCheck %s
+
+// CHECK-NOT: /usr/include{{$}}
+// CHECK-NOT: /usr/local/include{{$}}
+// CHECK: End of search list.
More information about the cfe-commits
mailing list