Similar to the problem reported for -Wstringop-overflow in pr98266 and already fixed, -Warray-bounds is also susceptible to false positives in assignments and copies involving virtual inheritance. Because the two warnings don't share code yet (hopefully in GCC 12) the attached patch adds its own workaround for this problem to gimple-array-bounds.cc, this one slightly more crude because of the limited insight the array bounds checking has into the checked expressions.
Tested on x86_64-linux. Martin
PR middle-end/98266 - bogus array subscript is partly outside array bounds on virtual inheritance gcc/ChangeLog: PR middle-end/98266 * gimple-array-bounds.cc (array_bounds_checker::check_array_bounds): Avoid checking references involving artificial members. gcc/testsuite/ChangeLog: PR middle-end/98266 * g++.dg/warn/Warray-bounds-15.C: New test. diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc index 2576556f76b..413deacece4 100644 --- a/gcc/gimple-array-bounds.cc +++ b/gcc/gimple-array-bounds.cc @@ -911,8 +911,16 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree, else if (TREE_CODE (t) == ADDR_EXPR) { checker->check_addr_expr (location, t); - *walk_subtree = FALSE; + *walk_subtree = false; } + else if (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF + && DECL_ARTIFICIAL (TREE_OPERAND (t, 1))) + /* Hack: Skip MEM_REF checking for artificial members to avoid false + positives for C++ classes with virtual bases. See pr98266 and + pr97595. */ + *walk_subtree = false; + /* Propagate the no-warning bit to the outer expression. */ if (warned) TREE_NO_WARNING (t) = true; diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-15.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-15.C new file mode 100644 index 00000000000..eb75527dc3d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-15.C @@ -0,0 +1,30 @@ +/* PR middle-end/98266 - bogus array subscript is partly outside array + bounds on virtual inheritance + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +#if __cplusplus < 201103L +# define noexcept throw () +#endif + +struct A +{ + virtual ~A () noexcept; + const char* s; +}; + +struct B: virtual A { }; +struct C: virtual B { }; +struct D: virtual A { }; // { dg-bogus "\\\[-Warray-bounds" } + +struct E: virtual B, virtual D +{ + E (const char*); +}; + +void f (E); + +void g () +{ + f (E ("")); +}