diff options
author | David Malcolm <dmalcolm@redhat.com> | 2017-07-20 14:53:06 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2017-07-21 21:24:10 -0400 |
commit | 311126753eccea14582fd84dffa0c2ae42ecdb66 (patch) | |
tree | 92ac92d45404f2fbe5a7bbf17776bc812a2c0ff6 | |
parent | f4ab82085f180b7264407ce7f0920eefd73d8010 (diff) | |
download | gcc-311126753eccea14582fd84dffa0c2ae42ecdb66.tar.gz |
C: highlight return types when complaining about mismatches
This patch uses the BLT infrastructure to highlight the return type
of a function when complaining about code within the function that
doesn't match it.
For example, given:
warning: 'return' with a value, in function returning void
return 42;
^~
note: declared here
void test_1 (void)
^~~~~~
the patch converts the location and wording of the note to highlight
the return type:
warning: 'return' with a value, in function returning void
return 42;
^~
note: the return type was declared as 'void' here
void test_1 (void)
^~~~
gcc/c/ChangeLog:
* c-typeck.c (get_location_of_return_type): New function.
(attempt_to_highlight_return_type): New function.
(c_finish_return): Convert "inform" calls to calls to
attempt_to_highlight_return_type.
gcc/testsuite/ChangeLog:
* gcc.dg/bad-return-type.c: New test case.
-rw-r--r-- | gcc/c/c-typeck.c | 57 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/bad-return-type.c | 67 |
2 files changed, 120 insertions, 4 deletions
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index c37cc33ddb5..73622461ea7 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -9884,6 +9884,57 @@ c_finish_goto_ptr (location_t loc, tree expr) return add_stmt (t); } +/* Attempt to use BLT locate the return type within FNDECL, returning + UNKNOWN_LOCATION if there is a problem (or if BLT is disabled). */ + +static location_t +get_location_of_return_type (tree fndecl) +{ + blt_node *node = blt_get_node_for_tree (fndecl); + if (!node) + return UNKNOWN_LOCATION; + + /* We have a direct-declarator. + Go up two to find the external-declaration. */ + blt_node *ext_decl = node->get_ancestor_of_kind (BLT_EXTERNAL_DECLARATION); + if (!ext_decl) + return UNKNOWN_LOCATION; + + /* Locate the declaration-specifiers within the direct-declarator. */ + blt_node *dss + = ext_decl->get_first_child_of_kind (BLT_DECLARATION_SPECIFIERS); + if (!dss) + return UNKNOWN_LOCATION; + + /* Locate the type-specifier within the decl specifiers. */ + blt_node *ts = dss->get_first_child_of_kind (BLT_TYPE_SPECIFIER); + if (!ts) + return UNKNOWN_LOCATION; + + /* FIXME: we want just the return type, not "extern" etc. */ + return ts->get_range (); +} + +/* Attempt to locate the return type within FNDECL; if successful, + emit a note highlighting the return type; otherwise emit a note + highlighting the decl. */ + +static void +attempt_to_highlight_return_type (tree fndecl) +{ + location_t ret_type_loc = get_location_of_return_type (fndecl); + if (ret_type_loc == UNKNOWN_LOCATION) + inform (DECL_SOURCE_LOCATION (fndecl), "declared here"); + else + { + tree result = DECL_RESULT (fndecl); + tree return_type = TREE_TYPE (result); + inform (ret_type_loc, "the return type was declared as %qT here", + return_type); + } +} + + /* Generate a C `return' statement. RETVAL is the expression for what to return, or a null pointer for `return;' with no value. LOC is the location of the return statement, or the location of the expression, @@ -9956,8 +10007,7 @@ c_finish_return (location_t loc, tree retval, tree origtype) "%<return%> with no value, in function returning non-void"); no_warning = true; if (warned_here) - inform (DECL_SOURCE_LOCATION (current_function_decl), - "declared here"); + attempt_to_highlight_return_type (current_function_decl); } } else if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE) @@ -9973,8 +10023,7 @@ c_finish_return (location_t loc, tree retval, tree origtype) (xloc, OPT_Wpedantic, "ISO C forbids " "%<return%> with expression, in function returning void"); if (warned_here) - inform (DECL_SOURCE_LOCATION (current_function_decl), - "declared here"); + attempt_to_highlight_return_type (current_function_decl); } else { diff --git a/gcc/testsuite/gcc.dg/bad-return-type.c b/gcc/testsuite/gcc.dg/bad-return-type.c new file mode 100644 index 00000000000..095b767b952 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bad-return-type.c @@ -0,0 +1,67 @@ +/* Verify that we can highlight the return type for various kinds + of bogus return. */ + +/* { dg-options "-fdiagnostics-show-caret -fblt -Wreturn-type" } */ + +void test_1 (void) // { dg-line return_line } +{ + return 42; // { dg-warning "'return' with a value, in function returning void" } + /* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ + /* { dg-message "the return type was declared as 'void' here" "" { target *-*-* } return_line } */ + /* { dg-begin-multiline-output "" } + void test_1 (void) + ^~~~ + { dg-end-multiline-output "" } */ +} + +/* As before, but with different whitespace. */ + +void // { dg-line return_line_2 } +test_2 (void) +{ + return 42; // { dg-warning "'return' with a value, in function returning void" } + /* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ + /* { dg-message "the return type was declared as 'void' here" "" { target *-*-* } return_line_2 } */ + /* { dg-begin-multiline-output "" } + void + ^~~~ + { dg-end-multiline-output "" } */ +} + +/* As before, but with "extern". */ + +extern void test_3 (void) // { dg-line return_line_3 } +{ + return 42; // { dg-warning "'return' with a value, in function returning void" } + /* { dg-begin-multiline-output "" } + return 42; + ^~ + { dg-end-multiline-output "" } */ + /* { dg-message "the return type was declared as 'void' here" "" { target *-*-* } return_line_3 } */ + /* { dg-begin-multiline-output "" } + extern void test_3 (void) + ^~~~ + { dg-end-multiline-output "" } */ +} + +/* Type mismatch for non-void return. */ + +extern int test_4 (void) // { dg-line return_line_4 } +{ + return; // { dg-warning "'return' with no value, in function returning non-void" } + /* { dg-begin-multiline-output "" } + return; + ^~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-message "the return type was declared as 'int' here" "" { target *-*-* } return_line_4 } */ + /* { dg-begin-multiline-output "" } + extern int test_4 (void) + ^~~ + { dg-end-multiline-output "" } */ +} |