From 62c1880509356446f798cba36393cd749791de4b Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 28 Aug 2015 09:18:40 -0400
Subject: [PATCH 53/66] FIXME: C: Show ranges (of trees) in c_finish_return
 (and show fundecl when relevant)

---
 gcc/c/c-typeck.c                           | 52 ++++++++++++++++++++++--------
 gcc/testsuite/gcc.dg/diagnostic-ranges-2.c | 38 +++++++++++++++++++++-
 2 files changed, 75 insertions(+), 15 deletions(-)

diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index bcfd218..a725624 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -9403,8 +9403,14 @@ c_finish_return (location_t loc, tree retval, tree origtype)
   bool npc = false;
   size_t rank = 0;
 
+  source_range expr_range;
+  if (retval && CAN_HAVE_RANGE_P (retval))
+    expr_range = EXPR_LOCATION_RANGE (retval);
+  else
+    expr_range = source_range::from_location (loc);
+
   if (TREE_THIS_VOLATILE (current_function_decl))
-    warning_at (loc, 0,
+    warning_at (expr_range, 0,
 		"function declared %<noreturn%> has a %<return%> statement");
 
   if (flag_cilkplus && contains_array_notation_expr (retval))
@@ -9415,14 +9421,15 @@ c_finish_return (location_t loc, tree retval, tree origtype)
 	return error_mark_node;
       if (rank >= 1)
 	{
-	  error_at (loc, "array notation expression cannot be used as a "
+	  error_at (expr_range, "array notation expression cannot be used as a "
 		    "return value");
 	  return error_mark_node;
 	}
     }
   if (flag_cilkplus && retval && contains_cilk_spawn_stmt (retval))
     {
-      error_at (loc, "use of %<_Cilk_spawn%> in a return statement is not "
+      error_at (expr_range,
+		"use of %<_Cilk_spawn%> in a return statement is not "
 		"allowed");
       return error_mark_node;
     }
@@ -9446,24 +9453,36 @@ c_finish_return (location_t loc, tree retval, tree origtype)
       if ((warn_return_type || flag_isoc99)
 	  && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
 	{
+	  bool warned_here;
 	  if (flag_isoc99)
-	    pedwarn (loc, 0, "%<return%> with no value, in "
-		     "function returning non-void");
+	    warned_here = pedwarn
+	      (loc, 0,
+	       "%<return%> with no value, in function returning non-void");
 	  else
-	    warning_at (loc, OPT_Wreturn_type, "%<return%> with no value, "
-			"in function returning non-void");
-	  no_warning = true;
+	    warned_here =
+	      warning_at (loc, OPT_Wreturn_type,
+			  "%<return%> with no value, "
+			  "in function returning non-void");
+	  if (warned_here)
+	    inform (DECL_SOURCE_LOCATION (current_function_decl),
+		    "declared here");
 	}
     }
   else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
     {
       current_function_returns_null = 1;
+      bool warned_here;
       if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
-	pedwarn (loc, 0,
-		 "%<return%> with a value, in function returning void");
+	warned_here = pedwarn
+	  (expr_range, 0,
+	   "%<return%> with a value, in function returning void");
       else
-	pedwarn (loc, OPT_Wpedantic, "ISO C forbids "
-		 "%<return%> with expression, in function returning void");
+	warned_here = pedwarn
+	  (expr_range, OPT_Wpedantic, "ISO C forbids "
+	   "%<return%> with expression, in function returning void");
+      if (warned_here)
+	inform (DECL_SOURCE_LOCATION (current_function_decl),
+		"declared here");
     }
   else
     {
@@ -9499,6 +9518,7 @@ c_finish_return (location_t loc, tree retval, tree origtype)
 	    case NON_LVALUE_EXPR:
 	    case PLUS_EXPR:
 	    case POINTER_PLUS_EXPR:
+	    case SOURCE_RANGE:
 	      inner = TREE_OPERAND (inner, 0);
 	      continue;
 
@@ -9508,6 +9528,8 @@ c_finish_return (location_t loc, tree retval, tree origtype)
 		 don't give a warning.  */
 	      {
 		tree op1 = TREE_OPERAND (inner, 1);
+		if (TREE_CODE (op1) == SOURCE_RANGE)
+		  op1 = TREE_OPERAND (op1, 0);
 
 		while (!POINTER_TYPE_P (TREE_TYPE (op1))
 		       && (CONVERT_EXPR_P (op1)
@@ -9523,6 +9545,8 @@ c_finish_return (location_t loc, tree retval, tree origtype)
 
 	    case ADDR_EXPR:
 	      inner = TREE_OPERAND (inner, 0);
+	      if (TREE_CODE (inner) == SOURCE_RANGE)
+		inner = TREE_OPERAND (inner, 0);
 
 	      while (REFERENCE_CLASS_P (inner)
 		     && !INDIRECT_REF_P (inner))
@@ -9534,11 +9558,11 @@ c_finish_return (location_t loc, tree retval, tree origtype)
 		  && DECL_CONTEXT (inner) == current_function_decl)
 		{
 		  if (TREE_CODE (inner) == LABEL_DECL)
-		    warning_at (loc, OPT_Wreturn_local_addr,
+		    warning_at (expr_range, OPT_Wreturn_local_addr,
 				"function returns address of label");
 		  else
 		    {
-		      warning_at (loc, OPT_Wreturn_local_addr,
+		      warning_at (expr_range, OPT_Wreturn_local_addr,
 				  "function returns address of local variable");
 		      tree zero = build_zero_cst (TREE_TYPE (res));
 		      t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero);
diff --git a/gcc/testsuite/gcc.dg/diagnostic-ranges-2.c b/gcc/testsuite/gcc.dg/diagnostic-ranges-2.c
index d6c4140..5fda2ea 100644
--- a/gcc/testsuite/gcc.dg/diagnostic-ranges-2.c
+++ b/gcc/testsuite/gcc.dg/diagnostic-ranges-2.c
@@ -1,4 +1,4 @@
-/* { dg-options "-fdiagnostics-show-caret" } */
+/* { dg-options "-fdiagnostics-show-caret -Wreturn-local-addr" } */
 
 /* Verify that various diagnostics show source code ranges.  */
 
@@ -110,3 +110,39 @@ int another_bad_binary_op (void)
           ~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~
    { dg-end-multiline-output "" } */
 }
+
+void surplus_return_when_void (void)
+{
+  return 500; /* { dg-warning "'return' with a value, in function returning void" } */
+/* { dg-begin-multiline-output "" }
+   return 500;
+          ^~~
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+ void surplus_return_when_void (void)
+      ^
+   { dg-end-multiline-output "" } */
+}
+
+int missing_return_value (void)
+{
+  return; /* { dg-warning "'return' with no value, in function returning non-void" } */
+/* { dg-begin-multiline-output "" }
+   return;
+   ^
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+ int missing_return_value (void)
+     ^
+   { dg-end-multiline-output "" } */
+}
+
+int *address_of_local (void)
+{
+  int i;
+  return &i; /* { dg-warning "function returns address of local variable" } */
+/* { dg-begin-multiline-output "" }
+   return &i;
+          ^~
+   { dg-end-multiline-output "" } */
+}
-- 
1.8.5.3

