llvm / llvm/llvm-project

[Driver][Linux] No fallback to GCC's private headers when resource-dir builtin headers are missing

Open
#212,555 2 comments 0 reactions 0 assignees View on GitHub
clang:driver platform:linux
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.