c: Don't emit -Wunterminated-string-initialization warning for multi-dimensional nonstring array initializers [PR117178]

Message ID Z8/qjCcChAQbmbOE@tucnak
State New
Headers
Series c: Don't emit -Wunterminated-string-initialization warning for multi-dimensional nonstring array initializers [PR117178] |

Commit Message

Jakub Jelinek March 11, 2025, 7:47 a.m. UTC
  Hi!

My/Kees' earlier patches adjusted -Wunterminated-string-initialization
warning so that it doesn't warn about initializers of nonstring decls
and that nonstring attribute is allowed on multi-dimensional arrays.
Unfortunately as this testcase shows, we still warn about initializers
of multi-dimensional array nonstring decls.

The problem is that in that case field passed to output_init_element
is actually INTEGER_CST, index into the array.
For RECORD_OR_UNION_TYPE_P (constructor_type) field is a FIELD_DECL
which we want to use, but otherwise (in arrays) IMHO we want to use
constructor_fields (which is the innermost FIELD_DECL whose part
is being initialized), or - if that is NULL - constructor_decl, the
whole decl being initialized with multi-dimensional array type.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2025-03-11  Jakub Jelinek  <jakub@redhat.com>

	PR c/117178
	* c-typeck.cc (output_init_element): Pass field to digest_init
	only for record/union types, otherwise pass constructor_fields
	if non-NULL and constructor_decl if constructor_fields is NULL.

	* gcc.dg/Wunterminated-string-initialization-2.c: New test.


	Jakub
  

Comments

Joseph Myers March 11, 2025, 6:39 p.m. UTC | #1
On Tue, 11 Mar 2025, Jakub Jelinek wrote:

> Hi!
> 
> My/Kees' earlier patches adjusted -Wunterminated-string-initialization
> warning so that it doesn't warn about initializers of nonstring decls
> and that nonstring attribute is allowed on multi-dimensional arrays.
> Unfortunately as this testcase shows, we still warn about initializers
> of multi-dimensional array nonstring decls.
> 
> The problem is that in that case field passed to output_init_element
> is actually INTEGER_CST, index into the array.
> For RECORD_OR_UNION_TYPE_P (constructor_type) field is a FIELD_DECL
> which we want to use, but otherwise (in arrays) IMHO we want to use
> constructor_fields (which is the innermost FIELD_DECL whose part
> is being initialized), or - if that is NULL - constructor_decl, the
> whole decl being initialized with multi-dimensional array type.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK, though it would be good also to have some tests using designated 
initializers (so [1][2] = "abc" and similar).
  

Patch

--- gcc/c/c-typeck.cc.jj	2025-03-10 09:30:59.826060100 +0100
+++ gcc/c/c-typeck.cc	2025-03-10 11:43:00.159461692 +0100
@@ -11419,7 +11419,11 @@  output_init_element (location_t loc, tre
   if (!require_constexpr_value
       || !npc
       || TREE_CODE (constructor_type) != POINTER_TYPE)
-    new_value = digest_init (loc, field, type, new_value, origtype, npc,
+    new_value = digest_init (loc,
+			     RECORD_OR_UNION_TYPE_P (constructor_type)
+			     ? field : constructor_fields
+			     ? constructor_fields : constructor_decl,
+			     type, new_value, origtype, npc,
 			     int_const_expr, arith_const_expr, strict_string,
 			     require_constant_value, require_constexpr_value);
   if (new_value == error_mark_node)
--- gcc/testsuite/gcc.dg/Wunterminated-string-initialization-2.c.jj	2025-03-10 11:50:48.945971803 +0100
+++ gcc/testsuite/gcc.dg/Wunterminated-string-initialization-2.c	2025-03-10 11:50:18.272396452 +0100
@@ -0,0 +1,62 @@ 
+/* PR c/117178 */
+/* { dg-do compile } */
+/* { dg-options "-Wunterminated-string-initialization" } */
+
+const char a[][4] __attribute__((nonstring)) = {
+  "ABCD",
+  "EFGH",
+  "IJK",
+  "LMNO"
+};
+const char b[][2][2] __attribute__((nonstring)) = {
+  { "PQ",
+    "R" },
+  { "S",
+    "TU" }
+};
+struct S { int c; char d[3][5] __attribute__((nonstring)); int e; } f = {
+  0,
+  { "abcde",
+    "defg",
+    "hijkl" },
+  1
+};
+struct T { int g; char h[3][2][2] __attribute__((nonstring)); int i; } j = {
+  0,
+  { { "m",
+      "no" },
+    { "pq",
+      "r" },
+    { "s",
+      "tu" } },
+  1
+};
+const char k[][4] = {
+  "ABCD",	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(5 chars into 4 available\\\)" } */
+  "EFGH",	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(5 chars into 4 available\\\)" } */
+  "IJK",
+  "LMNO"	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(5 chars into 4 available\\\)" } */
+};
+const char l[][2][2] = {
+  { "PQ",	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(3 chars into 2 available\\\)" } */
+    "R" },
+  { "S",
+    "TU" }	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(3 chars into 2 available\\\)" } */
+};
+struct U { int m; char n[3][5]; int o; } p = {
+  0,
+  { "abcde",	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(6 chars into 5 available\\\)" } */
+    "defg",
+    "hijkl" },	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(6 chars into 5 available\\\)" } */
+  1
+};
+struct V { int q; char r[3][2][2]; int s; } t = {
+  0,
+  { { "m",
+      "no" },	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(3 chars into 2 available\\\)" } */
+    { "pq",	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(3 chars into 2 available\\\)" } */
+      "r" },
+    { "s",
+      "tu" } },	/* { dg-warning "initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute \\\(3 chars into 2 available\\\)" } */
+  1
+};