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

Reply via email to