On Wed, Jun 04, 2014 at 03:15:02PM +0200, Marek Polacek wrote:
> On Mon, Jun 02, 2014 at 12:58:53AM -0400, S. Gilles wrote:
> 
> Thanks for tackling this.
> 
> > @@ -6858,6 +6858,9 @@
> >  /* 1 if this constructor is erroneous so far.  */
> >  static int constructor_erroneous;
> >  
> > +/* 1 if this constructor is the universal zero initializer { 0 } */
> 
> ".  */" at the end of the comment, please.

Applied.

> 
> > @@ -7317,12 +7321,8 @@
> >     set_nonincremental_init (braced_init_obstack);
> >      }
> >  
> > -  if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
> > -    {
> > -      missing_braces_mentioned = 1;
> > -      warning_init (input_location, OPT_Wmissing_braces,
> > -               "missing braces around initializer");
> > -    }
> > +  if (implicit == 1)
> > +      found_missing_braces = 1;
> 
> Wrong indentation, there should be only two spaces.

Applied.

> 
> > +  /* Warn when some structs are initialized with direct aggregation.  */
> > +  if (!implicit && found_missing_braces && warn_missing_braces
> > +      && !constructor_zeroinit)
> > +    {
> > +      warning_init (input_location, OPT_Wmissing_braces,
> > +               "missing braces around initializer");
> > +    }
> > +
> 
> Please use "loc" instead of input_location.

Applied.

> 
> > @@ -8594,6 +8598,11 @@
> >    designator_depth = 0;
> >    designator_erroneous = 0;
> >  
> > +  if (!implicit && value.value && !integer_zerop (value.value))
> > +    {
> > +      constructor_zeroinit = 0;
> > +    }
> > +
> 
> You can drop the braces here.

Applied - thanks for catching these.

> 
> But the problem I see is that this patch treats even "{ 0, 0 }" as
> a "universal zero initializer", thus we wouldn't warn on say:
> 
> /* -Wmissing-braces -Wmissing-field-initializers */
> struct T { int a, b; };
> struct U { int a, b; struct T t; };
> 
> void
> f (void)
> {
>   int a[2][2][2] = { 0, 0, 0 };
>   struct U u = { 0, 0 };
> }
> 
> I'm not sure whether that is desirable.

That is/was partially intentional. I probably should have mentioned that
originally, especially with the { 0, 0 } in the test case.

I believe an argument can be made that this behavior isn't undesirable:
the standard (unless I am mistaken) makes initialization to any number
of zeros equivalent (as long as there are not more zeros than elements),
so anyone who initializes a struct to { 0, 0 } is probably trying to
zero it out. If they don't use braces when they should, or if they use
six zeros instead of seven, the error will result in the structure being
initialized as they wanted anyway. If they use nonzero values for part
of their initialization, then there's a chance that the definition has
changed, that they aren't intentionally applying aggregation, etc.

As I write it, though, that argument seems far less compelling than when
I thought of it, especially since, with this patch, an assignment of
something like { { 0, 0 }, 0 } would cause warnings, and the `it still
probably works as they intended' argument would still apply. It makes
much more sense to have { 0 } as the only exception to properly filling
out an assignment.

Therefore, I have also amended the patch to add the length-checking from
the previous logic.  The test case is also updated to make sure that
holds. The amended patch is attached (along with the ChangeLog entries
from the first version).

> 
>       Marek

-- 
S. Gilles
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 211081)
+++ gcc/c/c-typeck.c	(working copy)
@@ -74,9 +74,9 @@
    if expr.original_code == SIZEOF_EXPR.  */
 tree c_last_sizeof_arg;
 
-/* Nonzero if we've already printed a "missing braces around initializer"
-   message within this initializer.  */
-static int missing_braces_mentioned;
+/* Nonzero if we might need to print a "missing braces around
+   initializer" message within this initializer.  */
+static int found_missing_braces;
 
 static int require_constant_value;
 static int require_constant_elements;
@@ -6858,6 +6858,9 @@
 /* 1 if this constructor is erroneous so far.  */
 static int constructor_erroneous;
 
+/* 1 if this constructor is the universal zero initializer { 0 }.  */
+static int constructor_zeroinit;
+
 /* Structure for managing pending initializer elements, organized as an
    AVL tree.  */
 
@@ -7019,7 +7022,7 @@
   constructor_stack = 0;
   constructor_range_stack = 0;
 
-  missing_braces_mentioned = 0;
+  found_missing_braces = 0;
 
   spelling_base = 0;
   spelling_size = 0;
@@ -7114,6 +7117,7 @@
   constructor_type = type;
   constructor_incremental = 1;
   constructor_designated = 0;
+  constructor_zeroinit = 1;
   designator_depth = 0;
   designator_erroneous = 0;
 
@@ -7317,12 +7321,8 @@
 	set_nonincremental_init (braced_init_obstack);
     }
 
-  if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
-    {
-      missing_braces_mentioned = 1;
-      warning_init (input_location, OPT_Wmissing_braces,
-		    "missing braces around initializer");
-    }
+  if (implicit == 1)
+    found_missing_braces = 1;
 
   if (TREE_CODE (constructor_type) == RECORD_TYPE
 	   || TREE_CODE (constructor_type) == UNION_TYPE)
@@ -7455,6 +7455,17 @@
 	}
     }
 
+  if (vec_safe_length (constructor_elements) != 1)
+    constructor_zeroinit = 0;
+
+  /* Warn when some structs are initialized with direct aggregation.  */
+  if (!implicit && found_missing_braces && warn_missing_braces
+      && !constructor_zeroinit)
+    {
+      warning_init (loc, OPT_Wmissing_braces,
+		    "missing braces around initializer");
+    }
+
   /* Warn when some struct elements are implicitly initialized to zero.  */
   if (warn_missing_field_initializers
       && constructor_type
@@ -7461,10 +7472,6 @@
       && TREE_CODE (constructor_type) == RECORD_TYPE
       && constructor_unfilled_fields)
     {
-	bool constructor_zeroinit =
-	 (vec_safe_length (constructor_elements) == 1
-	  && integer_zerop ((*constructor_elements)[0].value));
-
 	/* Do not warn for flexible array members or zero-length arrays.  */
 	while (constructor_unfilled_fields
 	       && (!DECL_SIZE (constructor_unfilled_fields)
@@ -8594,6 +8601,9 @@
   designator_depth = 0;
   designator_erroneous = 0;
 
+  if (!implicit && value.value && !integer_zerop (value.value))
+    constructor_zeroinit = 0;
+
   /* Handle superfluous braces around string cst as in
      char x[] = {"foo"}; */
   if (string_flag
Index: gcc/testsuite/gcc.dg/pr53119.c
===================================================================
--- gcc/testsuite/gcc.dg/pr53119.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr53119.c	(working copy)
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+
+/* { dg-options "-Wmissing-braces -Wmissing-field-initializers" } */
+
+struct a {
+  int x, y, z;
+};
+
+struct b {
+  struct a w, z;
+};
+
+int main (void)
+{
+  struct a az = { 0 };
+  struct a anz = { 1 };   /* { dg-warning "missing initializer for" } */
+  struct a aez = { 0, 0 };   /* { dg-warning "missing initializer for" } */
+
+  struct b bz = { 0 };
+  struct b bnz = { 0, 0, 0, 0, 0, 0 };  /* { dg-warning "missing braces" }  */
+
+  return 0;
+}
+
+/* { dg-excess-errors "note" } */
gcc/ChangeLog:
        PR c/53119
c/
        * c-typeck.c (push_init_level, process_init_element,
        pop_init_level): Correct check for zero initialization, move
        missing brace warning to respect zero initialization.

        * gcc.dg/pr53119.c: New testcase.

Reply via email to