1: Sample code that reproduces the problem.
void omega(_Optional int *const *ppoi); // unknown side effects
_Optional int **ppoi;
void spinner(_Optional int *poi)
{
// constrains poi to non-null on the fallthrough path
if (!poi) return;
*poi = 1; // no recommended diagnostic
omega(&poi); // non-null constraint on poi is unaffected
*poi = 2; // no recommended diagnostic
ppoi = &poi; // address of poi escapes this function
omega(&poi); /* analysis discards constraint on poi because
omega could modify *ppoi (aka poi) */
*poi = 3; // recommended diagnostic
}
2: Exact command used to run SDCC on this sample code
sdcc --std=c23 -c /work/bug7.c
3: SDCC version tested (type "sdcc -v" to find it)
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/f8/f8l TD- 4.5.21 #16327 (Linux)
4: Copy of the error message or incorrect output, or a clear description of the observed versus expected behavior.
The above example from the Recommended Practice part of subsection 6.5.2 "Type qualifiers" in the _Optional TS is intended to illustrate best-case analysis that might be possible if making use of the information provided by const.
The value ofpoi, a pointer to an optional-qualified type, is constrained to be non-null on the fallthrough path of an if statement in the spinner function, therefore the implementation is recommended not to produce a diagnostic message for the lvalue *poi in the first assignment.
The address of poi is passed as an argument to the omega function. The side effects of omega are unknown, but the address of poi does not escape from spinner before the first call to omega. The parameter type is pointer to const-qualified type, thereforeomega cannot modify the value of poi through this pointer without a cast operation. The implementation is therefore recommended not to produce a diagnostic message for the lvalue *poi in the second assignment.
The address of poi is then assigned to ppoi, an object declared at file scope, before calling omega again. The side effects of \code{omega} are still unknown, which means that the call to omega can modify *ppoi, thereby assigning a null pointer value topoi. The implementation is therefore encouraged to produce a diagnostic message for the lvalue *poi in the last assignment.
SDCC produces a diagnostic message for the assignment *poi = 2 and for the assignment *poi = 3 but a diagnostic message is only expected for the latter:
/work/bug7.c:10: warning 355: pointer to _Optional could not be proven to be non-null at dereference
/work/bug7.c:14: warning 355: pointer to _Optional could not be proven to be non-null at dereference
This is not a bug because it concerns Recommended Practice. I thought it might be useful to report it regardless, in case there is scope for improvement (if the maintainers of SDCC consider that useful).