[Driver][Linux] No fallback to GCC's private headers when resource-dir builtin headers are missing
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
## Summary
On Linux, `Linux::AddClangSystemIncludeArgs()` adds `/include` as the search path for Clang's builtin C headers (`stddef.h`, `stdarg.h`, `stdbool.h`, `float.h`, `limits.h`, ...), but never checks that the path exists, and never falls back to anything else if it doesn't. If a Clang installation is missing `lib/clang//include` directory, any translation unit that includes one of these headers transitively (e.g. via ``) fails with error, even though a fully valid GCC installation with equivalent headers is detected and sitting right next to it.
## Steps to reproduce
1. Take `clang-tidy` binary and install it without its accompanying `lib/clang//include` resource directory. This is a real-world configuration: prebuilt binaries from [cpp-linter/clang-tools-static-binaries](https://github.com/cpp-linter/clang-tools-static-binaries) ship only the `clang-tidy`/`clang-format` executables, with no resource directory at all.
2. Run it on any C/C++ source file on a system with only GCC installed as the system compiler, e.g.:
```console
printf '#include \nint main(void){return 0;}\n' > repro.c
clang-tidy --checks='*' repro.c --
```
## Actual behavior
```
/usr/include/stdio.h:38:10: error: 'stddef.h' file not found [clang-diagnostic-error]
38 | #include
| ^~~~~~~~~~
```
Verbose output confirms the GCC installation is detected correctly:
```console
clang-tidy --checks='*' --extra-arg=-v repro.c --
```
```
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/15
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/15
```
`/usr/local/lib/clang/22/include` (the resource dir) does not exist, and `/usr/lib/gcc/x86_64-linux-gnu/15/include` - GCC's own private builtin header directory, which contains its own copies of `stddef.h`, `stdarg.h` etc. - is never added, even though `GCCInstallation` already resolved to that exact GCC install for other purposes (libstdc++ header search).
## Expected behavior
When the resource-dir's builtin headers are unavailable, Clang should be able to fall back to the detected GCC toolchain's private header directory, the same way it already falls back to it for other purposes, instead of hard-failing on every translation unit.
## Proposed fix
Patch `Linux::AddClangSystemIncludeArgs()` to fall back to `GCCInstallation.getInstallPath() + "/include"` when the resource-dir headers aren't present:
```diff
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -757,6 +757,17 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
(!getTriple().isMusl() || DriverArgs.hasArg(options::OPT_nostdlibinc)))
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
+ // Fall back to GCC's private builtin headers (stddef.h, stdarg.h, ...)
+ // when the resource-dir copy above doesn't exist, e.g. this clang binary
+ // was shipped without its lib/clang//include directory.
+ if (!D.getVFS().exists(ResourceDirInclude) &&
+ !DriverArgs.hasArg(options::OPT_nobuiltininc) &&
+ GCCInstallation.isValid()) {
+ SmallString<128> GCCBuiltinInclude(GCCInstallation.getInstallPath());
+ llvm::sys::path::append(GCCBuiltinInclude, "include");
+ addSystemInclude(DriverArgs, CC1Args, GCCBuiltinInclude);
+ }
+
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
```
Full patch attached:
[gcc-builtin-headers-fallback.patch](https://github.com/user-attachments/files/30471921/gcc-builtin-headers-fallback.patch)
Applies cleanly against `llvmorg-22.1.0`.
## Environment
- clang/clang-tidy version: LLVM 22.1.0 (reproduced against `llvmorg-22.1.0` driver sources)
- Target: `x86_64-unknown-linux-gnu`
- Host GCC: 15.2.0 (Ubuntu)
Contributor guide
Research direction
Start in clang/lib/Driver/ToolChains/Linux.cpp at Linux::AddClangSystemIncludeArgs(), then reproduce the missing-resource-dir case with the clang-tidy command shown. Verify the detected GCC installation and its private include directory, and confirm completion when a source including succeeds without the resource directory.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, linux
- Domain
- compilers, operating-systems
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100