* [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on'
@ 2008-07-17 21:49 Paul Pluzhnikov
2008-07-22 0:53 ` Tom Tromey
0 siblings, 1 reply; 9+ messages in thread
From: Paul Pluzhnikov @ 2008-07-17 21:49 UTC (permalink / raw)
To: gdb-patches
Greetings,
Long time GDB users are somewhat used to 'p->x' and 'p.x' meaning
the same thing. But, as test case below demonstrates, they don't
mean the same thing when 'set print object on' is in effect.
I believe it is desirable to make the behavior consistent -- either
always accept 'p.x' when 'p->x' was meant, or always insist on
correct form (which is what VisualStudio does).
Attached patch fixes the problem for field access (but not for
mem-function access -- that goes through different path), and
eliminates some redundant code.
Comments?
Test case demonstrating the problem:
--- cut ---
struct Foo {
int x;
Foo() : x(1) { }
virtual ~Foo() { }
};
struct Bar : public Foo {
Bar() : y(2), z(3) { }
int y, z;
};
int fn(Foo *f)
{
return f->x;
}
int main()
{
Bar b;
return fn(&b);
}
--- cut ---
(gdb) b fn
Breakpoint 1 at 0x4002e0: file print-obj.cc, line 14.
(gdb) r
Breakpoint 1, fn (f=0x7fffffffe690) at print-obj.cc:14
14 return f->x;
(gdb) p f
$1 = (Foo *) 0x7fffffffe690
(gdb) set print object on
(gdb) p f
$2 = (Bar *) 0x7fffffffe690
(gdb) p f->z # works
$3 = 3
(gdb) p f.z # doesn't work -- bug in gdb
There is no member or method named z.
# For members of 'Foo' it works either way:
(gdb) p f->x
$4 = 1
(gdb) p f.x
$5 = 1
Thanks,
--
Paul Pluzhnikov
2008-07-17 Paul Pluzhnikov <ppluzhnikov@google.com>
* eval.c (evaluate_subexp_standard): Treat 'p.x' and 'p->x' the same.
Index: eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.85
diff -u -p -u -r1.85 eval.c
--- eval.c 6 Jun 2008 20:58:08 -0000 1.85
+++ eval.c 17 Jul 2008 21:32:49 -0000
@@ -1374,23 +1374,6 @@ evaluate_subexp_standard (struct type *e
return value_literal_complex (arg1, arg2, builtin_type_f_complex_s16);
case STRUCTOP_STRUCT:
- tem = longest_to_int (exp->elts[pc + 1].longconst);
- (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
- arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
- if (noside == EVAL_SKIP)
- goto nosideret;
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- return value_zero (lookup_struct_elt_type (value_type (arg1),
- &exp->elts[pc + 2].string,
- 0),
- lval_memory);
- else
- {
- struct value *temp = arg1;
- return value_struct_elt (&temp, NULL, &exp->elts[pc + 2].string,
- NULL, "structure");
- }
-
case STRUCTOP_PTR:
tem = longest_to_int (exp->elts[pc + 1].longconst);
(*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
@@ -1430,8 +1413,10 @@ evaluate_subexp_standard (struct type *e
else
{
struct value *temp = arg1;
+ char *const name =
+ (op == STRUCTOP_STRUCT) ? "structure" : "structure pointer";
return value_struct_elt (&temp, NULL, &exp->elts[pc + 2].string,
- NULL, "structure pointer");
+ NULL, name);
}
case STRUCTOP_MEMBER:
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' 2008-07-17 21:49 [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' Paul Pluzhnikov @ 2008-07-22 0:53 ` Tom Tromey 2008-07-30 17:51 ` Paul Pluzhnikov 0 siblings, 1 reply; 9+ messages in thread From: Tom Tromey @ 2008-07-22 0:53 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: gdb-patches >>>>> "Paul" == Paul Pluzhnikov <ppluzhnikov@google.com> writes: Paul> Long time GDB users are somewhat used to 'p->x' and 'p.x' meaning Paul> the same thing. But, as test case below demonstrates, they don't Paul> mean the same thing when 'set print object on' is in effect. FWIW, I like this. I was always confused when I printed an object and saw a field, but was then unable to print the field directly. However, I recall bringing this up once, in the distant past. Someone pointed out a difficulty with this approach: there might be one field 'x' that would be used with the declared type, but another field, also named 'x', that would be used with the actual type. So, this could potentially be confusing (albeit in an already confusing situation). Maybe this can be documented or otherwise resolved. Also, IMO this patch could use an associated test case. Tom ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' 2008-07-22 0:53 ` Tom Tromey @ 2008-07-30 17:51 ` Paul Pluzhnikov 2008-08-07 17:31 ` Tom Tromey 2008-08-11 15:09 ` Tom Tromey 0 siblings, 2 replies; 9+ messages in thread From: Paul Pluzhnikov @ 2008-07-30 17:51 UTC (permalink / raw) To: tromey; +Cc: gdb-patches On Mon, Jul 21, 2008 at 5:52 PM, Tom Tromey <tromey@redhat.com> wrote: >>>>>> "Paul" == Paul Pluzhnikov <ppluzhnikov@google.com> writes: > > Paul> Long time GDB users are somewhat used to 'p->x' and 'p.x' meaning > Paul> the same thing. But, as test case below demonstrates, they don't > Paul> mean the same thing when 'set print object on' is in effect. > > FWIW, I like this. I was always confused when I printed an object and > saw a field, but was then unable to print the field directly. > > However, I recall bringing this up once, in the distant past. Someone > pointed out a difficulty with this approach: there might be one field > 'x' that would be used with the declared type, but another field, also > named 'x', that would be used with the actual type. So, this could > potentially be confusing (albeit in an already confusing situation). Thanks for bringing that up. I've modified the test case to have a field 'y' in both the base and derived classes (attached at the end), and the current situation is (IMHO) just as confusing before the patch as it is after :( Before patch (current behavior): Breakpoint 1, fn (f=0x7fffffffe690) at print-obj.cc:16 16 return f->y; (gdb) p *f $3 = {_vptr.Foo = 0x400570, x = 1, y = 2} (gdb) p f->y $4 = 2 (gdb) p f.y $5 = 2 (gdb) set print object on (gdb) p *f $6 = (Bar) {<Foo> = {_vptr.Foo = 0x400570, x = 1, y = 2}, y = 20, z = 30} (gdb) p f->y $7 = 20 (gdb) p f.y $8 = 2 // f.y and f->y do not mean the same thing :( (gdb) finish 0x0000000000400305 in main () at print-obj.cc:22 22 return fn(&b); Value returned is $9 = 2 // Confusing: 'print f->y' says '20'; but 'finish' says '2' After: Breakpoint 1, fn (f=0x7fffffffe660) at print-obj.cc:16 16 return f->y; (gdb) p *f $1 = {_vptr.Foo = 0x400570, x = 1, y = 2} (gdb) p f->y $2 = 2 (gdb) p f.y $3 = 2 // without "print object on" patch makes no difference (gdb) set print object on (gdb) p *f $4 = (Bar) {<Foo> = {_vptr.Foo = 0x400570, x = 1, y = 2}, y = 20, z = 30} (gdb) p f->y $5 = 20 (gdb) p f.y $6 = 20 // with "print object on" GDB is consistently treating f.y and f->y // as the same expression. (gdb) finish 0x0000000000400305 in main () at print-obj.cc:22 22 return fn(&b); Value returned is $7 = 2 // Still confusing ... > Maybe this can be documented or otherwise resolved. Some other alternatives (hand-simulated): A) Print both: (gbd) p f->y $14 = 2 (f->Foo::y) $15 = 20 (f->Bar::y) (gbd) p f.y $16 = 2 (f->Foo::y) $17 = 20 (f->Bar::y) B) Print warning: (gdb) p f.y Warning: more than one field 'y' resulted from lookup in dynamic type of 'f'; set 'print object off' to see the other 'y'. $18 = 20 C) Do what the language does: lookup field 'x' in the static type, and only try dynamic type if the first lookup failed: (gdb) p f.y $19 = 2 (gdb) p f->y $20 = 2 // The other field still accessible: (gdb) p f->Bar::y $21 = 20 // Lookup in Foo fails; try Bar (gdb) p f->z $22 = 30 I think "C" is the least confusing alternative. It may actually be good to do "C" independent of the 'print object' setting. > Also, IMO this patch could use an associated test case. Yes, I just wanted to see what people think about this before creating the test case. Thanks again. -- Paul Pluzhnikov // test case struct Foo { int x, y; Foo() : x(1), y(2) { } virtual ~Foo() { } virtual int method() = 0; }; struct Bar : public Foo { Bar() : y(20), z(30) { } int method() { return 42; } int y, z; }; int fn(Foo *f) { return f->y; } int main() { Bar b; return fn(&b); } ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' 2008-07-30 17:51 ` Paul Pluzhnikov @ 2008-08-07 17:31 ` Tom Tromey 2008-08-07 20:20 ` Daniel Jacobowitz 2008-08-11 15:09 ` Tom Tromey 1 sibling, 1 reply; 9+ messages in thread From: Tom Tromey @ 2008-08-07 17:31 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: gdb-patches >>>>> "Paul" == Paul Pluzhnikov <ppluzhnikov@google.com> writes: Paul> Thanks for bringing that up. I've modified the test case to have Paul> a field 'y' in both the base and derived classes (attached at the Paul> end), and the current situation is (IMHO) just as confusing before Paul> the patch as it is after :( Thanks for doing this. Paul> C) Do what the language does: lookup field 'x' in the static type, Paul> and only try dynamic type if the first lookup failed: Paul> I think "C" is the least confusing alternative. Paul> It may actually be good to do "C" independent of the 'print object' Paul> setting. I agree. This does sound better. Paul> Yes, I just wanted to see what people think about this before Paul> creating the test case. FWIW I'm definitely in favor. Tom ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' 2008-08-07 17:31 ` Tom Tromey @ 2008-08-07 20:20 ` Daniel Jacobowitz 0 siblings, 0 replies; 9+ messages in thread From: Daniel Jacobowitz @ 2008-08-07 20:20 UTC (permalink / raw) To: Tom Tromey; +Cc: Paul Pluzhnikov, gdb-patches On Thu, Aug 07, 2008 at 11:31:14AM -0600, Tom Tromey wrote: > Paul> C) Do what the language does: lookup field 'x' in the static type, > Paul> and only try dynamic type if the first lookup failed: > > Paul> I think "C" is the least confusing alternative. > Paul> It may actually be good to do "C" independent of the 'print object' > Paul> setting. > > I agree. This does sound better. I agree too. We have an extension that allows you to use "." on pointers with the implicit dereference; but it shouldn't change the type of the pointer, nor should ->. It's a reasonably well-defined extension as such things go. At least, until you involve user-defined operators. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' 2008-07-30 17:51 ` Paul Pluzhnikov 2008-08-07 17:31 ` Tom Tromey @ 2008-08-11 15:09 ` Tom Tromey 2008-08-19 18:05 ` Paul Pluzhnikov 1 sibling, 1 reply; 9+ messages in thread From: Tom Tromey @ 2008-08-11 15:09 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: gdb-patches >>>>> "Paul" == Paul Pluzhnikov <ppluzhnikov@google.com> writes: Paul> C) Do what the language does: lookup field 'x' in the static type, Paul> and only try dynamic type if the first lookup failed: It occurred to me last night that we must be careful not to do this in the overload resolution case. Looking at extra overloads from the dynamic type will yield the wrong answer. I think these code paths are separate in gdb, so that should not be a big deal, but I thought it would be good to be explicit about it. Tom ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' 2008-08-11 15:09 ` Tom Tromey @ 2008-08-19 18:05 ` Paul Pluzhnikov 2008-08-26 16:45 ` Paul Pluzhnikov 2008-10-22 22:32 ` Ulrich Weigand 0 siblings, 2 replies; 9+ messages in thread From: Paul Pluzhnikov @ 2008-08-19 18:05 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On Mon, Aug 11, 2008 at 8:08 AM, Tom Tromey <tromey@redhat.com> wrote: >>>>>> "Paul" == Paul Pluzhnikov <ppluzhnikov@google.com> writes: > > Paul> C) Do what the language does: lookup field 'x' in the static type, > Paul> and only try dynamic type if the first lookup failed: > > It occurred to me last night that we must be careful not to do this in > the overload resolution case. Actually, I think there are 2 separate cases: virtual and non-virtual function. We must not do this in the non-virtual case, but *should* do that in virtual case. IOW, 'print basep->virtfn()' and 'print basep.virtfn()' should be the same for consistency. > Looking at extra overloads from the > dynamic type will yield the wrong answer. I think these code paths > are separate in gdb, so that should not be a big deal, but I thought > it would be good to be explicit about it. I've added tests for these cases. Unfortunately, as I was adding tests, I discovered 4 new bugs :( The patch does not introduce any new failures for me. -- Paul Pluzhnikov gdb/ChangeLog 2008-08-19 Paul Pluzhnikov <ppluzhnikov@google.com> Changes to treat 'p.x' and 'p->x' the same. * eval.c (value_static_or_dynamic_member): New. (evaluate_subexp_standard): Call it. gdb/testsuite/ChangeLog 2008-08-19 Paul Pluzhnikov <ppluzhnikov@google.com> * gdb.cp/class3.exp: New test case. * gdb.cp/class3.cc: New source file. diff -Npur gdb.orig/eval.c gdb/eval.c --- gdb.orig/eval.c 2008-08-19 09:48:39.000000000 -0700 +++ gdb/eval.c 2008-08-19 10:14:04.000000000 -0700 @@ -44,10 +44,6 @@ /* This is defined in valops.c */ extern int overload_resolution; -/* JYG: lookup rtti type of STRUCTOP_PTR when this is set to continue - on with successful lookup for member/method of the rtti type. */ -extern int objectprint; - /* Prototypes for local functions. */ static struct value *evaluate_subexp_for_sizeof (struct expression *, int *); @@ -438,6 +434,51 @@ value_f90_subarray (struct value *array, return value_slice (array, low_bound, high_bound - low_bound + 1); } +static struct value * +value_static_or_dynamic_member(struct value *arg, char *string, + char *name, enum noside noside) +{ + struct type *type = value_type (arg); + struct value *temp; + + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (lookup_struct_elt_type (type, string, 0), + lval_memory); + temp = arg; + { + volatile struct gdb_exception except; + struct value *v = NULL; + TRY_CATCH (except, RETURN_MASK_ERROR) + { + v = value_struct_elt (&temp, NULL, string, NULL, name); + } + if (v) + return v; + } + + /* If we got here, value_struct_elt() above must have thrown, + and there is no field 'name' in 'type'. + Try dynamic type of 'arg' instead. */ + + if (TYPE_TARGET_TYPE(type) + && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS)) + { + struct type *real_type; + int full, top, using_enc; + real_type = value_rtti_target_type (arg, &full, &top, &using_enc); + if (real_type) + { + if (TYPE_CODE (type) == TYPE_CODE_PTR) + real_type = lookup_pointer_type (real_type); + else + real_type = lookup_reference_type (real_type); + + temp = arg = value_cast (real_type, arg); + } + } + return value_struct_elt (&temp, NULL, string, NULL, name); +} + struct value * evaluate_subexp_standard (struct type *expect_type, struct expression *exp, int *pos, @@ -1374,23 +1415,6 @@ evaluate_subexp_standard (struct type *e return value_literal_complex (arg1, arg2, builtin_type_f_complex_s16); case STRUCTOP_STRUCT: - tem = longest_to_int (exp->elts[pc + 1].longconst); - (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); - arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); - if (noside == EVAL_SKIP) - goto nosideret; - if (noside == EVAL_AVOID_SIDE_EFFECTS) - return value_zero (lookup_struct_elt_type (value_type (arg1), - &exp->elts[pc + 2].string, - 0), - lval_memory); - else - { - struct value *temp = arg1; - return value_struct_elt (&temp, NULL, &exp->elts[pc + 2].string, - NULL, "structure"); - } - case STRUCTOP_PTR: tem = longest_to_int (exp->elts[pc + 1].longconst); (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); @@ -1398,41 +1422,10 @@ evaluate_subexp_standard (struct type *e if (noside == EVAL_SKIP) goto nosideret; - /* 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. */ - { - struct type *type = value_type (arg1); - struct type *real_type; - int full, top, using_enc; - - if (objectprint && TYPE_TARGET_TYPE(type) && - (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS)) - { - real_type = value_rtti_target_type (arg1, &full, &top, &using_enc); - if (real_type) - { - if (TYPE_CODE (type) == TYPE_CODE_PTR) - real_type = lookup_pointer_type (real_type); - else - real_type = lookup_reference_type (real_type); - - arg1 = value_cast (real_type, arg1); - } - } - } - - if (noside == EVAL_AVOID_SIDE_EFFECTS) - return value_zero (lookup_struct_elt_type (value_type (arg1), - &exp->elts[pc + 2].string, - 0), - lval_memory); - else - { - struct value *temp = arg1; - return value_struct_elt (&temp, NULL, &exp->elts[pc + 2].string, - NULL, "structure pointer"); - } + return value_static_or_dynamic_member(arg1, &exp->elts[pc + 2].string, + (op == STRUCTOP_STRUCT) + ? "structure" : "structure pointer", + noside); case STRUCTOP_MEMBER: case STRUCTOP_MPTR: diff -Npur gdb.orig/testsuite/gdb.cp/class3.cc gdb/testsuite/gdb.cp/class3.cc --- gdb.orig/testsuite/gdb.cp/class3.cc 1969-12-31 16:00:00.000000000 -0800 +++ gdb/testsuite/gdb.cp/class3.cc 2008-08-19 10:06:13.000000000 -0700 @@ -0,0 +1,64 @@ +struct Base { + int x, y; + Base() : x(1), y(2) { } + virtual ~Base() { } + int fn() { return x + y; } + virtual int vfn() { return x + y; } +}; + +struct D1 : public Base { + D1() : y(20), d1(30) { } + int fn() { return x + y; } + virtual int vfn() { return x + y; } + int y, d1; +}; + + +struct D2 : public Base { + D2() : y(200), d2(300) { } + int fn() { return x + y; } + virtual int vfn() { return x + y; } + int y, d2; +}; + +struct D2v : public virtual Base { + D2v() : y(220), d2v(330) { } + int fn() { return x + y; } + virtual int vfn() { return x + y; } + int y, d2v; +}; + +struct D3: public virtual D1, public virtual D2 { + D3() : y(2000), d3(3000) { } + int fn() { return this->D1::x + y; } + virtual int vfn() { return this->D1::x + y; } + D1 *getD1() { return (D1*)this; } + D2 *getD2() { return (D2*)this; } + int y, d3; +}; + +int fn(Base *b) +{ + return b->y; +} + +int main() +{ + Base b; + D1 d1; + D2 d2; + D2v d2v; + D3 d3; + return (fn(&b) == 2 + && fn(&d1) == 2 + && fn(&d2) == 2 + && fn(&d2v) == 2 + && fn(d3.getD1()) == 2 + && fn(d3.getD2()) == 2) ? 0 : 1; +} + +int no_optimize(Base *b, D1 *d1, D2 *d2, D3 *d3) +{ + return b->fn() + d1->fn() + d2->fn() + d3->fn() + + b->vfn() + d1->vfn() + d2->vfn() + d3->vfn(); +} diff -Npur gdb.orig/testsuite/gdb.cp/class3.exp gdb/testsuite/gdb.cp/class3.exp --- gdb.orig/testsuite/gdb.cp/class3.exp 1969-12-31 16:00:00.000000000 -0800 +++ gdb/testsuite/gdb.cp/class3.exp 2008-08-19 10:12:52.000000000 -0700 @@ -0,0 +1,114 @@ +# 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 + } + +if { [skip_cplus_tests] } { continue } + +set prms_id 0 +set bug_id 0 + +set testfile "class3" +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} + +# Create and source the file that provides information about the compiler +# used to compile the test case. +if [get_compiler_info ${binfile} "c++"] { + return -1 +} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested ${testfile}.exp + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# ARGS is a list of quads: +# field +# its expected value +# whether b.field is a known failure +# whether b->field is a known failure +proc one_test {name args} { + foreach on_off {"on" "off"} { + gdb_test "set print object $on_off" "" + foreach extra $args { + set f [lindex $extra 0] + set v [lindex $extra 1] + set kfail1 [lindex $extra 2] + set kfail2 [lindex $extra 3] + + if {$kfail1 != ""} { + setup_kfail "*-*-*" $kfail1 + } + gdb_test "print b.$f" ".* = $v" "$name b.$f (print object $on_off)" + + if {$kfail2 != ""} { + setup_kfail "*-*-*" $kfail2 + } + gdb_test "print b->$f" ".* = $v" "$name b->$f (print object $on_off)" + } + } +} + + +if ![runto_main] then { + perror "couldn't run to main" + continue +} + +gdb_test "break fn" \ + "Breakpoint.*at.* file .*" "" + +gdb_test "continue" "Breakpoint .* at .*" "" + +# Looking at Base* +one_test "Base" {x 1} {y 2} { "fn()" 3 "gdb/NNN0" } \ + { "vfn()" 3 "gdb/NNN0" } +gdb_test "continue" "Breakpoint .* at .*" "" + +# Looking at D1* +one_test "D1" {x 1} {y 2} {"d1" 30} {"D1::y" 20 "gdb/NNN1"} \ + { "fn()" 3 "gdb/NNN0" } { "vfn()" 21 "gdb/NNN0" } +gdb_test "continue" "Breakpoint .* at .*" "" + +# Looking at D2* +one_test "D2" {x 1} {y 2} {"d2" 300} {"D2::y" 200 "gdb/NNN1"} \ + { "fn()" 3 "gdb/NNN0" } { "vfn()" 201 "gdb/NNN0" } +gdb_test "continue" "Breakpoint .* at .*" "" + +# Looking at D2v* +one_test "D2v" {x 1} {y 2} {"d2v" 330 "gdb/NNN2" "gdb/NNN2"} \ + {"D2::y" 220 "gdb/NNN2" "gdb/NNN2"} \ + { "fn()" 3 "gdb/NNN0" } { "vfn()" 221 "gdb/NNN0" } +gdb_test "continue" "Breakpoint .* at .*" "" + +# Looking at D1* part of D3 +one_test "D3::D1" {x 1} {y 2} {"d1" 30 "gdb/NNN3" "gdb/NNN3"} \ + {"D1::y" 20 "gdb/NNN3" "gdb/NNN3"} \ + { "fn()" 3 "gdb/NNN0" } { "vfn()" 21 "gdb/NNN0" "gdb/NNN0a" } +gdb_test "continue" "Breakpoint .* at .*" "" + +# Looking at D2* part of D3 +one_test "D3::D2" {x 1} {y 2} {"d2" 300 "gdb/NNN3" "gdb/NNN3"} \ + {"D2::y" 200 "gdb/NNN3" "gdb/NNN3"} \ + { "fn()" 3 "gdb/NNN0" } { "vfn()" 201 "gdb/NNN0" "gdb/NNN0a" } +gdb_test "continue" "Program exited normally\." "" ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' 2008-08-19 18:05 ` Paul Pluzhnikov @ 2008-08-26 16:45 ` Paul Pluzhnikov 2008-10-22 22:32 ` Ulrich Weigand 1 sibling, 0 replies; 9+ messages in thread From: Paul Pluzhnikov @ 2008-08-26 16:45 UTC (permalink / raw) To: gdb-patches Ping: http://sourceware.org/ml/gdb-patches/2008-08/msg00525.html -- Paul Pluzhnikov ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' 2008-08-19 18:05 ` Paul Pluzhnikov 2008-08-26 16:45 ` Paul Pluzhnikov @ 2008-10-22 22:32 ` Ulrich Weigand 1 sibling, 0 replies; 9+ messages in thread From: Ulrich Weigand @ 2008-10-22 22:32 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: Tom Tromey, gdb-patches Paul Pluzhnikov wrote: > gdb/ChangeLog > > 2008-08-19 Paul Pluzhnikov <ppluzhnikov@google.com> > > Changes to treat 'p.x' and 'p->x' the same. > * eval.c (value_static_or_dynamic_member): New. > (evaluate_subexp_standard): Call it. > > gdb/testsuite/ChangeLog > > 2008-08-19 Paul Pluzhnikov <ppluzhnikov@google.com> > > * gdb.cp/class3.exp: New test case. > * gdb.cp/class3.cc: New source file. Sorry for the late review. Tom just pointed me to this patch in the context of a different discussion ... In general, I think the approach looks right to me. However, the current patch does seem to have a couple of issues: > +static struct value * > +value_static_or_dynamic_member(struct value *arg, char *string, > + char *name, enum noside noside) > +{ > + struct type *type = value_type (arg); > + struct value *temp; > + > + if (noside == EVAL_AVOID_SIDE_EFFECTS) > + return value_zero (lookup_struct_elt_type (type, string, 0), > + lval_memory); > + temp = arg; > + { > + volatile struct gdb_exception except; > + struct value *v = NULL; > + TRY_CATCH (except, RETURN_MASK_ERROR) > + { > + v = value_struct_elt (&temp, NULL, string, NULL, name); > + } > + if (v) > + return v; > + } > + > + /* If we got here, value_struct_elt() above must have thrown, > + and there is no field 'name' in 'type'. > + Try dynamic type of 'arg' instead. */ > + > + if (TYPE_TARGET_TYPE(type) > + && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS)) > + { > + struct type *real_type; > + int full, top, using_enc; > + real_type = value_rtti_target_type (arg, &full, &top, &using_enc); > + if (real_type) > + { > + if (TYPE_CODE (type) == TYPE_CODE_PTR) > + real_type = lookup_pointer_type (real_type); > + else > + real_type = lookup_reference_type (real_type); > + > + temp = arg = value_cast (real_type, arg); > + } > + } > + return value_struct_elt (&temp, NULL, string, NULL, name); > +} You're treating looking up for type (EVAL_AVOID_SIDE_EFFECTS) differently from looking up for value; in the first case, you *never* look at the dynamic type -- that doesn't seem right to me (and in fact differs from what the original code does). Maybe you should add some "ptype p->x" tests to exercise this path as well. Also, you're calling value_static_or_dynamic_member both for class types *and* for pointer types -- but the whole dynamic type lookup as written only works for pointer types (starting with the if (TYPE_TARGET_TYPE)). If you really want to treat p.x and p->x equivalent in every case, why don't you call value_static_or_dynamic_member *always* with the class type (using a value_ind in the STRUCTOP_PTR case)? Then you'd use value_rtti_type instead of value_rtti_target_type. 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] 9+ messages in thread
end of thread, other threads:[~2008-10-22 22:32 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-07-17 21:49 [RFC] [patch] 'p->x' vs. 'p.x' and 'print object on' Paul Pluzhnikov 2008-07-22 0:53 ` Tom Tromey 2008-07-30 17:51 ` Paul Pluzhnikov 2008-08-07 17:31 ` Tom Tromey 2008-08-07 20:20 ` Daniel Jacobowitz 2008-08-11 15:09 ` Tom Tromey 2008-08-19 18:05 ` Paul Pluzhnikov 2008-08-26 16:45 ` Paul Pluzhnikov 2008-10-22 22:32 ` Ulrich Weigand
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox