From 311126753eccea14582fd84dffa0c2ae42ecdb66 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 20 Jul 2017 14:53:06 -0400 Subject: [PATCH 08/27] 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. --- gcc/c/c-typeck.c | 57 +++++++++++++++++++++++++++-- gcc/testsuite/gcc.dg/bad-return-type.c | 67 ++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/bad-return-type.c diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index c37cc33..7362246 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) "% 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 " "% 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 0000000..095b767 --- /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 "" } */ +} -- 1.8.5.3