From: David Malcolm Date: Mon, 13 Jun 2016 17:14:42 +0000 (+0000) Subject: C: fixits for named initializers X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f7e4f2e3f34178795180ed6160b135eb7072c987;p=gcc.git C: fixits for named initializers gcc/c/ChangeLog: * c-parser.c (c_parser_initelt): Provide location of name for new location_t param of set_init_label. * c-tree.h (set_init_label): Add location_t param. * c-typeck.c (set_init_index): Add "fieldname_loc" location_t param and use it when issuing error messages about unrecognized field names. Attempt to provide a fixit hint if appropriate, otherwise update the error message to provide the type name. gcc/testsuite/ChangeLog: * gcc.dg/c99-init-2.c (c): Update expected error message. * gcc.dg/init-bad-8.c (foo): Likewise. * gcc.dg/spellcheck-fields-3.c: New test case. From-SVN: r237387 --- diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index cd9f230e106..08fc250f79a 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,13 @@ +2016-06-13 David Malcolm + + * c-parser.c (c_parser_initelt): Provide location of name for new + location_t param of set_init_label. + * c-tree.h (set_init_label): Add location_t param. + * c-typeck.c (set_init_index): Add "fieldname_loc" location_t + param and use it when issuing error messages about unrecognized + field names. Attempt to provide a fixit hint if appropriate, + otherwise update the error message to provide the type name. + 2016-06-10 Thomas Schwinge PR c/71381 diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 94078a91f4c..ff32479685e 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -4397,6 +4397,7 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) /* Old-style structure member designator. */ set_init_label (c_parser_peek_token (parser)->location, c_parser_peek_token (parser)->value, + c_parser_peek_token (parser)->location, braced_init_obstack); /* Use the colon as the error location. */ pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_Wpedantic, @@ -4426,6 +4427,7 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) if (c_parser_next_token_is (parser, CPP_NAME)) { set_init_label (des_loc, c_parser_peek_token (parser)->value, + c_parser_peek_token (parser)->location, braced_init_obstack); c_parser_consume_token (parser); } diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index b4374e3e4bf..8f10a13f763 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -639,7 +639,7 @@ 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 void set_init_index (location_t, tree, tree, struct obstack *); -extern void set_init_label (location_t, 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 *); extern tree build_compound_literal (location_t, tree, tree, bool); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index a681d7696d0..ea04d5eed76 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -8211,7 +8211,7 @@ set_init_index (location_t loc, tree first, tree last, /* Within a struct initializer, specify the next field to be initialized. */ void -set_init_label (location_t loc, tree fieldname, +set_init_label (location_t loc, tree fieldname, location_t fieldname_loc, struct obstack *braced_init_obstack) { tree field; @@ -8230,7 +8230,24 @@ set_init_label (location_t loc, tree fieldname, field = lookup_field (constructor_type, fieldname); if (field == 0) - error_at (loc, "unknown field %qE specified in initializer", fieldname); + { + tree guessed_id = lookup_field_fuzzy (constructor_type, fieldname); + if (guessed_id) + { + rich_location rich_loc (line_table, fieldname_loc); + source_range component_range = + get_range_from_loc (line_table, fieldname_loc); + rich_loc.add_fixit_replace (component_range, + IDENTIFIER_POINTER (guessed_id)); + error_at_rich_loc + (&rich_loc, + "%qT has no member named %qE; did you mean %qE?", + constructor_type, fieldname, guessed_id); + } + else + error_at (fieldname_loc, "%qT has no member named %qE", + constructor_type, fieldname); + } else do { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index db8d555852c..878dfe02197 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-06-13 David Malcolm + + * gcc.dg/c99-init-2.c (c): Update expected error message. + * gcc.dg/init-bad-8.c (foo): Likewise. + * gcc.dg/spellcheck-fields-3.c: New test case. + 2016-06-13 Martin Liska * gcc.dg/predict-1.c: Distinguish between "loop iv compare" diff --git a/gcc/testsuite/gcc.dg/c99-init-2.c b/gcc/testsuite/gcc.dg/c99-init-2.c index d3a331ff355..c07005be249 100644 --- a/gcc/testsuite/gcc.dg/c99-init-2.c +++ b/gcc/testsuite/gcc.dg/c99-init-2.c @@ -9,7 +9,7 @@ typedef struct { } A; A a = { [2] = 1 }; /* { dg-error "(array index in non-array)|(near initialization)" } */ int b[] = { .B = 1 }; /* { dg-error "(field name not in record)|(near initialization)" } */ -A c[] = { [0].D = 1 }; /* { dg-error "unknown field" } */ +A c[] = { [0].D = 1 }; /* { dg-error "15: has no member named .D." } */ int d; int e = { d++ }; /* { dg-error "(is not constant)|(near initialization)" } */ A f[2] = { [0].C[0] = 1, [2] = { 2, { 1, 2 } } };/* { dg-error "(array index in initializer exceeds array bounds)|(near initialization)" } */ diff --git a/gcc/testsuite/gcc.dg/init-bad-8.c b/gcc/testsuite/gcc.dg/init-bad-8.c index b321323219c..f7b0f7f6886 100644 --- a/gcc/testsuite/gcc.dg/init-bad-8.c +++ b/gcc/testsuite/gcc.dg/init-bad-8.c @@ -6,5 +6,5 @@ struct S { int i, j, k; }; void foo (void) { - struct S s = { .i = 1, .j = 2, .l = 4}; /* { dg-error "34:unknown field .l. specified in initializer" } */ + struct S s = { .i = 1, .j = 2, .l = 4}; /* { dg-error "35: .struct S. has no member named .l." } */ } diff --git a/gcc/testsuite/gcc.dg/spellcheck-fields-3.c b/gcc/testsuite/gcc.dg/spellcheck-fields-3.c new file mode 100644 index 00000000000..003a0b5ea26 --- /dev/null +++ b/gcc/testsuite/gcc.dg/spellcheck-fields-3.c @@ -0,0 +1,66 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-show-caret -std=c99" } */ + +/* Tests of incorrect name initializers. + Verify that we get underlines and, where appropriate, fixit hints. */ + +struct foo +{ + int foo; + int bar; +}; + +union u +{ + int color; + int shape; +}; + +/* Old-style named initializers. */ + +struct foo old_style_f = { + foa: 1, /* { dg-error ".struct foo. has no member named .foa.; did you mean .foo." } */ +/* { dg-begin-multiline-output "" } + foa: 1, + ^~~ + foo + { dg-end-multiline-output "" } */ + + this_does_not_match: 3 /* { dg-error ".struct foo. has no member named .this_does_not_match." } */ + +/* { dg-begin-multiline-output "" } + this_does_not_match: 3 + ^~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +}; + +union u old_style_u = { colour: 3 }; /* { dg-error ".union u. has no member named .colour.; did you mean .color.?" } */ +/* { dg-begin-multiline-output "" } + union u old_style_u = { colour: 3 }; + ^~~~~~ + color + { dg-end-multiline-output "" } */ + +/* C99-style named initializers. */ + +struct foo c99_style_f = { + .foa = 1, /* { dg-error ".struct foo. has no member named .foa.; did you mean .foo." } */ +/* { dg-begin-multiline-output "" } + .foa = 1, + ^~~ + foo + { dg-end-multiline-output "" } */ + + .this_does_not_match = 3 /* { dg-error ".struct foo. has no member named .this_does_not_match." } */ +/* { dg-begin-multiline-output "" } + .this_does_not_match = 3 + ^~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +}; + +union u c99_style_u = { .colour=3 }; /* { dg-error ".union u. has no member named .colour.; did you mean .color.?" } */ +/* { dg-begin-multiline-output "" } + union u c99_style_u = { .colour=3 }; + ^~~~~~ + color + { dg-end-multiline-output "" } */