Martin Sebor <mse...@gmail.com> writes:

> On 6/8/20 7:07 PM, Asher Gordon wrote:
>>
>> OK, these will be easy to fix. Should my other patch¹ (which implements
>> -Wuniversal-initializer) also have PR c/95379?
>
> I'm sure that would be fine but since it's a separate enhancement
> it doesn't need to.  It's up to you.

I decided not to, because my original report does not deal with
-Wuniversal-initializer. So like you said, it's a separate enhancement.

> I don't think GCC has its own generic linked list container.
> There's TREE_CHAIN of tree nodes, but that's probably not
> the best choice for this purpose.  I think the vec template
> (defined in <vec.h>) would come closest to it (like
> constructor_stack::elements).

I have implemented this. I wasn't sure what the second argument for the
'vec' template should be, so I just used 'va_gc' since that was used for
'elements' in the same structure.

>>> I realize the patch doesn't change the text of the message but...
>>> if the name of the field is known at this point, mentioning it in
>>> the message would be a helpful touch.  If it isn't, then "a field"
>>> would be grammatically more correct.  In addition, pointing to
>>> the definition of the struct in a follow-on note would also be
>>> helpful (and in line with other similar messages).  These
>>> improvements are unrelated to the change you're making so could
>>> be made separately, but since you're already making changes here
>>> it's an opportunity to make them now (otherwise they're unlikely
>>> to happen).
>>
>> I will look into this.

The field name is not known, but it is easy to create a structure to
hold both the location and field name for each positional init. So that
is what I have done, and now the field name is reported in the
warning. Also, instead of just saying 'struct', I also had it refer to
the name of the struct (e.g. 'struct foo') by using '%qT'.

I also added a note after the warning showing where the field was
defined in the structure, like this:

    inform (DECL_SOURCE_LOCATION (info.field),
            "in definition of %qT", constructor_type);

However, I think it would be preferable to point to the definition of
the structure itself, since that is where the attribute is. Something
like this:

    inform (DECL_SOURCE_LOCATION (constructor_type),
            "%qT defined here", constructor_type);

Unfortunately, the above does not work since 'constructor_type' is a
type rather than a variable, and thus DECL_SOURCE_LOCATION does not work
on it. Do you know if there is something similar to DECL_SOURCE_LOCATION
that can be used on types like 'constructor_type'?

I also added PR c/95379 to the commit message, and I made the subject
shorter because of the added length of "PR c/95379". The updated patch
can be found below. I'm going to send my updated -Wuniversal-initializer
patch as a reply to that message.
From 280492c8833c11a3aaf435f0ad63ab8a24a8c584 Mon Sep 17 00:00:00 2001
From: Asher Gordon <asd...@posteo.net>
Date: Wed, 3 Jun 2020 17:20:08 -0400
Subject: [PATCH] PR c/95379 Treat { 0 } specially for -Wdesignated-init.

gcc/c/ChangeLog:

	PR c/95379
	* c-typeck.c (warning_init): Allow variable arguments.
	(struct positional_init_info): New type.
	(struct initializer_stack): Add positional_init_info for
	-Wdesignated-init warnings.
	(start_init): Initialize
	initializer_stack->positional_init_info.
	(finish_init): Free initializer_stack->positional_init_info.
	(pop_init_level): Move -Wdesignated-init warning here from
	process_init_element so that we can treat { 0 } specially.
	(process_init_element): Instead of warning on
	-Wdesignated-init here, remember a list of locations and
	fields where we should warn, and do the actual warning in
	pop_init_level.

gcc/ChangeLog:

	PR c/95379
	* doc/extend.texi: Document { 0 } as a special case for the
	designated_init attribute.

gcc/testsuite/ChangeLog:

	PR c/95379
	* gcc.dg/Wdesignated-init-3.c: New test.
---
 gcc/c/c-typeck.c                          | 69 ++++++++++++++++++++---
 gcc/doc/extend.texi                       |  4 ++
 gcc/testsuite/gcc.dg/Wdesignated-init-3.c | 12 ++++
 3 files changed, 77 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/Wdesignated-init-3.c

diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index d97dcf50374..1bae124c6dc 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -104,7 +104,7 @@ static void push_string (const char *);
 static void push_member_name (tree);
 static int spelling_length (void);
 static char *print_spelling (char *);
-static void warning_init (location_t, int, const char *);
+static void warning_init (location_t, int, const char *, ...);
 static tree digest_init (location_t, tree, tree, tree, bool, bool, int);
 static void output_init_element (location_t, tree, tree, bool, tree, tree, bool,
 				 bool, struct obstack *);
@@ -6423,11 +6423,12 @@ pedwarn_init (location_t loc, int opt, const char *gmsgid, ...)
    controls this warning.  GMSGID identifies the message.  The
    component name is taken from the spelling stack.  */
 
-static void
-warning_init (location_t loc, int opt, const char *gmsgid)
+static void ATTRIBUTE_GCC_DIAG (3,4)
+warning_init (location_t loc, int opt, const char *gmsgid, ...)
 {
   char *ofwhat;
   bool warned;
+  va_list ap;
 
   auto_diagnostic_group d;
 
@@ -6437,7 +6438,9 @@ warning_init (location_t loc, int opt, const char *gmsgid)
   location_t exploc = expansion_point_location_if_in_system_header (loc);
 
   /* The gmsgid may be a format string with %< and %>. */
-  warned = warning_at (exploc, opt, gmsgid);
+  va_start (ap, gmsgid);
+  warned = emit_diagnostic_valist (DK_WARNING, exploc, opt, gmsgid, &ap);
+  va_end (ap);
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat && warned)
     inform (exploc, "(near initialization for %qs)", ofwhat);
@@ -8179,6 +8182,22 @@ struct constructor_range_stack
 
 static struct constructor_range_stack *constructor_range_stack;
 
+/* This structure stores information for positional initializers
+   (field and location).  */
+struct positional_init_info {
+  location_t loc;
+  tree field;
+
+  /* So that the vector operations can set this to zero.  */
+  void
+  operator= (int value)
+  {
+    gcc_assert (value == 0);
+    loc = 0;
+    field = NULL_TREE;
+  }
+};
+
 /* This stack records separate initializers that are nested.
    Nested initializers can't happen in ANSI C, but GNU C allows them
    in cases like { ... (struct foo) { ... } ... }.  */
@@ -8197,6 +8216,7 @@ struct initializer_stack
   char require_constant_value;
   char require_constant_elements;
   rich_location *missing_brace_richloc;
+  vec<struct positional_init_info, va_gc> *positional_init_info;
 };
 
 static struct initializer_stack *initializer_stack;
@@ -8222,6 +8242,7 @@ start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level,
   p->top_level = constructor_top_level;
   p->next = initializer_stack;
   p->missing_brace_richloc = richloc;
+  vec_alloc (p->positional_init_info, 0);
   initializer_stack = p;
 
   constructor_decl = decl;
@@ -8287,6 +8308,8 @@ finish_init (void)
   spelling_size = p->spelling_size;
   constructor_top_level = p->top_level;
   initializer_stack = p->next;
+
+  vec_free (p->positional_init_info);
   XDELETE (p);
 }

@@ -8744,6 +8767,33 @@ pop_init_level (location_t loc, int implicit,
 	  }
     }
 
+  /* Warn when positional initializers are used for a structure with
+     the designated_init attribute, but make an exception for { 0 }.  */
+  if (!constructor_zeroinit
+      && vec_safe_length (initializer_stack->positional_init_info))
+    {
+      struct positional_init_info info;
+
+      gcc_assert (constructor_type);
+      gcc_assert (TREE_CODE (constructor_type) == RECORD_TYPE);
+
+      for (unsigned int i = 0;
+	   vec_safe_iterate (initializer_stack->positional_init_info, i, &info);
+	   i++)
+	{
+	  warning_init (info.loc,
+			OPT_Wdesignated_init,
+			"positional initialization of field %qD in %qT "
+			"declared with %<designated_init%> attribute",
+			info.field, constructor_type);
+	  inform (DECL_SOURCE_LOCATION (info.field),
+		  "in definition of %qT", constructor_type);
+	}
+    }
+
+  /* We must free this here so we don't warn again later.  */
+  vec_free (initializer_stack->positional_init_info);
+
   /* Pad out the end of the structure.  */
   if (p->replacement_value.value)
     /* If this closes a superfluous brace pair,
@@ -9975,10 +10025,13 @@ process_init_element (location_t loc, struct c_expr value, bool implicit,
       && TREE_CODE (constructor_type) == RECORD_TYPE
       && lookup_attribute ("designated_init",
 			   TYPE_ATTRIBUTES (constructor_type)))
-    warning_init (loc,
-		  OPT_Wdesignated_init,
-		  "positional initialization of field "
-		  "in %<struct%> declared with %<designated_init%> attribute");
+    {
+      /* Remember where we got a positional initializer so we can warn
+	 if it initializes a field of a structure with the
+	 designated_init attribute.  */
+      struct positional_init_info info = { loc, constructor_fields };
+      vec_safe_push (initializer_stack->positional_init_info, info);
+    }
 
   /* If we've exhausted any levels that didn't have braces,
      pop them now.  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index e656e66a80c..70d25d6c779 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -8101,6 +8101,10 @@ attribute is to allow the programmer to indicate that a structure's
 layout may change, and that therefore relying on positional
 initialization will result in future breakage.
 
+Note that the universal zero initializer, @code{@{ 0 @}}, is considered
+a special case and will not produce a warning when used to initialize a
+structure with the @code{designated_init} attribute.
+
 GCC emits warnings based on this attribute by default; use
 @option{-Wno-designated-init} to suppress them.
 
diff --git a/gcc/testsuite/gcc.dg/Wdesignated-init-3.c b/gcc/testsuite/gcc.dg/Wdesignated-init-3.c
new file mode 100644
index 00000000000..1da3ed5bef4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wdesignated-init-3.c
@@ -0,0 +1,12 @@
+/* PR c/95379 */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+struct Des {
+  int x;
+  int y;
+} __attribute__ ((designated_init));
+
+struct Des d1 = { 0 }; /* { dg-bogus "(positional|near initialization)" } */
+struct Des d2 = { 5 }; /* { dg-warning "(positional|near initialization)" } */
+struct Des d3 = { 0, 0 }; /* { dg-warning "(positional|near initialization)" } */
-- 
2.26.2

Thanks,
Asher

-- 
Reader, suppose you were an idiot.  And suppose you were a member of
Congress.  But I repeat myself.
                -- Mark Twain
                               --------
I prefer to send and receive mail encrypted. Please send me your
public key, and if you do not have my public key, please let me
know. Thanks.

GPG fingerprint: 38F3 975C D173 4037 B397  8095 D4C9 C4FC 5460 8E68

Attachment: signature.asc
Description: PGP signature

Reply via email to