https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127480

            Bug ID: 127480
           Summary: [15/16/17 Regression] False-positive -Warray-bounds on
                    unreachable downcast in loop
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: james at jamespanayis dot com
  Target Milestone: ---

Created attachment 65630
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65630&action=edit
Preprocessed file

Repro:

struct buffer {
  char* out;
  void (*grow)(buffer&);
};

struct extended_buffer : buffer {
  char last_value;
};

int main() {
  char out = 0;
  buffer buf{&out, [](buffer&) {}};
  for (int i = 0; i < 2; ++i) {
    if (!buf.grow) static_cast<extended_buffer&>(buf).last_value = 'x';
    else buf.grow(buf);
    *buf.out = 'x';
  }
  return out != 'x';
}

Compiler Output:

<source>: In function 'int main()':
<source>:14:20: warning: array subscript 'extended_buffer[0]' is partly outside
array bounds of 'buffer [1]' [-Warray-bounds=]
   14 |     if (!buf.grow) static_cast<extended_buffer&>(buf).last_value = 'x';
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:12:10: note: object 'buf' of size 16
   12 |   buffer buf{&out, [](buffer&) {}};
      |          ^~~

Command:
g++ -std=c++11 -O2 -Warray-bounds -c repro-buffer.cc -o repro-buffer.o

Target:
x86_64-linux-gnu

Explanation:

This models a buffer dispatch in which a null grow pointer corresponds to an
extended buffer implementation.

buf.grow initially points to the non-capturing lambda, which does nothing and
never modifies buf. buf.out remains &out, so the output write changes only the
local out variable, not any part of buf.

So both iterations take the else branch. The downcast would be undefined if
evaluated for this buffer object, but it is provably never evaluated. The
program is well-defined and returns zero.

Expected behaviour:

No bounds warning. This is a false-positive-diagnostic report, not a claim of
runtime miscompilation nor a C++ standards-conformance violation.

The warning is also enabled by -Wall, so it causes a compilation failure with
-O2 -Wall -Werror.

Additional testing (all with -std=c++11 -Warray-bounds):

GCC 15.1.0, 15.2.0, 15.3.0, 16.2.0, and trunk 17.0.0 (20260918) emit the
warning with -O2 and -O3, but not with -O0 and -O1.

GCC 4.9.4, 11.5.0, 12.5.0, 13.4.0, 14.1.0, and 14.4.0, and Clang 21.1.8 and
22.1.2 do not emit the warning with -O0, -O1, -O2, or -O3.

GCC 14.1.0, 14.4.0, 15.1.0, 15.3.0, 16.2.0, and 17.0 were tested through
Compiler Explorer. The other listed versions were tested locally on Ubuntu
26.04.

Thus this seems to be a GCC 15 diagnostic regression.

Either of these changes independently eliminates the warning at both -O2 and
-O3:

- Remove the loop so its body executes only once.
- Remove the *buf.out = 'x'; statement.

Possibly related bug report:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110620 also concerns a bounds
diagnostic on a logically unreachable path.

Reply via email to