From bb440aa08b3a570ef8e8cdcb7675eb814455fe5d Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 1 Sep 2015 16:18:19 -0400
Subject: [PATCH 49/56] FIXME: C++ FE: various capture and use of tree ranges

---
 gcc/cp/call.c    | 47 +++++++++++++++++++++++++++++++----------------
 gcc/cp/cp-tree.h |  5 +++--
 gcc/cp/error.c   | 19 +++++++++++++++++++
 gcc/cp/parser.c  | 26 +++++++++++++++++++-------
 gcc/cp/typeck.c  | 27 +++++++++++++++++++++------
 5 files changed, 93 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 367d42b..c79aec1 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "function.h"
 #include "cgraph.h"
 #include "internal-fn.h"
+#include "gcc-rich-location.h"
 
 /* The various kinds of conversion.  */
 
@@ -162,7 +163,7 @@ static tree build_java_interface_fn_ref (tree, tree);
 		     /*c_cast_p=*/false, (COMPLAIN))
 static tree convert_like_real (conversion *, tree, tree, int, int, bool,
 			       bool, tsubst_flags_t);
-static void op_error (location_t, enum tree_code, enum tree_code, tree,
+static void op_error (range_or_loc, enum tree_code, enum tree_code, tree,
 		      tree, tree, bool);
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
 							 tsubst_flags_t);
@@ -4031,16 +4032,19 @@ print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
 			      struct z_candidate *candidates)
 {
   tree name = DECL_NAME (OVL_CURRENT (fn));
-  location_t loc = location_of (name);
+  source_range range = range_of (name);
+  gcc_rich_location richloc (range);
 
   if (!any_strictly_viable (candidates))
-    error_at (loc, "no matching function for call to %<%D(%A)%>",
-	      name, build_tree_list_vec (args));
+    error_at_rich_loc (&richloc,
+		       "no matching function for call to %<%D(%A)%>",
+		       name, build_tree_list_vec (args));
   else
-    error_at (loc, "call of overloaded %<%D(%A)%> is ambiguous",
-	      name, build_tree_list_vec (args));
+    error_at_rich_loc (&richloc,
+		       "call of overloaded %<%D(%A)%> is ambiguous",
+		       name, build_tree_list_vec (args));
   if (candidates)
-    print_z_candidates (loc, candidates);
+    print_z_candidates (location_of (name), candidates);
 }
 
 /* Return an expression for a call to FN (a namespace-scope function,
@@ -4415,10 +4419,11 @@ op_error_string (const char *errmsg, int ntypes, bool match)
 }
 
 static void
-op_error (location_t loc, enum tree_code code, enum tree_code code2,
+op_error (range_or_loc src_range, enum tree_code code, enum tree_code code2,
 	  tree arg1, tree arg2, tree arg3, bool match)
 {
   const char *opname;
+  location_t loc = src_range.m_start;
 
   if (code == MODIFY_EXPR)
     opname = assignment_operator_name_info[code2].name;
@@ -4472,9 +4477,17 @@ op_error (location_t loc, enum tree_code code, enum tree_code code2,
 
     default:
       if (arg2)
-	if (flag_diagnostics_show_caret)
-	  error_at (loc, op_error_string (G_("%<operator%s%>"), 2, match),
-		    opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+	if (flag_diagnostics_show_caret || flag_dump_location_details)
+	  {
+	    gcc_rich_location richloc (src_range);
+	    richloc.add_expr_with_caption (arg1, global_dc,
+					   G_("type %qT"), TREE_TYPE (arg1));
+	    richloc.add_expr_with_caption (arg2, global_dc,
+					   G_("type %qT"), TREE_TYPE (arg2));
+	    error_at_rich_loc (&richloc,
+			       op_error_string (G_("%<operator%s%>"), 2, match),
+			       opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+	  }
 	else
 	  error_at (loc, op_error_string (G_("%<operator%s%> in %<%E %s %E%>"),
 					  2, match),
@@ -5328,7 +5341,7 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
 }
 
 static tree
-build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
+build_new_op_1 (source_range src_range, enum tree_code code, int flags, tree arg1,
 		tree arg2, tree arg3, tree *overload, tsubst_flags_t complain)
 {
   struct z_candidate *candidates = 0, *cand;
@@ -5344,6 +5357,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
   void *p;
   bool strict_p;
   bool any_viable_p;
+  location_t loc = src_range.m_start;
 
   if (error_operand_p (arg1)
       || error_operand_p (arg2)
@@ -5559,7 +5573,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 	    code = PREINCREMENT_EXPR;
 	  else
 	    code = PREDECREMENT_EXPR;
-	  result = build_new_op_1 (loc, code, flags, arg1, NULL_TREE,
+	  result = build_new_op_1 (src_range, code, flags, arg1, NULL_TREE,
 				   NULL_TREE, overload, complain);
 	  break;
 
@@ -5585,7 +5599,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 		  {
 		    /* ... Otherwise, report the more generic
 		       "no matching operator found" error */
-		    op_error (loc, code, code2, arg1, arg2, arg3, FALSE);
+		    op_error (src_range, code, code2, arg1, arg2, arg3, FALSE);
 		    print_z_candidates (loc, candidates);
 		  }
 	    }
@@ -5775,13 +5789,14 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 /* Wrapper for above.  */
 
 tree
-build_new_op (location_t loc, enum tree_code code, int flags,
+build_new_op (range_or_loc src_range, enum tree_code code, int flags,
 	      tree arg1, tree arg2, tree arg3,
 	      tree *overload, tsubst_flags_t complain)
 {
   tree ret;
   bool subtime = timevar_cond_start (TV_OVERLOAD);
-  ret = build_new_op_1 (loc, code, flags, arg1, arg2, arg3,
+  //src_range.debug ("build_new_op (as source_range)");
+  ret = build_new_op_1 (src_range, code, flags, arg1, arg2, arg3,
 			overload, complain);
   timevar_cond_stop (TV_OVERLOAD, subtime);
   return ret;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 784a616..d8a3365 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5426,7 +5426,7 @@ extern tree build_new_method_call		(tree, tree, vec<tree, va_gc> **,
 						 tsubst_flags_t);
 extern tree build_special_member_call		(tree, tree, vec<tree, va_gc> **,
 						 tree, int, tsubst_flags_t);
-extern tree build_new_op			(location_t, enum tree_code,
+extern tree build_new_op			(range_or_loc, enum tree_code,
 						 int, tree, tree, tree, tree *,
 						 tsubst_flags_t);
 extern tree build_op_call			(tree, vec<tree, va_gc> **,
@@ -5758,6 +5758,7 @@ extern void maybe_warn_variadic_templates       (void);
 extern void maybe_warn_cpp0x			(cpp0x_warn_str str);
 extern bool pedwarn_cxx98                       (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
 extern location_t location_of                   (tree);
+extern source_range range_of                    (tree);
 extern void qualified_name_lookup_error		(tree, tree, tree,
 						 location_t);
 
@@ -6482,7 +6483,7 @@ extern tree cp_build_function_call_nary         (tree, tsubst_flags_t, ...)
 						ATTRIBUTE_SENTINEL;
 extern tree cp_build_function_call_vec		(tree, vec<tree, va_gc> **,
 						 tsubst_flags_t);
-extern tree build_x_binary_op			(location_t,
+extern tree build_x_binary_op			(range_or_loc,
 						 enum tree_code, tree,
 						 enum tree_code, tree,
 						 enum tree_code, tree *,
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index cd4d71d..0a45122 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2930,6 +2930,25 @@ location_of (tree t)
   return EXPR_LOC_OR_LOC (t, input_location);
 }
 
+/* Return the source range of a tree passed to %+ formats.  */
+
+source_range
+range_of (tree t)
+{
+  if (TYPE_P (t))
+    {
+      t = TYPE_MAIN_DECL (t);
+      if (t == NULL_TREE)
+	return source_range::from_location (input_location);
+    }
+  else if (TREE_CODE (t) == OVERLOAD)
+    t = OVL_FUNCTION (t);
+
+  if (DECL_P (t))
+    return DECL_LOCATION_RANGE (t);
+  return EXPR_RANGE_OR_LOC (t, input_location);
+}
+
 /* Now the interfaces from error et al to dump_type et al. Each takes an
    on/off VERBOSE flag and supply the appropriate TFF_ flags to a dump_
    function.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 232a960..2f781fb 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6491,6 +6491,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 	  break;
 
 	default:
+	  set_source_range (&postfix_expression, loc, input_location);
 	  if (pidk_return != NULL)
 	    * pidk_return = idk;
           if (member_access_only_p)
@@ -7489,6 +7490,8 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 							 non_constant_p))
 	expression = error_mark_node;
 
+      set_source_range (&expression, loc, input_location);
+
       return expression;
     }
 
@@ -8275,6 +8278,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
      get_rhs:
       current.tree_type = binops_by_token[token->type].tree_type;
       current.loc = token->location;
+      current.range = token->range;
 
       /* We used the operator token.  */
       cp_lexer_consume_token (parser->lexer);
@@ -8368,7 +8372,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 			      ? boolean_type_node : TREE_TYPE (current.lhs),
 			      current.lhs, rhs);
       else
-	current.lhs = build_x_binary_op (current.loc, current.tree_type,
+	current.lhs = build_x_binary_op (current.range, current.tree_type,
 					 current.lhs, current.lhs_type,
 					 rhs, rhs_type, &overload,
 					 complain_flags (decltype_p));
@@ -8643,8 +8647,10 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
       tree assignment_expression;
 
       /* Parse the next assignment-expression.  */
+      location_t startloc = cp_lexer_peek_token (parser->lexer)->location;
       assignment_expression
 	= cp_parser_assignment_expression (parser, pidk, cast_p, decltype_p);
+      set_source_range (&assignment_expression, startloc, input_location);
 
       /* We don't create a temporary for a call that is the immediate operand
 	 of decltype or on the RHS of a comma.  But when we see a comma, we
@@ -26238,12 +26244,18 @@ cp_parser_check_class_key (enum tag_types class_key, tree type)
     return;
   if ((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type))
     {
-      if (permerror (input_location, "%qs tag used in naming %q#T",
-		     class_key == union_type ? "union"
-		     : class_key == record_type ? "struct" : "class",
-		     type))
-	inform (DECL_SOURCE_LOCATION (TYPE_NAME (type)),
-		"%q#T was previously declared here", type);
+      rich_location rl_tag_reuse (input_source_range);
+      if (permerror_at_rich_loc (&rl_tag_reuse,
+                                 "%qs tag used in naming %q#T",
+                                 class_key == union_type ? "union"
+                                 : class_key == record_type ? "struct" : "class",
+                                 type))
+        {
+          rich_location rl_prev_decl (DECL_LOCATION_RANGE (TYPE_NAME (type)));
+          inform_at_rich_loc (&rl_prev_decl,
+                              "%q#T was previously declared here",
+                              type);
+        }
     }
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index fa1176b..b06cbac 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-objc.h"
 #include "c-family/c-ubsan.h"
 #include "params.h"
+#include "gcc-rich-location.h"
 
 static tree cp_build_addr_expr_strict (tree, tsubst_flags_t);
 static tree cp_build_function_call (tree, tree, tsubst_flags_t);
@@ -3808,7 +3809,7 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
    ARG2_CODE as ERROR_MARK.  */
 
 tree
-build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
+build_x_binary_op (range_or_loc src_range, enum tree_code code, tree arg1,
 		   enum tree_code arg1_code, tree arg2,
 		   enum tree_code arg2_code, tree *overload,
 		   tsubst_flags_t complain)
@@ -3816,6 +3817,7 @@ build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
   tree orig_arg1;
   tree orig_arg2;
   tree expr;
+  location_t loc = src_range.m_start;
 
   orig_arg1 = arg1;
   orig_arg2 = arg2;
@@ -3832,7 +3834,7 @@ build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
   if (code == DOTSTAR_EXPR)
     expr = build_m_component_ref (arg1, arg2, complain);
   else
-    expr = build_new_op (loc, code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
+    expr = build_new_op (src_range, code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
 			 overload, complain);
 
   /* Check for cases such as x+y<<z which users are likely to
@@ -4879,8 +4881,16 @@ cp_build_binary_op (location_t location,
   if (!result_type)
     {
       if (complain & tf_error)
-	error ("invalid operands of types %qT and %qT to binary %qO",
-	       TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	{
+	  gcc_rich_location richloc (location);
+	  richloc.maybe_add_expr_with_caption (orig_op0, global_dc,
+					       G_("type %qT"), TREE_TYPE (orig_op0));
+	  richloc.maybe_add_expr_with_caption (orig_op1, global_dc,
+					       G_("type %qT"), TREE_TYPE (orig_op1));
+	  error_at_rich_loc (&richloc,
+			     "invalid operands of types %qT and %qT to binary %qO",
+			     TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	}
       return error_mark_node;
     }
 
@@ -8644,8 +8654,13 @@ 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'");
+	{
+	  gcc_rich_location richloc (input_location);
+	  richloc.maybe_add_expr (retval);
+	  permerror_at_rich_loc (&richloc,
+				 "return-statement with a value, in function "
+				 "returning 'void'");
+	}
       current_function_returns_null = 1;
 
       /* There's really no value to return, after all.  */
-- 
1.8.5.3

