* [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 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 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 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).