1: Sample code that reproduces the problem.
int compare(_Optional char *p, char *q)
{
if (p)
return p >= q;
return 0;
}
Save as optional-relational-conversion.c.
2: Exact command used to run SDCC on this sample code.
sdcc -mz80 --std-c99 --stack-auto -S optional-relational-conversion.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.
Also reproducible in Compiler Explorer with SDCC 4.6.0 and SDCC trunk (4.6.4 #17013 when tested on 21 Oct): https://godbolt.org/z/jxsGaf8vK
4: Copy of the error message or incorrect output, or a clear description of the observed versus expected behaviour.
optional-relational-conversion.c:4: warning 358: pointer to _Optional could not be proven to be non-null at relational operator
Only p has type pointer to optional-qualified type, and its value has been checked before the comparison. I expected no _Optional diagnostic. The caller must still satisfy the ordinary requirements for ordering pointers; this example does not assert that arbitrary pointer values can be ordered.
Adding a check of q suppresses the warning, as does removing _Optional from the declaration of p. The same unwanted warning occurs for <, >, <= and >=.
With --dump-i-code, SDCC shows a conversion of q from char * to _Optional char * before the comparison. The recommended diagnostic should depend on the optional-qualified referenced types of the source operands, rather than qualification introduced by this internal conversion. The source operand q has no optional-qualified referenced type.
This also appears relevant to CBUtilLib's comparison of a checked strchr result with its unqualified input pointer. Unlike [bugs:#4148], the reduced example has no structure members.
My fork of Clang does not have the same issue: https://godbolt.org/z/v1z9nE8xE
Please consider the attached candidate bug fix. It was created with help from Codex, so it will need approval from someone else (e.g. @spth). It looks to me like quite a nice simplification/unification: the existing
POINTER_NONNULL_CHECKmechanism is now used for comparison operations too.Multiple ternary operators in an expression might not be the most elegant C code. Still, I think having two of them in an expression isn't that bad vs. introducing a helper function (that is only used once) containing a switch and making the file 20 lines longer. So I'd prefer just the ternary operators in both expressions instead of those two helper functions.
Did you consider that compilers can warn about missing
casestatements but not about missing ternary operators? I'm just curious.Not really, but I don't think it justifies the extra overhead of 2x20 lines here; also a bug here wouldn't be that bad - it wouldn't affect the generated code, it would just result in a slightly wrong text in a warning.
See attached revised patch.
Looks good to me.
Fixed by [r17068]
Related
Commit: [r17068]