summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2017-07-20 14:53:06 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2017-07-21 21:24:10 -0400
commit311126753eccea14582fd84dffa0c2ae42ecdb66 (patch)
tree92ac92d45404f2fbe5a7bbf17776bc812a2c0ff6
parentf4ab82085f180b7264407ce7f0920eefd73d8010 (diff)
downloadgcc-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.c57
-rw-r--r--gcc/testsuite/gcc.dg/bad-return-type.c67
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 "" } */
+}