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

            Bug ID: 91688
           Summary: -Woverride-init could use an intermediate mode of
                    operation
           Product: gcc
           Version: 9.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: eblake at redhat dot com
  Target Milestone: ---

Right now, -Woverride-init is so strong that it interferes with the use of
gcc's extension of ranged-array initializer syntax as a common way to
pre-initialize an array to a specific non-zero default value then override
specific members in the array to a different value.  Thus, it is not part of
-Wall (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=24010#c4).

However, this warning is so strong that the qemu project is unable to use
-Woverride-init (it would fail to compile due to intentional reinitialization
overrides of ranged defaults), but thus failed to diagnose a bug (a partial
initialization caused zero-initialization of an unmentioned member, overriding
an earlier explicit mention of that member:
https://lists.gnu.org/archive/html/qemu-devel/2019-09/msg01143.html), at least
without using pragmas to temporarily silence the warning.

I am wondering if it would be possible to split this warning into two
categories: -Woverride-init=1 (preferably hoisted into -Wall) which warns about
obvious inadvertent overrides, and -Woverride-init=2 (only part of -Wextra, if
at all) that warns about all overrides, where the difference depends on whether
the second initializer occurs on a subobject that is larger in size than the
first initializer's subobject.

For some demonstrations of what I mean (and intentionally using
-Wno-missing-braces):

$ cat foo.c
#include <stdio.h>

struct A {
  int i;
  int j;
};
struct B {
  struct A one;
  struct A two;
  struct A three;
  int four[2];
};

void dump (struct B *b)
{
  printf ("one=[%d,%d],two=[%d,%d],three=[%d,%d],four=[%d,%d]\n",
          b->one.i, b->one.j, b->two.i, b->two.j, b->three.i, b->three.j,
          b->four[0], b->four[1]);
}

int main(void)
{
  struct B b1 = {
                 .one.i = 1,
                 .two.j = 2,
                 3,
                 .four[1] = 9,
                 .one = { 5, 6 },
                 .two = { 7 },
                 .three = { .j = 8 },
                 .four[0 ... 1] = 4,
  };
  struct B b2 = {
                 .one = { 4, 5 },
                 .two = { 6 },
                 .three = { .j = 7 },
                 .four[0 ... 1] = 4,
                 .one.i = 1,
                 .two.j = 2,
                 3,
                 .four[1] = 9,
  };
  dump (&b1);
  dump (&b2);
  return 0;
}
$ gcc -Wall -Wextra -Wno-missing-braces -o foo foo.c
foo.c: In function ‘main’:
foo.c:28:11: warning: initialized field overwritten [-Woverride-init]
   28 |    .one = { 5, 6 },
      |           ^
foo.c:28:11: note: (near initialization for ‘b1.one’)
foo.c:29:11: warning: initialized field overwritten [-Woverride-init]
   29 |    .two = { 7 },
      |           ^
foo.c:29:11: note: (near initialization for ‘b1.two’)
foo.c:30:13: warning: initialized field overwritten [-Woverride-init]
   30 |    .three = { .j = 8 },
      |             ^
foo.c:30:13: note: (near initialization for ‘b1.three’)
foo.c:31:21: warning: initialized field overwritten [-Woverride-init]
   31 |    .four[0 ... 1] = 4,
      |                     ^
foo.c:31:21: note: (near initialization for ‘b1.four[1]’)
foo.c:38:13: warning: initialized field overwritten [-Woverride-init]
   38 |    .one.i = 1,
      |             ^
foo.c:38:13: note: (near initialization for ‘b2.one.i’)
foo.c:41:15: warning: initialized field overwritten [-Woverride-init]
   41 |    .four[1] = 9,
      |               ^
foo.c:41:15: note: (near initialization for ‘b2.four[1]’)

The four warnings for b1 all make sense at -Woverride-init=1: they are clearly
inadvertent, in that the second half of initializers all touch a larger subset
of the overall b2 object than the first half (providing both members for .one
overrides the earlier specific setting of .one.i; providing a partial
initializer for .two implies a zero-initialization override of the earlier
.two.j; providing a partial initializer for .three implies a
zero-initialization override of the earlier (non-designated) .three.i, and
doing a ranged initializer over .four[0 ... 1] overrides the earlier specific
initialization of .four[1].)

However, while the first warning of b2 is reasonable (the explicit
initialization of .one.i overrides the earlier explicit initialization of
.one),  this is a case of a more-specific override (.one.i is a smaller subset
of b2 than .one), and the second one is the show-stopper that prevents the use
of -Woverride-init in -Wall (it is intentional that a ranged initializer sets a
non-zero default, and then later initializers of obvious smaller scope change
that default).  So the warnings emitted here would fit better in
-Woverride-init=2.

Perhaps we could even go one step further and have -Woverride-init=3 to catch
the case of the double-initialization of b2.two.j (first to its implicit
zero-initialization due to the partial initializer for .two, then again via the
explicit designator .two.j) and b2.three.i (again, due to implicit
zero-initializion from the partial initializer for .three, before the explicit
initialization from the (non-designated) .three.i)- but it is GOOD that gcc
does not warn about these cases under the existing -Woverride-init.

At any rate, with this enhancement, qemu could use -Woverride-init=1 (perhaps
even automatically as part of -Wall), without worrying about having to use
pragmas around the cases where it does intentional overrides of a non-zero
default.

(qemu uses an explicit -Wno-initializer-overrides to overcome the clang
spelling of the warning, because clang has the same 6 warnings as gcc on my
example code, where the 6th one interferes with intentional use, and because
clang sticks -Winitializer-overrides in -Wall, whereas gcc was smart enough to
stick it only in -Wextra)

Reply via email to