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).
As of current SDCC trunk, since the recent merge of the
_Optionalbranch, we only get the warning in line 34.Confirmed that only the warning at line 34 appears now. Great progress.
I am attaching a proposed bugfix for this issue, created with assistance from Codex. I hope that it will prove acceptable when reviewed by SDCC's maintainers.
I did the following testing of the proposed patch:
i.e.
make -j2
make -C support/regression clean-results
make -C support/regression -j2 test-ucz80
make -C support/valdiag clean
make -C support/valdiag -j2
Summary for 'ucz80': 0 failures, 36740 tests, 6407 test cases, 7347620 bytes, 1613638336 ticks
Summary for 'mcs51': 0 failures, 652 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'mcs51-large': 0 failures, 650 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'mcs51-stack-auto': 0 failures, 651 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'ds390': 0 failures, 638 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'z80': 0 failures, 641 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'z180': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'r2k': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'r4k': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'sm83': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'tlcs90': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 's08': 0 failures, 639 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'mos6502': 0 failures, 639 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'f8': 0 failures, 638 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'pdk13': 0 failures, 641 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'pdk14': 0 failures, 639 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'pdk15': 0 failures, 637 tests, 373 test cases, 0 bytes, 0 ticks