From 2cf6a7fa0dbdd26285e829e916fd9b8befb65fb6 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 16 Oct 2018 02:52:31 -0400
Subject: [PATCH 10/35] FIXME: WIP on binary operator

---
 gcc/c/c-typeck.c                                 | 40 ++----------------------
 gcc/cp/call.c                                    | 16 ++++++++--
 gcc/cp/typeck.c                                  | 18 +++++++++--
 gcc/gcc-rich-location.c                          | 30 ++++++++++++++++++
 gcc/gcc-rich-location.h                          | 31 ++++++++++++++++++
 gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C | 16 ++++++++--
 6 files changed, 105 insertions(+), 46 deletions(-)

diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 9d09b8d..f2a5fc0 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -11044,38 +11044,6 @@ build_vec_cmp (tree_code code, tree type,
   return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
 }
 
-/* Subclass of range_label for labelling the type of EXPR when reporting
-   a type mismatch between EXPR and OTHER_EXPR.
-   Either or both of EXPR and OTHER_EXPR could be NULL.  */
-
-class maybe_range_label_for_tree_type_mismatch : public range_label
-{
- public:
-  maybe_range_label_for_tree_type_mismatch (tree expr, tree other_expr)
-  : m_expr (expr), m_other_expr (other_expr)
-  {
-  }
-
-  label_text get_text (unsigned range_idx) const FINAL OVERRIDE
-  {
-    if (m_expr == NULL_TREE
-	|| !EXPR_P (m_expr))
-      return label_text (NULL, false);
-    tree expr_type = TREE_TYPE (m_expr);
-
-    tree other_type = NULL_TREE;
-    if (m_other_expr && EXPR_P (m_other_expr))
-      other_type = TREE_TYPE (m_other_expr);
-
-   range_label_for_type_mismatch inner (expr_type, other_type);
-   return inner.get_text (range_idx);
-  }
-
- private:
-  tree m_expr;
-  tree m_other_expr;
-};
-
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    LOCATION is the operator's location.
@@ -12206,12 +12174,8 @@ build_binary_op (location_t location, enum tree_code code,
 
   if (!result_type)
     {
-      gcc_rich_location richloc (location);
-      maybe_range_label_for_tree_type_mismatch
-	label_for_op0 (orig_op0, orig_op1),
-	label_for_op1 (orig_op1, orig_op0);
-      richloc.maybe_add_expr (orig_op0, &label_for_op0);
-      richloc.maybe_add_expr (orig_op1, &label_for_op1);
+      binary_op_rich_location richloc (location, // FIXME
+				       orig_op0, orig_op1);
       binary_op_error (&richloc, code, TREE_TYPE (op0), TREE_TYPE (op1));
       return error_mark_node;
     }
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index cd0c0f6..354a833 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4761,8 +4761,20 @@ 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 (EXPR_HAS_LOCATION (arg1)
+		&& EXPR_HAS_LOCATION (arg2))
+	      {
+		binary_op_rich_location richloc (get_pure_location (loc), //FIXME
+						 arg1, arg2);
+		error_at (&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%>"), 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),
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index c921096..67f20d7 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5272,9 +5272,21 @@ cp_build_binary_op (location_t location,
   if (!result_type)
     {
       if (complain & tf_error)
-	error_at (location,
-		  "invalid operands of types %qT and %qT to binary %qO",
-		  TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	{
+	  if (EXPR_HAS_LOCATION (orig_op0)
+	      && EXPR_HAS_LOCATION (orig_op1))
+	    {
+	      binary_op_rich_location richloc (get_pure_location (location), // FIXME
+					       orig_op0, orig_op1);
+	      error_at (&richloc,
+			"invalid operands of types %qT and %qT to binary %qO",
+			TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	    }
+	  else
+	    error_at (location,
+		      "invalid operands of types %qT and %qT to binary %qO",
+		      TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	}
       return error_mark_node;
     }
 
diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c
index 81beb61..9335569 100644
--- a/gcc/gcc-rich-location.c
+++ b/gcc/gcc-rich-location.c
@@ -182,3 +182,33 @@ gcc_rich_location::add_fixit_insert_formatted (const char *content,
   else
     add_fixit_insert_before (insertion_point, content);
 }
+
+/* FIXME.  */
+
+label_text
+maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const
+{
+  if (m_expr == NULL_TREE
+      || !EXPR_P (m_expr))
+    return label_text (NULL, false);
+  tree expr_type = TREE_TYPE (m_expr);
+
+  tree other_type = NULL_TREE;
+  if (m_other_expr && EXPR_P (m_other_expr))
+    other_type = TREE_TYPE (m_other_expr);
+
+  range_label_for_type_mismatch inner (expr_type, other_type);
+  return inner.get_text (range_idx);
+}
+
+/* FIXME.  */
+
+binary_op_rich_location::binary_op_rich_location (location_t loc,
+						  tree arg0, tree arg1)
+: gcc_rich_location (loc),
+  m_label_for_arg0 (arg0, arg1),
+  m_label_for_arg1 (arg1, arg0)
+{
+  maybe_add_expr (arg0, &m_label_for_arg0);
+  maybe_add_expr (arg1, &m_label_for_arg1);
+}
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index d282fd4..03cfe42 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -162,4 +162,35 @@ class range_label_for_type_mismatch : public range_label
   tree m_other_type;
 };
 
+/* Subclass of range_label for labelling the type of EXPR when reporting
+   a type mismatch between EXPR and OTHER_EXPR.
+   Either or both of EXPR and OTHER_EXPR could be NULL.  */
+
+class maybe_range_label_for_tree_type_mismatch : public range_label
+{
+ public:
+  maybe_range_label_for_tree_type_mismatch (tree expr, tree other_expr)
+  : m_expr (expr), m_other_expr (other_expr)
+  {
+  }
+
+  label_text get_text (unsigned range_idx) const FINAL OVERRIDE;
+
+ private:
+  tree m_expr;
+  tree m_other_expr;
+};
+
+/* FIXME.  Highlights the types of the arguments.  */
+
+class binary_op_rich_location : public gcc_rich_location
+{
+ public:
+  binary_op_rich_location (location_t loc, tree arg0, tree arg1);
+
+ private:
+  maybe_range_label_for_tree_type_mismatch m_label_for_arg0;
+  maybe_range_label_for_tree_type_mismatch m_label_for_arg1;
+};
+
 #endif /* GCC_RICH_LOCATION_H */
diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
index 4ab7656..643f842 100644
--- a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
+++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
@@ -11,7 +11,10 @@ void test_1 ()
 
 /* { dg-begin-multiline-output "" }
    myvec[1] / ptr;
-   ~~~~~~~~~^~~~~
+   ~~~~~~~~ ^ ~~~
+          |   |
+          |   const int*
+          __m128 {aka float}
    { dg-end-multiline-output "" } */
 }
 
@@ -28,8 +31,12 @@ int test_2 (void)
 /* { dg-begin-multiline-output "" }
    return (some_function ()
            ~~~~~~~~~~~~~~~~
+                         |
+                         s
     + some_other_function ());
-    ^~~~~~~~~~~~~~~~~~~~~~~~
+    ^ ~~~~~~~~~~~~~~~~~~~~~~
+                          |
+                          t
    { dg-end-multiline-output "" } */
 }
 
@@ -37,8 +44,11 @@ int test_3 (struct s param_s, struct t param_t)
 {
   return param_s && param_t; // { dg-error "no match for .operator" }
 
+  // FIXME: use correct underline for operator here:
 /* { dg-begin-multiline-output "" }
    return param_s && param_t;
-          ~~~~~~~~^~~~~~~~~~
+          ~~~~~~~ ^  ~~~~~~~
+          |          |
+          s          t
    { dg-end-multiline-output "" } */
 }
-- 
1.8.5.3

