gdb/doc/ChangeLog:
authorAnton Gorenkov <xgsa@sourceware.org>
Sat, 14 Apr 2012 12:18:50 +0000 (12:18 +0000)
committerAnton Gorenkov <xgsa@sourceware.org>
Sat, 14 Apr 2012 12:18:50 +0000 (12:18 +0000)
2012-04-14  Anton Gorenkov <xgsa@yandex.ru>

PR mi/13393
* gdb.texinfo (Print Settings): Extend the description for "set print
object".
(GDB/MI Variable Objects): Extend the description for -var-create and
-var-list-children.

gdb/testsuite/ChangeLog:

2012-04-14  Anton Gorenkov <xgsa@yandex.ru>

PR mi/13393
* gdb.mi/mi-var-rtti.cc: New file.
* gdb.mi/mi-var-rtti.exp: New file.
* lib/mi-support.exp (mi_varobj_update_with_child_type_change): New
function.
(mi_varobj_update_with_type_change): updated to avoid code duplication.

gdb/ChangeLog:

2012-04-14  Anton Gorenkov <xgsa@yandex.ru>

PR mi/13393
* value.c (value_actual_type): New function.
* value.h (value_actual_type): New declaration.
* varobj.c (update_type_if_necessary): New function.
(varobj_create): Call value_actual_type instead of
value_type.
(install_dynamic_child): distinct changed and type changed MI variable
objects.
(update_dynamic_varobj_children): Updated for install_dynamic_child
change.  All callers updated.
(varobj_update): Support for MI variable object type change if
the value changed and RTTI is used to determine the type.
(create_child_with_value): Call value_actual_type instead of
value_type.
(adjust_value_for_child_access): Extended with a new parameter which
specify whether the given value should be casted to enclosing type.
All callers updated.

gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.mi/mi-var-rtti.cc [new file with mode: 0644]
gdb/testsuite/gdb.mi/mi-var-rtti.exp [new file with mode: 0644]
gdb/testsuite/lib/mi-support.exp
gdb/value.c
gdb/value.h
gdb/varobj.c

index 98e5ef6..5ff4c97 100644 (file)
@@ -1,3 +1,23 @@
+2012-04-14  Anton Gorenkov <xgsa@yandex.ru>
+
+       PR mi/13393
+       * value.c (value_actual_type): New function.
+       * value.h (value_actual_type): New declaration.
+       * varobj.c (update_type_if_necessary): New function.
+       (varobj_create): Call value_actual_type instead of
+       value_type.
+       (install_dynamic_child): distinct changed and type changed MI variable
+       objects.
+       (update_dynamic_varobj_children): Updated for install_dynamic_child
+       change.  All callers updated.
+       (varobj_update): Support for MI variable object type change if 
+       the value changed and RTTI is used to determine the type.
+       (create_child_with_value): Call value_actual_type instead of
+       value_type.
+       (adjust_value_for_child_access): Extended with a new parameter which 
+       specify whether the given value should be casted to enclosing type.
+       All callers updated.
+
 2012-04-14  Yao Qi  <yao@codesourcery.com>
 
        Import gnulib module inttypes from git
index ecb3409..e288b9e 100644 (file)
@@ -1,3 +1,11 @@
+2012-04-14  Anton Gorenkov <xgsa@yandex.ru>
+
+       PR mi/13393
+       * gdb.texinfo (Print Settings): Extend the description for "set print
+       object".
+       (GDB/MI Variable Objects): Extend the description for -var-create and
+       -var-list-children.
+
 2012-04-11  Siva Chandra Reddy  <sivachandra@google.com>
 
        * gdb.texinfo (Examining Data): Document the 'explore' command.
index 37ffbb1..613782e 100644 (file)
@@ -8666,7 +8666,8 @@ When displaying a pointer to an object, identify the @emph{actual}
 the virtual function table.  Note that the virtual function table is
 required---this feature can only work for objects that have run-time
 type identification; a single virtual method in the object's declared
-type is sufficient.
+type is sufficient.  Note that this setting is also taken into account when
+working with variable objects via MI (@pxref{GDB/MI}).
 
 @item set print object off
 Display only the declared type of objects, without reference to the
@@ -29103,7 +29104,10 @@ will not be interesting.
 
 @item type
 The varobj's type.  This is a string representation of the type, as
-would be printed by the @value{GDBN} CLI.
+would be printed by the @value{GDBN} CLI.  If @samp{print object}
+(@pxref{Print Settings, set print object}) is set to @code{on}, the
+@emph{actual} (derived) type of the object is shown rather than the
+@emph{declared} one.
 
 @item thread-id
 If a variable object is bound to a specific thread, then this is the
@@ -29274,7 +29278,10 @@ Number of children this child has.  For a dynamic varobj, this will be
 0.
 
 @item type
-The type of the child.
+The type of the child.  If @samp{print object}
+(@pxref{Print Settings, set print object}) is set to @code{on}, the
+@emph{actual} (derived) type of the object is shown rather than the
+@emph{declared} one.
 
 @item value
 If values were requested, this is the value.
index bfcc42d..92ddbe8 100644 (file)
@@ -1,3 +1,12 @@
+2012-04-14  Anton Gorenkov <xgsa@yandex.ru>
+
+       PR mi/13393
+       * gdb.mi/mi-var-rtti.cc: New file.
+       * gdb.mi/mi-var-rtti.exp: New file.
+       * lib/mi-support.exp (mi_varobj_update_with_child_type_change): New
+       function.
+       (mi_varobj_update_with_type_change): updated to avoid code duplication.
+
 2012-04-11  Siva Chandra Reddy  <sivachandra@google.com>
 
        * gdb.python/Makefile.in: Add py-explore and py-explore-cc to
diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644 (file)
index 0000000..d05f660
--- /dev/null
@@ -0,0 +1,360 @@
+/* Copyright 2012 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/>.
+*/
+
+struct Base {
+    Base() : A(1) {}
+    virtual ~Base() {}  // Enforce type to have vtable
+    int A;
+};
+
+struct Derived : public Base {
+    Derived() : B(2), C(3) {}
+    int B;
+    int C;
+};
+
+
+void use_rtti_for_ptr_test ()
+{
+  /*: BEGIN: use_rtti_for_ptr :*/
+       Derived d;
+       Base* ptr = &d;
+       const Base* constPtr = &d;
+       Base* const ptrConst = &d;
+       Base const* const constPtrConst = &d;
+  /*:
+       set testname use_rtti_for_ptr
+       set_print_object off $testname
+       check_new_derived_without_rtti ptr {Base \*} $testname
+       check_new_derived_without_rtti constPtr {const Base \*} $testname
+       check_new_derived_without_rtti ptrConst {Base \* const} $testname
+       check_new_derived_without_rtti constPtrConst {const Base \* const} \
+               $testname
+
+       set_print_object on $testname
+       check_new_derived_with_rtti ptr {Derived \*} $testname
+       check_new_derived_with_rtti constPtr {const Derived \*} $testname
+       check_new_derived_with_rtti ptrConst {Derived \* const} $testname
+       check_new_derived_with_rtti constPtrConst {const Derived \* const} \
+               $testname
+  :*/
+       return;
+  /*: END: use_rtti_for_ptr :*/
+}
+
+
+void use_rtti_for_ref_test ()
+{
+  /*: BEGIN: use_rtti_for_ref :*/
+       Derived d;
+       Base& ref = d;
+       const Base& constRef = d;
+  /*: 
+       set testname use_rtti_for_ref
+       set_print_object off $testname
+       check_new_derived_without_rtti ref {Base \&} $testname
+       check_new_derived_without_rtti constRef {const Base \&} $testname
+
+       set_print_object on $testname
+       check_new_derived_with_rtti ref {Derived \&} $testname
+       check_new_derived_with_rtti constRef {const Derived \&} $testname
+  :*/
+       return;
+  /*: END: use_rtti_for_ref :*/
+}
+
+
+void use_rtti_for_ptr_child_test ()
+{
+  /*: BEGIN: use_rtti_for_ptr_child :*/
+       Derived d;
+       struct S {      
+               Base* ptr;
+               const Base* constPtr;
+               Base* const ptrConst;
+               Base const* const constPtrConst;
+               S ( Base* v ) :
+                       ptr ( v ),
+                       constPtr ( v ),
+                       ptrConst ( v ),
+                       constPtrConst ( v ) {}
+       } s ( &d );
+  /*: 
+       set testname use_rtti_for_ptr_child
+
+       set_print_object off $testname
+       mi_create_varobj VAR s "create varobj for s (without RTTI) in $testname"
+       mi_list_varobj_children VAR {
+           { VAR.public public 4 }
+       } "list children of s (without RTTI) in $testname"
+       mi_list_varobj_children VAR.public {
+           { VAR.public.ptr ptr 1 {Base \*} }
+           { VAR.public.constPtr constPtr 1 {const Base \*} }
+           { VAR.public.ptrConst ptrConst 1 {Base \* const} }
+           { VAR.public.constPtrConst constPtrConst 1 {const Base \* const} }
+       } "list children of s.public (without RTTI) in $testname"
+       check_derived_without_rtti VAR.public.ptr s.ptr $testname
+       check_derived_without_rtti VAR.public.constPtr s.constPtr $testname
+       check_derived_without_rtti VAR.public.ptrConst s.ptrConst $testname
+       check_derived_without_rtti VAR.public.constPtrConst s.constPtrConst \
+               $testname
+       mi_delete_varobj VAR "delete varobj for s (without RTTI) in $testname"
+
+       set_print_object on $testname
+       mi_create_varobj VAR s "create varobj for s (with RTTI) in $testname"
+       mi_list_varobj_children VAR {
+           { VAR.public public 4 }
+       } "list children of s (with RTTI) in $testname"
+       mi_list_varobj_children VAR.public {
+           { VAR.public.ptr ptr 2 {Derived \*} }
+           { VAR.public.constPtr constPtr 2 {const Derived \*} }
+           { VAR.public.ptrConst ptrConst 2 {Derived \* const} }
+           { VAR.public.constPtrConst constPtrConst 2 {const Derived \* const}}
+       } "list children of s.public (with RTTI) in $testname"
+       check_derived_with_rtti VAR.public.ptr s.ptr $testname
+       check_derived_with_rtti VAR.public.constPtr s.constPtr $testname
+       check_derived_with_rtti VAR.public.ptrConst s.ptrConst $testname
+       check_derived_with_rtti VAR.public.constPtrConst s.constPtrConst \
+               $testname
+       mi_delete_varobj VAR "delete varobj for s (with RTTI) in $testname"
+  :*/
+       return;
+  /*: END: use_rtti_for_ptr_child :*/
+}
+
+
+void use_rtti_for_ref_child_test ()
+{
+  /*: BEGIN: use_rtti_for_ref_child :*/
+       Derived d;
+       struct S {      
+               Base& ref;
+               const Base& constRef;
+               S ( Base& v ) :
+                       ref ( v ),
+                       constRef ( v ) {}
+       } s ( d );
+  /*: 
+       set testname use_rtti_for_ref_child
+
+       set_print_object off $testname
+       mi_create_varobj VAR s "create varobj for s (without RTTI) in $testname"
+       mi_list_varobj_children VAR {
+           { VAR.public public 2 }
+       } "list children of s (without RTTI) in $testname"
+       mi_list_varobj_children VAR.public {
+           { VAR.public.ref ref 1 {Base \&} }
+           { VAR.public.constRef constRef 1 {const Base \&} }
+       } "list children of s.public (without RTTI) in $testname"
+       check_derived_without_rtti VAR.public.ref s.ref $testname
+       check_derived_without_rtti VAR.public.constRef s.constRef  $testname
+       mi_delete_varobj VAR "delete varobj for s (without RTTI) in $testname"
+
+       set_print_object on $testname
+       mi_create_varobj VAR s "create varobj for s (with RTTI) in $testname"
+       mi_list_varobj_children VAR {
+           { VAR.public public 2 }
+       } "list children of s (with RTTI) in $testname"
+       mi_list_varobj_children VAR.public {
+           { VAR.public.ref ref 2 {Derived \&} }
+           { VAR.public.constRef constRef 2 {const Derived \&} }
+       } "list children of s.public (with RTTI) in $testname"
+       check_derived_with_rtti VAR.public.ref s.ref $testname
+       check_derived_with_rtti VAR.public.constRef s.constRef $testname
+       mi_delete_varobj VAR "delete varobj for s (with RTTI) in $testname"
+  :*/
+       return;
+  /*: END: use_rtti_for_ref_child :*/
+}
+
+
+struct First {
+    First() : F(-1) {}
+    int F;
+};
+
+
+struct MultipleDerived : public First, Base {
+    MultipleDerived() : B(2), C(3) {}
+    int B;
+    int C;
+};
+
+
+void use_rtti_with_multiple_inheritence_test ()
+{
+  /*: BEGIN: use_rtti_with_multiple_inheritence :*/
+       MultipleDerived d;
+       Base* ptr = &d;
+       Base& ref = d;
+  /*:
+       set testname use_rtti_with_multiple_inheritence
+       set_print_object off $testname
+       check_new_derived_without_rtti ptr {Base \*} $testname
+       check_new_derived_without_rtti ref {Base \&} $testname
+
+       set_print_object on $testname
+       mi_create_varobj_checked VAR ptr {MultipleDerived \*} \
+           "create varobj for ptr (with RTTI) in $testname"
+       mi_list_varobj_children VAR {
+           { VAR.First First 1 First }
+           { VAR.Base Base 1 Base }
+           { VAR.public public 2 }
+       } "list children of ptr (with RTTI) in $testname"
+       mi_list_varobj_children "VAR.First" {
+           { VAR.First.public public 1 }
+       } "list children of ptr.First (with RTTI) in $testname"
+       mi_list_varobj_children "VAR.First.public" {
+           { VAR.First.public.F F 0 int }
+       } "list children of ptr.Base.public (with RTTI) in $testname"
+       mi_list_varobj_children "VAR.Base" {
+           { VAR.Base.public public 1 }
+       } "list children of ptr.Base (with RTTI) in $testname"
+       mi_list_varobj_children "VAR.Base.public" {
+           { VAR.Base.public.A A 0 int }
+       } "list children of ptr.Base.public (with RTTI) in $testname"
+       mi_list_varobj_children "VAR.public" {
+           { VAR.public.B B 0 int }
+           { VAR.public.C C 0 int }
+       } "list children of ptr.public (with RTTI) in $testname"
+
+       mi_delete_varobj VAR \
+           "delete varobj for ptr (with RTTI) in $testname"
+  :*/
+       return;
+  /*: END: use_rtti_with_multiple_inheritence :*/
+}
+
+
+void type_update_when_use_rtti_test ()
+{
+  /*: BEGIN: type_update_when_use_rtti :*/
+       Derived d;
+  /*: 
+       set testname type_update_when_use_rtti
+
+       set_print_object on $testname
+       mi_create_varobj_checked PTR ptr {Base \*} \
+               "create varobj for ptr in $testname"
+       check_derived_children_without_rtti PTR ptr $testname
+
+       mi_create_varobj S s "create varobj for S in $testname"
+       mi_list_varobj_children S {
+           { S.public public 1 }
+       } "list children of s in $testname"
+       mi_list_varobj_children S.public {
+           { S.public.ptr ptr 1 {Base \*} }
+       } "list children of s.public in $testname"
+       check_derived_children_without_rtti S.public.ptr s.ptr $testname
+  :*/
+
+       Base* ptr = &d;
+       struct S {
+               Base* ptr;
+               S ( Base* v ) :
+                       ptr ( v ) {}
+       } s ( &d );
+  /*:
+       mi_varobj_update_with_type_change PTR {Derived \*} 2 \
+               "update ptr to derived in $testname"
+       check_derived_with_rtti PTR ptr $testname
+
+       mi_varobj_update_with_child_type_change S S.public.ptr {Derived \*} 2 \
+               "update s.ptr to derived in $testname"
+       check_derived_with_rtti S.public.ptr s.ptr $testname
+  :*/
+
+       ptr = 0;
+       s.ptr = 0;
+  /*:
+       mi_varobj_update_with_type_change PTR {Base \*} 1 \
+               "update ptr back to base type in $testname"
+       mi_delete_varobj PTR "delete varobj for ptr in $testname"
+
+       mi_varobj_update_with_child_type_change S S.public.ptr {Base \*} 1 \
+               "update s.ptr back to base type in $testname"
+       mi_delete_varobj S "delete varobj for s in $testname"
+  :*/
+       return;
+  /*: END: type_update_when_use_rtti :*/
+}
+
+
+void skip_type_update_when_not_use_rtti_test ()
+{
+  /*: BEGIN: skip_type_update_when_not_use_rtti :*/
+       Derived d;
+  /*: 
+       set testname skip_type_update_when_not_use_rtti
+
+       set_print_object off $testname
+       mi_create_varobj_checked PTR ptr {Base \*} \
+               "create varobj for ptr in $testname"
+       check_derived_children_without_rtti PTR ptr $testname
+
+       mi_create_varobj S s "create varobj for S in $testname"
+       mi_list_varobj_children S {
+           { S.public public 1 }
+       } "list children of s in $testname"
+       mi_list_varobj_children S.public {
+           { S.public.ptr ptr 1 {Base \*} }
+       } "list children of s.public in $testname"
+       check_derived_children_without_rtti S.public.ptr s.ptr $testname
+  :*/
+
+       Base* ptr = &d;
+       struct S {
+               Base* ptr;
+               S ( Base* v ) :
+                       ptr ( v ) {}
+       } s ( &d );
+  /*: 
+       mi_varobj_update PTR {PTR PTR.public.A} \
+               "update ptr to derived type in $testname"
+       check_derived_without_rtti PTR ptr $testname
+
+       mi_varobj_update S {S.public.ptr S.public.ptr.public.A} \
+               "update s to derived type in $testname"
+       check_derived_without_rtti S.public.ptr s.ptr $testname
+  :*/
+
+       ptr = 0;
+       s.ptr = 0;
+  /*:
+       mi_varobj_update PTR {PTR  PTR.public.A} \
+               "update ptr back to base type in $testname"
+       mi_delete_varobj PTR "delete varobj for ptr in $testname"
+
+       mi_varobj_update S {S.public.ptr S.public.ptr.public.A} \
+               "update s back to base type in $testname"
+       mi_delete_varobj S "delete varobj for s in $testname"
+  :*/
+       return;
+  /*: END: skip_type_update_when_not_use_rtti :*/
+}
+
+
+int main ()
+{
+       use_rtti_for_ptr_test();
+       use_rtti_for_ref_test();
+       use_rtti_for_ptr_child_test();
+       use_rtti_for_ref_child_test();
+       use_rtti_with_multiple_inheritence_test();
+       type_update_when_use_rtti_test();
+       skip_type_update_when_not_use_rtti_test();
+       return 0;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.exp b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
new file mode 100644 (file)
index 0000000..5e43bae
--- /dev/null
@@ -0,0 +1,124 @@
+# Copyright 2012 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 { [skip_cplus_tests] } { continue }
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if [mi_gdb_start] {
+    continue
+}
+
+set testfile mi-var-rtti
+set srcfile "$testfile.cc"
+set executable ${testfile}
+set binfile $objdir/$subdir/$testfile
+set opts {debug c++}
+
+if [build_executable $testfile.exp $executable $srcfile $opts] {
+    return -1;
+}
+
+mi_gdb_load ${binfile}
+
+mi_prepare_inline_tests $srcfile
+
+# Enable using RTTI to determine real types of the objects
+proc set_print_object {state testname} {
+    mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \
+        {\^done} \
+        "-interpreter-exec console \"set print object ${state}\" in $testname"
+}
+
+proc check_derived_children_without_rtti {varobj_name var_name testname} {
+    mi_list_varobj_children ${varobj_name} "
+        { ${varobj_name}.public public 1 }
+    " "list children of ${var_name} (without RTTI) in $testname"
+    mi_list_varobj_children "${varobj_name}.public" "
+        { ${varobj_name}.public.A A 0 int }
+    " "list children of ${var_name}.public (without RTTI) in $testname"
+}
+
+proc check_derived_content_without_rtti {varobj_name var_name testname} {
+    mi_check_varobj_value ${varobj_name}.public.A 1 \
+        "check ${var_name}->A (without RTTI) in $testname"
+}
+
+proc check_derived_without_rtti {varobj_name var_name testname} {
+    check_derived_children_without_rtti ${varobj_name} ${var_name} ${testname}
+    check_derived_content_without_rtti ${varobj_name} ${var_name} ${testname}
+}
+
+proc check_new_derived_without_rtti {var_name var_type testname} {
+    set varobj_name VAR
+    mi_create_varobj_checked ${varobj_name} ${var_name} ${var_type} \
+        "create varobj for ${var_name} (without RTTI) in ${testname}"
+    check_derived_without_rtti ${varobj_name} ${var_name} ${testname}
+    mi_delete_varobj ${varobj_name} \
+        "delete varobj for ${var_name} (without RTTI) in ${testname}"
+}
+
+proc check_derived_children_with_rtti {varobj_name var_name testname} {
+    mi_list_varobj_children ${varobj_name} "
+        { ${varobj_name}.Base Base 1 Base }
+        { ${varobj_name}.public public 2 }
+    " "list children of ${var_name} (with RTTI) in $testname"
+    mi_list_varobj_children "${varobj_name}.Base" "
+        { ${varobj_name}.Base.public public 1 }
+    " "list children of ${var_name}.Base (with RTTI) in $testname"
+    mi_list_varobj_children "${varobj_name}.Base.public" "
+        { ${varobj_name}.Base.public.A A 0 int }
+    " "list children of ${var_name}.Base.public (with RTTI) in $testname"
+    mi_list_varobj_children "${varobj_name}.public" "
+        { ${varobj_name}.public.B B 0 int }
+        { ${varobj_name}.public.C C 0 int }
+    " "list children of ${var_name}.public (with RTTI) in $testname"
+}
+
+proc check_derived_content_with_rtti {varobj_name var_name testname} {
+    mi_check_varobj_value ${varobj_name}.Base.public.A 1 \
+        "check ${var_name}->A (with RTTI) in $testname"
+    mi_check_varobj_value ${varobj_name}.public.B 2 \
+        "check ${var_name}->B (with RTTI) in $testname"
+    mi_check_varobj_value ${varobj_name}.public.C 3 \
+        "check ${var_name}->C (with RTTI) in $testname"
+}
+
+proc check_derived_with_rtti {varobj_name var_name testname} {
+    check_derived_children_with_rtti ${varobj_name} ${var_name} $testname
+    check_derived_content_with_rtti ${varobj_name} ${var_name} $testname
+}
+
+proc check_new_derived_with_rtti {var_name var_type testname} {
+    set varobj_name VAR
+    mi_create_varobj_checked ${varobj_name} ${var_name} ${var_type} \
+        "create varobj for ${var_name} (with RTTI) in $testname"
+    check_derived_with_rtti ${varobj_name} ${var_name} $testname
+    mi_delete_varobj ${varobj_name} \
+        "delete varobj for ${var_name} (with RTTI) in $testname"
+}
+
+mi_run_inline_test use_rtti_for_ptr
+mi_run_inline_test use_rtti_for_ref
+mi_run_inline_test use_rtti_for_ptr_child
+mi_run_inline_test use_rtti_for_ref_child
+mi_run_inline_test use_rtti_with_multiple_inheritence
+mi_run_inline_test type_update_when_use_rtti
+mi_run_inline_test skip_type_update_when_not_use_rtti
+
+mi_gdb_exit
+return 0
index 7f8642f..401565d 100644 (file)
@@ -1298,13 +1298,17 @@ proc mi_varobj_update { name expected testname } {
     mi_gdb_test "-var-update $name" $er $testname
 }
 
-proc mi_varobj_update_with_type_change { name new_type new_children testname } {
-    set v "{name=\"$name\",in_scope=\"true\",type_changed=\"true\",new_type=\"$new_type\",new_num_children=\"$new_children\",has_more=\".\"}"
+proc mi_varobj_update_with_child_type_change { name child_name new_type new_children testname } {
+    set v "{name=\"$child_name\",in_scope=\"true\",type_changed=\"true\",new_type=\"$new_type\",new_num_children=\"$new_children\",has_more=\".\"}"
     set er "\\^done,changelist=\\\[$v\\\]"
     verbose -log "Expecting: $er"
     mi_gdb_test "-var-update $name" $er $testname
 }
 
+proc mi_varobj_update_with_type_change { name new_type new_children testname } {
+    mi_varobj_update_with_child_type_change $name $name $new_type $new_children $testname
+}
+
 # A helper that turns a key/value list into a regular expression
 # matching some MI output.
 proc mi_varobj_update_kv_helper {list} {
index c23803a..eae3e2d 100644 (file)
@@ -834,6 +834,47 @@ value_enclosing_type (struct value *value)
   return value->enclosing_type;
 }
 
+/* Look at value.h for description.  */
+
+struct type *
+value_actual_type (struct value *value, int resolve_simple_types,
+                  int *real_type_found)
+{
+  struct value_print_options opts;
+  struct value *target;
+  struct type *result;
+
+  get_user_print_options (&opts);
+
+  if (real_type_found)
+    *real_type_found = 0;
+  result = value_type (value);
+  if (opts.objectprint)
+    {
+      if (TYPE_CODE (result) == TYPE_CODE_PTR
+         || TYPE_CODE (result) == TYPE_CODE_REF)
+        {
+          struct type *real_type;
+
+          real_type = value_rtti_indirect_type (value, NULL, NULL, NULL);
+          if (real_type)
+            {
+              if (real_type_found)
+                *real_type_found = 1;
+              result = real_type;
+            }
+        }
+      else if (resolve_simple_types)
+        {
+          if (real_type_found)
+            *real_type_found = 1;
+          result = value_enclosing_type (value);
+        }
+    }
+
+  return result;
+}
+
 static void
 require_not_optimized_out (const struct value *value)
 {
index 4d04a20..03aa5fd 100644 (file)
@@ -138,6 +138,22 @@ extern struct type *value_enclosing_type (struct value *);
 extern void set_value_enclosing_type (struct value *val,
                                      struct type *new_type);
 
+/* Returns value_type or value_enclosing_type depending on
+   value_print_options.objectprint.
+
+   If RESOLVE_SIMPLE_TYPES is 0 the enclosing type will be resolved
+   only for pointers and references, else it will be returned
+   for all the types (e.g. structures).  This option is useful
+   to prevent retrieving enclosing type for the base classes fields.
+
+   REAL_TYPE_FOUND is used to inform whether the real type was found
+   (or just static type was used).  The NULL may be passed if it is not
+   necessary. */
+
+extern struct type *value_actual_type (struct value *value,
+                                      int resolve_simple_types,
+                                      int *real_type_found);
+
 extern int value_pointed_to_offset (struct value *value);
 extern void set_value_pointed_to_offset (struct value *value, int val);
 extern int value_embedded_offset (struct value *value);
index 2e4dabf..3086499 100644 (file)
@@ -270,6 +270,9 @@ static void cppush (struct cpstack **pstack, char *name);
 
 static char *cppop (struct cpstack **pstack);
 
+static int update_type_if_necessary (struct varobj *var,
+                                    struct value *new_value);
+
 static int install_new_value (struct varobj *var, struct value *value, 
                              int initial);
 
@@ -716,8 +719,14 @@ varobj_create (char *objname,
 
          var->type = value_type (type_only_value);
        }
-      else 
-       var->type = value_type (value);
+       else
+         {
+           int real_type_found = 0;
+
+           var->type = value_actual_type (value, 0, &real_type_found);
+           if (real_type_found)
+             value = value_cast (var->type, value);
+         }
 
       /* Set language info */
       lang = variable_language (var);
@@ -1005,6 +1014,7 @@ restrict_range (VEC (varobj_p) *children, int *from, int *to)
 static void
 install_dynamic_child (struct varobj *var,
                       VEC (varobj_p) **changed,
+                      VEC (varobj_p) **type_changed,
                       VEC (varobj_p) **new,
                       VEC (varobj_p) **unchanged,
                       int *cchanged,
@@ -1027,12 +1037,18 @@ install_dynamic_child (struct varobj *var,
     {
       varobj_p existing = VEC_index (varobj_p, var->children, index);
 
+      int type_updated = update_type_if_necessary (existing, value);
+      if (type_updated)
+       {
+         if (type_changed)
+           VEC_safe_push (varobj_p, *type_changed, existing);
+       }
       if (install_new_value (existing, value, 0))
        {
-         if (changed)
+         if (!type_updated && changed)
            VEC_safe_push (varobj_p, *changed, existing);
        }
-      else if (unchanged)
+      else if (!type_updated && unchanged)
        VEC_safe_push (varobj_p, *unchanged, existing);
     }
 }
@@ -1055,6 +1071,7 @@ dynamic_varobj_has_child_method (struct varobj *var)
 static int
 update_dynamic_varobj_children (struct varobj *var,
                                VEC (varobj_p) **changed,
+                               VEC (varobj_p) **type_changed,
                                VEC (varobj_p) **new,
                                VEC (varobj_p) **unchanged,
                                int *cchanged,
@@ -1190,6 +1207,7 @@ update_dynamic_varobj_children (struct varobj *var,
          if (v == NULL)
            gdbpy_print_stack ();
          install_dynamic_child (var, can_mention ? changed : NULL,
+                                can_mention ? type_changed : NULL,
                                 can_mention ? new : NULL,
                                 can_mention ? unchanged : NULL,
                                 can_mention ? cchanged : NULL, i, name, v);
@@ -1245,7 +1263,7 @@ varobj_get_num_children (struct varobj *var)
 
          /* If we have a dynamic varobj, don't report -1 children.
             So, try to fetch some children first.  */
-         update_dynamic_varobj_children (var, NULL, NULL, NULL, &dummy,
+         update_dynamic_varobj_children (var, NULL, NULL, NULL, NULL, &dummy,
                                          0, 0, 0);
        }
       else
@@ -1271,8 +1289,8 @@ varobj_list_children (struct varobj *var, int *from, int *to)
       /* This, in theory, can result in the number of children changing without
         frontend noticing.  But well, calling -var-list-children on the same
         varobj twice is not something a sane frontend would do.  */
-      update_dynamic_varobj_children (var, NULL, NULL, NULL, &children_changed,
-                                     0, 0, *to);
+      update_dynamic_varobj_children (var, NULL, NULL, NULL, NULL,
+                                     &children_changed, 0, 0, *to);
       restrict_range (var->children, from, to);
       return var->children;
     }
@@ -1619,6 +1637,43 @@ install_new_value_visualizer (struct varobj *var)
 #endif
 }
 
+/* When using RTTI to determine variable type it may be changed in runtime when
+   the variable value is changed.  This function checks whether type of varobj
+   VAR will change when a new value NEW_VALUE is assigned and if it is so
+   updates the type of VAR.  */
+
+static int
+update_type_if_necessary (struct varobj *var, struct value *new_value)
+{
+  if (new_value)
+    {
+      struct value_print_options opts;
+
+      get_user_print_options (&opts);
+      if (opts.objectprint)
+       {
+         struct type *new_type;
+         char *curr_type_str, *new_type_str;
+
+         new_type = value_actual_type (new_value, 0, 0);
+         new_type_str = type_to_string (new_type);
+         curr_type_str = varobj_get_type (var);
+         if (strcmp (curr_type_str, new_type_str) != 0)
+           {
+             var->type = new_type;
+
+             /* This information may be not valid for a new type.  */
+             varobj_delete (var, NULL, 1);
+             VEC_free (varobj_p, var->children);
+             var->num_children = -1;
+             return 1;
+           }
+       }
+    }
+
+  return 0;
+}
+
 /* Assign a new value to a variable object.  If INITIAL is non-zero,
    this is the first assignement after the variable object was just
    created, or changed type.  In that case, just assign the value 
@@ -1948,8 +2003,9 @@ varobj_update (struct varobj **varp, int explicit)
         value_of_root variable dispose of the varobj if the type
         has changed.  */
       new = value_of_root (varp, &type_changed);
+      if (update_type_if_necessary(*varp, new))
+         type_changed = 1;
       r.varobj = *varp;
-
       r.type_changed = type_changed;
       if (install_new_value ((*varp), new, type_changed))
        r.changed = 1;
@@ -1990,6 +2046,8 @@ varobj_update (struct varobj **varp, int explicit)
          struct type *new_type;
 
          new = value_of_child (v->parent, v->index);
+         if (update_type_if_necessary(v, new))
+           r.type_changed = 1;
          if (new)
            new_type = value_type (new);
          else
@@ -2019,7 +2077,8 @@ varobj_update (struct varobj **varp, int explicit)
         invoked.  */
       if (v->pretty_printer)
        {
-         VEC (varobj_p) *changed = 0, *new = 0, *unchanged = 0;
+         VEC (varobj_p) *changed = 0, *type_changed = 0, *unchanged = 0;
+         VEC (varobj_p) *new = 0;
          int i, children_changed = 0;
 
          if (v->frozen)
@@ -2037,7 +2096,7 @@ varobj_update (struct varobj **varp, int explicit)
                 it.  */
              if (!varobj_has_more (v, 0))
                {
-                 update_dynamic_varobj_children (v, NULL, NULL, NULL,
+                 update_dynamic_varobj_children (v, NULL, NULL, NULL, NULL,
                                                  &dummy, 0, 0, 0);
                  if (varobj_has_more (v, 0))
                    r.changed = 1;
@@ -2051,8 +2110,8 @@ varobj_update (struct varobj **varp, int explicit)
 
          /* If update_dynamic_varobj_children returns 0, then we have
             a non-conforming pretty-printer, so we skip it.  */
-         if (update_dynamic_varobj_children (v, &changed, &new, &unchanged,
-                                             &children_changed, 1,
+         if (update_dynamic_varobj_children (v, &changed, &type_changed, &new,
+                                             &unchanged, &children_changed, 1,
                                              v->from, v->to))
            {
              if (children_changed || new)
@@ -2064,6 +2123,18 @@ varobj_update (struct varobj **varp, int explicit)
                 popped from the work stack first, and so will be
                 added to result first.  This does not affect
                 correctness, just "nicer".  */
+             for (i = VEC_length (varobj_p, type_changed) - 1; i >= 0; --i)
+               {
+                 varobj_p tmp = VEC_index (varobj_p, type_changed, i);
+                 varobj_update_result r = {0};
+
+                 /* Type may change only if value was changed.  */
+                 r.varobj = tmp;
+                 r.changed = 1;
+                 r.type_changed = 1;
+                 r.value_installed = 1;
+                 VEC_safe_push (varobj_update_result, stack, &r);
+               }
              for (i = VEC_length (varobj_p, changed) - 1; i >= 0; --i)
                {
                  varobj_p tmp = VEC_index (varobj_p, changed, i);
@@ -2090,9 +2161,10 @@ varobj_update (struct varobj **varp, int explicit)
              if (r.changed || r.children_changed)
                VEC_safe_push (varobj_update_result, result, &r);
 
-             /* Free CHANGED and UNCHANGED, but not NEW, because NEW
-                has been put into the result vector.  */
+             /* Free CHANGED, TYPE_CHANGED and UNCHANGED, but not NEW,
+                because NEW has been put into the result vector.  */
              VEC_free (varobj_p, changed);
+             VEC_free (varobj_p, type_changed);
              VEC_free (varobj_p, unchanged);
 
              continue;
@@ -2367,7 +2439,7 @@ create_child_with_value (struct varobj *parent, int index, const char *name,
   if (value != NULL)
     /* If the child had no evaluation errors, var->value
        will be non-NULL and contain a valid type.  */
-    child->type = value_type (value);
+    child->type = value_actual_type (value, 0, NULL);
   else
     /* Otherwise, we must compute the type.  */
     child->type = (*child->root->lang->type_of_child) (child->parent, 
@@ -2948,6 +3020,10 @@ varobj_floating_p (struct varobj *var)
    to all types and dereferencing pointers to
    structures.
 
+   If LOOKUP_ACTUAL_TYPE is set the enclosing type of the
+   value will be fetched and if it differs from static type
+   the value will be casted to it.
+
    Both TYPE and *TYPE should be non-null.  VALUE
    can be null if we want to only translate type.
    *VALUE can be null as well -- if the parent
@@ -2959,7 +3035,8 @@ varobj_floating_p (struct varobj *var)
 static void
 adjust_value_for_child_access (struct value **value,
                                  struct type **type,
-                                 int *was_ptr)
+                                 int *was_ptr,
+                                 int lookup_actual_type)
 {
   gdb_assert (type && *type);
 
@@ -3004,6 +3081,20 @@ adjust_value_for_child_access (struct value **value,
   /* The 'get_target_type' function calls check_typedef on
      result, so we can immediately check type code.  No
      need to call check_typedef here.  */
+
+  /* Access a real type of the value (if necessary and possible).  */
+  if (value && *value && lookup_actual_type)
+    {
+      struct type *enclosing_type;
+      int real_type_found = 0;
+
+      enclosing_type = value_actual_type (*value, 1, &real_type_found);
+      if (real_type_found)
+        {
+          *type = enclosing_type;
+          *value = value_cast (enclosing_type, *value);
+        }
+    }
 }
 
 /* Implement the "value_is_changeable_p" varobj callback for most
@@ -3044,7 +3135,7 @@ c_number_of_children (struct varobj *var)
   int children = 0;
   struct type *target;
 
-  adjust_value_for_child_access (NULL, &type, NULL);
+  adjust_value_for_child_access (NULL, &type, NULL, 0);
   target = get_target_type (type);
 
   switch (TYPE_CODE (type))
@@ -3160,7 +3251,7 @@ c_describe_child (struct varobj *parent, int index,
       *cfull_expression = NULL;
       parent_expression = varobj_get_path_expr (get_path_expr_parent (parent));
     }
-  adjust_value_for_child_access (&value, &type, &was_ptr);
+  adjust_value_for_child_access (&value, &type, &was_ptr, 0);
       
   switch (TYPE_CODE (type))
     {
@@ -3456,16 +3547,29 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
 static int
 cplus_number_of_children (struct varobj *var)
 {
+  struct value *value = NULL;
   struct type *type;
   int children, dont_know;
+  int lookup_actual_type = 0;
+  struct value_print_options opts;
 
   dont_know = 1;
   children = 0;
 
+  get_user_print_options (&opts);
+
   if (!CPLUS_FAKE_CHILD (var))
     {
       type = get_value_type (var);
-      adjust_value_for_child_access (NULL, &type, NULL);
+
+      /* It is necessary to access a real type (via RTTI).  */
+      if (opts.objectprint)
+        {
+          value = var->value;
+          lookup_actual_type = (TYPE_CODE (var->type) == TYPE_CODE_REF
+                               || TYPE_CODE (var->type) == TYPE_CODE_PTR);
+        }
+      adjust_value_for_child_access (&value, &type, NULL, lookup_actual_type);
 
       if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
          ((TYPE_CODE (type)) == TYPE_CODE_UNION))
@@ -3492,7 +3596,17 @@ cplus_number_of_children (struct varobj *var)
       int kids[3];
 
       type = get_value_type (var->parent);
-      adjust_value_for_child_access (NULL, &type, NULL);
+
+      /* It is necessary to access a real type (via RTTI).  */
+      if (opts.objectprint)
+        {
+         struct varobj *parent = var->parent;
+
+         value = parent->value;
+         lookup_actual_type = (TYPE_CODE (parent->type) == TYPE_CODE_REF
+                               || TYPE_CODE (parent->type) == TYPE_CODE_PTR);
+        }
+      adjust_value_for_child_access (&value, &type, NULL, lookup_actual_type);
 
       cplus_class_num_children (type, kids);
       if (strcmp (var->name, "public") == 0)
@@ -3574,7 +3688,10 @@ cplus_describe_child (struct varobj *parent, int index,
   struct value *value;
   struct type *type;
   int was_ptr;
+  int lookup_actual_type = 0;
   char *parent_expression = NULL;
+  struct varobj *var;
+  struct value_print_options opts;
 
   if (cname)
     *cname = NULL;
@@ -3585,24 +3702,18 @@ cplus_describe_child (struct varobj *parent, int index,
   if (cfull_expression)
     *cfull_expression = NULL;
 
-  if (CPLUS_FAKE_CHILD (parent))
-    {
-      value = parent->parent->value;
-      type = get_value_type (parent->parent);
-      if (cfull_expression)
-       parent_expression
-         = varobj_get_path_expr (get_path_expr_parent (parent->parent));
-    }
-  else
-    {
-      value = parent->value;
-      type = get_value_type (parent);
-      if (cfull_expression)
-       parent_expression
-         = varobj_get_path_expr (get_path_expr_parent (parent));
-    }
+  get_user_print_options (&opts);
+
+  var = (CPLUS_FAKE_CHILD (parent)) ? parent->parent : parent;
+  if (opts.objectprint)
+    lookup_actual_type = (TYPE_CODE (var->type) == TYPE_CODE_REF
+                         || TYPE_CODE (var->type) == TYPE_CODE_PTR);
+  value = var->value;
+  type = get_value_type (var);
+  if (cfull_expression)
+    parent_expression = varobj_get_path_expr (get_path_expr_parent (var));
 
-  adjust_value_for_child_access (&value, &type, &was_ptr);
+  adjust_value_for_child_access (&value, &type, &was_ptr, lookup_actual_type);
 
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT
       || TYPE_CODE (type) == TYPE_CODE_UNION)