1: Sample code that reproduces the problem.
_Optional int *poi;
void chandler(_Optional int **ppoi)
{
int i;
// constrains poi to non-null on the fallthrough path
if (!poi) return;
*poi = 1; // no recommended diagnostic
*ppoi = &i; // non-null constraint on poi is unaffected
*poi = 2; // no recommended diagnostic
}
void monica(_Optional int **ppoi, _Optional int *lpoi)
{
// constrains poi and lpoi to non-null on the fallthrough path
if (!poi || !lpoi) return;
*poi = 1; // no recommended diagnostic
*ppoi = lpoi; // non-null constraint on poi is unaffected
*poi = 2; // no recommended diagnostic
}
void rachel(_Optional int **ppoi_1, _Optional int **ppoi_2)
{
int i;
// constrains *ppoi_1 to non-null on the fallthrough path
if (!*ppoi_1) return;
**ppoi_1 = 1; // no recommended diagnostic
*ppoi_2 = &i; // non-null constraint on *ppoi_1 is unaffected
**ppoi_1 = 2; // no recommended diagnostic
}
2: Exact command used to run SDCC on this sample code
sdcc --std=c23 -c /work/bug6.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 examples from the Recommended Practice part of subsection 6.5.2 "Type qualifiers" in the _Optional TS are intended to illustrate best-case analysis that might be possible if a translator takes into account whether the value assigned to a pointer (that could alias another pointer) can be null, and therefore whether it is necessary to discard previously-inferred constraints on the value of other pointers that the analyser is tracking.
In chandler, the value of poi, an object declared at file scope that points to an optional-qualified type, is constrained to be non-null on the fallthrough path of an if statement, therefore the implementation is recommended not to produce a diagnostic message for the lvalue *poi in the first assignment. ppoi, a pointer to a pointer to an optional-qualified type, cannot be proven not to point to poi without interprocedural analysis. The assignment of &i to the lvalue *ppoi can modify the value of poi, but the assigned value is not a null pointer. The implementation is therefore recommended not to produce a diagnostic message for the lvalue *poi in the last assignment.
The monica function is similar to chandler except that the assigned value can be proven by flow-sensitive analysis to be non-null, as opposed to its non-null value being a known compile-time constant.
The rachel function is similar to chandler except that the address of the potentially-aliased pointer is passed as an argument instead of the potentially-aliased pointer being a global variable.
SDCC produces diagnostic messages for the final assignment in each function:
/work/bug6.c:12: warning 355: pointer to _Optional could not be proven to be non-null at dereference
/work/bug6.c:22: warning 355: pointer to _Optional could not be proven to be non-null at dereference
/work/bug6.c:34: warning 355: pointer to _Optional could not be proven to be non-null at dereference
Ideally, no diagnostic messages would be produced for these examples.
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).