Menu ▾ ▴

#4002 No diagnostic message when subtracting 0 from a pointer to an _Optional type

open
nobody
None
other
5
2026-09-18
2026-06-06
No

1: Sample code that reproduces the problem.

int *green(_Optional int *poi)
{
  return poi - 0; // recommended diagnostic 
}

2: Exact command used to run SDCC on this sample code

sdcc --stack-auto -c green.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.24 #16456 (Mac OS X ppc)

4: Copy of the error message or incorrect output, or a clear description of the observed versus expected behavior.

The above example is taken from the Recommended Practice part of subsection 6.5.2 "Type qualifiers" in the _Optional TS.

Implementations that perform data-flow analysis are encouraged to produce a diagnostic
message if one operand has type pointer to optional-qualified type, the other operand has integer type, the operands are evaluated, and analysis cannot prove that no path exists on which the value of the pointer operand is a null pointer.
A diagnostic is encouraged regardless of whether the expression that is added to or subtracted from a pointer is an integer constant expression with value zero, because the referenced type of the result of the + or - operator is not optional-qualified.

SDCC does not produce the recommended diagnostic message about the arithmetic operation, which makes implicit removal of the _Optional qualifier from the referenced type unsafe.

Related

Bugs: #4003

Discussion

  • Christopher Bazley

    I am attaching a proposed bugfix for this issue, created with assistance from Codex in ChatGPT Work. I hope that it will prove acceptable when reviewed by SDCC's maintainers.

    Note that this patch must be applied on top of the patch for [bugs:#4003] (i.e. in reverse numerical order).

    Conceptually, the change is from:

    • fold the subtraction to an assignment before diagnostic analysis
    • mark the result as a semantic dereference
    • rely on that surrogate marker being propagated through the transformed IR

    to:

    • mark the subtraction as temporarily preserved optional-pointer arithmetic
    • defer zero-folding until after data-flow diagnostic analysis
    • clear the preservation marker
    • run CSE simplification again, allowing the subtraction to be folded

    Consequently, the local variable semderef has been deleted.

    I have done the following testing:

    • complete diagnostic-validation results (support/valdiag) for the default targets.
    • complete runtime regression (support/regression) results for ucz80.

    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 'pdk15': 0 failures, 635 tests, 371 test cases, 0 bytes, 0 ticks

     

    Related

    Bugs: #4003


    Last edit: Maarten Brock 1 day ago
  • Christopher Bazley

    This candidate patch was reworked because of feedback on the proposed fix for bug #4003 and other bugs. The patch for this bug now comprises only test changes. It still depends on the fix for bug #4003.

     

    Last edit: Christopher Bazley 2026-09-18
  • Christopher Bazley

    I tested the reworked patch after rebasing it on the latest patch for bug #4003 and all tests passed.

    regression results:
    Summary for 'ucz80': 0 failures, 36745 tests, 6409 test cases, 7344907 bytes, 1613431321 ticks

    valdiag results:
    Summary for 'mcs51': 0 failures, 646 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'mcs51-large': 0 failures, 644 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'mcs51-stack-auto': 0 failures, 645 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'ds390': 0 failures, 632 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'z80': 0 failures, 635 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'z180': 0 failures, 634 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'r2k': 0 failures, 634 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'r4k': 0 failures, 634 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'sm83': 0 failures, 634 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'tlcs90': 0 failures, 634 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'hc08': 0 failures, 633 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 's08': 0 failures, 633 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'mos6502': 0 failures, 633 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'stm8': 0 failures, 636 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'f8': 0 failures, 632 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'pdk13': 0 failures, 636 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'pdk14': 0 failures, 634 tests, 369 test cases, 0 bytes, 0 ticks
    Summary for 'pdk15': 0 failures, 632 tests, 369 test cases, 0 bytes, 0 ticks

     

Log in to post a comment.