This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 09/17] C++: highlight return types when complaining about mismatches


This patch to the C++ frontend 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:

  error: return-statement with a value, in function returning 'void' [-fpermissive]
     return 42;
            ^~

the patch adds this note:

  note: the return type was declared as 'void' here
   void test_1 (void)
   ^~~~

gcc/cp/ChangeLog:
	* cp-tree.h (attempt_to_highlight_return_type): New decl.
	* decl.c (finish_function): Call attempt_to_highlight_return_type
	when complaining about missing return statements in non-void
	functions.
	* typeck.c: Include "blt.h".
	(get_location_of_return_type): New function.
	(attempt_to_highlight_return_type): New function.
	(check_return_expr): Call attempt_to_highlight_return_type when
	complaining about return statements that mismatch the "void-ness"
	of the function.

gcc/testsuite/ChangeLog:
	* g++.dg/bad-return-type.C: New test case.
---
 gcc/cp/cp-tree.h                       |   2 +
 gcc/cp/decl.c                          |   5 +-
 gcc/cp/typeck.c                        |  70 ++++++++++++++++-
 gcc/testsuite/g++.dg/bad-return-type.C | 135 +++++++++++++++++++++++++++++++++
 4 files changed, 206 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 16d8a48..ec83f78 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 bcf305c..84a275f 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 316d57f..054dca5 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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.  */
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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]