public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: David Malcolm <dmalcolm@redhat.com>
To: gcc-patches@gcc.gnu.org
Cc: David Malcolm <dmalcolm@redhat.com>
Subject: [PATCH 09/17] C++: highlight return types when complaining about mismatches
Date: Mon, 24 Jul 2017 19:39:00 -0000	[thread overview]
Message-ID: <1500926714-56988-10-git-send-email-dmalcolm@redhat.com> (raw)
In-Reply-To: <1500926714-56988-1-git-send-email-dmalcolm@redhat.com>

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

  parent reply	other threads:[~2017-07-24 19:39 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-24 19:31 [PATCH 00/17] RFC: New source-location representation; Language Server Protocol David Malcolm
2017-07-24 19:31 ` [PATCH 17/17] Language Server Protocol: work-in-progess on testsuite David Malcolm
2017-07-24 19:31 ` [PATCH 13/17] Add http-server.h and http-server.c David Malcolm
2017-07-24 19:31 ` [PATCH 03/17] Core of BLT implementation David Malcolm
2017-09-01 17:32   ` Jeff Law
2017-07-24 19:31 ` [PATCH 15/17] Language Server Protocol: add lsp::server abstract base class David Malcolm
2017-07-27  4:14   ` Trevor Saunders
2017-07-28 14:48     ` David Malcolm
2017-07-27  7:55   ` Richard Biener
2017-07-28 16:02     ` David Malcolm
2017-07-24 19:31 ` [PATCH 02/17] diagnostics: support prefixes within diagnostic_show_locus David Malcolm
2017-09-01 17:11   ` Jeff Law
2017-07-24 19:31 ` [PATCH 12/17] Add server.h and server.c David Malcolm
2017-07-26 14:35   ` Oleg Endo
2017-07-26 14:50     ` David Malcolm
2017-07-26 21:00       ` Mike Stump
2017-09-01 17:09   ` Jeff Law
2017-07-24 19:31 ` [PATCH 10/17] C++: provide fix-it hints in -Wsuggest-override David Malcolm
2017-07-24 19:31 ` [PATCH 11/17] Add JSON implementation David Malcolm
2017-09-01 17:06   ` Jeff Law
2017-07-24 19:31 ` [PATCH 01/17] Add param-type-mismatch.c/C testcases as a baseline David Malcolm
2017-07-24 19:56   ` Eric Gallager
2017-09-01 17:00   ` Jeff Law
2017-07-24 19:38 ` [PATCH 06/17] C: use BLT to highlight parameter of callee decl for mismatching types David Malcolm
2017-07-24 19:38 ` [PATCH 07/17] C++: " David Malcolm
2017-07-24 19:38 ` [PATCH 14/17] Add implementation of JSON-RPC David Malcolm
2017-07-24 19:39 ` [PATCH 04/17] C frontend: capture BLT information David Malcolm
2017-07-27 19:58   ` Martin Sebor
2017-07-24 19:39 ` [PATCH 08/17] C: highlight return types when complaining about mismatches David Malcolm
2017-07-24 19:39 ` David Malcolm [this message]
2017-07-24 19:40 ` [PATCH 05/17] C++ frontend: capture BLT information David Malcolm
2017-07-24 19:41 ` [PATCH 16/17] Language Server Protocol: proof-of-concept GCC implementation David Malcolm
2017-07-26 17:10 ` [PATCH 00/17] RFC: New source-location representation; Language Server Protocol Jim Wilson
2017-07-28  5:12   ` Alexandre Oliva
2017-07-27 19:51 ` Martin Sebor
2017-07-28 14:28   ` David Malcolm
2017-07-28 18:32     ` Martin Sebor
2017-10-11 19:32 ` David Malcolm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1500926714-56988-10-git-send-email-dmalcolm@redhat.com \
    --to=dmalcolm@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).