From 9b3c14ce2c57d8013c75eee3264a5d8f74fb10e0 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 18 Jul 2017 21:17:29 -0400
Subject: [PATCH 14/28] FIXME: C++: attempt_to_highlight_return_type (needs
 BLT; can we do something similar for C?)

---
 gcc/cp/cp-tree.h                       |   2 +
 gcc/cp/decl.c                          |   5 +-
 gcc/cp/typeck.c                        |  67 +++++++++++++++-
 gcc/testsuite/g++.dg/bad-return-type.C | 135 +++++++++++++++++++++++++++++++++
 4 files changed, 203 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/bad-return-type.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c4fecf3..80c3a3e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 8237555..20c24f0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
     }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a2f2fe4..4181f1d 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8870,6 +8870,59 @@ maybe_warn_about_returning_address_of_local (tree retval)
   return false;
 }
 
+/* FIXME.  */
+
+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 ();
+}
+
+/* FIXME.  */
+
+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
@@ -8995,8 +9048,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
@@ -9014,8 +9070,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.  */
diff --git a/gcc/testsuite/g++.dg/bad-return-type.C b/gcc/testsuite/g++.dg/bad-return-type.C
new file mode 100644
index 0000000..e62eb0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/bad-return-type.C
@@ -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 *
-- 
1.8.5.3

