# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

Package `modernc.org/cc/v4` is a C99 compiler **front end** (preprocessor + parser + type checker) written in Go. It does not generate code — it produces an AST plus typed/evaluated metadata that downstream tools (notably `modernc.org/ccgo`) consume. There is no `main` package; the only entry points are library functions in `cc.go`. Sibling versions (`v2`, `v3`, `v5`) live one directory up; do not edit those when working in `v4`.

## Build, generate, test

`go build ./...` and `go test ./...` work from this directory. The host `cc` (or `gcc`) **must** be on PATH because `NewConfig` execs it to extract predefined macros and include paths. Override via `CC=/path/to/compiler`.

Common Makefile targets (Linux / makefile assumes GNU tools — on Windows invoke the underlying `go` commands directly):

- `make test` — full suite, `-timeout 4h -failfast -short`, output tee'd to `log-test`. The non-short suite includes `TestMake` (cross-compiles a `fakecc.go` shim and runs it across many GOOS/GOARCH pairs; skipped on Windows and under `-short`).
- `make tmp` — `go test -v -run Translate`, summarizing TODOs.
- `make ast.go` — regenerates `ast.go` from `parser.yy` (see "Code generation" below).
- `make editor` — gofmt/vet/install loop, runs `staticcheck`. Use this before submitting changes.
- `make cpu` / `make mem` — profile a single test via `go tool pprof`.
- `make win32` / `make win64` — Linux-side cross-test against `*-w64-mingw32-cpp*` via the `CC_TEST_CPP` env var.
- `make build_all_targets` — compile-only check across every supported GOOS/GOARCH listed in `builder.json`.

Test flags (defined in `all_test.go` `TestMain`):

- `-re <regex>` — restrict large corpus walks (`TestTranslationPhase4`, `TestParse`, `TestTranslate`, `TestCPPExpand`, etc.) to matching paths.
- `-trc` — print every tested path as the walkers run.
- `-trcfails` — toggle extended failure tracing.

Run a single test with `go test -run TestParse -re some_regex -v`. The large walking tests iterate `modernc.org/ccorpus2` (an `embed.FS` of real-world C: CompCert, gcc torture, sqlite-amalgamation, tcc, sqlite, benchmarksgame, vnmakarov/mir, etc.), so even with `-short` the suite is slow.

Debug logging: build with `-tags=cc.dmesg` to enable `Dmesg()` (see `dmesg.go` vs `nodmesg.go`). It writes a per-run log directory under `os.TempDir()` and prints the path to stderr.

## Code generation

`ast.go` is **generated** (`// Code generated by yy. DO NOT EDIT.`). Pipeline (from `//go:generate` directives in `cc.go`):

1. `yy` (from `modernc.org/yy`) reads `parser.yy` and emits a fresh `ast.go`.
2. Two `sed` rewrites tighten Expression-related field types.
3. `patch ast.go ast.patch` swaps `ExpressionList.ExpressionList` from interface to concrete pointer and fixes the corresponding nil check in `Position()`.
4. `stringer` regenerates `stringer.go` for `tokCh`, `Kind`, `Linkage`, `StorageDuration`.
5. A final `go test -run ^Example` regenerates example outputs.

After any grammar change in `parser.yy`, run `go generate` (or `make ast.go`). Never edit `ast.go` directly — edit the patch if a tweak must persist. Hand-written companions live in `ast2.go` (accessor methods, `Linkage`/`StorageDuration` logic, helpers like `Declarator.Name`).

## Architecture

The pipeline is **scanner → preprocessor → parser → type checker**, exposed through three layered entry points in `cc.go`:

- `Preprocess(cfg, sources, w)` — runs scanner + cpp only, writes preprocessed text to `w`.
- `Parse(cfg, sources)` — preprocess + parse, returns `*AST` with no types resolved.
- `Translate(cfg, sources)` — preprocess + parse + type-check (`AST.check`), returns a fully analyzed `*AST`. If `Config.EvalAllMacros` is set, Translate additionally walks every object-like constant macro and tries to assign it a `Value`.

`cc.Builtin` is a large string of `__builtin_*` prototypes and macro shims; callers prepend it as a synthetic `Source` together with `cfg.Predefined` (see `_examples/struct.go` and `fakecc.go` for the canonical setup).

### Files and their roles

 File | Role |
---|---|
 `scanner.go` | Byte → token. Defines `tokCh` (the rune codes for multi-char tokens, allocated in the Unicode PUA), `Token`, `Source` plumbing. |
 `cpp.go` | C preprocessor: `cppParser` parses `if-section`/`control-line`/`textLine`; `cpp` performs macro expansion, `#include` resolution, conditional groups. Includes the `Macro` type. `PragmaHandler` callback returns `SkipSource` to stop the current file (used to implement `#pragma once`). |
 `parser.yy` | The yacc grammar. Tokens are listed at the top with their literal spellings. |
 `parser.go` | Hand-written recursive descent that mirrors the grammar (not yacc-generated). Also hosts the `Scope` type and ident lookup. |
 `ast.go` | **Generated** node types — one struct per production with a `Case` discriminator (e.g. `AdditiveExpressionAdd`). Every node implements `Node` (`Position()`); expression nodes also implement `ExpressionNode` (`Type()`, `Value()`, `Pure()`). |
 `ast2.go` | Hand-written accessors that read private fields populated during checking. |
 `check.go` | Type checker. Owns `AST`, the `ctx` (per-translation-unit checker state), `ExpressionNode`, the `flags` set, and almost all `check`/`eval` methods on AST nodes. |
 `type.go` | The `Type` interface and implementations: `PredefinedType`, `PointerType`, `ArrayType`, `StructType`, `UnionType`, `EnumType`, `FunctionType`, `InvalidType`. `Kind` enum and the integer/float/complex kind tables live here. |
 `value.go` | `Value` interface plus concrete value types (`Int64Value`, `UInt64Value`, `Float64Value`, `LongDoubleValue` using `math/big`, complex variants, `StringValue`/`UTF16StringValue`/`UTF32StringValue`, `Unknown`, `Zero`, `VoidValue`). |
 `abi.go` | Per-(GOOS, GOARCH) `AbiType` size/align tables generated from GCC. `NewABI` is the constructor; `Config.ABI` selects them. |
 `cc.go` | Public API: `NewConfig`, `Preprocess`/`Parse`/`Translate`, `Config`, `Source`, `Builtin` string, `NodeSource`/`NodeTokens`, the `errors` slice helper. `newConfig` execs the host CC with `-dM -E -` and `-v -E -` to harvest macros and include paths, retrying with offending flags stripped (see `fixArgs`). |
 `etc.go` | Misc helpers: `LongDouble64Flag` (GOOS/GOARCH → the right `-mlong-double-64` style flag, or `""` when unsupported), `LeastCommonAncestorField`, `origin`/`todo`/`trc`/`errorf`, position translation. |
 `stringer.go` | **Generated** `String()` methods for `tokCh`, `Kind`, `Linkage`, `StorageDuration`. |
 `dmesg.go` / `nodmesg.go` | Mutually exclusive build-tag pair (`cc.dmesg` vs not) gating `Dmesg`. |
 `fakecc.go` | `//go:build ignore` — built into a CC-replacement binary by `TestMake` so the package can replay real `make` builds (HDF5, MPFR, qbe, …) of upstream projects with our front end. |
 `all_test.go` | Everything under `Test*`. Tests share `defaultCfg0` set up in `init()`; large walking tests parallelize via the in-file `parallel` type. |
 `ast_test.go` | Generated `Example*` tests, each showing the AST for a tiny snippet. |
 `testdata/` | Local-only test inputs (`bug/`, `cpp-expand/`, `include/`, `issue127/`, `jhjourdan/`, `preprocess/`, `tcc-0.9.27/`). Large external corpora are pulled from `modernc.org/ccorpus2` (an `embed.FS`, accessed as `cfs` in tests). |
 `_examples/` | Standalone runnable examples (`go run _examples/struct.go`). Underscore means the directory is excluded from package builds. |

### Cross-cutting types

- `Config` (`cc.go`) — everything the front end needs: ABI, include paths (`IncludePaths` for `#include "…"`, `SysIncludePaths` for `#include <…>`; the special `"@"` or `""` entry means "directory of the includer"), predefined macros, optional `FS` (overrides `os.Open`), `PragmaHandler`, default integer kinds, behavior flags (`Header`, `UnsignedEnums`, `IgnoreNegativeShiftAmounts`, `IgnoreStaticAssert`, `EvalAllMacros`). `keywords` (private) is the keyword-rune map, cloned and trimmed when `-ansi`, `-fno-asm`, or `-std=…` strips GCC extensions.
- `AST` (`check.go`) — the root: `TranslationUnit`, `Macros`, file `Scope`, sets of all `Structs`/`Unions`, and after `Translate` a populated set of canonical `Type` fields (`Int`, `Long`, `SizeT`, …).
- `Scope` (`parser.go`) — `Nodes map[string][]Node` plus `Parent`/`Children`. The dynamic types stored under a name are documented above the struct: `*Declarator`, `*EnumSpecifier`, `*Enumerator`, `*LabelDeclaration`, `*LabeledStatement`, `*Parameter`, `*StructOrUnionSpecifier`.
- `Source` (`cc.go`) — `Name`, `Value` (string / `[]byte` / `fs.File` / `io.ReadCloser` / `io.Reader` / nil = open by name), optional `FS` overriding `Config.FS`. Closable values are closed by the front end.
- `Macro` (`cpp.go`) and the `protectedMacros` set (e.g. `__FILE__`, `__LINE__`, `defined`).

### Things that look weird but are intentional

- `NewConfig` shells out to the host C compiler. It is described as "expensive — cache it". Tests call it once via `defaultCfg0`/`defaultCfg`.
- `fixArgs` retries CC after stripping flags the host CC rejected, parsing the diagnostic text (`unknown argument` / `unrecognized command-line option`) to find them. This is how the package stays portable across GCC vs. Apple clang.
- `LongDouble64Flag` returns either `-mlong-double-64` or `""`. When non-empty, `NewConfig` automatically calls `AdjustLongDouble()` to fold `long double` into `double` for ABIs that need it (`linux/arm64`, `linux/riscv64`, etc.). Tests pass it in via `init()`.
- `ExpressionList.ExpressionList` is a concrete pointer (not the generated interface) because of `ast.patch` — keep this in mind when modifying the grammar.
- `purer` / `valuer` / `typer` / `resolver` are embedded carrier structs that give many AST nodes their `Pure()`/`Value()`/`Type()`/`ResolvedIn()` methods. The fields are populated during `check`, not parse — calling them before `Translate` returns zero values.
- The `-short` flag skips `TestMake` (which compiles `fakecc.go` and runs real upstream builds) but keeps the corpus walks. Both can take a long time.
- The package is heavily used by `modernc.org/ccgo` (and downstream `modernc.org/sqlite`, `modernc.org/libc`). Public API breaks should be considered carefully — there is a `retract v4.27.2` line in `go.mod` showing the project does use retraction when needed.
