1: Sample code that reproduces the problem.
struct S
{
int *a[2];
};
int f(_Optional struct S *s)
{
if (!s)
return 0;
return *s->a[0];
}
2: Exact command used to run SDCC on this sample code.
sdcc -mz80 --stack-auto --std-c11 -S inherited-optional.c
The problem also reproduces with -mstm8 and -mmos65c02 in place of -mz80.
3: SDCC versions tested (type "sdcc -v" to find it).
Compiler Explorer's SDCC trunk compiler, checked on 20 October 2026:
SDCC : mcs51/z80/z180/r2k/r2ka/r3ka/r4k/r5k/r6k/sm83/tlcs90/ez80/z80n/r800/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15/mos6502/mos65c02/huc6280/f8/f8l TD- 4.6.4 #17013 (Linux)
published under GNU General Public License (GPL)
Also reproduced in a local build using the shared compiler sources and the Z80, STM8 and MOS6502 port sources from r17041, including the fix for [bugs:#4161].
4: Copy of the error message or incorrect output, or a clear description of the observed versus expected behaviour.
<source>:10: warning 355: pointer to _Optional could not be proven to be non-null at dereference
No diagnostic is expected for the return expression. The preceding check establishes that s is non-null, and a[0] has type pointer to unqualified int, not pointer to _Optional int.
Copying the member's value into a local pointer before dereferencing it suppresses the warning:
int *p = s->a[0];
return *p;
Replacing the array member with an ordinary pointer member and returning *s->p also suppresses the warning.
5: Relationship to previous fixes and suggested correction.
The fix for [bugs:#4161] in [r17041] corrects the placement of inherited volatile qualification for array members in geniCodeStruct, but leaves the corresponding _Optional handling unchanged:
SPEC_OPTIONAL (retype) |= SPEC_OPTIONAL (etype);
For an array of pointers, retype denotes the terminal int specifier. The assignment therefore incorrectly qualifies the referenced int, rather than the array's pointer elements. The resulting iCode makes the loaded pointer appear to point to _Optional int, producing the false warning. This problem predates r17041; that revision fixes the analogous volatile case only.
Moving inherited _Optional qualification to the element type removes the false warning on Z80, STM8 and 65C02 in targeted checks, while retaining warnings for an unchecked s and for repeated volatile reads of genuinely nullable pointer members.
Any new fix should handle all qualifiers consistently and correctly, rather than adding another qualifier-specific special case. Inherited qualification must be applied to the member's type, recursively through array derivations to its element type, while preserving existing qualification at deeper pointer levels. Tests should cover both pointer and non-pointer members, arrays and nested arrays, and distinguish qualification of pointer elements from qualification of their referenced types.
This is separate from [bugs:#4162], which concerns removal of _Optional by unary &, and [bugs:#4164], which concerns qualification of array typedefs during declaration processing. The reproducer uses neither unary & nor a typedef. Applying both candidate fixes leaves this warning present.
Attaching a candidate fix for this bug. Usual caveat: patch was created with help from Codex; Codex did exactly what I instructed it to do.
Looks ok to me.
Thanks for the review. Committed as [r17087].
Related
Commit: [r17087]
The #4165 ucz80 regression testing is complete: 0 failures, 37,146 tests, 6,466 test cases.
Diff: