As noted in bug 88642, the C front end fails to give errors or
pedwarns for scalar initializers with too many levels of surrounding
braces. There is a warning for redundant braces around a scalar
initializer within a larger braced initializer (valid for a single
such level within a structure, union or array initializer; not valid
for more than one such level, or where the outer layer of braces is
itself for a scalar, either redundant braces themselves or part of a
compound literal), but this never becomes an error even for invalid
cases. Check for this case and turn the warning into a permerror when
there are more levels of braces than permitted. The existing warning
is unchanged for a single (permitted) level of redundant braces around
a scalar initializer inside a structure, union or array initializer,
and it's also unchanged that no such warning is given for a single
(permitted) level of redundant braces around a top-level scalar
initializer.
Technically this is a C2y issue (these rules on valid initializers
moved into Constraints as a result of N3346, accepted in Minneapolis;
previously, as a "shall" outside constraints, violating these rules
resulted in compile-time undefined behavior without requiring a
diagnostic).
Hopefully little code is actually relying on not getting an error
here. In view of gcc.dg/tree-ssa/ssa-dse-10.c showing that at least
some code may be using such over-braced initializers (initializer of
pubKeys at line 1167 in that test; I'm not at all sure how that
initializer ends up getting interpreted to translate it to something
equivalent but properly structured), this is made a permerror rather
than a hard error, so -fpermissive (as already used by that test) can
be used to disable the error (the default -fpermissive for old
standards modes is not a problem given that before C2y this is
undefined behavior not a constraint violation).
Bootstrapped with no regressions for x86_64-pc-linux-gnu.
PR c/88642
gcc/c/
* c-typeck.cc (constructor_braced_scalar): New variable.
(struct constructor_stack): Add braced_scalar field.
(really_start_incremental_init): Handle constructor_braced_scalar
and braced_scalar field.
(push_init_level): Handle constructor_braced_scalar and
braced_scalar field. Give permerror rather than warning for
nested braces around scalar initializer.
(pop_init_level): Handle constructor_braced_scalar and
braced_scalar field.
gcc/testsuite/
* gcc.dg/c2y-init-1.c: New test.
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 6c807a2a7927..b96215adc768 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -10132,6 +10132,10 @@ static int constructor_zeroinit;
/* 1 if this constructor should have padding bits zeroed (C23 {}. */
static bool constructor_zero_padding_bits;
+/* 1 if this constructor is a braced scalar initializer (further nested levels
+ of braces are an error). */
+static bool constructor_braced_scalar;
+
/* Structure for managing pending initializer elements, organized as an
AVL tree. */
@@ -10203,6 +10207,7 @@ struct constructor_stack
char incremental;
char designated;
bool zero_padding_bits;
+ bool braced_scalar;
int designator_depth;
};
@@ -10379,6 +10384,7 @@ really_start_incremental_init (tree type)
p->incremental = constructor_incremental;
p->designated = constructor_designated;
p->zero_padding_bits = constructor_zero_padding_bits;
+ p->braced_scalar = constructor_braced_scalar;
p->designator_depth = designator_depth;
p->next = 0;
constructor_stack = p;
@@ -10394,6 +10400,7 @@ really_start_incremental_init (tree type)
constructor_designated = 0;
constructor_zero_padding_bits = false;
constructor_zeroinit = 1;
+ constructor_braced_scalar = false;
designator_depth = 0;
designator_erroneous = 0;
@@ -10453,6 +10460,7 @@ really_start_incremental_init (tree type)
/* Handle the case of int x = {5}; */
constructor_fields = constructor_type;
constructor_unfilled_fields = constructor_type;
+ constructor_braced_scalar = true;
}
}
@@ -10529,6 +10537,7 @@ push_init_level (location_t loc, int implicit,
p->incremental = constructor_incremental;
p->designated = constructor_designated;
p->zero_padding_bits = constructor_zero_padding_bits;
+ p->braced_scalar = constructor_braced_scalar;
p->designator_depth = designator_depth;
p->next = constructor_stack;
p->range_stack = 0;
@@ -10546,6 +10555,7 @@ push_init_level (location_t loc, int implicit,
/* If the upper initializer has padding bits zeroed, that includes
all nested initializers as well. */
constructor_zero_padding_bits = p->zero_padding_bits;
+ constructor_braced_scalar = false;
constructor_pending_elts = 0;
if (!implicit)
{
@@ -10664,7 +10674,15 @@ push_init_level (location_t loc, int implicit,
else
{
if (constructor_type != error_mark_node)
- warning_init (input_location, 0, "braces around scalar initializer");
+ {
+ if (p->braced_scalar)
+ permerror_init (input_location, 0,
+ "braces around scalar initializer");
+ else
+ warning_init (input_location, 0,
+ "braces around scalar initializer");
+ constructor_braced_scalar = true;
+ }
constructor_fields = constructor_type;
constructor_unfilled_fields = constructor_type;
}
@@ -10886,6 +10904,7 @@ pop_init_level (location_t loc, int implicit,
constructor_incremental = p->incremental;
constructor_designated = p->designated;
constructor_zero_padding_bits = p->zero_padding_bits;
+ constructor_braced_scalar = p->braced_scalar;
designator_depth = p->designator_depth;
constructor_pending_elts = p->pending_elts;
constructor_depth = p->depth;
diff --git a/gcc/testsuite/gcc.dg/c2y-init-1.c
b/gcc/testsuite/gcc.dg/c2y-init-1.c
new file mode 100644
index 000000000000..2fa200d283f9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2y-init-1.c
@@ -0,0 +1,48 @@
+/* Test invalid initializers that are consistent with the syntax: undefined
+ behavior ("shall" in Semantics not Constraints) before C2y, constraint
+ violation in C2y. Scalar cases; see bug 88642. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+struct s { int a; };
+union u { int a; };
+
+int i1 = { 1, 2 }; /* { dg-error "excess elements in scalar initializer" } */
+int i2 = { { 1 } }; /* { dg-error "braces around scalar initializer" } */
+int i3 = { { 1, } }; /* { dg-error "braces around scalar initializer" } */
+int i4 = { { 1 }, }; /* { dg-error "braces around scalar initializer" } */
+int i5 = { 1, { } }; /* { dg-error "excess elements in scalar initializer" } */
+/* { dg-error "braces around scalar initializer" "braces" { target *-*-* } .-1
} */
+int i6 = { { } }; /* { dg-error "braces around scalar initializer" } */
+int i7 = { { }, }; /* { dg-error "braces around scalar initializer" } */
+int i8 = { { { 1 } } }; /* { dg-error "braces around scalar initializer" } */
+struct s s1 =
+ {
+ { /* { dg-warning "braces around scalar initializer" } */
+ { 1 } /* { dg-error "braces around scalar initializer" } */
+ }
+ };
+union u u1 =
+ {
+ { /* { dg-warning "braces around scalar initializer" } */
+ { 1 } /* { dg-error "braces around scalar initializer" } */
+ }
+ };
+int a1[1] =
+ {
+ { /* { dg-warning "braces around scalar initializer" } */
+ { 1 } /* { dg-error "braces around scalar initializer" } */
+ }
+ };
+int *p1 = &(int) { { 1 } }; /* { dg-error "braces around scalar initializer" }
*/
+int *p2 = &(int) { { 1, } }; /* { dg-error "braces around scalar initializer"
} */
+
+int ok1 = { 1 };
+struct s ok2 = { { 1 } }; /* { dg-warning "braces around scalar initializer" }
*/
+struct s ok3 = { { 1, } }; /* { dg-warning "braces around scalar initializer"
} */
+int *ok4 = &(int) { 1 };
+int *ok5 = &(int) { 1, };
+int ok6[1] = { { 1 } }; /* { dg-warning "braces around scalar initializer" } */
+int ok7[1] = { { 1, } }; /* { dg-warning "braces around scalar initializer" }
*/
+union u ok8 = { { 1 } }; /* { dg-warning "braces around scalar initializer" }
*/
+union u ok9 = { { 1, } }; /* { dg-warning "braces around scalar initializer" }
*/
--
Joseph S. Myers
[email protected]