@@ -7146,6 +7146,8 @@ extern tree finish_left_unary_fold_expr (tree, int);
extern tree finish_right_unary_fold_expr (tree, int);
extern tree finish_binary_fold_expr (tree, tree, int);
+extern void attempt_to_highlight_return_type (tree fndecl);
+
/* in typeck2.c */
extern void require_complete_eh_spec_types (tree, tree);
extern void cxx_incomplete_type_diagnostic (location_t, const_tree,
@@ -15643,8 +15643,9 @@ finish_function (int flags)
&& !DECL_DESTRUCTOR_P (fndecl)
&& targetm.warn_func_return (fndecl))
{
- warning (OPT_Wreturn_type,
- "no return statement in function returning non-void");
+ if (warning (OPT_Wreturn_type,
+ "no return statement in function returning non-void"))
+ attempt_to_highlight_return_type (current_function_decl);
TREE_NO_WARNING (fndecl) = 1;
}
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "params.h"
#include "gcc-rich-location.h"
#include "asan.h"
+#include "blt.h"
static tree cp_build_addr_expr_strict (tree, tsubst_flags_t);
static tree cp_build_function_call (tree, tree, tsubst_flags_t);
@@ -8869,6 +8870,61 @@ maybe_warn_about_returning_address_of_local (tree retval)
return false;
}
+/* 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 within a function-definition,
+ or a member-declaration.
+ Locate the function-definition or member-declaration. */
+ blt_node *iter;
+ for (iter = node; iter; iter = iter->get_parent ())
+ if (iter->get_kind () == BLT_FUNCTION_DEFINITION
+ || iter->get_kind () == BLT_MEMBER_DECLARATION)
+ break;
+ if (!iter)
+ return UNKNOWN_LOCATION;
+
+ /* Locate the decl specifiers within the function-definition
+ or member-declaration. */
+ blt_node *dss = iter->get_first_child_of_kind (BLT_DECL_SPECIFIER_SEQ);
+ if (!dss)
+ return UNKNOWN_LOCATION;
+
+ /* Locate the type-specifier within the decl specifiers. It ought to
+ be "void". */
+ blt_node *ts = dss->get_first_child_of_kind (BLT_TYPE_SPECIFIER);
+ if (!ts)
+ return UNKNOWN_LOCATION;
+
+ return ts->get_range ();
+}
+
+/* Attempt to locate the return type within FNDECL; if successful,
+ emit a note highlighting it. */
+
+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)
+ return;
+
+ 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);
+}
+
+
/* Check that returning RETVAL from the current function is valid.
Return an expression explicitly showing all conversions required to
change RETVAL into the function return type, and to assign it to
@@ -8994,8 +9050,11 @@ check_return_expr (tree retval, bool *no_warning)
if (!retval && fn_returns_value_p)
{
if (functype != error_mark_node)
- permerror (input_location, "return-statement with no value, in "
- "function returning %qT", valtype);
+ {
+ if (permerror (input_location, "return-statement with no value, in "
+ "function returning %qT", valtype))
+ attempt_to_highlight_return_type (current_function_decl);
+ }
/* Remember that this function did return. */
current_function_returns_value = 1;
/* And signal caller that TREE_NO_WARNING should be set on the
@@ -9013,8 +9072,11 @@ check_return_expr (tree retval, bool *no_warning)
its side-effects. */
finish_expr_stmt (retval);
else
- permerror (input_location, "return-statement with a value, in function "
- "returning 'void'");
+ {
+ if (permerror (input_location, "return-statement with a value,"
+ " in function returning %<void%>"))
+ attempt_to_highlight_return_type (current_function_decl);
+ }
current_function_returns_null = 1;
/* There's really no value to return, after all. */
new file mode 100644
@@ -0,0 +1,135 @@
+/* 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-error "return-statement 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-error "return-statement 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-error "return-statement 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-error "return-statement with no value, in function returning 'int'" }
+ /* { 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 "" } */
+}
+
+/* Falling off the end of a non-void function. */
+
+extern int test_5 (void) // { dg-line return_line_5 }
+{
+} // { dg-warning "no return statement in function returning non-void" }
+/* { dg-begin-multiline-output "" }
+ }
+ ^
+ { dg-end-multiline-output "" } */
+// { dg-message "the return type was declared as 'int' here" "" { target *-*-* } return_line_5 }
+/* { dg-begin-multiline-output "" }
+ extern int test_5 (void)
+ ^~~
+ { dg-end-multiline-output "" } */
+
+/* Member function. */
+
+struct test_6
+{
+ void member (void) // { dg-line return_line_6 }
+ {
+ return 42; // { dg-error "return-statement 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_6 }
+ /* { dg-begin-multiline-output "" }
+ void member (void)
+ ^~~~
+ { dg-end-multiline-output "" } */
+ }
+};
+
+/* Function template. */
+// TODO: highlight "void" for these
+template <typename T>
+void test_7 (T t)
+{
+ return 42; // { dg-error "return-statement with a value, in function returning 'void'" }
+/* { dg-begin-multiline-output "" }
+ return 42;
+ ^~
+ { dg-end-multiline-output "" } */
+}
+
+/* Class template. */
+
+template <typename T>
+struct test_8
+{
+ void member (T t) // { dg-line return_line_8 }
+ {
+ return 42; // { dg-error "return-statement 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_8 }
+ /* { dg-begin-multiline-output "" }
+ void member (T t)
+ ^~~~
+ { dg-end-multiline-output "" } */
+ }
+};
+
+// TODO: complex return type e.g. const char *