Files
Bear-mirror/docs/requirements/recognition-cpp20-modules.md
Laszlo NagyandClaude Opus 4.8 08b72c08d5 docs(requirements): make the criteria minimal and every scenario real
Criterion-by-criterion pass over the 24 requirement files for a
minimal-but-complete contract set. Sixteen criteria that carried no
contract a user relies on are deleted (over-enumeration, restatements
of another file's contract, an unobservable same-source-twice rule that
duplicate detection collapses, untestable "may" disclaimers). Seventeen
instance-enumerations become one owned property each - source-extension
lists, kept-flag and link-flag lists, per-shape repeats, the MSVC /link
tail folded into "family-defined link-stage flag sets" - with the lists
retained as subject-matter references and a representative scenario
declared to cover them. Every generalization was checked to imply each
instance it replaces.

About thirty-five acceptance criteria that a real test already guarded
had no Given-When-Then scenario; these are written down now, modeled on
what the tests actually assert, and the implementing tests are tagged.
The genuine coverage gaps are closed with new tests: exact-exit-code
propagation, all-dropped and understood-but-empty exit codes, the
forced-preload rejection (the long-open mode-selection gap), a Fortran
entry, a masquerade launcher recorded under a compiler name, duplicate
output order, header/real-entry dedup, response-file source
participation, output-field path formatting, and reporting-failure
tolerance in wrapper mode. Coverage: 24/24 implemented requirements.

Found by the /requirements skill audit (dogfooding 1038d916).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:02:04 +00:00

3.3 KiB

title, status
title status
Recognize C++20 module compilations implemented

Intent

When a user builds a project that uses C++20 modules, the build invokes the compiler on module-interface source files (typically .cppm, .ixx, .ccm) and on module-related driver flags (e.g. clang++ --precompile, -fmodule-file=). The user expects the generated compile_commands.json to include these compilations the same way it includes ordinary .cpp translation units. Clang tooling (clangd, clang-tidy) needs the module inputs and module-path flags to follow imports and produce accurate diagnostics.

Acceptance criteria

  • A compilation whose source file has a recognized C++20 module-interface extension produces a database entry like any other translation unit. The recognized set: .cppm, .ixx, .mxx, .ccm, .cxxm, .c++m.
  • Module-related driver flags, value-carrying or not, never swallow a following source file and never suppress or corrupt the entry. The recognized set:
    • --precompile (Clang module-interface compile)
    • -fmodule-file=* (Clang/GCC, including the <name>=<file> form)
    • -fmodule-map-file=*
    • -fmodule-name=*
    • -fmodules, -fno-modules, -fcxx-modules
    • -fmodules-ts (Clang transitional)
    • -fprebuilt-module-path=*
    • -fbuiltin-module-map
    • -fimplicit-modules, -fno-implicit-modules
    • GCC: -fmodules-ts, -fmodule-header, -fmodule-only, -fmodule-mapper=*, -fmodule-lazy
  • Precompiled module artifacts (.pcm, BMI files) are not classified as sources. They appear on argv but never as the entry's file field.

Non-functional constraints

  • The recognition layer must remain extension-driven for the source check. Probe-based detection of module-interface units is out of scope.

Known limitations

Module dependency-graph awareness, BMI cache discovery, and module-map authoring are accepted exclusions: this contract covers capturing the module compilation invocations and nothing more.

Testing

Given a build that compiles a module-interface unit:

When the user runs bear -- clang++ -std=c++20 --precompile foo.cppm -o foo.pcm, then the resulting compile_commands.json contains one entry whose file is foo.cppm and whose arguments preserve --precompile and the input/output paths.

Given a build that consumes a precompiled module:

When the user runs bear -- clang++ -std=c++20 -fmodule-file=foo=foo.pcm -c main.cpp, then the resulting compile_commands.json contains one entry whose file is main.cpp with the -fmodule-file=foo=foo.pcm flag preserved, and no entry is produced for foo.pcm.

Given a mixed build with one module interface and one consumer:

When the user runs both commands above in sequence, then compile_commands.json contains exactly two entries (one for foo.cppm, one for main.cpp).

Given a GCC build using -fmodules-ts:

When the user runs bear -- g++ -std=c++20 -fmodules-ts -c mod.cppm, then the resulting compile_commands.json contains one entry whose file is mod.cppm.

The .cppm scenarios above are representative of every extension in the recognized set. The --precompile, -fmodule-file=, and -fmodules-ts scenarios are representative of every flag in the recognized set, value-carrying and plain alike.

Notes

  • Demand: issue #637.