[PATCH 16/22] C/C++ frontend: use tree ranges in various diagnostics

David Malcolm dmalcolm@redhat.com
Thu Sep 10 20:32:00 GMT 2015


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.

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                                   |   6 +-
 gcc/c/c-typeck.c                                   | 123 ++++++++++------
 gcc/cp/typeck.c                                    |   3 +-
 gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c | 159 +++++++++++++++++++++
 6 files changed, 250 insertions(+), 53 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index ff6f90f..77962fc 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.  */
 
@@ -4340,6 +4341,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;
@@ -4391,7 +4393,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 bb17fcc..b9a5d72 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -804,7 +804,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 4303496..0c62496 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -2037,12 +2037,12 @@ 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;
 
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT));
-  assert_loc = c_parser_peek_token (parser)->location;
+  assert_loc = c_parser_peek_token (parser)->range;
   if (flag_isoc99)
     pedwarn_c99 (assert_loc, OPT_Wpedantic,
 		 "ISO C99 does not support %<_Static_assert%>");
@@ -2052,8 +2052,8 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
   c_parser_consume_token (parser);
   if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     return;
-  value_loc = c_parser_peek_token (parser)->location;
   value = c_parser_expr_no_commas (parser, NULL).value;
+  value_loc = EXPR_LOCATION_RANGE (value);
   parser->lex_untranslated_string = true;
   if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
     {
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 4123f11..506abb3 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2851,7 +2851,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.
@@ -2873,6 +2873,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
   int nargs;
   tree *argarray;
 
+  source_range func_range = EXPR_LOCATION_RANGE (function);
 
   /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
   STRIP_TYPE_NOPS (function);
@@ -2921,13 +2922,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;
     }
@@ -2958,11 +2959,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");
      }
 
@@ -2999,7 +3001,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;
     }
@@ -5734,6 +5736,13 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
   tree rname = NULL_TREE;
   bool objc_ok = false;
 
+  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;
@@ -5756,14 +5765,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;                                                           \
@@ -5785,14 +5794,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;                                                           \
@@ -5814,14 +5823,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;                                                           \
@@ -5881,7 +5890,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 "
@@ -6050,7 +6059,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 "
@@ -6067,7 +6076,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"),
@@ -6158,7 +6167,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:
@@ -6187,7 +6196,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);
@@ -6234,7 +6243,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"),
@@ -6252,7 +6261,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 *%>"),
@@ -6277,7 +6286,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"),
@@ -6296,7 +6305,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 "
@@ -6315,7 +6324,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 "
@@ -6332,7 +6341,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"),
@@ -6356,7 +6365,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"),
@@ -6371,7 +6380,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"),
@@ -6396,7 +6405,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 +9405,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))
@@ -9408,14 +9423,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 +9455,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
     {
@@ -9532,11 +9560,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);
@@ -11055,7 +11083,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;
     }
 
@@ -11294,7 +11322,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 388558c..b5a131c 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4841,7 +4841,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
new file mode 100644
index 0000000..10ab7db
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/diagnostic-tree-expr-ranges.c
@@ -0,0 +1,159 @@
+/* { dg-options "-fdiagnostics-show-caret -Wreturn-local-addr" } */
+
+/* Verify that various diagnostics show source code ranges.  */
+
+/* These ones make use of tree ranges.  */
+
+void test_nonconst_static_assert (int i)
+{
+  _Static_assert (i > 0, "message"); /* { dg-error "expression in static assertion is not constant" } */
+/*
+{ dg-begin-multiline-output "" }
+   _Static_assert (i > 0, "message");
+                   ^~~~~
+{ 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



More information about the Gcc-patches mailing list