From 311126753eccea14582fd84dffa0c2ae42ecdb66 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
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)
 	       "%<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 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

