From 5dd9a9d0c9294455077ba6401701fd3566dcf07c Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 4 Jan 2017 17:40:59 +0000 Subject: [PATCH] C FE: implement fix-it hint for -Wmissing-braces gcc/c/ChangeLog: * c-parser.c (c_parser_declaration_or_fndef): Create a rich_location at init_loc and parse it to start_init. (last_init_list_comma): New global. (c_parser_braced_init): Update last_init_list_comma when parsing commas. Pass it to pop_init_level. Pass location of closing brace to pop_init_level. (c_parser_postfix_expression_after_paren_type): Create a rich_location at type_loc and parse it to start_init. (c_parser_omp_declare_reduction): Likewise for loc. * c-tree.h (start_init): Add rich_location * param. (pop_init_level): Add location_t param. * c-typeck.c (struct initializer_stack): Add field "missing_brace_richloc". (start_init): Add richloc param, use it to initialize the stack node's missing_brace_richloc. (last_init_list_comma): New decl. (finish_implicit_inits): Pass last_init_list_comma to pop_init_level. (push_init_level): When finding missing open braces, add fix-it hints to the richloc. (pop_init_level): Add "insert_before" param and pass it when calling pop_init_level. Add fixits about missing close braces to any richloc. Use the richloc for the -Wmissing-braces warning. (set_designator): Pass last_init_list_comma to pop_init_level. (process_init_element): Likewise. gcc/testsuite/ChangeLog: * gcc.dg/Wmissing-braces-fixits.c: New test case. From-SVN: r244061 --- gcc/c/ChangeLog | 29 +++ gcc/c/c-parser.c | 26 ++- gcc/c/c-tree.h | 5 +- gcc/c/c-typeck.c | 53 +++-- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/Wmissing-braces-fixits.c | 202 ++++++++++++++++++ 6 files changed, 297 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Wmissing-braces-fixits.c diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index d9146b37e88..6f8cf00a1da 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,32 @@ +2017-01-04 David Malcolm + + * c-parser.c (c_parser_declaration_or_fndef): Create a + rich_location at init_loc and parse it to start_init. + (last_init_list_comma): New global. + (c_parser_braced_init): Update last_init_list_comma when parsing + commas. Pass it to pop_init_level. Pass location of closing + brace to pop_init_level. + (c_parser_postfix_expression_after_paren_type): Create a + rich_location at type_loc and parse it to start_init. + (c_parser_omp_declare_reduction): Likewise for loc. + * c-tree.h (start_init): Add rich_location * param. + (pop_init_level): Add location_t param. + * c-typeck.c (struct initializer_stack): Add field + "missing_brace_richloc". + (start_init): Add richloc param, use it to initialize + the stack node's missing_brace_richloc. + (last_init_list_comma): New decl. + (finish_implicit_inits): Pass last_init_list_comma to + pop_init_level. + (push_init_level): When finding missing open braces, add fix-it + hints to the richloc. + (pop_init_level): Add "insert_before" param and pass it + when calling pop_init_level. Add fixits about missing + close braces to any richloc. Use the richloc for the + -Wmissing-braces warning. + (set_designator): Pass last_init_list_comma to pop_init_level. + (process_init_element): Likewise. + 2017-01-01 Jakub Jelinek Update copyright years. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 6d443da2069..c7679c2644a 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1847,8 +1847,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_consume_token (parser); if (auto_type_p) { - start_init (NULL_TREE, asm_name, global_bindings_p ()); init_loc = c_parser_peek_token (parser)->location; + rich_location richloc (line_table, init_loc); + start_init (NULL_TREE, asm_name, global_bindings_p (), &richloc); init = c_parser_expr_no_commas (parser, NULL); if (TREE_CODE (init.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1))) @@ -1904,8 +1905,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, || !vec_safe_is_empty (parser->cilk_simd_fn_tokens)) c_finish_omp_declare_simd (parser, d, NULL_TREE, omp_declare_simd_clauses); - start_init (d, asm_name, global_bindings_p ()); init_loc = c_parser_peek_token (parser)->location; + rich_location richloc (line_table, init_loc); + start_init (d, asm_name, global_bindings_p (), &richloc); init = c_parser_initializer (parser); finish_init (); } @@ -4325,6 +4327,11 @@ c_parser_initializer (c_parser *parser) } } +/* The location of the last comma within the current initializer list, + or UNKNOWN_LOCATION if not within one. */ + +location_t last_init_list_comma; + /* Parse a braced initializer list. TYPE is the type specified for a compound literal, and NULL_TREE for other initializers and for nested braced lists. NESTED_P is true for nested braced lists, @@ -4362,7 +4369,10 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, if (parser->error) break; if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); + { + last_init_list_comma = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + } else break; if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) @@ -4376,13 +4386,13 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, ret.original_code = ERROR_MARK; ret.original_type = NULL; c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>"); - pop_init_level (brace_loc, 0, &braced_init_obstack); + pop_init_level (brace_loc, 0, &braced_init_obstack, last_init_list_comma); obstack_free (&braced_init_obstack, NULL); return ret; } location_t close_loc = next_tok->location; c_parser_consume_token (parser); - ret = pop_init_level (brace_loc, 0, &braced_init_obstack); + ret = pop_init_level (brace_loc, 0, &braced_init_obstack, close_loc); obstack_free (&braced_init_obstack, NULL); set_c_expr_source_range (&ret, brace_loc, close_loc); return ret; @@ -8218,7 +8228,8 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, tree type_expr = NULL_TREE; bool type_expr_const = true; check_compound_literal_type (type_loc, type_name); - start_init (NULL_TREE, NULL, 0); + rich_location richloc (line_table, type_loc); + start_init (NULL_TREE, NULL, 0, &richloc); type = groktypename (type_name, &type_expr, &type_expr_const); start_loc = c_parser_peek_token (parser)->location; if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) @@ -17140,8 +17151,9 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) else { tree st = push_stmt_list (); - start_init (omp_priv, NULL_TREE, 0); location_t loc = c_parser_peek_token (parser)->location; + rich_location richloc (line_table, loc); + start_init (omp_priv, NULL_TREE, 0, &richloc); struct c_expr init = c_parser_initializer (parser); finish_init (); finish_decl (omp_priv, loc, init.value, diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 26048845978..ae01450f90e 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -642,12 +642,13 @@ extern tree c_cast_expr (location_t, struct c_type_name *, tree); extern tree build_c_cast (location_t, tree, tree); extern void store_init_value (location_t, tree, tree, tree); extern void maybe_warn_string_init (location_t, tree, struct c_expr); -extern void start_init (tree, tree, int); +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 struct c_expr pop_init_level (location_t, int, struct obstack *); +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, diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 54ae7d808aa..63e0dc6b298 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -7494,6 +7494,7 @@ struct initializer_stack char top_level; char require_constant_value; char require_constant_elements; + rich_location *missing_brace_richloc; }; static struct initializer_stack *initializer_stack; @@ -7501,7 +7502,8 @@ static struct initializer_stack *initializer_stack; /* Prepare to parse and output the initializer for variable DECL. */ void -start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level) +start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level, + rich_location *richloc) { const char *locus; struct initializer_stack *p = XNEW (struct initializer_stack); @@ -7517,6 +7519,7 @@ start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level) p->spelling_size = spelling_size; p->top_level = constructor_top_level; p->next = initializer_stack; + p->missing_brace_richloc = richloc; initializer_stack = p; constructor_decl = decl; @@ -7701,6 +7704,8 @@ really_start_incremental_init (tree type) } } +extern location_t last_init_list_comma; + /* Called when we see an open brace for a nested initializer. Finish off any pending levels with implicit braces. */ void @@ -7711,14 +7716,16 @@ finish_implicit_inits (location_t loc, struct obstack *braced_init_obstack) if (RECORD_OR_UNION_TYPE_P (constructor_type) && constructor_fields == 0) process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack), + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), true, braced_init_obstack); else if (TREE_CODE (constructor_type) == ARRAY_TYPE && constructor_max_index && tree_int_cst_lt (constructor_max_index, constructor_index)) process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack), + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), true, braced_init_obstack); else break; @@ -7837,7 +7844,12 @@ push_init_level (location_t loc, int implicit, } if (implicit == 1) - found_missing_braces = 1; + { + found_missing_braces = 1; + if (initializer_stack->missing_brace_richloc) + initializer_stack->missing_brace_richloc->add_fixit_insert_before + (loc, "{"); + } if (RECORD_OR_UNION_TYPE_P (constructor_type)) { @@ -7915,7 +7927,8 @@ push_init_level (location_t loc, int implicit, struct c_expr pop_init_level (location_t loc, int implicit, - struct obstack *braced_init_obstack) + struct obstack *braced_init_obstack, + location_t insert_before) { struct constructor_stack *p; struct c_expr ret; @@ -7929,10 +7942,15 @@ pop_init_level (location_t loc, int implicit, pop any inner levels that didn't have explicit braces. */ while (constructor_stack->implicit) process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack), + pop_init_level (loc, 1, braced_init_obstack, + insert_before), true, braced_init_obstack); gcc_assert (!constructor_range_stack); } + else + if (initializer_stack->missing_brace_richloc) + initializer_stack->missing_brace_richloc->add_fixit_insert_before + (insert_before, "}"); /* Now output all pending elements. */ constructor_incremental = 1; @@ -7989,8 +8007,12 @@ pop_init_level (location_t loc, int implicit, /* 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"); + { + gcc_assert (initializer_stack->missing_brace_richloc); + warning_at_rich_loc (initializer_stack->missing_brace_richloc, + OPT_Wmissing_braces, + "missing braces around initializer"); + } /* Warn when some struct elements are implicitly initialized to zero. */ if (warn_missing_field_initializers @@ -8129,7 +8151,8 @@ set_designator (location_t loc, int array, braces. */ while (constructor_stack->implicit) process_init_element (input_location, - pop_init_level (loc, 1, braced_init_obstack), + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), true, braced_init_obstack); constructor_designated = 1; return 0; @@ -9198,7 +9221,8 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, if (RECORD_OR_UNION_TYPE_P (constructor_type) && constructor_fields == 0) process_init_element (loc, - pop_init_level (loc, 1, braced_init_obstack), + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), true, braced_init_obstack); else if ((TREE_CODE (constructor_type) == ARRAY_TYPE || VECTOR_TYPE_P (constructor_type)) @@ -9206,7 +9230,8 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, && tree_int_cst_lt (constructor_max_index, constructor_index)) process_init_element (loc, - pop_init_level (loc, 1, braced_init_obstack), + pop_init_level (loc, 1, braced_init_obstack, + last_init_list_comma), true, braced_init_obstack); else break; @@ -9539,7 +9564,8 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, gcc_assert (constructor_stack->implicit); process_init_element (loc, pop_init_level (loc, 1, - braced_init_obstack), + braced_init_obstack, + last_init_list_comma), true, braced_init_obstack); } for (p = range_stack; @@ -9549,7 +9575,8 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, gcc_assert (constructor_stack->implicit); process_init_element (loc, pop_init_level (loc, 1, - braced_init_obstack), + braced_init_obstack, + last_init_list_comma), true, braced_init_obstack); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 65f63605435..8ad30173c77 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2017-01-04 David Malcolm + + * gcc.dg/Wmissing-braces-fixits.c: New test case. + 2017-01-04 Nathan Sidwell PR c++/66735 diff --git a/gcc/testsuite/gcc.dg/Wmissing-braces-fixits.c b/gcc/testsuite/gcc.dg/Wmissing-braces-fixits.c new file mode 100644 index 00000000000..37998d04adf --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wmissing-braces-fixits.c @@ -0,0 +1,202 @@ +/* { dg-options "-Wmissing-braces -fdiagnostics-show-caret" } */ + +struct sf2 { int i; int j; }; +struct sf3 { int i; int j; int k; }; +struct sa2 { int arr[2]; }; +struct sa3 { int arr[3]; }; + +int arr_12[12] = \ + { 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11}; + +int arr_12_1[12][1] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + {} {} {} {} {} {} + 6, 7, 8, 9, 10, 11}; + {} {} {} {} { } { } + { dg-end-multiline-output "" } */ + +int arr_1_12[1][12] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { + 6, 7, 8, 9, 10, 11}; + } + { dg-end-multiline-output "" } */ + +int arr_2_6[2][6] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { } + 6, 7, 8, 9, 10, 11}; + { } + { dg-end-multiline-output "" } */ + +int arr_2_2_3[2][2][3] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { + { } { } + } + 6, 7, 8, 9, 10, 11}; + { + { } { } + } + { dg-end-multiline-output "" } */ + +int arr_2_3_2[2][3][2] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { + { } { } { } + } + 6, 7, 8, 9, 10, 11}; + { + { } { } { } + } + { dg-end-multiline-output "" } */ + +int arr_6_2[6][2] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { } { } { } + 6, 7, 8, 9, 10, 11}; + { } { } { } + { dg-end-multiline-output "" } */ + +int arr_3_2_2[3][2][2] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { + { } { } + } { + { } + 6, 7, 8, 9, 10, 11}; + { } + } { + { } { } + } + { dg-end-multiline-output "" } */ + +int arr_3_4[3][4] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { } { + 6, 7, 8, 9, 10, 11}; + } { } + { dg-end-multiline-output "" } */ + +int arr_4_3[4][3] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { } { } + 6, 7, 8, 9, 10, 11}; + { } { } + { dg-end-multiline-output "" } */ + +int arr_2_1_6[2][1][6] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { + { } + } + 6, 7, 8, 9, 10, 11}; + { + { } + } + { dg-end-multiline-output "" } */ + +struct sf2 arr_6_sf2[6] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { } { } { } + 6, 7, 8, 9, 10, 11}; + { } { } { } + { dg-end-multiline-output "" } */ + +struct sf3 arr_4_sf3[4] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { } { } + 6, 7, 8, 9, 10, 11}; + { } { } + { dg-end-multiline-output "" } */ + +struct sa2 arr_6_sa2[6] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { + { } + } { + { } + } { + { } + } + 6, 7, 8, 9, 10, 11}; + { + { } + } { + { } + } { + { } + } + { dg-end-multiline-output "" } */ + +struct sa3 arr_4_sa3[4] = \ + { 0, 1, 2, 3, 4, 5, /* { dg-warning "missing braces around initializer" } */ + 6, 7, 8, 9, 10, 11}; + /* { dg-begin-multiline-output "" } + { 0, 1, 2, 3, 4, 5, + ^ + { + { } + } { + { } + } + 6, 7, 8, 9, 10, 11}; + { + { } + } { + { } + } + { dg-end-multiline-output "" } */ -- 2.30.2