Skip to content

cc: a 64-bit case TYPE is not a 64-bit case VALUE - #616

Merged
staalmannen merged 1 commit into
mainfrom
claude/upgrade-ape-c-library-mmZGd
Oct 8, 2026
Merged

staalmannen merged 1 commit into
mainfrom
claude/upgrade-ape-c-library-mmZGd

Conversation

@staalmannen

Copy link
Copy Markdown
Owner

The chicken rebuild went from 8 duplicate cases in switch 0' to 4. The four that went were runtime.c:12578, the switch on 64-bit bits', which is the L-suffix fix confirmed where it was predicted. The four that remain are 12525, the switch on a plain int, and they were never the suffix: the same four were there before.

Two defects in cc/pswt.c, and only the second was audible.

pgen.c:342 sets a case's `isv' from typev[type] alone -- the TYPE -- and doswit discarded every such case in a switch whose expression is 32 bits, under the comment "can never match". That sentence is about a VALUE too wide to appear; it was being applied to a small number with a wide type. chicken.h writes every immediate as ((C_word)(C_SPECIAL_BITS | 0x10)) and C_word is 64 bits here, so four of decode_literal2's eight labels are 0x0e/0x1e/0x3e/0x4e wearing int64_t, and the switch would have fallen to default for all four at run time. Silent: the file compiles.

And `nc' was the number of non-default cases, counted before that loop could drop any, while alloc() is a hunk bump allocator that does not zero. So qsort and the duplicate scan ran over nc entries of which the last few had never been written, and reported those against each other -- naming a case the program does not contain. Five dropped labels give exactly four reports, all of value 0, which is the arithmetic in the message.

C 6.8.4.2p5 decides it and gcc agrees when asked: a case label "is converted to the promoted type of the controlling expression", so a wide label is truncated and then compared like any other -- case 0x100000001LL: in a switch on an int is reached by 1, and a label that truncates onto another one is a genuine duplicate rather than something to throw away. The (long) cast already performed exactly that conversion, so the fix is deleting the drop plus nc = q - iq. The warning stays and is now about the value, guarded by c->isv so an ordinary case 0xffffffffU: in an unsigned switch does not warn on sign extension.

My first fix and my first test were both the other rule -- drop only what does not survive truncation -- and gcc refused to compile the test that asserted it, because case 0x100000000LL: truncates onto case 0:. Checking against the host first changed what the fix should be, not just whether the test was right.

switchcase-test.c is the regression test. Section 2 is the one that matters: a compiler with only the loud half fixed compiles cleanly and selects the wrong arm, so the error going away is not evidence -- only asking which arm ran separates them. 0 failures on gcc, where long is 64 bits so neither bug can arise, which says the test is written correctly and nothing more.

Watch the first full rebuild: a 64-bit-typed label that truncates onto another one used to be dropped silently and is now a duplicate cases error, so a package that relied on that fails loudly rather than quietly.

Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs

The chicken rebuild went from 8 `duplicate cases in switch 0' to 4.
The four that went were runtime.c:12578, the switch on 64-bit `bits',
which is the L-suffix fix confirmed where it was predicted.  The four
that remain are 12525, the switch on a plain int, and they were never
the suffix: the same four were there before.

Two defects in cc/pswt.c, and only the second was audible.

pgen.c:342 sets a case's `isv' from typev[type] alone -- the TYPE --
and doswit discarded every such case in a switch whose expression is
32 bits, under the comment "can never match".  That sentence is about
a VALUE too wide to appear; it was being applied to a small number
with a wide type.  chicken.h writes every immediate as
((C_word)(C_SPECIAL_BITS | 0x10)) and C_word is 64 bits here, so four
of decode_literal2's eight labels are 0x0e/0x1e/0x3e/0x4e wearing
int64_t, and the switch would have fallen to default for all four at
run time.  Silent: the file compiles.

And `nc' was the number of non-default cases, counted before that
loop could drop any, while alloc() is a hunk bump allocator that does
not zero.  So qsort and the duplicate scan ran over nc entries of
which the last few had never been written, and reported those against
each other -- naming a case the program does not contain.  Five
dropped labels give exactly four reports, all of value 0, which is
the arithmetic in the message.

C 6.8.4.2p5 decides it and gcc agrees when asked: a case label "is
converted to the promoted type of the controlling expression", so a
wide label is truncated and then compared like any other --
case 0x100000001LL: in a switch on an int is reached by 1, and a
label that truncates onto another one is a genuine duplicate rather
than something to throw away.  The (long) cast already performed
exactly that conversion, so the fix is deleting the drop plus
nc = q - iq.  The warning stays and is now about the value, guarded
by c->isv so an ordinary case 0xffffffffU: in an unsigned switch does
not warn on sign extension.

My first fix and my first test were both the other rule -- drop only
what does not survive truncation -- and gcc refused to compile the
test that asserted it, because case 0x100000000LL: truncates onto
case 0:.  Checking against the host first changed what the fix should
be, not just whether the test was right.

switchcase-test.c is the regression test.  Section 2 is the one that
matters: a compiler with only the loud half fixed compiles cleanly
and selects the wrong arm, so the error going away is not evidence --
only asking which arm ran separates them.  0 failures on gcc, where
long is 64 bits so neither bug can arise, which says the test is
written correctly and nothing more.

Watch the first full rebuild: a 64-bit-typed label that truncates
onto another one used to be dropped silently and is now a duplicate
cases error, so a package that relied on that fails loudly rather
than quietly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
@staalmannen
staalmannen merged commit 0344c81 into main Oct 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants