aspect-build / aspect-build/rules_lint

clang_tidy aspect strips absolute -isystem paths as MSVC flags → 'cstdint' file not found with hermetic LLVM toolchain on macOS

Open
#924 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Starlark
Stars
154
Forks
125
Avg merge
3d 21h
Merged PRs (30d)
20

Description

> **Disclosure:** This report was generated by Claude (Anthropic) from an automated investigation while integrating the `clang_tidy` aspect with a hermetic LLVM toolchain. The root cause was traced to source and the repro observed directly, but please verify before acting.

### Summary

On macOS with a hermetic LLVM toolchain (`toolchains_llvm`), the `clang_tidy` aspect fails every C++ target with:

```
error: 'cstdint' file not found [clang-diagnostic-error]
```

The cause is `_update_flag` in `lint/clang_tidy.bzl` treating any argument that starts with `/` as an MSVC `/flag` and dropping it — which includes the **absolute C++ standard-library include path** that the toolchain passes as a separate token after `-isystem`.

### Root cause

`lint/clang_tidy.bzl` (v2.7.1, also present on `main`), in `_update_flag`:

```python
elif (flag.startswith("/")):
# strip all other microsoft params
return []
```

`_safe_flags` runs `_update_flag` over each token of the toolchain compile command line individually. Bazel / `toolchains_llvm` passes system include dirs as **two tokens**, e.g.:

```
-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1
```

The path token starts with `/`, so it is stripped (the preceding `-isystem` is kept, now orphaned). The libc++ headers become unreachable, so `` (and other stdlib headers) fail to resolve.

This is macOS-specific in practice: on Linux the toolchain's libc++/sysroot paths are exec-root-relative (`external/...`), so they don't start with `/` and survive. On macOS, `toolchains_llvm` uses the absolute Xcode SDK path.

### Reproduction

- Bazel 9.x (Bzlmod), macOS.
- Hermetic toolchain via `toolchains_llvm` (e.g. LLVM 19.x).
- A trivial `cc_library` whose source does `#include `.
- Run the `clang_tidy` aspect over it.

Result: `error: 'cstdint' file not found [clang-diagnostic-error]`.

Setting `verbose = True` on the aspect confirms it — the absolute libc++ path appears in the `skipped flags:` line:

```
skipped flags: -Wall -Wthread-safety -Wself-assign /Applications/Xcode.app/.../MacOSX.sdk/usr/include/c++/v1 -Wno-module-import-in-extern-c -Wno-builtin-macro-redefined
```

### Impact

The `clang_tidy` aspect is effectively unusable with a hermetic LLVM toolchain on macOS — every C++ translation unit errors out on standard-library headers. It is independent of which checks are enabled, since the failure is a `clang-diagnostic-error` at parse time.

### Suggested fix

The MSVC `/flag` heuristic should not consume absolute POSIX paths. Options:

- Don't strip a `/`-prefixed token that is the **argument of a preceding** `-isystem`/`-I`/`-iquote`/`-isysroot` (handle include-flag pairs together).
- Only apply the MSVC remap when actually targeting MSVC (gate on the toolchain/platform).
- Distinguish MSVC flags from filesystem paths (an absolute path with `/` separators that exists on disk is not `/D`, `/I`, or `/std:`).

### Related

- #566 — same failure family (clang-tidy can't resolve toolchain stdlib headers on macOS), reported as a symptom; the underlying `_update_flag` strip isn't identified there.
- #779 (open) — adds `-isysroot`; helps the symptom, but the `/`-prefix strip in `_update_flag` remains, so absolute `-isystem` paths are still dropped.

### Versions

- `aspect_rules_lint` v2.7.1 (strip also present on `main`)
- Bazel 9.1.x, `toolchains_llvm` (LLVM 19.1.7), macOS

Contributor guide

Open the contributing guide

Research direction

Read `_update_flag` and `_safe_flags` in `lint/clang_tidy.bzl`, then reproduce with the described `cc_library` including `` and the `clang_tidy` aspect on macOS using `toolchains_llvm`. Check how the separate `-isystem` path token is handled. Done means the absolute SDK include path is preserved and the aspect no longer reports `cstdint` missing.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
62/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.