test: support target-matrix and post-ABI IR checks - #2319
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
bf3ac2a to
1c8e3cd
Compare
LLGo baseline benchmarks
Program measurements
Core language and compiler benchmarks
Compared with |
11e94b6 to
b8e5518
Compare
|
/review |
b8e5518 to
d12e4d4
Compare
|
/review |
d12e4d4 to
45ffb53
Compare
|
/review |
386ff27 to
ac6f7b1
Compare
|
/review |
|
/review |
|
/review |
|
/review |
There was a problem hiding this comment.
Review: target-matrix and post-ABI IR checks
Solid, well-structured PR. The Spec-based refactor of littest is a clear improvement over the old Mode enum, error handling is consistent, dead code (generalizeClosureEnvAttrs, genZip/inCompilerDir, out.ll special-casing) is cleanly removed, and the multi-target merge logic (LCS + per-GOARCH grouping) is thoughtfully separated. Empty-slice guards are present in the merge/rewrite functions, and the panic→error recovery in genTargetVariants correctly re-panics on unexpected payloads.
Findings below are non-blocking; the first is the one most worth confirming. No blocking correctness bugs found.
Verification: four review dimensions (quality, performance, security, docs) run against the fixed diff range 7f954d6...17d1c86.
Additional notes (no inline location)
- Performance (informational): per-target compiles in
testFrom/testIRTargetsandgenTargetVariantsscale linearly with the target matrix, andForceRebuild=true(required for correctness — a cache hit skips the module text) means each compile pays full build cost. Fine for test tooling; just keepLITTESTmatrices deliberately small. - Docs (cosmetic):
CLAUDE.md:80-83shows both// LITTEST ...and// LITTEST: POST-ABI ...markers in one fenced block. They are mutually exclusive first-line markers; splitting into two blocks (asdev/README.mddoes) would avoid reading them as one header.
| func additionalIRTargets(targets []littest.Target, currentPrefix string) []littest.Target { | ||
| additional := make([]littest.Target, 0, len(targets)) | ||
| for _, target := range targets { | ||
| prefixes := filecheck.TargetPrefixes(target.GOOS, target.GOARCH, "") |
There was a problem hiding this comment.
[P2] additionalIRTargets dedup uses inconsistent prefix derivation
currentPrefix is computed by the caller from the actual generated base target via filecheck.TargetPrefixes(goos, goarch, generated.Target), so if the base build has a non-empty named Target it becomes TARGET-<X>. But here each matrix entry's prefix is recomputed with an empty target string (TargetPrefixes(target.GOOS, target.GOARCH, "")), yielding <GOOS>-<GOARCH>. When the base target is named, the equality check never matches, so the entry equal to the base is not skipped and gets recompiled/rechecked redundantly. In the common golden-test flow Target is empty so this is latent, but the two sides derive the prefix from different inputs. Consider deduplicating on GOOS/GOARCH directly, or feeding the same TargetPrefixes inputs on both sides.
| default: | ||
| return Spec{}, false, nil |
There was a problem hiding this comment.
[P3] Malformed LITTEST marker silently disables the spec file
A first line that starts with the marker but doesn't parse — e.g. // LITTEST: POST-ABI-EXTRA or // LITTESTfoo — fails the exact-match switch and both HasPrefix(marker, X+" ") cases, so it falls into default and returns found=false, treating the file as having no marker at all. Given the fail-loud handling elsewhere (parseTargets errors on bad targets), a mistyped LITTEST/LITTEST: POST-ABI directive vanishing silently is inconsistent and could mask an author error. Consider returning an error when the line begins with the marker prefix but doesn't parse.
| seen := make(map[string]struct{}, len(fields)) | ||
| for _, field := range fields { | ||
| goos, goarch, ok := strings.Cut(field, "/") | ||
| if !ok || goos == "" || goarch == "" || strings.Contains(goarch, "/") { |
There was a problem hiding this comment.
[P3] parseTargets: whitelist GOOS/GOARCH characters
parseTargets rejects empty components and a goarch containing /, but not ., .., backslashes, or other path-meaningful characters. These values later flow into a result.<GOOS>-<GOARCH>.txt filename (cltest.go) and into a FileCheck --check-prefix= arg. Practical path traversal is blocked (only one / is guaranteed and it's stripped; reaching the write requires the target to actually compile), and prefixes are passed as separate argv entries so there's no injection — but a defensive whitelist like ^[a-z0-9_]+$ on GOOS/GOARCH would remove the ambiguity cheaply. Also note the strings.Contains(goarch, "/") guard is what rejects a/b/c (since Cut splits on the first /); a brief comment there would clarify intent.
62dc5f3 to
d1aedbd
Compare
9df1593 to
64ac44b
Compare
64ac44b to
8b5e93f
Compare
Summary
Add explicit, source-embedded FileCheck support for target matrices and opt-in post-ABI IR while keeping focused handwritten checks as the default.
// LITTEST <GOOS/GOARCH...>cross-generates the existing default IR stage for every listed target.// LITTEST: POST-ABI <GOOS/GOARCH...>explicitly selects target-ABI-lowered, pre-optimization IR.CHECKand applicable GOARCH assertions. Add it to the matrix when it has a distinct IR contract.CHECK,ARM64,DARWIN-ARM64: portable assertions useCHECK, same-architecture assertions useARM64/AMD64, and only true OS differences use the exact target prefix.litgensupports automatic target-matrix maintenance at the default and post-ABI stages. It first merges all-target output, then safely merges identical gaps among two or more targets with the same GOARCH.nest|swiftself, jmpbuf sizes, setjmp names, and stderr symbols are replaced by explicit target assertions.// LITTEST, because cross-cgo additionally requires a target C compiler, headers, and sysroot; their explicit platform checks run on matching platform CI.out.llIR-check modes remain removed; source-embedded FileCheck is the only IR golden path.Validation
go fmt ./...git diff --checkgo test ./internal/littest ./internal/filecheck ./internal/llgen ./chore/litgen ./cl/cltestgo test ./chore/litgen -coverprofile=...(80.7% statement coverage)go run ./chore/litgen -u --check clgo test ./cl -count=1on Darwin/arm64 (includes current and additional matrix targets; 307.038s)ARM64folding while retainingLINUX-AMD64differencesgoallc-ubuntu, proving Linux current-target checks are deduplicated while Darwin/arm64 and Linux/arm64 share the generated architecture contract