public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [patch] smart pointer support
@ 2010-07-20 15:58 sami wagiaalla
  2010-07-23 23:37 ` Tom Tromey
  0 siblings, 1 reply; 19+ messages in thread
From: sami wagiaalla @ 2010-07-20 15:58 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 735 bytes --]

The '->' operator can be overloaded in C++ and when overloaded it 
forwards the function call or member reference to the return type. Example:

template < typename Type> class SmartPointer{
   Type* p;
  public:
   SmartPointer(Type *pointer){
     p = pointer;
   }

   Type* operator->(){
     return p;
   }
};


class MyType{
   public:
   void foo(){
     printf("I am foo\n");
   }
};

int main(){
   MyType mt;

   SmartPointer<MyType> sp(&mt);

   sp->foo();

   return 0;
}

Here sp->foo() really means (sp->)->foo()

This patch adds support for that in gdb

This patch adds a test to the test suite to test for the functionality 
above and was regression tested by running the test suite on Fedora 13 
on x8664 with gcc 444


[-- Attachment #2: smart_pointer.patch --]
[-- Type: text/plain, Size: 6019 bytes --]

Support overloading of 'operator->'.

2010-07-20  Sami Wagiaalla  <swagiaal@redhat.com>

	 PR C++/11500:
	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
	* eval.c (evaluate_subexp_standard): Check for overload of
	'operator->'.

2010-07-20  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.cp/smartp.exp: New test.
	* gdb.cp/smartp.cc : New test.

diff --git a/gdb/eval.c b/gdb/eval.c
index ea3d8a0..5f4ab2f 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1431,6 +1431,20 @@ evaluate_subexp_standard (struct type *expect_type,
 	  else
 	    {
 	      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+	      /* For C++ check to see if the operator '->' has been overloaded.
+	         If the operator has been overloaded replace arg2 with the value
+	         returned by the custom operator and continue evaluation.  */
+	      if (exp->language_defn->la_language == language_cplus)
+		{
+		  struct type *arg_type = value_type (arg2);
+		  if (arg_type && TYPE_CODE (arg_type) == TYPE_CODE_STRUCT)
+		    {
+		      struct value *value = value_x_unop (arg2, op, noside);
+		      if (value)
+			arg2 = value;
+		    }
+		}
 	    }
 	  /* Now, say which argument to start evaluating from */
 	  tem = 2;
@@ -1818,6 +1832,20 @@ evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
 
+      /* For C++ check to see if operator '->' has been overloaded.
+         If so replace arg1 with the value returned by evaluating
+         operator->().  */
+      if (exp->language_defn->la_language == language_cplus)
+	{
+	  struct type *arg_type = value_type (arg1);
+
+	  if (arg_type && TYPE_CODE (arg_type) == TYPE_CODE_STRUCT)
+	    {
+	      struct value *value = value_x_unop (arg1, op, noside);
+	      if (value)
+		arg1 = value;
+	    }
+	}
       /* JYG: if print object is on we need to replace the base type
 	 with rtti type in order to continue on with successful
 	 lookup of member / method only available in the rtti type. */
diff --git a/gdb/testsuite/gdb.cp/smartp.cc b/gdb/testsuite/gdb.cp/smartp.cc
new file mode 100644
index 0000000..a42db6f
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.cc
@@ -0,0 +1,95 @@
+class Type1{
+  public:
+  int foo(){
+    return 11;
+  }
+};
+
+class Type2{
+  public:
+  int foo(){
+    return 22;
+  }
+};
+
+class Type3{
+  public:
+  int foo(int){
+    return 33;
+  }
+  int foo(char){
+    return 44;
+  }
+};
+
+class Type4 {
+  public:
+    int a;
+    int b;
+};
+
+int foo (Type3, float)
+{
+  return 55;
+}
+
+class MyPointer{
+  Type1 *p;
+ public:
+  MyPointer(Type1 *pointer){
+    p = pointer;
+  }
+
+  Type1 *operator->(){
+    return p;
+  }
+};
+
+template <typename T> class SmartPointer{
+  T* p;
+ public:
+  SmartPointer(T *pointer){
+    p = pointer;
+  }
+
+  T *operator->(){
+    return p;
+  }
+};
+
+int main(){
+  Type1 mt1;
+  Type2 mt2;
+  Type3 mt3;
+
+  Type4 mt4;
+  mt4.a = 11;
+  mt4.b = 12;
+
+  MyPointer mp(&mt1);
+  Type1 *mtp = &mt1;
+
+  SmartPointer<Type1> sp1(&mt1);
+  SmartPointer<Type2> sp2(&mt2);
+  SmartPointer<Type3> sp3(&mt3);
+  SmartPointer<Type4> sp4(&mt4);
+
+  mp->foo();
+  mtp->foo();
+
+  sp1->foo();
+  sp2->foo();
+
+  sp3->foo(1);
+  sp3->foo('a');
+
+  sp4->a;
+  sp4->b;
+
+  Type4 *mt4p = &mt4;
+  mt4p->a;
+  mt4p->b;
+
+  return 0; // end of main
+}
+
diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp
new file mode 100644
index 0000000..335ecf8
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.exp
@@ -0,0 +1,68 @@
+# Copyright 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set testfile smartp
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+    untested "Couldn't compile test program"
+    return -1
+}
+
+# Get things started.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+############################################
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint main"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "end of main"]
+gdb_continue_to_breakpoint "end of main"
+
+# Test that overloaded arrow operator works
+gdb_test "p mp->foo()"            "= 11"
+
+# Test that regular arrow operator still works
+gdb_test "p mtp->foo()"            "= 11"
+
+# Test that templated smart pointers work
+gdb_test "p sp1->foo()"            "= 11"
+gdb_test "p sp2->foo()"            "= 22"
+
+# Test that overload resolution works properly
+# with smart pointers
+gdb_test "p sp3->foo(1)"           "= 33"
+gdb_test "p sp3->foo('a')"         "= 44"
+
+# Test smart pointers work for member references
+gdb_test "p sp4->a"         "= 11"
+gdb_test "p sp4->b"         "= 12"
+
+# Test regular arrow operator still works for
+# member references
+gdb_test "p mt4p->a"         "= 11"
+gdb_test "p mt4p->b"         "= 12"
+
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 0c40905..91f9c0c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -616,6 +616,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
     case UNOP_IND:
       strcpy (ptr, "*");
       break;
+    case STRUCTOP_PTR:
+      strcpy (ptr, "->");
+      break;
     default:
       error (_("Invalid unary operation specified."));
     }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-07-20 15:58 [patch] smart pointer support sami wagiaalla
@ 2010-07-23 23:37 ` Tom Tromey
  2010-08-05 18:46   ` sami wagiaalla
  0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2010-07-23 23:37 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Sami> The '->' operator can be overloaded in C++ and when overloaded it
Sami> forwards the function call or member reference to the return
Sami> type.

Thanks for working on this.

Sami> +	      /* For C++ check to see if the operator '->' has been overloaded.
Sami> +	         If the operator has been overloaded replace arg2 with the value
Sami> +	         returned by the custom operator and continue evaluation.  */
Sami> +	      if (exp->language_defn->la_language == language_cplus)
Sami> +		{
Sami> +		  struct type *arg_type = value_type (arg2);
Sami> +		  if (arg_type && TYPE_CODE (arg_type) == TYPE_CODE_STRUCT)

I think if you are going to use value_x_unop, you ought to use
unop_user_defined_p as well.  Maybe that means changes to
unop_user_defined_p.

Also, I think you will need a while loop here.  operator-> might itself
return an object that has an operator->.  There should be a test case
for this as well.

I was wondering if the STRUCTOP_PTR / STRUCTOP_STRUCT conflation in the
method case could cause problems.  Maybe a new test would be good, just
to make that clear.  The "." case should not cause the operator to be
used -- or at least, "." on a struct, gdb supports "." on a pointer as
an extension, I'm not sure what we should do there.

Otherwise, looking good.

Tom

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-07-23 23:37 ` Tom Tromey
@ 2010-08-05 18:46   ` sami wagiaalla
  2010-08-05 22:57     ` Ulrich Weigand
  0 siblings, 1 reply; 19+ messages in thread
From: sami wagiaalla @ 2010-08-05 18:46 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 2409 bytes --]

On 07/23/2010 07:37 PM, Tom Tromey wrote:
>>>>>> "Sami" == sami wagiaalla<swagiaal@redhat.com>  writes:
>
> Sami>  The '->' operator can be overloaded in C++ and when overloaded it
> Sami>  forwards the function call or member reference to the return
> Sami>  type.
>
> Thanks for working on this.
>

Np. This was fun :)

> Sami>  +	      /* For C++ check to see if the operator '->' has been overloaded.
> Sami>  +	         If the operator has been overloaded replace arg2 with the value
> Sami>  +	         returned by the custom operator and continue evaluation.  */
> Sami>  +	      if (exp->language_defn->la_language == language_cplus)
> Sami>  +		{
> Sami>  +		  struct type *arg_type = value_type (arg2);
> Sami>  +		  if (arg_type&&  TYPE_CODE (arg_type) == TYPE_CODE_STRUCT)
>
> I think if you are going to use value_x_unop, you ought to use
> unop_user_defined_p as well.  Maybe that means changes to
> unop_user_defined_p.
>

Done. I avoided it in the beginning because I thought I wouldn't need to 
check for TYPE_CODE (arg_type) == TYPE_CODE_STRUCT but ended up needing 
it and never went back to unop_user_defined_p.

> Also, I think you will need a while loop here.  operator->  might itself
> return an object that has an operator->.  There should be a test case
> for this as well.
>

This turned out to be a little hairy when operator->() returns a copy 
instead of a reference. Some flavours of this are easy to fix by setting 
the VALUE_LVAL of the value returned by call_function_by_hand to 
lval_memory, and other cases are harder. I have spent a day looking at 
this but couldn't come up with anything. So I added a test and marked it 
as kfail and update the bug. I also, added tests for the cases the work.

> I was wondering if the STRUCTOP_PTR / STRUCTOP_STRUCT conflation in the
> method case could cause problems.  Maybe a new test would be good, just
> to make that clear.  The "." case should not cause the operator to be
> used -- or at least, "." on a struct, gdb supports "." on a pointer as
> an extension, I'm not sure what we should do there.
>

I added test for the '.' case both the extension and the plain '.' there 
are also tests in the patch for none overloaded -> operator

> Otherwise, looking good.
>

I will wait until the template stuff is in before committing this. The 
template test cases in this patch might fail otherwise.

Thanks for the review.

Sami



[-- Attachment #2: smart_pointer.patch --]
[-- Type: text/plain, Size: 7405 bytes --]

Support overloading of 'operator->'.

2010-08-03  Sami Wagiaalla  <swagiaal@redhat.com>

	 PR C++/11500:
	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
	* eval.c (evaluate_subexp_standard): Check for overload of
	'operator->'.
	* infcall.c (call_function_by_hand): Set VALUE_LVAL of the
	returned value to lval_memory.

2010-08-03  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.cp/smartp.exp: New test.
	* gdb.cp/smartp.cc : New test.

diff --git a/gdb/eval.c b/gdb/eval.c
index ba75952..e88ab13 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1431,6 +1431,19 @@ evaluate_subexp_standard (struct type *expect_type,
 	  else
 	    {
 	      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+	      /* For C++ check to see if the operator '->' has been overloaded.
+	         If the operator has been overloaded replace arg2 with the value
+	         returned by the custom operator and continue evaluation.  */
+	      if (exp->language_defn->la_language == language_cplus)
+		{
+		  while (unop_user_defined_p(op, arg2))
+		    {
+		      struct value *value = value_x_unop (arg2, op, noside);
+		      if (value)
+			arg2 = value;
+		    }
+		}
 	    }
 	  /* Now, say which argument to start evaluating from */
 	  tem = 2;
@@ -1819,6 +1832,18 @@ evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
 
+      /* For C++ check to see if operator '->' has been overloaded.
+         If so replace arg1 with the value returned by evaluating
+         operator->().  */
+      if (exp->language_defn->la_language == language_cplus)
+	{
+	  while ((unop_user_defined_p(op, arg1)))
+	    {
+	      struct value *value = value_x_unop (arg1, op, noside);
+	      if (value)
+		arg1 = value;
+	    }
+	}
       /* JYG: if print object is on we need to replace the base type
 	 with rtti type in order to continue on with successful
 	 lookup of member / method only available in the rtti type. */
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 0c9a3af..6f7620e 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -1026,6 +1026,7 @@ When the function is done executing, GDB will silently stop."),
 	    retval = allocate_value (values_type);
 	    gdbarch_return_value (gdbarch, value_type (function), values_type,
 				  retbuf, value_contents_raw (retval), NULL);
+	    VALUE_LVAL (retval) = lval_memory;
 	    break;
 	  case RETURN_VALUE_STRUCT_CONVENTION:
 	    retval = value_at (values_type, struct_addr);
diff --git a/gdb/testsuite/gdb.cp/smartp.cc b/gdb/testsuite/gdb.cp/smartp.cc
new file mode 100644
index 0000000..ab3eb54
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.cc
@@ -0,0 +1,144 @@
+class Type1{
+  public:
+  int foo(){
+    return 11;
+  }
+};
+
+class Type2{
+  public:
+  int foo(){
+    return 22;
+  }
+};
+
+class Type3{
+  public:
+  int foo(int){
+    return 33;
+  }
+  int foo(char){
+    return 44;
+  }
+};
+
+class Type4 {
+  public:
+    int a;
+    int b;
+};
+
+int foo (Type3, float)
+{
+  return 55;
+}
+
+class MyPointer{
+  Type1 *p;
+ public:
+  MyPointer(Type1 *pointer){
+    p = pointer;
+  }
+
+  Type1 *operator->(){
+    return p;
+  }
+};
+
+template <typename T> class SmartPointer{
+  T *p;
+ public:
+  SmartPointer(T *pointer){
+    p = pointer;
+  }
+
+  T *operator->(){
+    return p;
+  }
+};
+
+
+class A {
+ public:
+  int inta;
+  int foo() { return 66; }
+};
+
+class B {
+ public:
+  A a;
+  A* operator->(){
+    return &a;
+  }
+};
+
+class C {
+ public:
+  B b;
+  B& operator->(){
+    return b;
+  }
+};
+
+class C2 {
+ public:
+  B b;
+  B operator->(){
+    return b;
+  }
+};
+
+int main(){
+  Type1 mt1;
+  Type2 mt2;
+  Type3 mt3;
+
+  Type4 mt4;
+  mt4.a = 11;
+  mt4.b = 12;
+
+  MyPointer mp(&mt1);
+  Type1 *mtp = &mt1;
+
+  SmartPointer<Type1> sp1(&mt1);
+  SmartPointer<Type2> sp2(&mt2);
+  SmartPointer<Type3> sp3(&mt3);
+  SmartPointer<Type4> sp4(&mt4);
+
+  mp->foo();
+  mtp->foo();
+
+  sp1->foo();
+  sp2->foo();
+
+  sp3->foo(1);
+  sp3->foo('a');
+
+  sp4->a;
+  sp4->b;
+
+  Type4 *mt4p = &mt4;
+  mt4p->a;
+  mt4p->b;
+
+  A a;
+  B b;
+  C c;
+  C2 c2;
+
+  a.inta = 77;
+  b.a = a;
+  c.b = b;
+  c2.b = b;
+
+  a.foo();
+  b->foo();
+  c->foo();
+
+  b->inta = 77;
+  c->inta = 77;
+  c2->inta = 77;
+
+  return 0; // end of main
+}
+
diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp
new file mode 100644
index 0000000..dd0e862
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.exp
@@ -0,0 +1,82 @@
+# Copyright 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set testfile smartp
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+    untested "Couldn't compile test program"
+    return -1
+}
+
+# Get things started.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+############################################
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint main"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "end of main"]
+gdb_continue_to_breakpoint "end of main"
+
+# Test that overloaded arrow operator works
+gdb_test "p mp->foo()"            "= 11"
+
+# Test that regular arrow operator still works
+gdb_test "p mtp->foo()"            "= 11"
+
+# Test that normal '.' operator still works.
+gdb_test "p mt1.foo()"             "= 11"
+
+# test that gdb extension '.' for pointers still works.
+gdb_test "p mt4p.a"                "= 11"
+
+# Test that templated smart pointers work
+gdb_test "p sp1->foo()"            "= 11"
+gdb_test "p sp2->foo()"            "= 22"
+
+# Test that overload resolution works properly
+# with smart pointers
+gdb_test "p sp3->foo(1)"           "= 33"
+gdb_test "p sp3->foo('a')"         "= 44"
+
+# Test smart pointers work for member references
+gdb_test "p sp4->a"         "= 11"
+gdb_test "p sp4->b"         "= 12"
+
+# Test regular arrow operator still works for
+# member references
+gdb_test "p mt4p->a"         "= 11"
+gdb_test "p mt4p->b"         "= 12"
+
+# Test that overloading of -> works recursively
+gdb_test "p b->foo()"         "= 66"
+gdb_test "p c->foo()"         "= 66"
+gdb_test "p c->inta"          "= 77"
+
+setup_kfail "gdb/11606" "*-*-*"
+gdb_test "p c2->inta"          "= 77"
+
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 0c40905..91f9c0c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -616,6 +616,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
     case UNOP_IND:
       strcpy (ptr, "*");
       break;
+    case STRUCTOP_PTR:
+      strcpy (ptr, "->");
+      break;
     default:
       error (_("Invalid unary operation specified."));
     }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-05 18:46   ` sami wagiaalla
@ 2010-08-05 22:57     ` Ulrich Weigand
  2010-08-06 16:23       ` sami wagiaalla
  0 siblings, 1 reply; 19+ messages in thread
From: Ulrich Weigand @ 2010-08-05 22:57 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches, tromey

sami wagiaalla wrote:

> 	* infcall.c (call_function_by_hand): Set VALUE_LVAL of the
> 	returned value to lval_memory.


> @@ -1026,6 +1026,7 @@ When the function is done executing, GDB will silently stop."),
>  	    retval = allocate_value (values_type);
>  	    gdbarch_return_value (gdbarch, value_type (function), values_type,
>  				  retbuf, value_contents_raw (retval), NULL);
> +	    VALUE_LVAL (retval) = lval_memory;
>  	    break;

This part looks broken.  Setting VALUE_LVAL to lval_memory implies the
value actually *has* location information pointing to memory, that is
in particular, a memory address.

Since this value doesn't have that information, and in general it may
not even exist (function return values may be passed in registers), I
don't see how this can be valid here.

Bye,
Ulrich


-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-05 22:57     ` Ulrich Weigand
@ 2010-08-06 16:23       ` sami wagiaalla
  2010-08-06 16:48         ` Ulrich Weigand
  0 siblings, 1 reply; 19+ messages in thread
From: sami wagiaalla @ 2010-08-06 16:23 UTC (permalink / raw)
  To: gdb-patches

On 08/05/2010 06:57 PM, Ulrich Weigand wrote:
> sami wagiaalla wrote:
>
>> 	* infcall.c (call_function_by_hand): Set VALUE_LVAL of the
>> 	returned value to lval_memory.
>
>
>> @@ -1026,6 +1026,7 @@ When the function is done executing, GDB will silently stop."),
>>   	    retval = allocate_value (values_type);
>>   	    gdbarch_return_value (gdbarch, value_type (function), values_type,
>>   				  retbuf, value_contents_raw (retval), NULL);
>> +	    VALUE_LVAL (retval) = lval_memory;
>>   	    break;
>
> This part looks broken.  Setting VALUE_LVAL to lval_memory implies the
> value actually *has* location information pointing to memory, that is
> in particular, a memory address.
>
> Since this value doesn't have that information, and in general it may
> not even exist (function return values may be passed in registers), I
> don't see how this can be valid here.
>

Hmm I see. I was under the impression that here the value is copied from 
the inferior's return location to gdb memory. As the patch stands (with 
the kfail) this can be removed, but I am actually looking for guidance 
on how to ensure that this value is available for gdb to perform further 
function calls that utilize it, especially when the return value is a 
copy not a reference. As is described in this bug: 
http://sourceware.org/bugzilla/show_bug.cgi?id=11606

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-06 16:23       ` sami wagiaalla
@ 2010-08-06 16:48         ` Ulrich Weigand
  2010-08-06 17:29           ` Tom Tromey
  2010-08-06 21:33           ` sami wagiaalla
  0 siblings, 2 replies; 19+ messages in thread
From: Ulrich Weigand @ 2010-08-06 16:48 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

sami wagiaalla wrote:

> Hmm I see. I was under the impression that here the value is copied from 
> the inferior's return location to gdb memory. As the patch stands (with 
> the kfail) this can be removed, but I am actually looking for guidance 
> on how to ensure that this value is available for gdb to perform further 
> function calls that utilize it, especially when the return value is a 
> copy not a reference. As is described in this bug: 
> http://sourceware.org/bugzilla/show_bug.cgi?id=11606

So there's two issues here.  The first question is, what can you expect
from a GDB value representing the return value of an inferior function
call?  You will *always* get the value itself, as bytes copied to GDB's
memory.  In *some* cases, the value will in addition be of type lval_memory
meaning that the value is also present in inferior memory, *and you know
where*.  See existing code:

        switch (gdbarch_return_value (gdbarch, value_type (function),
                                      target_values_type, NULL, NULL, NULL))
          {
          case RETURN_VALUE_REGISTER_CONVENTION:
          case RETURN_VALUE_ABI_RETURNS_ADDRESS:
          case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
            retval = allocate_value (values_type);
            gdbarch_return_value (gdbarch, value_type (function), values_type,
                                  retbuf, value_contents_raw (retval), NULL);
            break;
          case RETURN_VALUE_STRUCT_CONVENTION:
            retval = value_at (values_type, struct_addr);
            break;
          }

In the second case, we get a lval_memory value including the address
("struct_addr") where it resides.  In the first case, we just get a
non_lval value because the value doesn't reside in memory in the first
place; it was returned in registers.

Thinking more about this, the value_at case actually looks broken,
because while the value is in memory, that memory slot was just
temporarily allocated on the stack, and will go away as soon as
we return from call_function_by_hand!  So it might in fact be
better to just return a non_lval in that case, too ...


The second question is:  Well, if all we have is a non_lval, can we still
call a member function?  In priciple we could do the same what C++ does
and allocate a temporary copy on the stack; we'd probably want to this
at the time we call the member function in call_function_by_hand, similar
to how we already create temporary copies of call arguments as required.
That seems the way forward to fix the bug you point out ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-06 16:48         ` Ulrich Weigand
@ 2010-08-06 17:29           ` Tom Tromey
  2010-08-08 15:01             ` Ulrich Weigand
  2010-08-06 21:33           ` sami wagiaalla
  1 sibling, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2010-08-06 17:29 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: sami wagiaalla, gdb-patches

>>>>> "Ulrich" == Ulrich Weigand <uweigand@de.ibm.com> writes:

Ulrich> In *some* cases, the value will in addition be of type
Ulrich> lval_memory meaning that the value is also present in inferior
Ulrich> memory, *and you know where*.

Along these lines, I'm curious to know why value_must_coerce_to_target
returns 0 for TYPE_CODE_STRUCT.  Maybe that is just an oversight?
Perhaps it should also check for lval_internalvar_component?

Tom

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-06 16:48         ` Ulrich Weigand
  2010-08-06 17:29           ` Tom Tromey
@ 2010-08-06 21:33           ` sami wagiaalla
  2010-08-06 22:20             ` Tom Tromey
  1 sibling, 1 reply; 19+ messages in thread
From: sami wagiaalla @ 2010-08-06 21:33 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 253 bytes --]

Great!.. Thanks for the pointers. I am not going to be working on that 
bug right away, but I will add a pointer to this discussion in case 
someone else picks it up by the time I get to it.

I have also correct and attached the patch.

Thanks,
   Sami

[-- Attachment #2: smart_pointer.patch --]
[-- Type: text/plain, Size: 6798 bytes --]

Support overloading of 'operator->'.

2010-08-06  Sami Wagiaalla  <swagiaal@redhat.com>

	 PR C++/11500:
	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
	* eval.c (evaluate_subexp_standard): Check for overload of
	'operator->'.

2010-08-06  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.cp/smartp.exp: New test.
	* gdb.cp/smartp.cc : New test.

diff --git a/gdb/eval.c b/gdb/eval.c
index ba75952..e88ab13 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1431,6 +1431,19 @@ evaluate_subexp_standard (struct type *expect_type,
 	  else
 	    {
 	      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+	      /* For C++ check to see if the operator '->' has been overloaded.
+	         If the operator has been overloaded replace arg2 with the value
+	         returned by the custom operator and continue evaluation.  */
+	      if (exp->language_defn->la_language == language_cplus)
+		{
+		  while (unop_user_defined_p(op, arg2))
+		    {
+		      struct value *value = value_x_unop (arg2, op, noside);
+		      if (value)
+			arg2 = value;
+		    }
+		}
 	    }
 	  /* Now, say which argument to start evaluating from */
 	  tem = 2;
@@ -1819,6 +1832,18 @@ evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
 
+      /* For C++ check to see if operator '->' has been overloaded.
+         If so replace arg1 with the value returned by evaluating
+         operator->().  */
+      if (exp->language_defn->la_language == language_cplus)
+	{
+	  while ((unop_user_defined_p(op, arg1)))
+	    {
+	      struct value *value = value_x_unop (arg1, op, noside);
+	      if (value)
+		arg1 = value;
+	    }
+	}
       /* JYG: if print object is on we need to replace the base type
 	 with rtti type in order to continue on with successful
 	 lookup of member / method only available in the rtti type. */
diff --git a/gdb/testsuite/gdb.cp/smartp.cc b/gdb/testsuite/gdb.cp/smartp.cc
new file mode 100644
index 0000000..ab3eb54
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.cc
@@ -0,0 +1,144 @@
+class Type1{
+  public:
+  int foo(){
+    return 11;
+  }
+};
+
+class Type2{
+  public:
+  int foo(){
+    return 22;
+  }
+};
+
+class Type3{
+  public:
+  int foo(int){
+    return 33;
+  }
+  int foo(char){
+    return 44;
+  }
+};
+
+class Type4 {
+  public:
+    int a;
+    int b;
+};
+
+int foo (Type3, float)
+{
+  return 55;
+}
+
+class MyPointer{
+  Type1 *p;
+ public:
+  MyPointer(Type1 *pointer){
+    p = pointer;
+  }
+
+  Type1 *operator->(){
+    return p;
+  }
+};
+
+template <typename T> class SmartPointer{
+  T *p;
+ public:
+  SmartPointer(T *pointer){
+    p = pointer;
+  }
+
+  T *operator->(){
+    return p;
+  }
+};
+
+
+class A {
+ public:
+  int inta;
+  int foo() { return 66; }
+};
+
+class B {
+ public:
+  A a;
+  A* operator->(){
+    return &a;
+  }
+};
+
+class C {
+ public:
+  B b;
+  B& operator->(){
+    return b;
+  }
+};
+
+class C2 {
+ public:
+  B b;
+  B operator->(){
+    return b;
+  }
+};
+
+int main(){
+  Type1 mt1;
+  Type2 mt2;
+  Type3 mt3;
+
+  Type4 mt4;
+  mt4.a = 11;
+  mt4.b = 12;
+
+  MyPointer mp(&mt1);
+  Type1 *mtp = &mt1;
+
+  SmartPointer<Type1> sp1(&mt1);
+  SmartPointer<Type2> sp2(&mt2);
+  SmartPointer<Type3> sp3(&mt3);
+  SmartPointer<Type4> sp4(&mt4);
+
+  mp->foo();
+  mtp->foo();
+
+  sp1->foo();
+  sp2->foo();
+
+  sp3->foo(1);
+  sp3->foo('a');
+
+  sp4->a;
+  sp4->b;
+
+  Type4 *mt4p = &mt4;
+  mt4p->a;
+  mt4p->b;
+
+  A a;
+  B b;
+  C c;
+  C2 c2;
+
+  a.inta = 77;
+  b.a = a;
+  c.b = b;
+  c2.b = b;
+
+  a.foo();
+  b->foo();
+  c->foo();
+
+  b->inta = 77;
+  c->inta = 77;
+  c2->inta = 77;
+
+  return 0; // end of main
+}
+
diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp
new file mode 100644
index 0000000..dd0e862
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.exp
@@ -0,0 +1,82 @@
+# Copyright 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set testfile smartp
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+    untested "Couldn't compile test program"
+    return -1
+}
+
+# Get things started.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+############################################
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint main"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "end of main"]
+gdb_continue_to_breakpoint "end of main"
+
+# Test that overloaded arrow operator works
+gdb_test "p mp->foo()"            "= 11"
+
+# Test that regular arrow operator still works
+gdb_test "p mtp->foo()"            "= 11"
+
+# Test that normal '.' operator still works.
+gdb_test "p mt1.foo()"             "= 11"
+
+# test that gdb extension '.' for pointers still works.
+gdb_test "p mt4p.a"                "= 11"
+
+# Test that templated smart pointers work
+gdb_test "p sp1->foo()"            "= 11"
+gdb_test "p sp2->foo()"            "= 22"
+
+# Test that overload resolution works properly
+# with smart pointers
+gdb_test "p sp3->foo(1)"           "= 33"
+gdb_test "p sp3->foo('a')"         "= 44"
+
+# Test smart pointers work for member references
+gdb_test "p sp4->a"         "= 11"
+gdb_test "p sp4->b"         "= 12"
+
+# Test regular arrow operator still works for
+# member references
+gdb_test "p mt4p->a"         "= 11"
+gdb_test "p mt4p->b"         "= 12"
+
+# Test that overloading of -> works recursively
+gdb_test "p b->foo()"         "= 66"
+gdb_test "p c->foo()"         "= 66"
+gdb_test "p c->inta"          "= 77"
+
+setup_kfail "gdb/11606" "*-*-*"
+gdb_test "p c2->inta"          "= 77"
+
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 0c40905..91f9c0c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -616,6 +616,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
     case UNOP_IND:
       strcpy (ptr, "*");
       break;
+    case STRUCTOP_PTR:
+      strcpy (ptr, "->");
+      break;
     default:
       error (_("Invalid unary operation specified."));
     }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-06 21:33           ` sami wagiaalla
@ 2010-08-06 22:20             ` Tom Tromey
  2010-08-09 15:59               ` sami wagiaalla
  0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2010-08-06 22:20 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Ulrich Weigand, gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Sami> Great!.. Thanks for the pointers. I am not going to be working on that
Sami> bug right away, but I will add a pointer to this discussion in case
Sami> someone else picks it up by the time I get to it.

Thanks.

This is looking good.

Sami> +	      if (exp->language_defn->la_language == language_cplus)
Sami> +		{
Sami> +		  while (unop_user_defined_p(op, arg2))

Space before paren.

Also, I don't think the language_cplus check should be needed.
None of the other calls to unop_user_defined_p are gated that way.

Sami> +		      struct value *value = value_x_unop (arg2, op, noside);
Sami> +		      if (value)
Sami> +			arg2 = value;

This seems strange.  When can the result here be NULL?  And what does
that mean?  It seems like this either ought to be impossible, or it
should be an error of some kind.

Sami> +      if (exp->language_defn->la_language == language_cplus)
Sami> +	{
Sami> +	  while ((unop_user_defined_p(op, arg1)))
Sami> +	    {
Sami> +	      struct value *value = value_x_unop (arg1, op, noside);
Sami> +	      if (value)
Sami> +		arg1 = value;

Same notes as above :)

Sami> +++ b/gdb/testsuite/gdb.cp/smartp.cc

We haven't been super diligent about this -- but please put a GPL header
on this file.

Sami> +if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
Sami> +    untested "Couldn't compile test program"
Sami> +    return -1
Sami> +}
Sami> +
Sami> +# Get things started.
Sami> +
Sami> +gdb_exit
Sami> +gdb_start
Sami> +gdb_reinitialize_dir $srcdir/$subdir
Sami> +gdb_load ${binfile}

I think prepare_for_testing can be used here.

Tom

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-06 17:29           ` Tom Tromey
@ 2010-08-08 15:01             ` Ulrich Weigand
  0 siblings, 0 replies; 19+ messages in thread
From: Ulrich Weigand @ 2010-08-08 15:01 UTC (permalink / raw)
  To: Tom Tromey; +Cc: sami wagiaalla, gdb-patches

Tom Tromey wrote:

> Along these lines, I'm curious to know why value_must_coerce_to_target
> returns 0 for TYPE_CODE_STRUCT.  Maybe that is just an oversight?
> Perhaps it should also check for lval_internalvar_component?

Well, I guess this is because the value-coerce-to-target mechanism was
introduced by Dan for a specific purpose, that is to allow lazy handling
of GDB-internally generated literal values (in particular string constants).

It was never intended to handle pushing arbitrary non-lvalues, like those
generated from inferior calls (or arbitray value arithmetic) to the target.

Now maybe this could be extended to do so; but it seems we'd have to carefully
think about exactly when we want this to happen.  For example, if you have
a variable residing in a register, you currently cannot take its address in
GDB.  If value_coerce_to_target were to blindly push *everything* to the
target, this would succeed, and you'd have a pointer to a malloc'ed location
holding a copy of the register value -- which is presumably not what you
intended ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-06 22:20             ` Tom Tromey
@ 2010-08-09 15:59               ` sami wagiaalla
  2010-08-09 17:35                 ` Tom Tromey
  0 siblings, 1 reply; 19+ messages in thread
From: sami wagiaalla @ 2010-08-09 15:59 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 502 bytes --]


> Sami>  +		      struct value *value = value_x_unop (arg2, op, noside);
> Sami>  +		      if (value)
> Sami>  +			arg2 = value;
>
> This seems strange.  When can the result here be NULL?  And what does
> that mean?  It seems like this either ought to be impossible, or it
> should be an error of some kind.
>

Yes this is incorrect. value_x_unop never returns null. If the operator 
is not found it throws an error. I added a try catch statement and tests 
for the failing case.

New patch attached.

[-- Attachment #2: smart_pointer.patch --]
[-- Type: text/plain, Size: 7691 bytes --]

Support overloading of 'operator->'.

2010-08-09  Sami Wagiaalla  <swagiaal@redhat.com>

	 PR C++/11500:
	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
	* eval.c (evaluate_subexp_standard): Check for overload of
	'operator->'.

2010-08-09  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.cp/smartp.exp: New test.
	* gdb.cp/smartp.cc : New test.

diff --git a/gdb/eval.c b/gdb/eval.c
index ba75952..9786c1e 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1431,6 +1431,24 @@ evaluate_subexp_standard (struct type *expect_type,
 	  else
 	    {
 	      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+	      /* Check to see if the operator '->' has been overloaded.  If the operator
+	         has been overloaded replace arg2 with the value returned by the custom
+	         operator and continue evaluation.  */
+	      while (unop_user_defined_p (op, arg2))
+		{
+		  volatile struct gdb_exception except;
+		  struct value *value = NULL;
+		  TRY_CATCH (except, RETURN_MASK_ERROR)
+		    {
+		      value = value_x_unop (arg2, op, noside);
+		    }
+
+		  if (except.reason < 0)
+		    break;
+
+		  arg2 = value;
+		}
 	    }
 	  /* Now, say which argument to start evaluating from */
 	  tem = 2;
@@ -1819,6 +1837,23 @@ evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
 
+      /* Check to see if operator '->' has been overloaded.  If so replace
+         arg1 with the value returned by evaluating operator->().  */
+      while (unop_user_defined_p (op, arg1))
+	{
+	  volatile struct gdb_exception except;
+	  struct value *value = NULL;
+	  TRY_CATCH (except, RETURN_MASK_ERROR)
+	    {
+	      value = value_x_unop (arg1, op, noside);
+	    }
+
+	  if (except.reason < 0)
+	    break;
+
+	  arg1 = value;
+	}
+
       /* JYG: if print object is on we need to replace the base type
 	 with rtti type in order to continue on with successful
 	 lookup of member / method only available in the rtti type. */
diff --git a/gdb/testsuite/gdb.cp/smartp.cc b/gdb/testsuite/gdb.cp/smartp.cc
new file mode 100644
index 0000000..baa8f46
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.cc
@@ -0,0 +1,163 @@
+/* This test script is part of GDB, the GNU debugger.
+
+   Copyright 1999, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+   */
+
+class Type1{
+  public:
+  int foo(){
+    return 11;
+  }
+};
+
+class Type2{
+  public:
+  int foo(){
+    return 22;
+  }
+};
+
+class Type3{
+  public:
+  int foo(int){
+    return 33;
+  }
+  int foo(char){
+    return 44;
+  }
+};
+
+class Type4 {
+  public:
+    int a;
+    int b;
+};
+
+int foo (Type3, float)
+{
+  return 55;
+}
+
+class MyPointer{
+  Type1 *p;
+ public:
+  MyPointer(Type1 *pointer){
+    p = pointer;
+  }
+
+  Type1 *operator->(){
+    return p;
+  }
+};
+
+template <typename T> class SmartPointer{
+  T *p;
+ public:
+  SmartPointer(T *pointer){
+    p = pointer;
+  }
+
+  T *operator->(){
+    return p;
+  }
+};
+
+
+class A {
+ public:
+  int inta;
+  int foo() { return 66; }
+};
+
+class B {
+ public:
+  A a;
+  A* operator->(){
+    return &a;
+  }
+};
+
+class C {
+ public:
+  B b;
+  B& operator->(){
+    return b;
+  }
+};
+
+class C2 {
+ public:
+  B b;
+  B operator->(){
+    return b;
+  }
+};
+
+int main(){
+  Type1 mt1;
+  Type2 mt2;
+  Type3 mt3;
+
+  Type4 mt4;
+  mt4.a = 11;
+  mt4.b = 12;
+
+  MyPointer mp(&mt1);
+  Type1 *mtp = &mt1;
+
+  SmartPointer<Type1> sp1(&mt1);
+  SmartPointer<Type2> sp2(&mt2);
+  SmartPointer<Type3> sp3(&mt3);
+  SmartPointer<Type4> sp4(&mt4);
+
+  mp->foo();
+  mtp->foo();
+
+  sp1->foo();
+  sp2->foo();
+
+  sp3->foo(1);
+  sp3->foo('a');
+
+  sp4->a;
+  sp4->b;
+
+  Type4 *mt4p = &mt4;
+  mt4p->a;
+  mt4p->b;
+
+  A a;
+  B b;
+  C c;
+  C2 c2;
+
+  a.inta = 77;
+  b.a = a;
+  c.b = b;
+  c2.b = b;
+
+  a.foo();
+  b->foo();
+  c->foo();
+
+  b->inta = 77;
+  c->inta = 77;
+  c2->inta = 77;
+
+  return 0; // end of main
+}
+
diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp
new file mode 100644
index 0000000..01c8a11
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.exp
@@ -0,0 +1,74 @@
+# Copyright 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set testfile smartp
+set srcfile ${testfile}.cc
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}] } {
+     return -1
+}
+
+############################################
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint main"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "end of main"]
+gdb_continue_to_breakpoint "end of main"
+
+# Test that overloaded arrow operator works
+gdb_test "p mp->foo()"            "= 11"
+
+# Test that regular arrow operator still works
+gdb_test "p mtp->foo()"            "= 11"
+
+# Test that normal '.' operator still works.
+gdb_test "p mt1.foo()"             "= 11"
+
+# test that gdb extension '.' for pointers still works.
+gdb_test "p mt4p.a"                "= 11"
+
+# Test that templated smart pointers work
+gdb_test "p sp1->foo()"            "= 11"
+gdb_test "p sp2->foo()"            "= 22"
+
+# Test that overload resolution works properly
+# with smart pointers
+gdb_test "p sp3->foo(1)"           "= 33"
+gdb_test "p sp3->foo('a')"         "= 44"
+
+# Test smart pointers work for member references
+gdb_test "p sp4->a"         "= 11"
+gdb_test "p sp4->b"         "= 12"
+
+# Test regular arrow operator still works for
+# member references
+gdb_test "p mt4p->a"         "= 11"
+gdb_test "p mt4p->b"         "= 12"
+
+# Test that incorrect use of the arrow operator
+# is still handled correctly.
+gdb_test "p mt4->fake"       "There is no member named fake."
+gdb_test "p mt4->fake()"     "Couldn't find method Type4::fake"
+
+# Test that overloading of -> works recursively
+gdb_test "p b->foo()"         "= 66"
+gdb_test "p c->foo()"         "= 66"
+gdb_test "p c->inta"          "= 77"
+
+setup_kfail "gdb/11606" "*-*-*"
+gdb_test "p c2->inta"          "= 77"
+
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 0c40905..91f9c0c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -616,6 +616,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
     case UNOP_IND:
       strcpy (ptr, "*");
       break;
+    case STRUCTOP_PTR:
+      strcpy (ptr, "->");
+      break;
     default:
       error (_("Invalid unary operation specified."));
     }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-09 15:59               ` sami wagiaalla
@ 2010-08-09 17:35                 ` Tom Tromey
  2010-08-09 18:04                   ` sami wagiaalla
  0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2010-08-09 17:35 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Tom> This seems strange.  When can the result here be NULL?  And what does
Tom> that mean?  It seems like this either ought to be impossible, or it
Tom> should be an error of some kind.

Sami> Yes this is incorrect. value_x_unop never returns null. If the
Sami> operator is not found it throws an error. I added a try catch
Sami> statement and tests for the failing case.

Why a try/catch?  I would think that letting any error propagate would
be more appropriate.

Tom

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-09 17:35                 ` Tom Tromey
@ 2010-08-09 18:04                   ` sami wagiaalla
  2010-08-09 18:23                     ` Jan Kratochvil
  0 siblings, 1 reply; 19+ messages in thread
From: sami wagiaalla @ 2010-08-09 18:04 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 797 bytes --]


> Tom>  This seems strange.  When can the result here be NULL?  And what does
> Tom>  that mean?  It seems like this either ought to be impossible, or it
> Tom>  should be an error of some kind.
>
> Sami>  Yes this is incorrect. value_x_unop never returns null. If the
> Sami>  operator is not found it throws an error. I added a try catch
> Sami>  statement and tests for the failing case.
>
> Why a try/catch?  I would think that letting any error propagate would
> be more appropriate.
>

At first I wanted to avoid the error message changing. I expected an 
error message like "You cant use -> on a non-pointer" but it turns out 
you can :). So the catch is to allow that extension to continue working. 
Although personally I don't think these extensions should be allowed.

Test case added.

[-- Attachment #2: smart_pointer.patch --]
[-- Type: text/plain, Size: 7793 bytes --]

Support overloading of 'operator->'.

2010-08-09  Sami Wagiaalla  <swagiaal@redhat.com>

	 PR C++/11500:
	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
	* eval.c (evaluate_subexp_standard): Check for overload of
	'operator->'.

2010-08-09  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.cp/smartp.exp: New test.
	* gdb.cp/smartp.cc : New test.

diff --git a/gdb/eval.c b/gdb/eval.c
index ba75952..9786c1e 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1431,6 +1431,24 @@ evaluate_subexp_standard (struct type *expect_type,
 	  else
 	    {
 	      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+	      /* Check to see if the operator '->' has been overloaded.  If the operator
+	         has been overloaded replace arg2 with the value returned by the custom
+	         operator and continue evaluation.  */
+	      while (unop_user_defined_p (op, arg2))
+		{
+		  volatile struct gdb_exception except;
+		  struct value *value = NULL;
+		  TRY_CATCH (except, RETURN_MASK_ERROR)
+		    {
+		      value = value_x_unop (arg2, op, noside);
+		    }
+
+		  if (except.reason < 0)
+		    break;
+
+		  arg2 = value;
+		}
 	    }
 	  /* Now, say which argument to start evaluating from */
 	  tem = 2;
@@ -1819,6 +1837,23 @@ evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
 
+      /* Check to see if operator '->' has been overloaded.  If so replace
+         arg1 with the value returned by evaluating operator->().  */
+      while (unop_user_defined_p (op, arg1))
+	{
+	  volatile struct gdb_exception except;
+	  struct value *value = NULL;
+	  TRY_CATCH (except, RETURN_MASK_ERROR)
+	    {
+	      value = value_x_unop (arg1, op, noside);
+	    }
+
+	  if (except.reason < 0)
+	    break;
+
+	  arg1 = value;
+	}
+
       /* JYG: if print object is on we need to replace the base type
 	 with rtti type in order to continue on with successful
 	 lookup of member / method only available in the rtti type. */
diff --git a/gdb/testsuite/gdb.cp/smartp.cc b/gdb/testsuite/gdb.cp/smartp.cc
new file mode 100644
index 0000000..baa8f46
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.cc
@@ -0,0 +1,163 @@
+/* This test script is part of GDB, the GNU debugger.
+
+   Copyright 1999, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+   */
+
+class Type1{
+  public:
+  int foo(){
+    return 11;
+  }
+};
+
+class Type2{
+  public:
+  int foo(){
+    return 22;
+  }
+};
+
+class Type3{
+  public:
+  int foo(int){
+    return 33;
+  }
+  int foo(char){
+    return 44;
+  }
+};
+
+class Type4 {
+  public:
+    int a;
+    int b;
+};
+
+int foo (Type3, float)
+{
+  return 55;
+}
+
+class MyPointer{
+  Type1 *p;
+ public:
+  MyPointer(Type1 *pointer){
+    p = pointer;
+  }
+
+  Type1 *operator->(){
+    return p;
+  }
+};
+
+template <typename T> class SmartPointer{
+  T *p;
+ public:
+  SmartPointer(T *pointer){
+    p = pointer;
+  }
+
+  T *operator->(){
+    return p;
+  }
+};
+
+
+class A {
+ public:
+  int inta;
+  int foo() { return 66; }
+};
+
+class B {
+ public:
+  A a;
+  A* operator->(){
+    return &a;
+  }
+};
+
+class C {
+ public:
+  B b;
+  B& operator->(){
+    return b;
+  }
+};
+
+class C2 {
+ public:
+  B b;
+  B operator->(){
+    return b;
+  }
+};
+
+int main(){
+  Type1 mt1;
+  Type2 mt2;
+  Type3 mt3;
+
+  Type4 mt4;
+  mt4.a = 11;
+  mt4.b = 12;
+
+  MyPointer mp(&mt1);
+  Type1 *mtp = &mt1;
+
+  SmartPointer<Type1> sp1(&mt1);
+  SmartPointer<Type2> sp2(&mt2);
+  SmartPointer<Type3> sp3(&mt3);
+  SmartPointer<Type4> sp4(&mt4);
+
+  mp->foo();
+  mtp->foo();
+
+  sp1->foo();
+  sp2->foo();
+
+  sp3->foo(1);
+  sp3->foo('a');
+
+  sp4->a;
+  sp4->b;
+
+  Type4 *mt4p = &mt4;
+  mt4p->a;
+  mt4p->b;
+
+  A a;
+  B b;
+  C c;
+  C2 c2;
+
+  a.inta = 77;
+  b.a = a;
+  c.b = b;
+  c2.b = b;
+
+  a.foo();
+  b->foo();
+  c->foo();
+
+  b->inta = 77;
+  c->inta = 77;
+  c2->inta = 77;
+
+  return 0; // end of main
+}
+
diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp
new file mode 100644
index 0000000..2cea473
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.exp
@@ -0,0 +1,77 @@
+# Copyright 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set testfile smartp
+set srcfile ${testfile}.cc
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}] } {
+     return -1
+}
+
+############################################
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint main"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "end of main"]
+gdb_continue_to_breakpoint "end of main"
+
+# Test that overloaded arrow operator works
+gdb_test "p mp->foo()"            "= 11"
+
+# Test that regular arrow operator still works
+gdb_test "p mtp->foo()"            "= 11"
+
+# Test that normal '.' operator still works.
+gdb_test "p mt1.foo()"             "= 11"
+
+# test that gdb extension '.' for pointers still works.
+gdb_test "p mt4p.a"                "= 11"
+
+# test that gdb extension '->' for structs still works.
+gdb_test "p mt4->a"                "= 11"
+
+# Test that templated smart pointers work
+gdb_test "p sp1->foo()"            "= 11"
+gdb_test "p sp2->foo()"            "= 22"
+
+# Test that overload resolution works properly
+# with smart pointers
+gdb_test "p sp3->foo(1)"           "= 33"
+gdb_test "p sp3->foo('a')"         "= 44"
+
+# Test smart pointers work for member references
+gdb_test "p sp4->a"         "= 11"
+gdb_test "p sp4->b"         "= 12"
+
+# Test regular arrow operator still works for
+# member references
+gdb_test "p mt4p->a"         "= 11"
+gdb_test "p mt4p->b"         "= 12"
+
+# Test that incorrect use of the arrow operator
+# is still handled correctly.
+gdb_test "p mt4->fake"       "There is no member named fake."
+gdb_test "p mt4->fake()"     "Couldn't find method Type4::fake"
+
+# Test that overloading of -> works recursively
+gdb_test "p b->foo()"         "= 66"
+gdb_test "p c->foo()"         "= 66"
+gdb_test "p c->inta"          "= 77"
+
+setup_kfail "gdb/11606" "*-*-*"
+gdb_test "p c2->inta"          "= 77"
+
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 0c40905..91f9c0c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -616,6 +616,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
     case UNOP_IND:
       strcpy (ptr, "*");
       break;
+    case STRUCTOP_PTR:
+      strcpy (ptr, "->");
+      break;
     default:
       error (_("Invalid unary operation specified."));
     }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-09 18:04                   ` sami wagiaalla
@ 2010-08-09 18:23                     ` Jan Kratochvil
  2010-08-16 20:31                       ` sami wagiaalla
  0 siblings, 1 reply; 19+ messages in thread
From: Jan Kratochvil @ 2010-08-09 18:23 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

On Mon, 09 Aug 2010 20:04:15 +0200, sami wagiaalla wrote:
> +
> +	      /* Check to see if the operator '->' has been overloaded.  If the operator
> +	         has been overloaded replace arg2 with the value returned by the custom
> +	         operator and continue evaluation.  */
> +	      while (unop_user_defined_p (op, arg2))
> +		{
> +		  volatile struct gdb_exception except;
> +		  struct value *value = NULL;
> +		  TRY_CATCH (except, RETURN_MASK_ERROR)
> +		    {
> +		      value = value_x_unop (arg2, op, noside);
> +		    }
> +
> +		  if (except.reason < 0)
> +		    break;

What if some other error kind occurs?  It would get hidden.  Such as:
    error (_("This target does not support function calls."));

In the case you want to go with the TRY_CATCH case you should IMO specialize
the error message you want to catch to some:
    throw_error (THE_GREAT_NEW_KIND_OF_ERROR, that message);

To correctly check just that specific error kind in EXCEPT (and throw it again
otherwise).


OTOH I believe instead of making a new special kind of error message the
function calling schematics could be changed to not error itself and return
some normal error return value instead.


Regards,
Jan

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-09 18:23                     ` Jan Kratochvil
@ 2010-08-16 20:31                       ` sami wagiaalla
  2010-08-16 20:59                         ` Pedro Alves
  0 siblings, 1 reply; 19+ messages in thread
From: sami wagiaalla @ 2010-08-16 20:31 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1219 bytes --]

On 08/09/2010 02:23 PM, Jan Kratochvil wrote:
> On Mon, 09 Aug 2010 20:04:15 +0200, sami wagiaalla wrote:
>> +
>> +	      /* Check to see if the operator '->' has been overloaded.  If the operator
>> +	         has been overloaded replace arg2 with the value returned by the custom
>> +	         operator and continue evaluation.  */
>> +	      while (unop_user_defined_p (op, arg2))
>> +		{
>> +		  volatile struct gdb_exception except;
>> +		  struct value *value = NULL;
>> +		  TRY_CATCH (except, RETURN_MASK_ERROR)
>> +		    {
>> +		      value = value_x_unop (arg2, op, noside);
>> +		    }
>> +
>> +		  if (except.reason<  0)
>> +		    break;
>
> What if some other error kind occurs?  It would get hidden.  Such as:
>      error (_("This target does not support function calls."));
>
> In the case you want to go with the TRY_CATCH case you should IMO specialize
> the error message you want to catch to some:
>      throw_error (THE_GREAT_NEW_KIND_OF_ERROR, that message);
>
> To correctly check just that specific error kind in EXCEPT (and throw it again
> otherwise).
>

I have created a new error type SYMBOL_NOT_FOUND_ERROR and updated the 
needed throw locations and the catch statements. Patch attached.

[-- Attachment #2: smart_pointer.patch --]
[-- Type: text/x-patch, Size: 10490 bytes --]

Support overloading of 'operator->'.

2010-08-16  Sami Wagiaalla  <swagiaal@redhat.com>

	 PR C++/11500:
	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
	* eval.c (evaluate_subexp_standard): Check for overload of
	'operator->'.
	* exceptions.h: New error SYMBOL_NOT_FOUND_ERROR.
	* valarith.c (value_x_binop): Throw SYMBOL_NOT_FOUND_ERROR.
	(value_x_unop): Ditto.
	* valops.c: Include "exceptions.h".
	(find_overload_match): Throw SYMBOL_NOT_FOUND_ERROR.
	(value_struct_elt): Ditto.

2010-08-16  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.cp/smartp.exp: New test.
	* gdb.cp/smartp.cc : New test.

diff --git a/gdb/eval.c b/gdb/eval.c
index ba75952..8b99dac 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1431,6 +1431,28 @@ evaluate_subexp_standard (struct type *expect_type,
 	  else
 	    {
 	      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+	      /* Check to see if the operator '->' has been overloaded.  If the operator
+	         has been overloaded replace arg2 with the value returned by the custom
+	         operator and continue evaluation.  */
+	      while (unop_user_defined_p (op, arg2))
+		{
+		  volatile struct gdb_exception except;
+		  struct value *value = NULL;
+		  TRY_CATCH (except, RETURN_MASK_ERROR)
+		    {
+		      value = value_x_unop (arg2, op, noside);
+		    }
+
+		  if (except.reason < 0)
+		    {
+		      if (except.error == SYMBOL_NOT_FOUND_ERROR)
+			break;
+		      else
+			throw_exception (except);
+		    }
+		  arg2 = value;
+		}
 	    }
 	  /* Now, say which argument to start evaluating from */
 	  tem = 2;
@@ -1819,6 +1841,27 @@ evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
 
+      /* Check to see if operator '->' has been overloaded.  If so replace
+         arg1 with the value returned by evaluating operator->().  */
+      while (unop_user_defined_p (op, arg1))
+	{
+	  volatile struct gdb_exception except;
+	  struct value *value = NULL;
+	  TRY_CATCH (except, RETURN_MASK_ERROR)
+	    {
+	      value = value_x_unop (arg1, op, noside);
+	    }
+
+	  if (except.reason < 0)
+	    {
+	      if (except.error == SYMBOL_NOT_FOUND_ERROR)
+		break;
+	      else
+		throw_exception (except);
+	    }
+	  arg1 = value;
+	}
+
       /* JYG: if print object is on we need to replace the base type
 	 with rtti type in order to continue on with successful
 	 lookup of member / method only available in the rtti type. */
diff --git a/gdb/exceptions.h b/gdb/exceptions.h
index 7d68a36..55263ed 100644
--- a/gdb/exceptions.h
+++ b/gdb/exceptions.h
@@ -78,6 +78,9 @@ enum errors {
   /* Feature is not supported in this copy of GDB.  */
   UNSUPPORTED_ERROR,
 
+  /* The requested symbol was not found.  */
+  SYMBOL_NOT_FOUND_ERROR,
+
   /* Add more errors here.  */
   NR_ERRORS
 };
diff --git a/gdb/testsuite/gdb.cp/smartp.cc b/gdb/testsuite/gdb.cp/smartp.cc
new file mode 100644
index 0000000..baa8f46
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.cc
@@ -0,0 +1,163 @@
+/* This test script is part of GDB, the GNU debugger.
+
+   Copyright 1999, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+   */
+
+class Type1{
+  public:
+  int foo(){
+    return 11;
+  }
+};
+
+class Type2{
+  public:
+  int foo(){
+    return 22;
+  }
+};
+
+class Type3{
+  public:
+  int foo(int){
+    return 33;
+  }
+  int foo(char){
+    return 44;
+  }
+};
+
+class Type4 {
+  public:
+    int a;
+    int b;
+};
+
+int foo (Type3, float)
+{
+  return 55;
+}
+
+class MyPointer{
+  Type1 *p;
+ public:
+  MyPointer(Type1 *pointer){
+    p = pointer;
+  }
+
+  Type1 *operator->(){
+    return p;
+  }
+};
+
+template <typename T> class SmartPointer{
+  T *p;
+ public:
+  SmartPointer(T *pointer){
+    p = pointer;
+  }
+
+  T *operator->(){
+    return p;
+  }
+};
+
+
+class A {
+ public:
+  int inta;
+  int foo() { return 66; }
+};
+
+class B {
+ public:
+  A a;
+  A* operator->(){
+    return &a;
+  }
+};
+
+class C {
+ public:
+  B b;
+  B& operator->(){
+    return b;
+  }
+};
+
+class C2 {
+ public:
+  B b;
+  B operator->(){
+    return b;
+  }
+};
+
+int main(){
+  Type1 mt1;
+  Type2 mt2;
+  Type3 mt3;
+
+  Type4 mt4;
+  mt4.a = 11;
+  mt4.b = 12;
+
+  MyPointer mp(&mt1);
+  Type1 *mtp = &mt1;
+
+  SmartPointer<Type1> sp1(&mt1);
+  SmartPointer<Type2> sp2(&mt2);
+  SmartPointer<Type3> sp3(&mt3);
+  SmartPointer<Type4> sp4(&mt4);
+
+  mp->foo();
+  mtp->foo();
+
+  sp1->foo();
+  sp2->foo();
+
+  sp3->foo(1);
+  sp3->foo('a');
+
+  sp4->a;
+  sp4->b;
+
+  Type4 *mt4p = &mt4;
+  mt4p->a;
+  mt4p->b;
+
+  A a;
+  B b;
+  C c;
+  C2 c2;
+
+  a.inta = 77;
+  b.a = a;
+  c.b = b;
+  c2.b = b;
+
+  a.foo();
+  b->foo();
+  c->foo();
+
+  b->inta = 77;
+  c->inta = 77;
+  c2->inta = 77;
+
+  return 0; // end of main
+}
+
diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp
new file mode 100644
index 0000000..2cea473
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.exp
@@ -0,0 +1,77 @@
+# Copyright 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set testfile smartp
+set srcfile ${testfile}.cc
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}] } {
+     return -1
+}
+
+############################################
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint main"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "end of main"]
+gdb_continue_to_breakpoint "end of main"
+
+# Test that overloaded arrow operator works
+gdb_test "p mp->foo()"            "= 11"
+
+# Test that regular arrow operator still works
+gdb_test "p mtp->foo()"            "= 11"
+
+# Test that normal '.' operator still works.
+gdb_test "p mt1.foo()"             "= 11"
+
+# test that gdb extension '.' for pointers still works.
+gdb_test "p mt4p.a"                "= 11"
+
+# test that gdb extension '->' for structs still works.
+gdb_test "p mt4->a"                "= 11"
+
+# Test that templated smart pointers work
+gdb_test "p sp1->foo()"            "= 11"
+gdb_test "p sp2->foo()"            "= 22"
+
+# Test that overload resolution works properly
+# with smart pointers
+gdb_test "p sp3->foo(1)"           "= 33"
+gdb_test "p sp3->foo('a')"         "= 44"
+
+# Test smart pointers work for member references
+gdb_test "p sp4->a"         "= 11"
+gdb_test "p sp4->b"         "= 12"
+
+# Test regular arrow operator still works for
+# member references
+gdb_test "p mt4p->a"         "= 11"
+gdb_test "p mt4p->b"         "= 12"
+
+# Test that incorrect use of the arrow operator
+# is still handled correctly.
+gdb_test "p mt4->fake"       "There is no member named fake."
+gdb_test "p mt4->fake()"     "Couldn't find method Type4::fake"
+
+# Test that overloading of -> works recursively
+gdb_test "p b->foo()"         "= 66"
+gdb_test "p c->foo()"         "= 66"
+gdb_test "p c->inta"          "= 77"
+
+setup_kfail "gdb/11606" "*-*-*"
+gdb_test "p c2->inta"          "= 77"
+
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 0c40905..f9ca51f 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -541,7 +541,8 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	}
       return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
     }
-  error (_("member function %s not found"), tstr);
+  throw_error (SYMBOL_NOT_FOUND_ERROR,
+               _("member function %s not found"), tstr);
 #ifdef lint
   return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
 #endif
@@ -616,6 +617,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
     case UNOP_IND:
       strcpy (ptr, "*");
       break;
+    case STRUCTOP_PTR:
+      strcpy (ptr, "->");
+      break;
     default:
       error (_("Invalid unary operation specified."));
     }
@@ -641,7 +645,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	}
       return call_function_by_hand (argvec[0], nargs, argvec + 1);
     }
-  error (_("member function %s not found"), tstr);
+  throw_error (SYMBOL_NOT_FOUND_ERROR,
+               _("member function %s not found"), tstr);
+
   return 0;			/* For lint -- never reached */
 }
 \f
diff --git a/gdb/valops.c b/gdb/valops.c
index f1eb041..2ac99cb 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -46,6 +46,7 @@
 #include "observer.h"
 #include "objfiles.h"
 #include "symtab.h"
+#include "exceptions.h"
 
 extern int overload_debug;
 /* Local functions.  */
@@ -2196,7 +2197,8 @@ value_struct_elt (struct value **argp, struct value **args,
     }
 
   if (!v)
-    error (_("Structure has no component named %s."), name);
+    throw_error (SYMBOL_NOT_FOUND_ERROR,
+                 _("Structure has no component named %s."), name);
   return v;
 }
 
@@ -2517,7 +2519,9 @@ find_overload_match (struct type **arg_types, int nargs,
 
   /* Did we find a match ?  */
   if (method_oload_champ == -1 && func_oload_champ == -1)
-    error (_("No symbol \"%s\" in current context."), name);
+    throw_error (SYMBOL_NOT_FOUND_ERROR,
+                 _("No symbol \"%s\" in current context."),
+                 name);
 
   /* If we have found both a method match and a function
      match, find out which one is better, and calculate match

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-16 20:31                       ` sami wagiaalla
@ 2010-08-16 20:59                         ` Pedro Alves
  2010-08-17 16:16                           ` sami wagiaalla
  0 siblings, 1 reply; 19+ messages in thread
From: Pedro Alves @ 2010-08-16 20:59 UTC (permalink / raw)
  To: gdb-patches; +Cc: sami wagiaalla

On Monday 16 August 2010 21:31:06, sami wagiaalla wrote:
> @@ -78,6 +78,9 @@ enum errors {
>    /* Feature is not supported in this copy of GDB.  */
>    UNSUPPORTED_ERROR,
>  
> +  /* The requested symbol was not found.  */
> +  SYMBOL_NOT_FOUND_ERROR,
> +

How's this different from the existing NOT_FOUND_ERROR?

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-16 20:59                         ` Pedro Alves
@ 2010-08-17 16:16                           ` sami wagiaalla
  2010-08-17 17:15                             ` Tom Tromey
  0 siblings, 1 reply; 19+ messages in thread
From: sami wagiaalla @ 2010-08-17 16:16 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 425 bytes --]

On 08/16/2010 04:59 PM, Pedro Alves wrote:
> On Monday 16 August 2010 21:31:06, sami wagiaalla wrote:
>> @@ -78,6 +78,9 @@ enum errors {
>>     /* Feature is not supported in this copy of GDB.  */
>>     UNSUPPORTED_ERROR,
>>
>> +  /* The requested symbol was not found.  */
>> +  SYMBOL_NOT_FOUND_ERROR,
>> +
>
> How's this different from the existing NOT_FOUND_ERROR?
>

Ops. My bad, I missed that. Updated patch attached.

[-- Attachment #2: smart_pointer.patch --]
[-- Type: text/x-patch, Size: 10022 bytes --]

Support overloading of 'operator->'.

2010-08-16  Sami Wagiaalla  <swagiaal@redhat.com>

	 PR C++/11500:
	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
	* eval.c (evaluate_subexp_standard): Check for overload of
	'operator->'.
	* valarith.c (value_x_binop): Throw NOT_FOUND_ERROR.
	(value_x_unop): Ditto.
	* valops.c: Include "exceptions.h".
	(find_overload_match): Throw NOT_FOUND_ERROR.
	(value_struct_elt): Ditto.

2010-08-16  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.cp/smartp.exp: New test.
	* gdb.cp/smartp.cc : New test.

diff --git a/gdb/eval.c b/gdb/eval.c
index ba75952..065cf2c 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1431,6 +1431,28 @@ evaluate_subexp_standard (struct type *expect_type,
 	  else
 	    {
 	      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+	      /* Check to see if the operator '->' has been overloaded.  If the operator
+	         has been overloaded replace arg2 with the value returned by the custom
+	         operator and continue evaluation.  */
+	      while (unop_user_defined_p (op, arg2))
+		{
+		  volatile struct gdb_exception except;
+		  struct value *value = NULL;
+		  TRY_CATCH (except, RETURN_MASK_ERROR)
+		    {
+		      value = value_x_unop (arg2, op, noside);
+		    }
+
+		  if (except.reason < 0)
+		    {
+		      if (except.error == NOT_FOUND_ERROR)
+			break;
+		      else
+			throw_exception (except);
+		    }
+		  arg2 = value;
+		}
 	    }
 	  /* Now, say which argument to start evaluating from */
 	  tem = 2;
@@ -1819,6 +1841,27 @@ evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
 
+      /* Check to see if operator '->' has been overloaded.  If so replace
+         arg1 with the value returned by evaluating operator->().  */
+      while (unop_user_defined_p (op, arg1))
+	{
+	  volatile struct gdb_exception except;
+	  struct value *value = NULL;
+	  TRY_CATCH (except, RETURN_MASK_ERROR)
+	    {
+	      value = value_x_unop (arg1, op, noside);
+	    }
+
+	  if (except.reason < 0)
+	    {
+	      if (except.error == NOT_FOUND_ERROR)
+		break;
+	      else
+		throw_exception (except);
+	    }
+	  arg1 = value;
+	}
+
       /* JYG: if print object is on we need to replace the base type
 	 with rtti type in order to continue on with successful
 	 lookup of member / method only available in the rtti type. */
diff --git a/gdb/testsuite/gdb.cp/smartp.cc b/gdb/testsuite/gdb.cp/smartp.cc
new file mode 100644
index 0000000..baa8f46
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.cc
@@ -0,0 +1,163 @@
+/* This test script is part of GDB, the GNU debugger.
+
+   Copyright 1999, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+   */
+
+class Type1{
+  public:
+  int foo(){
+    return 11;
+  }
+};
+
+class Type2{
+  public:
+  int foo(){
+    return 22;
+  }
+};
+
+class Type3{
+  public:
+  int foo(int){
+    return 33;
+  }
+  int foo(char){
+    return 44;
+  }
+};
+
+class Type4 {
+  public:
+    int a;
+    int b;
+};
+
+int foo (Type3, float)
+{
+  return 55;
+}
+
+class MyPointer{
+  Type1 *p;
+ public:
+  MyPointer(Type1 *pointer){
+    p = pointer;
+  }
+
+  Type1 *operator->(){
+    return p;
+  }
+};
+
+template <typename T> class SmartPointer{
+  T *p;
+ public:
+  SmartPointer(T *pointer){
+    p = pointer;
+  }
+
+  T *operator->(){
+    return p;
+  }
+};
+
+
+class A {
+ public:
+  int inta;
+  int foo() { return 66; }
+};
+
+class B {
+ public:
+  A a;
+  A* operator->(){
+    return &a;
+  }
+};
+
+class C {
+ public:
+  B b;
+  B& operator->(){
+    return b;
+  }
+};
+
+class C2 {
+ public:
+  B b;
+  B operator->(){
+    return b;
+  }
+};
+
+int main(){
+  Type1 mt1;
+  Type2 mt2;
+  Type3 mt3;
+
+  Type4 mt4;
+  mt4.a = 11;
+  mt4.b = 12;
+
+  MyPointer mp(&mt1);
+  Type1 *mtp = &mt1;
+
+  SmartPointer<Type1> sp1(&mt1);
+  SmartPointer<Type2> sp2(&mt2);
+  SmartPointer<Type3> sp3(&mt3);
+  SmartPointer<Type4> sp4(&mt4);
+
+  mp->foo();
+  mtp->foo();
+
+  sp1->foo();
+  sp2->foo();
+
+  sp3->foo(1);
+  sp3->foo('a');
+
+  sp4->a;
+  sp4->b;
+
+  Type4 *mt4p = &mt4;
+  mt4p->a;
+  mt4p->b;
+
+  A a;
+  B b;
+  C c;
+  C2 c2;
+
+  a.inta = 77;
+  b.a = a;
+  c.b = b;
+  c2.b = b;
+
+  a.foo();
+  b->foo();
+  c->foo();
+
+  b->inta = 77;
+  c->inta = 77;
+  c2->inta = 77;
+
+  return 0; // end of main
+}
+
diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp
new file mode 100644
index 0000000..2cea473
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/smartp.exp
@@ -0,0 +1,77 @@
+# Copyright 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set testfile smartp
+set srcfile ${testfile}.cc
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug c++}] } {
+     return -1
+}
+
+############################################
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint main"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "end of main"]
+gdb_continue_to_breakpoint "end of main"
+
+# Test that overloaded arrow operator works
+gdb_test "p mp->foo()"            "= 11"
+
+# Test that regular arrow operator still works
+gdb_test "p mtp->foo()"            "= 11"
+
+# Test that normal '.' operator still works.
+gdb_test "p mt1.foo()"             "= 11"
+
+# test that gdb extension '.' for pointers still works.
+gdb_test "p mt4p.a"                "= 11"
+
+# test that gdb extension '->' for structs still works.
+gdb_test "p mt4->a"                "= 11"
+
+# Test that templated smart pointers work
+gdb_test "p sp1->foo()"            "= 11"
+gdb_test "p sp2->foo()"            "= 22"
+
+# Test that overload resolution works properly
+# with smart pointers
+gdb_test "p sp3->foo(1)"           "= 33"
+gdb_test "p sp3->foo('a')"         "= 44"
+
+# Test smart pointers work for member references
+gdb_test "p sp4->a"         "= 11"
+gdb_test "p sp4->b"         "= 12"
+
+# Test regular arrow operator still works for
+# member references
+gdb_test "p mt4p->a"         "= 11"
+gdb_test "p mt4p->b"         "= 12"
+
+# Test that incorrect use of the arrow operator
+# is still handled correctly.
+gdb_test "p mt4->fake"       "There is no member named fake."
+gdb_test "p mt4->fake()"     "Couldn't find method Type4::fake"
+
+# Test that overloading of -> works recursively
+gdb_test "p b->foo()"         "= 66"
+gdb_test "p c->foo()"         "= 66"
+gdb_test "p c->inta"          "= 77"
+
+setup_kfail "gdb/11606" "*-*-*"
+gdb_test "p c2->inta"          "= 77"
+
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 0c40905..6de8c0d 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -541,7 +541,8 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	}
       return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
     }
-  error (_("member function %s not found"), tstr);
+  throw_error (NOT_FOUND_ERROR,
+               _("member function %s not found"), tstr);
 #ifdef lint
   return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
 #endif
@@ -616,6 +617,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
     case UNOP_IND:
       strcpy (ptr, "*");
       break;
+    case STRUCTOP_PTR:
+      strcpy (ptr, "->");
+      break;
     default:
       error (_("Invalid unary operation specified."));
     }
@@ -641,7 +645,9 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	}
       return call_function_by_hand (argvec[0], nargs, argvec + 1);
     }
-  error (_("member function %s not found"), tstr);
+  throw_error (NOT_FOUND_ERROR,
+               _("member function %s not found"), tstr);
+
   return 0;			/* For lint -- never reached */
 }
 \f
diff --git a/gdb/valops.c b/gdb/valops.c
index f1eb041..70f24ca 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -46,6 +46,7 @@
 #include "observer.h"
 #include "objfiles.h"
 #include "symtab.h"
+#include "exceptions.h"
 
 extern int overload_debug;
 /* Local functions.  */
@@ -2196,7 +2197,8 @@ value_struct_elt (struct value **argp, struct value **args,
     }
 
   if (!v)
-    error (_("Structure has no component named %s."), name);
+    throw_error (NOT_FOUND_ERROR,
+                 _("Structure has no component named %s."), name);
   return v;
 }
 
@@ -2517,7 +2519,9 @@ find_overload_match (struct type **arg_types, int nargs,
 
   /* Did we find a match ?  */
   if (method_oload_champ == -1 && func_oload_champ == -1)
-    error (_("No symbol \"%s\" in current context."), name);
+    throw_error (NOT_FOUND_ERROR,
+                 _("No symbol \"%s\" in current context."),
+                 name);
 
   /* If we have found both a method match and a function
      match, find out which one is better, and calculate match

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-17 16:16                           ` sami wagiaalla
@ 2010-08-17 17:15                             ` Tom Tromey
  2010-10-19 20:55                               ` sami wagiaalla
  0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2010-08-17 17:15 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Sami> 2010-08-16  Sami Wagiaalla  <swagiaal@redhat.com>
Sami> 	 PR C++/11500:
Sami> 	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
Sami> 	* eval.c (evaluate_subexp_standard): Check for overload of
Sami> 	'operator->'.
Sami> 	* valarith.c (value_x_binop): Throw NOT_FOUND_ERROR.
Sami> 	(value_x_unop): Ditto.
Sami> 	* valops.c: Include "exceptions.h".
Sami> 	(find_overload_match): Throw NOT_FOUND_ERROR.
Sami> 	(value_struct_elt): Ditto.

Sami> 2010-08-16  Sami Wagiaalla  <swagiaal@redhat.com>

Sami> 	* gdb.cp/smartp.exp: New test.
Sami> 	* gdb.cp/smartp.cc : New test.

Ok.

Tom

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch] smart pointer support
  2010-08-17 17:15                             ` Tom Tromey
@ 2010-10-19 20:55                               ` sami wagiaalla
  0 siblings, 0 replies; 19+ messages in thread
From: sami wagiaalla @ 2010-10-19 20:55 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches


> Sami>  2010-08-16  Sami Wagiaalla<swagiaal@redhat.com>
> Sami>  	PR C++/11500:
> Sami>  	* valarith.c (value_x_unop): Handle STRUCTOP_PTR.
> Sami>  	* eval.c (evaluate_subexp_standard): Check for overload of
> Sami>  	'operator->'.
> Sami>  	* valarith.c (value_x_binop): Throw NOT_FOUND_ERROR.
> Sami>  	(value_x_unop): Ditto.
> Sami>  	* valops.c: Include "exceptions.h".
> Sami>  	(find_overload_match): Throw NOT_FOUND_ERROR.
> Sami>  	(value_struct_elt): Ditto.
>
> Sami>  2010-08-16  Sami Wagiaalla<swagiaal@redhat.com>
>
> Sami>  	* gdb.cp/smartp.exp: New test.
> Sami>  	* gdb.cp/smartp.cc : New test.
>
> Ok.
>

Committed.

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2010-10-19 20:55 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-20 15:58 [patch] smart pointer support sami wagiaalla
2010-07-23 23:37 ` Tom Tromey
2010-08-05 18:46   ` sami wagiaalla
2010-08-05 22:57     ` Ulrich Weigand
2010-08-06 16:23       ` sami wagiaalla
2010-08-06 16:48         ` Ulrich Weigand
2010-08-06 17:29           ` Tom Tromey
2010-08-08 15:01             ` Ulrich Weigand
2010-08-06 21:33           ` sami wagiaalla
2010-08-06 22:20             ` Tom Tromey
2010-08-09 15:59               ` sami wagiaalla
2010-08-09 17:35                 ` Tom Tromey
2010-08-09 18:04                   ` sami wagiaalla
2010-08-09 18:23                     ` Jan Kratochvil
2010-08-16 20:31                       ` sami wagiaalla
2010-08-16 20:59                         ` Pedro Alves
2010-08-17 16:16                           ` sami wagiaalla
2010-08-17 17:15                             ` Tom Tromey
2010-10-19 20:55                               ` sami wagiaalla

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).