[RFC/Patch] Call overloaded operators to perform valid Python operations on struct/class values.

Siva Chandra sivachandra@google.com
Mon Dec 2 19:28:00 GMT 2013


Hi,

This is a follow up to this thread:
https://sourceware.org/ml/gdb/2013-11/msg00101.html

Part of Doug's response there seemed to indicate that calling
overloaded operators to perform valid Python operations has not yet
been implemented. The attached patch adds this "feature". I could not
yet think of a reason as to why adding this could be bad (as in,
leading to ambiguity or something similar).

ChangeLog

2013-12-02  Siva Chandra Reddy  <sivachandra@google.com>

        Call overloaded operators to perform valid Python operations on
        struct/class values.

        * python/py-value.c (valpy_binop): Call value_x_binop for struct
        and class values.

        testsuite/
        * gdb.python/py-value-cc.cc: Improve test case.
        * gdb.python/py-value-cc.exp: Add new tests.
-------------- next part --------------
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 40254b9..22c2dbc 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -762,6 +762,8 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
       struct value *arg1, *arg2;
       struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ());
       struct value *res_val = NULL;
+      enum exp_opcode op = OP_NULL;
+      int handled = 0;
 
       /* If the gdb.Value object is the second operand, then it will be passed
 	 to us as the OTHER argument, and SELF will be an entirely different
@@ -793,6 +795,7 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
 	    CHECK_TYPEDEF (rtype);
 	    rtype = STRIP_REFERENCE (rtype);
 
+            handled = 1;
 	    if (TYPE_CODE (ltype) == TYPE_CODE_PTR
 		&& is_integral_type (rtype))
 	      res_val = value_ptradd (arg1, value_as_long (arg2));
@@ -800,7 +803,10 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
 		     && is_integral_type (ltype))
 	      res_val = value_ptradd (arg2, value_as_long (arg1));
 	    else
-	      res_val = value_binop (arg1, arg2, BINOP_ADD);
+              {
+                handled = 0;
+                op = BINOP_ADD;
+              }
 	  }
 	  break;
 	case VALPY_SUB:
@@ -813,6 +819,7 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
 	    CHECK_TYPEDEF (rtype);
 	    rtype = STRIP_REFERENCE (rtype);
 
+            handled = 1;
 	    if (TYPE_CODE (ltype) == TYPE_CODE_PTR
 		&& TYPE_CODE (rtype) == TYPE_CODE_PTR)
 	      /* A ptrdiff_t for the target would be preferable here.  */
@@ -822,38 +829,49 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
 		     && is_integral_type (rtype))
 	      res_val = value_ptradd (arg1, - value_as_long (arg2));
 	    else
-	      res_val = value_binop (arg1, arg2, BINOP_SUB);
+              {
+	         handled = 0;
+                 op = BINOP_SUB;
+              }
 	  }
 	  break;
 	case VALPY_MUL:
-	  res_val = value_binop (arg1, arg2, BINOP_MUL);
+	  op = BINOP_MUL;
 	  break;
 	case VALPY_DIV:
-	  res_val = value_binop (arg1, arg2, BINOP_DIV);
+	  op = BINOP_DIV;
 	  break;
 	case VALPY_REM:
-	  res_val = value_binop (arg1, arg2, BINOP_REM);
+	  op = BINOP_REM;
 	  break;
 	case VALPY_POW:
-	  res_val = value_binop (arg1, arg2, BINOP_EXP);
+	  op = BINOP_EXP;
 	  break;
 	case VALPY_LSH:
-	  res_val = value_binop (arg1, arg2, BINOP_LSH);
+	  op = BINOP_LSH;
 	  break;
 	case VALPY_RSH:
-	  res_val = value_binop (arg1, arg2, BINOP_RSH);
+	  op = BINOP_RSH;
 	  break;
 	case VALPY_BITAND:
-	  res_val = value_binop (arg1, arg2, BINOP_BITWISE_AND);
+	  op = BINOP_BITWISE_AND;
 	  break;
 	case VALPY_BITOR:
-	  res_val = value_binop (arg1, arg2, BINOP_BITWISE_IOR);
+	  op = BINOP_BITWISE_IOR;
 	  break;
 	case VALPY_BITXOR:
-	  res_val = value_binop (arg1, arg2, BINOP_BITWISE_XOR);
+	  op = BINOP_BITWISE_XOR;
 	  break;
 	}
 
+      if (!handled)
+        {
+          if (binop_user_defined_p (op, arg1, arg2))
+            res_val = value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL);
+          else
+            res_val = value_binop (arg1, arg2, op);
+        }
+
       if (res_val)
 	result = value_to_value_object (res_val);
 
diff --git a/gdb/testsuite/gdb.python/py-value-cc.cc b/gdb/testsuite/gdb.python/py-value-cc.cc
index c010fc9..ff605c4 100644
--- a/gdb/testsuite/gdb.python/py-value-cc.cc
+++ b/gdb/testsuite/gdb.python/py-value-cc.cc
@@ -16,8 +16,19 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 class A {
+ public:
+  int operator+ (const int a);
+
+ public:
+  int a_;
 };
 
+int
+A::operator+ (const int a)
+{
+  return a + a_;
+}
+
 typedef int *int_ptr;
 
 int
@@ -35,5 +46,8 @@ int
 main ()
 {
   A obj;
+
+  obj.a_ = 5;
+
   return func (obj);
 }
diff --git a/gdb/testsuite/gdb.python/py-value-cc.exp b/gdb/testsuite/gdb.python/py-value-cc.exp
index 55c3b97..026deb5 100644
--- a/gdb/testsuite/gdb.python/py-value-cc.exp
+++ b/gdb/testsuite/gdb.python/py-value-cc.exp
@@ -34,13 +34,30 @@ if ![runto_main] {
 gdb_breakpoint [gdb_get_line_number "Break here."]
 gdb_continue_to_breakpoint "Break here" ".*Break here.*"
 
-gdb_test "python print (str(gdb.parse_and_eval(\"a\").type))" "const A &"
-gdb_test "python print (str(gdb.parse_and_eval(\"a\").referenced_value().type))" "const A"
-gdb_test "python print (str(gdb.parse_and_eval(\"int_ref\").type))" "int &"
-gdb_test "python print (str(gdb.parse_and_eval(\"int_ref\").referenced_value().type))" "int"
-gdb_test "python print (str(gdb.parse_and_eval(\"int_ref\").referenced_value()))" "10"
-
-gdb_test "python print (str(gdb.parse_and_eval(\"int_ptr_ref\").dereference().type))" "int"
-gdb_test "python print (str(gdb.parse_and_eval(\"int_ptr_ref\").referenced_value().type))" "int_ptr"
-gdb_test "python print (str(gdb.parse_and_eval(\"int_ptr_ref\").referenced_value().dereference()))" "10"
-gdb_test "python print (str(gdb.parse_and_eval(\"int_ptr_ref\").referenced_value().referenced_value()))" "10"
+gdb_test_no_output "python a = gdb.parse_and_eval('a')" "eval a"
+gdb_test_no_output "python int_ref = gdb.parse_and_eval('int_ref')" \
+  "eval int_ref"
+gdb_test_no_output "python int_ptr_ref = gdb.parse_and_eval('int_ptr_ref')" \
+  "eval int_ptr_ref"
+
+# Tests for gdb.Value.referenced_value()
+gdb_test "python print str(a.type)" "const A &" "a.type"
+gdb_test "python print str(a.referenced_value().type)" "const A" \
+  "a.referenced_value().type"
+gdb_test "python print str(int_ref.type)" "int &" "int_ref.type"
+gdb_test "python print str(int_ref.referenced_value().type)" "int" \
+  "int_ref.referenced_value().type"
+gdb_test "python print str(int_ref.referenced_value())" "10" \
+  "int_ref.referenced_value()"
+
+gdb_test "python print str(int_ptr_ref.dereference().type)" "int" \
+  "int_ptr_ref.dereference().type"
+gdb_test "python print str(int_ptr_ref.referenced_value().type)" "int_ptr" \
+  "int_ptr_ref.referenced_value().type"
+gdb_test "python print str(int_ptr_ref.referenced_value().dereference())" \
+  "10" "int_ptr_ref.referenced_value().dereference()"
+gdb_test "python print str(int_ptr_ref.referenced_value().referenced_value())" \
+  "10" "int_ptr_ref.referenced_value().referenced_value()"
+
+# Test overloaded operators.
+gdb_test "python print a + 5" "10" "a + 5"


More information about the Gdb-patches mailing list