Bug A — MCEmitter: label NNNN placed twice compiling yyjson at -O0
Status: FIXED. yyjson compiles, links, and runs at both -O0 and -O1 and
matches clang. The defect was in the front end, not the emitter: a goto
label whose first mention is inside a constant-false (codegen-suppressed)
region was assigned c_cg_label_new's suppression sentinel instead of a real
CG-label id, so it later aliased the function's first real label and the -O0
native emitter aborted placing that id twice. parse_function_body now keys
goto-label allocation off whether the function emits at all
(Parser.cur_func_emits), not the momentary suppress depth. Regression:
test/parse/cases/6_8_06_01_goto_label_in_dead_branch.c.
Original report (kept for the root-cause record):
Component: the symptom prints from the machine-code emitter (src/arch/*/
MCEmitter label pass), but the root cause is front-end label allocation.
Severity: kit cannot compile yyjson at -O0 at all.
Symptom
yyjson.c:9041:1: fatal: MCEmitter: label 6020 placed twice
The line (and the internal label number) move slightly with the input, but it
always lands on a fail_*: epilogue label of a large writer function —
yyjson_write_single (yyjson.c:8947–9044) or 9053–9216). These functions are big yyjson_write_minify
(switch bodies whose arms all goto a
shared handful of fail_alloc:/fail_type:/fail_num:/fail_str: epilogues
(via the return_err macro). The emitter places the same internal label
twice — i.e. a basic-block/label-dedup defect when many predecessors branch to
one shared, late label in a large function.
Reproduce
make provision-ecosystem # once (network)
KIT=build/kit
SDK="$(xcrun --sdk macosx --show-sdk-path)"
YY="$(sh scripts/ecosystem.sh srcdir yyjson)"
# Fails at -O0:
$KIT cc -O0 --sysroot "$SDK" -I "$YY" -c "$YY/yyjson.c" -o /tmp/yyjson.o
Notes for digging
- -O1 compiles this TU fine — the bug is specific to the -O0 native emitter path, not the optimizer. (At -O1 yyjson then trips Bug B at link instead.)
- The internal label is an MCEmitter label id, not a source label, so this is in the backend label/branch fixup, not the C front end.
- Likely the same shared-late-label shape can be reduced to a small synthetic
function (big
switch, every armgoto fail;, onefail:at the end). A minimal reducer is still TODO — drop it next to this doc asyyjson_label.conce found.