diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index a36397b..356518f 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1376,9 +1376,10 @@ static tree c_parser_attributes (c_parser *); static struct c_expr c_parser_initializer (c_parser *); static struct c_expr c_parser_braced_init (c_parser *, tree, bool, struct obstack *); -static void c_parser_initelt (c_parser *, struct obstack *); -static void c_parser_initval (c_parser *, struct c_expr *, - struct obstack *); +static void c_parser_initelt (c_parser *, struct obstack *, bool *, + HOST_WIDE_INT *, location_t *); +static void c_parser_initval (c_parser *, struct c_expr *, struct obstack *, + bool *, HOST_WIDE_INT *, location_t *); static tree c_parser_compound_statement (c_parser *); static void c_parser_compound_statement_nostart (c_parser *); static void c_parser_label (c_parser *); @@ -4568,6 +4569,12 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); matching_braces braces; braces.consume_open (parser); + bool to_warn_excess_elements = false; + HOST_WIDE_INT warn_expected_elements = 0; + HOST_WIDE_INT warn_extra_elements = 0; + location_t warn_end_loc = 0; + location_t warn_start_loc = 0; + warn_start_loc = 0; if (nested_p) { finish_implicit_inits (brace_loc, outer_obstack); @@ -4585,7 +4592,9 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, comma. */ while (true) { - c_parser_initelt (parser, &braced_init_obstack); + c_parser_initelt (parser, &braced_init_obstack, + &to_warn_excess_elements, &warn_expected_elements, + &warn_start_loc); if (parser->error) break; if (c_parser_next_token_is (parser, CPP_COMMA)) @@ -4597,8 +4606,25 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, break; if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) break; + if (to_warn_excess_elements) + { + ++warn_extra_elements; + warn_end_loc = c_parser_peek_token(parser)->location; + } } } + if (to_warn_excess_elements && !(parser->error)) + { + if (! warn_end_loc) + warn_end_loc = warn_start_loc; + location_t combined_loc = make_location (warn_start_loc, warn_start_loc, + warn_end_loc); + pedwarn_init (combined_loc, 0, + "excess elements in array initializer " + "(%wu elements, %wu expected)", + warn_expected_elements + warn_extra_elements + 1, + warn_expected_elements); + } c_token *next_tok = c_parser_peek_token (parser); if (next_tok->type != CPP_CLOSE_BRACE) { @@ -4621,7 +4647,9 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, /* Parse a nested initializer, including designators. */ static void -c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) +c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack, + bool *to_warn_excess_elements, + HOST_WIDE_INT *warn_expected_elements, location_t *warn_start_loc) { /* Parse any designator or designator list. A single array designator may have the subsequent "=" omitted in GNU C, but a @@ -4757,7 +4785,9 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) /* Now parse and process the remainder of the initializer, starting with this message expression as a primary-expression. */ - c_parser_initval (parser, &mexpr, braced_init_obstack); + c_parser_initval (parser, &mexpr, braced_init_obstack, + to_warn_excess_elements, warn_expected_elements, + warn_start_loc); return; } c_parser_consume_token (parser); @@ -4817,7 +4847,8 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) } } } - c_parser_initval (parser, NULL, braced_init_obstack); + c_parser_initval (parser, NULL, braced_init_obstack, to_warn_excess_elements, + warn_expected_elements, warn_start_loc); } /* Parse a nested initializer; as c_parser_initializer but parses @@ -4828,7 +4859,10 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) static void c_parser_initval (c_parser *parser, struct c_expr *after, - struct obstack * braced_init_obstack) + struct obstack * braced_init_obstack, + bool *to_warn_excess_elements, + HOST_WIDE_INT *warn_expected_elements, + location_t *warn_start_loc) { struct c_expr init; gcc_assert (!after || c_dialect_objc ()); @@ -4845,7 +4879,9 @@ c_parser_initval (c_parser *parser, struct c_expr *after, && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR) init = convert_lvalue_to_rvalue (loc, init, true, true); } - process_init_element (loc, init, false, braced_init_obstack); + process_init_element (loc, init, false, braced_init_obstack, + to_warn_excess_elements, warn_expected_elements, + warn_start_loc); } /* Parse a compound statement (possibly a function body) (C90 6.6.2, diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 96c7ae7..7fb804c 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -662,13 +662,21 @@ extern void start_init (tree, tree, int, rich_location *); extern void finish_init (void); extern void really_start_incremental_init (tree); extern void finish_implicit_inits (location_t, struct obstack *); -extern void push_init_level (location_t, int, struct obstack *); +extern void push_init_level (location_t, int, struct obstack *, + bool *to_warn_excess_elements = NULL, + HOST_WIDE_INT *warn_expected_elements = 0, + location_t *warn_start_loc = 0); extern struct c_expr pop_init_level (location_t, int, struct obstack *, location_t); extern void set_init_index (location_t, tree, tree, struct obstack *); extern void set_init_label (location_t, tree, location_t, struct obstack *); extern void process_init_element (location_t, struct c_expr, bool, - struct obstack *); + struct obstack *, + bool *to_warn_excess_elements = NULL, + HOST_WIDE_INT *warn_expected_elements = 0, + location_t *warn_start_loc = 0); +extern void pedwarn_init (location_t, int, const char *, ...) + ATTRIBUTE_GCC_DIAG (3,0); extern tree build_compound_literal (location_t, tree, tree, bool); extern void check_compound_literal_type (location_t, struct c_type_name *); extern tree c_start_case (location_t, location_t, tree, bool); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 73e7460..0f42570 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -6124,7 +6124,7 @@ error_init (location_t loc, const char *gmsgid) it is unconditionally given. GMSGID identifies the message. The component name is taken from the spelling stack. */ -static void ATTRIBUTE_GCC_DIAG (3,0) +void ATTRIBUTE_GCC_DIAG (3,0) pedwarn_init (location_t loc, int opt, const char *gmsgid, ...) { /* Use the location where a macro was expanded rather than where @@ -7961,7 +7961,10 @@ finish_implicit_inits (location_t loc, struct obstack *braced_init_obstack) void push_init_level (location_t loc, int implicit, - struct obstack *braced_init_obstack) + struct obstack *braced_init_obstack, + bool *to_warn_excess_elements, + HOST_WIDE_INT *warn_expected_elements, + location_t *warn_start_loc) { struct constructor_stack *p; tree value = NULL_TREE; @@ -7973,7 +7976,19 @@ push_init_level (location_t loc, int implicit, if (RECORD_OR_UNION_TYPE_P (constructor_type) && constructor_fields) value = find_init_member (constructor_fields, braced_init_obstack); else if (TREE_CODE (constructor_type) == ARRAY_TYPE) - value = find_init_member (constructor_index, braced_init_obstack); + { + if (constructor_max_index != NULL_TREE + && constructor_index != NULL_TREE + && tree_int_cst_lt (constructor_max_index, constructor_index)) + { + if (to_warn_excess_elements && *to_warn_excess_elements == false) + { + *to_warn_excess_elements = true; + *warn_start_loc = loc; + } + } + value = find_init_member (constructor_index, braced_init_obstack); + } } p = XNEW (struct constructor_stack); @@ -8135,6 +8150,17 @@ push_init_level (location_t loc, int implicit, constructor_fields = constructor_type; constructor_unfilled_fields = constructor_type; } + + if (to_warn_excess_elements && *to_warn_excess_elements == false + && constructor_type != error_mark_node + && TREE_CODE (constructor_type) == ARRAY_TYPE + && constructor_max_index != NULL_TREE) + { + tree subtype = TYPE_MAIN_VARIANT(TREE_TYPE (constructor_type)); + if (TREE_CODE (subtype) != ARRAY_TYPE + && tree_fits_uhwi_p (constructor_max_index)) + *warn_expected_elements += (tree_to_uhwi(constructor_max_index) + 1); + } } /* At the end of an implicit or explicit brace level, @@ -9389,7 +9415,10 @@ output_pending_init_elements (int all, struct obstack * braced_init_obstack) void process_init_element (location_t loc, struct c_expr value, bool implicit, - struct obstack * braced_init_obstack) + struct obstack * braced_init_obstack, + bool *to_warn_excess_elements, + HOST_WIDE_INT *warn_expected_elements, + location_t *warn_start_loc) { tree orig_value = value.value; int string_flag @@ -9552,7 +9581,10 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE)) { - push_init_level (loc, 1, braced_init_obstack); + push_init_level (loc, 1, braced_init_obstack, + to_warn_excess_elements, warn_expected_elements, + warn_start_loc); + continue; } @@ -9644,7 +9676,10 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE)) { - push_init_level (loc, 1, braced_init_obstack); + push_init_level (loc, 1, braced_init_obstack, + to_warn_excess_elements, + warn_expected_elements, warn_start_loc); + continue; } @@ -9686,7 +9721,9 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE || eltcode == UNION_TYPE || eltcode == VECTOR_TYPE)) { - push_init_level (loc, 1, braced_init_obstack); + push_init_level (loc, 1, braced_init_obstack, + to_warn_excess_elements, + warn_expected_elements, warn_start_loc); continue; } @@ -9694,8 +9731,16 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, && (tree_int_cst_lt (constructor_max_index, constructor_index) || integer_all_onesp (constructor_max_index))) { - pedwarn_init (loc, 0, - "excess elements in array initializer"); + if (to_warn_excess_elements && *to_warn_excess_elements == false) + { + *to_warn_excess_elements = true; + if (tree_fits_uhwi_p (constructor_max_index)) + { + *warn_expected_elements += \ + (tree_to_uhwi (constructor_max_index) + 1); + } + *warn_start_loc = loc; + } break; }