Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Unused Includes Cleanup #128421

Unanswered
moyo1997 asked this question in Ideas
Discussion options

Hello! I have a PR (#127295) intended to remove unused #include directives from 102 source files in CoreCLR.

Goals & Benefits

  • Reduced coupling — removing unnecessary transitive dependencies makes the header graph cleaner and easier to reason about
  • Easier refactoring — when headers aren't included where they aren't needed, future header changes trigger fewer unnecessary recompilations
  • Improved code clarity — each file's includes reflect its actual dependencies, making it easier for contributors to understand what a file uses

Approach

The initial pass was generated by an automated tool without cross-platform context, then iterated to fix issues across all target platforms. The final result was validated through binary-level comparison of compiled output across all CI platforms and configurations.

Validation Methodology

Two CI builds were run, publishing .obj/.o files for all 102 modified source files:

Build Description
[#1421850] With include cleanup (PR changes)
[#1422568] Baseline (no cleanup)

Artifacts were downloaded (~15.7 GB across 40 platform/config combinations) and compared using platform-appropriate tools: llvm-objdump for disassemblable objects, pyelftools for LoongArch64 ELF sections, and binary/string analysis for LTCG objects.

Results

Disassemblable objects (x64, ARM64, ARM, RISC-V, WASM): 11,301 files compared. 5,868 were byte-identical. The remaining 3,919 diffs were exclusively __LINE__ constant shifts (e.g., line 825 → 824) caused by removed #include lines shifting source line numbers. Zero opcode, register, branch target, or structural changes.

LTCG/WPO objects (Windows Release): All 1,255 objects had diffs fully explained by removed header path strings, changed anonymous namespace hashes (?A0x... values — deterministic but path-sensitive), and removed type metadata from unused headers. Cross-validated against non-LTCG (Checked) builds of the same sources, which produce identical machine code.

LoongArch64 native objects: 87 identical code sections, 132 with immediate-field-only diffs (__LINE__). Zero structural changes. Verified by extracting executable ELF sections and comparing instruction words.

x86_64 cross-compiled objects (LoongArch build): 4 identical, 30 with constant-only __LINE__ diffs. Zero structural changes, even with TARGET_LOONGARCH64 defines active.

Conclusion

This PR produces zero code-generation changes across all platforms and configurations.

Every observed diff falls into one of two categories:

  1. __LINE__ macro shifts — removing an #include line shifts subsequent line numbers by 1–2, changing only debug-info constants
  2. LTCG metadata — removed header paths and type info that was never referenced in compiled code

No removed include provided macros, constants, type definitions, or declarations that affected any compiled code path on any architecture (x64, ARM64, ARM, RISC-V, WASM, LoongArch64) in any configuration (Debug, Checked, Release). All CI pipelines pass.

Feedback Welcome

I understand this is a large mechanical change, so I want to make sure it lands cleanly. If you spot an include that should be kept e.g. for documentation, forward-compatibility, or a platform I may have missed, please flag it and I'm happy to restore it.

You must be logged in to vote

Replies: 1 comment

Comment options

As described multiple times, this task shouldn't be performed without basic understanding of the codebase, and should never be done mechanically.

  • Reduced coupling — removing unnecessary transitive dependencies makes the header graph cleaner and easier to reason about
  • Improved code clarity — each file's includes reflect its actual dependencies, making it easier for contributors to understand what a file uses

This is largely incorrect. Many headers are used directly, and the compilation successes because they are happened to brought from transitive dependencies.

For example, callcounting.h is removed from callcounting.cpp. This should never happen with the basic sense of C++ standard practice.

The final result was validated through binary-level comparison of compiled output across all CI platforms and configurations.

This repo contains code that's currently never enabled in any configuration, but still has usage during development. CI is not enough for validating them.

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Ideas
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /