From 4f77beffc109a618a11a26d1db088ddfde903ed2 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 27 Aug 2015 16:36:59 -0400
Subject: [PATCH 19/43] FIXME: C/C++ frontend: use tree ranges in various
 diagnostics

Screenshot:
 https://dmalcolm.fedorapeople.org/gcc/2015-09-09/tree-ranges.html

This mostly affects the C frontend, but it touches c-common.h so the
C++ frontend needs a slight adjustment.

FIXME:
  This needs some rewrites.

gcc/c-family/ChangeLog:
	* c-common.c: Include gcc-rich-location.h.
	(binary_op_error): Add params orig_op0 and orig_op1; use them
	to add ranges and captions to the error.
	* c-common.h (binary_op_error): Add params orig_op0 and orig_op1.

gcc/c/ChangeLog:
	* c-parser.c (c_parser_static_assert_declaration_no_semi):
	Convert locals "assert_loc" and "value_loc" from location_t to
	source_range, thus using ranges in diagnostics.
	* c-typeck.c (inform_declaration): Use DECL_LOCATION_RANGE
	of the decl, rather than DECL_SOURCE_LOCATION.
	(build_function_call_vec): Use the EXPR_LOCATION_RANGE of
	the function when issuing diagnostics, rather than "loc".
	(convert_for_assignment): Emit range-based diagnostics, rather
	than locations when CAN_HAVE_RANGE_P (rhs).
	(c_finish_return): Likewise when CAN_HAVE_RANGE_P (retval).
	When issuing warnings about erroneous presence/absence of return
	values, show the location of current_function_decl using inform.
	(build_binary_op): Pass orig_op0 and orig_op1 to binary_op_error.

gcc/cp/ChangeLog:
	* typeck.c (cp_build_binary_op): Pass orig_op0 and orig_op1 to
	binary_op_error.

gcc/testsuite/ChangeLog:
	* gcc.dg/diagnostic-tree-expr-ranges.c: New file.
---
 gcc/c-family/c-common.c                            |   9 +-
 gcc/c-family/c-common.h                            |   3 +-
 gcc/c/c-parser.c                                   |   2 +-
 gcc/c/c-typeck.c                                   | 122 ++++++++++-------
 gcc/cp/typeck.c                                    |   3 +-
 gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c | 146 ++++++++++++++++++++-
 6 files changed, 233 insertions(+), 52 deletions(-)

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index c102bbd..c51d9d1 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "wide-int-print.h"
 #include "gimple-expr.h"
+#include "gcc-rich-location.h"
 
 cpp_reader *parse_in;		/* Declared in c-pragma.h.  */
 
@@ -4350,6 +4351,7 @@ c_register_builtin_type (tree type, const char* name)
 
 void
 binary_op_error (location_t location, enum tree_code code,
+		 tree orig_op0, tree orig_op1,
 		 tree type0, tree type1)
 {
   const char *opname;
@@ -4401,7 +4403,12 @@ binary_op_error (location_t location, enum tree_code code,
     default:
       gcc_unreachable ();
     }
-  error_at (location,
+  gcc_rich_location richloc (location);
+  richloc.maybe_add_expr_with_caption (orig_op0, global_dc,
+				       "%qT", TREE_TYPE (orig_op0));
+  richloc.maybe_add_expr_with_caption (orig_op1, global_dc,
+				       "%qT", TREE_TYPE (orig_op1));
+  error_at_rich_loc (&richloc,
 	    "invalid operands to binary %s (have %qT and %qT)", opname,
 	    type0, type1);
 }
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index b0a7661..d2939d4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -818,7 +818,8 @@ extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
 extern tree c_alignof_expr (location_t, tree);
 /* Print an error message for invalid operands to arith operation CODE.
    NOP_EXPR is used as a special case (see truthvalue_conversion).  */
-extern void binary_op_error (location_t, enum tree_code, tree, tree);
+extern void binary_op_error (location_t, enum tree_code, tree, tree,
+			     tree, tree);
 extern tree fix_string_type (tree);
 extern void constant_expression_warning (tree);
 extern void constant_expression_error (tree);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index d39d7a2..1315a57 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -2067,7 +2067,7 @@ c_parser_static_assert_declaration (c_parser *parser)
 static void
 c_parser_static_assert_declaration_no_semi (c_parser *parser)
 {
-  location_t assert_loc, value_loc;
+  source_range assert_loc, value_loc;
   tree value;
   tree string;
 
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index c2e16c6..6b6e2c1 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2841,7 +2841,7 @@ static void
 inform_declaration (tree decl)
 {
   if (decl && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_IS_BUILTIN (decl)))
-    inform (DECL_SOURCE_LOCATION (decl), "declared here");
+    inform (DECL_LOCATION_RANGE (decl), "declared here");
 }
 
 /* Build a function call to function FUNCTION with parameters PARAMS.
@@ -2908,13 +2908,13 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 		  function);
       else if (DECL_P (function))
 	{
-	  error_at (loc,
+	  error_at (func_range,
 		    "called object %qD is not a function or function pointer",
 		    function);
 	  inform_declaration (function);
 	}
       else
-	error_at (loc,
+	error_at (func_range,
 		  "called object is not a function or function pointer");
       return error_mark_node;
     }
@@ -2945,11 +2945,12 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
       /* This situation leads to run-time undefined behavior.  We can't,
 	 therefore, simply error unless we can prove that all possible
 	 executions of the program must execute the code.  */
-      warning_at (loc, 0, "function called through a non-compatible type");
+      warning_at (func_range, 0,
+		  "function called through a non-compatible type");
 
       if (VOID_TYPE_P (return_type)
 	  && TYPE_QUALS (return_type) != TYPE_UNQUALIFIED)
-	pedwarn (loc, 0,
+	pedwarn (func_range, 0,
 		 "function with qualified void return type called");
      }
 
@@ -2986,7 +2987,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
   if (VOID_TYPE_P (TREE_TYPE (result)))
     {
       if (TYPE_QUALS (TREE_TYPE (result)) != TYPE_UNQUALIFIED)
-	pedwarn (loc, 0,
+	pedwarn (func_range, 0,
 		 "function with qualified void return type called");
       return result;
     }
@@ -5731,6 +5732,13 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
      function returning a wrong-type macro defined in a system header.  */
   location = expansion_point_location_if_in_system_header (location);
 
+  source_range rhs_range;
+
+  if (CAN_HAVE_RANGE_P (rhs))
+    rhs_range = EXPR_LOCATION_RANGE (rhs);
+  else
+    rhs_range = source_range::from_location (expr_loc);
+
   if (errtype == ic_argpass)
     {
       tree selector;
@@ -5753,14 +5761,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
   /* This macro is used to emit diagnostics to ensure that all format
      strings are complete sentences, visible to gettext and checked at
      compile time.  */
-#define PEDWARN_FOR_ASSIGNMENT(LOCATION, PLOC, OPT, AR, AS, IN, RE)	 \
+#define PEDWARN_FOR_ASSIGNMENT(LOCATION, RANGE, OPT, AR, AS, IN, RE)	 \
   do {                                                                   \
     switch (errtype)                                                     \
       {                                                                  \
       case ic_argpass:                                                   \
-        if (pedwarn (PLOC, OPT, AR, parmnum, rname))			 \
-          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))	         \
-		  ? DECL_SOURCE_LOCATION (fundecl) : PLOC,		 \
+        if (pedwarn (RANGE, OPT, AR, parmnum, rname))                    \
+          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))                \
+                 ? DECL_SOURCE_LOCATION (fundecl) : RANGE.m_start,       \
                   "expected %qT but argument is of type %qT",            \
                   type, rhstype);                                        \
         break;                                                           \
@@ -5782,14 +5790,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
      strings are complete sentences, visible to gettext and checked at
      compile time.  It is the same as PEDWARN_FOR_ASSIGNMENT but with an
      extra parameter to enumerate qualifiers.  */
-#define PEDWARN_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
+#define PEDWARN_FOR_QUALIFIERS(LOCATION, RANGE, OPT, AR, AS, IN, RE, QUALS) \
   do {                                                                   \
     switch (errtype)                                                     \
       {                                                                  \
       case ic_argpass:                                                   \
-        if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))		 \
-          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))	         \
-		  ? DECL_SOURCE_LOCATION (fundecl) : PLOC,		 \
+        if (pedwarn (RANGE, OPT, AR, parmnum, rname, QUALS))		 \
+          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))                \
+                 ? DECL_SOURCE_LOCATION (fundecl) : RANGE.m_start,       \
                   "expected %qT but argument is of type %qT",            \
                   type, rhstype);                                        \
         break;                                                           \
@@ -5811,14 +5819,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
      strings are complete sentences, visible to gettext and checked at
      compile time.  It is the same as PEDWARN_FOR_QUALIFIERS but uses
      warning_at instead of pedwarn.  */
-#define WARNING_FOR_QUALIFIERS(LOCATION, PLOC, OPT, AR, AS, IN, RE, QUALS) \
+#define WARNING_FOR_QUALIFIERS(LOCATION, RANGE, OPT, AR, AS, IN, RE, QUALS) \
   do {                                                                   \
     switch (errtype)                                                     \
       {                                                                  \
       case ic_argpass:                                                   \
-        if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))           \
+        if (warning_at (RANGE, OPT, AR, parmnum, rname, QUALS))          \
           inform ((fundecl && !DECL_IS_BUILTIN (fundecl))                \
-                  ? DECL_SOURCE_LOCATION (fundecl) : PLOC,               \
+                  ? DECL_SOURCE_LOCATION (fundecl) : RANGE.m_start,      \
                   "expected %qT but argument is of type %qT",            \
                   type, rhstype);                                        \
         break;                                                           \
@@ -5878,7 +5886,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	  && TREE_CODE (type) == ENUMERAL_TYPE
 	  && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type))
 	{
-	  PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wc___compat,
+	  PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wc___compat,
 			          G_("enum conversion when passing argument "
 				     "%d of %qE is invalid in C++"),
 			          G_("enum conversion in assignment is "
@@ -6047,7 +6055,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 		     vice-versa.  */
 		  if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
 		      & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
-		    PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+		    PEDWARN_FOR_QUALIFIERS (location, rhs_range,
 					    OPT_Wdiscarded_qualifiers,
 					    G_("passing argument %d of %qE "
 					       "makes %q#v qualified function "
@@ -6064,7 +6072,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 		}
 	      else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
 		       & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
-		PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+		PEDWARN_FOR_QUALIFIERS (location, rhs_range,
 				        OPT_Wdiscarded_qualifiers,
 				        G_("passing argument %d of %qE discards "
 					   "%qv qualifier from pointer target type"),
@@ -6155,7 +6163,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	  switch (errtype)
 	    {
 	    case ic_argpass:
-	      error_at (expr_loc, "passing argument %d of %qE from pointer to "
+	      error_at (rhs_range, "passing argument %d of %qE from pointer to "
 			"non-enclosed address space", parmnum, rname);
 	      break;
 	    case ic_assign:
@@ -6184,7 +6192,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	  switch (errtype)
 	  {
 	  case ic_argpass:
-	    warning_at (expr_loc, OPT_Wsuggest_attribute_format,
+	    warning_at (rhs_range, OPT_Wsuggest_attribute_format,
 			"argument %d of %qE might be "
 			"a candidate for a format attribute",
 			parmnum, rname);
@@ -6231,7 +6239,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 
 	      if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
 		  & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl))
-		WARNING_FOR_QUALIFIERS (location, expr_loc,
+		WARNING_FOR_QUALIFIERS (location, rhs_range,
 				        OPT_Wdiscarded_array_qualifiers,
 				        G_("passing argument %d of %qE discards "
 					   "%qv qualifier from pointer target type"),
@@ -6249,7 +6257,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 		  (VOID_TYPE_P (ttr)
 		   && !null_pointer_constant
 		   && TREE_CODE (ttl) == FUNCTION_TYPE)))
-	    PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpedantic,
+	    PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wpedantic,
 				    G_("ISO C forbids passing argument %d of "
 				       "%qE between function pointer "
 				       "and %<void *%>"),
@@ -6274,7 +6282,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	      if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
 		  & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl))
 		{
-		  PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+		  PEDWARN_FOR_QUALIFIERS (location, rhs_range,
 				          OPT_Wdiscarded_qualifiers,
 				          G_("passing argument %d of %qE discards "
 					     "%qv qualifier from pointer target type"),
@@ -6293,7 +6301,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 		;
 	      /* If there is a mismatch, do warn.  */
 	      else if (warn_pointer_sign)
-		 PEDWARN_FOR_ASSIGNMENT (location, expr_loc, OPT_Wpointer_sign,
+		 PEDWARN_FOR_ASSIGNMENT (location, rhs_range, OPT_Wpointer_sign,
 				         G_("pointer targets in passing argument "
 					    "%d of %qE differ in signedness"),
 				         G_("pointer targets in assignment "
@@ -6312,7 +6320,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 		 where an ordinary one is wanted, but not vice-versa.  */
 	      if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
 		  & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
-		PEDWARN_FOR_QUALIFIERS (location, expr_loc,
+		PEDWARN_FOR_QUALIFIERS (location, rhs_range,
 				        OPT_Wdiscarded_qualifiers,
 				        G_("passing argument %d of %qE makes "
 					   "%q#v qualified function pointer "
@@ -6329,7 +6337,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
       else
 	/* Avoid warning about the volatile ObjC EH puts on decls.  */
 	if (!objc_ok)
-	  PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
+	  PEDWARN_FOR_ASSIGNMENT (location, rhs_range,
 			          OPT_Wincompatible_pointer_types,
 			          G_("passing argument %d of %qE from "
 				     "incompatible pointer type"),
@@ -6353,7 +6361,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	 or one that results from arithmetic, even including
 	 a cast to integer type.  */
       if (!null_pointer_constant)
-	PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
+	PEDWARN_FOR_ASSIGNMENT (location, rhs_range,
 			        OPT_Wint_conversion,
 			        G_("passing argument %d of %qE makes "
 				   "pointer from integer without a cast"),
@@ -6368,7 +6376,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     }
   else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
     {
-      PEDWARN_FOR_ASSIGNMENT (location, expr_loc,
+      PEDWARN_FOR_ASSIGNMENT (location, rhs_range,
 			      OPT_Wint_conversion,
 			      G_("passing argument %d of %qE makes integer "
 			         "from pointer without a cast"),
@@ -6393,7 +6401,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
   switch (errtype)
     {
     case ic_argpass:
-      error_at (expr_loc, "incompatible type for argument %d of %qE", parmnum,
+      error_at (rhs_range, "incompatible type for argument %d of %qE", parmnum,
 		rname);
       inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
 	      ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
@@ -9396,8 +9404,14 @@ c_finish_return (location_t loc, tree retval, tree origtype)
      in a function returning void.  */
   source_location xloc = expansion_point_location_if_in_system_header (loc);
 
+  source_range expr_range;
+  if (retval && CAN_HAVE_RANGE_P (retval))
+    expr_range = EXPR_LOCATION_RANGE (retval);
+  else
+    expr_range = source_range::from_location (xloc);
+
   if (TREE_THIS_VOLATILE (current_function_decl))
-    warning_at (xloc, 0,
+    warning_at (expr_range, 0,
 		"function declared %<noreturn%> has a %<return%> statement");
 
   if (flag_cilkplus && contains_array_notation_expr (retval))
@@ -9408,14 +9422,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;
     }
@@ -9439,24 +9454,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 (xloc, 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 (xloc, 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
     {
@@ -9527,11 +9554,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);
@@ -11058,7 +11085,7 @@ build_binary_op (location_t location, enum tree_code code,
       && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1))
 	  || !vector_types_compatible_elements_p (type0, type1)))
     {
-      binary_op_error (location, code, type0, type1);
+      binary_op_error (location, code, orig_op0, orig_op1, type0, type1);
       return error_mark_node;
     }
 
@@ -11297,7 +11324,8 @@ build_binary_op (location_t location, enum tree_code code,
 
   if (!result_type)
     {
-      binary_op_error (location, code, TREE_TYPE (op0), TREE_TYPE (op1));
+      binary_op_error (location, code, orig_op0, orig_op1,
+		       TREE_TYPE (op0), TREE_TYPE (op1));
       return error_mark_node;
     }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 9e6f949..4e6134f 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4867,7 +4867,8 @@ cp_build_binary_op (location_t location,
 	      || !vector_types_compatible_elements_p (type0, type1))
 	    {
 	      if (complain & tf_error)
-		binary_op_error (location, code, type0, type1);
+		binary_op_error (location, code, orig_op0, orig_op1,
+				 type0, type1);
 	      return error_mark_node;
 	    }
 	  arithmetic_types_p = 1;
diff --git a/gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c b/gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c
index 3318543..741f58a 100644
--- a/gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c
+++ b/gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c
@@ -1,4 +1,5 @@
-/* { dg-options "-fdiagnostics-show-caret" } */
+/* { dg-options "-fdiagnostics-show-caret -Wreturn-local-addr" } */
+
 
 void test_nonconst_static_assert (int i)
 {
@@ -10,3 +11,146 @@ void test_nonconst_static_assert (int i)
 { dg-end-multiline-output "" }
 */
 }
+
+extern void test_callee (int first, const char *second, int third);
+
+void test_bad_argument_types (int first, int second, int third)
+{
+  test_callee (first, first + second + third, third); /* { dg-warning "passing argument 2 of 'test_callee' makes pointer from integer without a cast" }  */
+
+/*
+{ dg-begin-multiline-output "" }
+   test_callee (first, first + second + third, third);
+                       ^~~~~~~~~~~~~~~~~~~~~~
+{ dg-end-multiline-output "" }
+{ dg-begin-multiline-output "" }
+ extern void test_callee (int first, const char *second, int third);
+             ^
+{ dg-end-multiline-output "" }
+FIXME: we ought to highlight the specific param in the decl
+*/
+
+  test_callee (first, &first, third); /* { dg-warning "passing argument 2 of 'test_callee' from incompatible pointer type" } */
+
+/*
+{ dg-begin-multiline-output "" }
+   test_callee (first, &first, third);
+                       ^~~~~~
+{ dg-end-multiline-output "" }
+{ dg-begin-multiline-output "" }
+ extern void test_callee (int first, const char *second, int third);
+             ^
+{ dg-end-multiline-output "" }
+FIXME: again, we ought to highlight the specific param in the decl
+*/
+
+  test_callee ("hello world", "", third); /* { dg-warning "passing argument 1 of 'test_callee' makes integer from pointer without a cast" } */
+
+/*
+{ dg-begin-multiline-output "" }
+   test_callee ("hello world", "", third);
+                ^~~~~~~~~~~~~
+{ dg-end-multiline-output "" }
+{ dg-begin-multiline-output "" }
+ extern void test_callee (int first, const char *second, int third);
+             ^
+{ dg-end-multiline-output "" }
+FIXME: and again, we ought to highlight the specific param in the decl
+*/
+
+}
+
+/* Adapted from https://gcc.gnu.org/wiki/ClangDiagnosticsComparison */
+
+void call_of_non_function_ptr (char **argP, char **argQ)
+{
+  (argP - argQ)(); /* { dg-error "called object is not a function or function pointer" } */
+
+/* { dg-begin-multiline-output "" }
+   (argP - argQ)();
+   ^~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  argP();       /* { dg-error "called object 'argP' is not a function or function pointer" } */
+
+/* { dg-begin-multiline-output "" }
+   argP();
+   ^~~~
+   { dg-end-multiline-output "" }
+   { dg-begin-multiline-output "" }
+ void call_of_non_function_ptr (char **argP, char **argQ)
+                                       ^
+   { dg-end-multiline-output "" } */
+  /* TODO: underline all of "argP" in the decl above. */
+}
+
+/* Adapted from https://gcc.gnu.org/wiki/ClangDiagnosticsComparison */
+
+typedef float __m128;
+void bad_binary_op ()
+{
+  __m128 myvec[2];
+  int const *ptr;
+  myvec[1]/ptr; /* { dg-error "invalid operands to binary /" } */
+
+/*
+{ dg-begin-multiline-output "" }
+   myvec[1]/ptr;
+   ~~~~~~~~^~~~
+{ dg-end-multiline-output "" } */
+
+}
+
+struct s {};
+struct t {};
+extern struct s some_function (void);
+extern struct t some_other_function (void);
+
+int another_bad_binary_op (void)
+{
+  return (some_function ()
+	  + some_other_function ()); /* { dg-error "invalid operands to binary +" } */
+
+/* { dg-begin-multiline-output "" }
+   return (some_function ()|
+           ~~~~~~~~~~~~~~~~+'struct s'
+    + some_other_function ());                                                  |
+    ^ ~~~~~~~~~~~~~~~~~~~~~~                                                    +'struct t'
+   { 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

