1: Sample code that reproduces the problem.
struct S
{
_Optional char *p;
};
int read_value(struct S *s, int clear)
{
if (s->p)
{
if (clear)
s->p = 0;
}
if (s->p)
return *s->p;
return 0;
}
Save as optional-rechecked-member.c.
2: Exact command used to run SDCC on this sample code.
sdcc -mz80 --std-c99 --stack-auto -S optional-rechecked-member.c
The same result occurs with -mmos65c02, -mstm8 and -mmcs51 in place of -mz80.
3: SDCC version tested.
SDCC 4.6.4 #17038 (Linux), official snapshot dated 20 October 2026. This includes the fix for [bugs:#4148] in [r17036].
4: Copy of the error message or incorrect output, or a clear description of the observed versus expected behaviour.
optional-rechecked-member.c:15: warning 355: pointer to _Optional could not be proven to be non-null at dereference
See Compiler Explorer with SDCC 4.6.0 and trunk (4.6.4 r17013 when checked on 21 October 2026): https://godbolt.org/z/Y9E1Eh1ao
I expected no warning. The second if (s->p) checks the value after the conditional assignment. There is no assignment, call or volatile access between that check and *s->p.
With r17038, removing the first if (s->p), leaving if (clear) s->p = 0; followed by the fresh check, removes warning 355. Compiler Explorer's compiler labelled SDCC trunk was still r17013 when checked on 21 October 2026; it continues to warn for this simplified case because it predates the first-member fix in [r17036]. See https://godbolt.org/z/fWo38nYMd .
Adding a char member before p does not remove it, so both first and subsequent member positions are affected. Replacing the member with a local pointer also avoids the warning.
This is distinct from [bugs:#3957], where analysis must account for an intervening assignment through a possible alias, and from [feature-requests:#1035], where an intervening write to a different member invalidates a previous check. Here the pointer is checked again after the assignment.
The pattern was isolated while investigating CBUtilLib's dictionary warnings. The larger dictionary functions also contain other assignments and calls; this reduction does not establish that this is their only analysis limitation.
Bugs: #3957
Bugs: #4148
Commit: [r17036]
Feature Requests: #1035
Diff:
Diff:
Diff:
Related
Bugs: #3957
Commit: [r17036]
Feature Requests: #1035
Attaching a candidate fix for this issue, created by Codex. It reuses the freshly checked member load, fixing both member positions while preserving warnings after potentially invalidating writes and calls. Bitfields are special-cased because two fields can share the same address but require different bit extraction.
All six diagnostic configurations and the full Z80 runtime suite passed: 37164 tests, 0 failures. Focused runtime tests also passed on 65C02, STM8 and MCS51.
@spth please would you be able to take a look at this at some point?
(I'm not sure special treatment of
_Atomicis justified given that SDCC does not yet support such types, but it does no obvious harm.)Last edit: Christopher Bazley 10 hours ago