public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* set print object on should affect MI varobjs (PR 13393)
@ 2011-12-02 19:50 xgsa
  2011-12-08  8:15 ` xgsa
  2011-12-20 17:47 ` Tom Tromey
  0 siblings, 2 replies; 47+ messages in thread
From: xgsa @ 2011-12-02 19:50 UTC (permalink / raw)
  To: gdb-patches

Hi,

(it seems that my previous message about this patch was lost somehow, so 
I resend it again; sorry, if I sent it twice)

The CLI "print" command shows user runtime type of C++ variable based on 
RTTI if "set print object" is "on". So gdb can show "real" type name for 
the objects that are stored by the interfaces and show their internals. 
Unfortunately, this information is not available via MI, so a lot of GUI 
tools that use it (e.g. Eclipse CDT) cann't access it.

Here is an example that demonstrates the case described above:

struct Base {
     Base() : a(1) {}
     virtual ~Base() {}  // Enforce type to have RTTI
     int a;
};

struct Derived : public Base {
     Derived() : b(2) {}
     int b;
};

int main() {
     Derived b;
     Base* aPtr = &b;   // aPtr should has Derived* type
     return 0;
}

This patch fixes this issue and also a few problems in gdb that are 
directly connected to the described above:
   - currently gdb loses cv-qualifiers after RTTI type access (e.g. if 
aPtr in the example above will be declared as "const Base*" then "print 
aPtr" in CLI with "set print object on" will return "Derived*" instead 
of "const Derived*".
   - "whatis" CLI command does not work for C++ references.

See also more details here: 
http://sourceware.org/bugzilla/show_bug.cgi?id=13393

A few tests on this feature are also added to gdb.mi test suite.
There is no regressions on gdb.mi & gdb.cp test suites (on 
x86-ubuntu-linux platform).


Thanks,
Anton


gdb/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

     PR 13393
     * gdb/valops.c (value_rtti_target_type): add support for references.
     Return also a reference or pointer type (because every caller do it 
after call that leads to code duplication)
     * gdb/c-valprint.c (c_value_print): updated for 
value_rtti_target_type() change.
     * gdb/eval.c (evaluate_subexp_standard): updated for 
value_rtti_target_type() change.
     * gdb/typeprint.c: updated for value_rtti_target_type() change.
     * gdb/gdbtypes.c: make make_qualified_type() available for 
value_rtti_target_type() from gdb/valops.c.
     * gdb/gdbtypes.h: declaraion of make_qualified_type() was added.
     * gdb/value.c(actual_type): new function.
     (coerce_ref): support for enclosing type setting for references (as 
it is done for pointers in value_ind())
     * gdb/value.h(actual_type): add prototype.
     * gdb/varobj.c(varobj_create): call actual_type() if necessary
     (create_child_with_value): call actual_type().
     (value_of_root): support for type change if the value changed and 
RTTI is used to determine type.
     (adjust_value_for_child_access): extended with a new parameter and 
cast given value to enclosing type is necessary.
     (c_number_of_children): update for extended 
adjust_value_for_child_access()
     (cplus_number_of_children): send a value as parameter if RTTI 
should be used to determine type
     (cplus_describe_child): determine whether RTTI type should be used

gdb/testsuite/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

     PR 13393
     * gdb.mi/mi-var-rtti.cc:: New file.
     * gdb.mi/mi-var-rtti.exp:: New file.


diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 3461b08..bfb3227 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -702,18 +702,8 @@ c_value_print (struct value *val, struct ui_file 
*stream,
            if (real_type)
          {
            /* RTTI entry found.  */
-          if (TYPE_CODE (type) == TYPE_CODE_PTR)
-            {
-              /* Create a pointer type pointing to the real
-             type.  */
-              type = lookup_pointer_type (real_type);
-            }
-          else
-            {
-              /* Create a reference type referencing the real
-             type.  */
-              type = lookup_reference_type (real_type);
-            }
+          type = real_type;
+
            /* Need to adjust pointer value.  */
            val = value_from_pointer (type, value_as_address (val) - top);

diff --git a/gdb/eval.c b/gdb/eval.c
index 5d758d1..7e6a6c5 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1992,14 +1992,7 @@ evaluate_subexp_standard (struct type *expect_type,
            {
              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);
-              }
            }
        }

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 614b813..52105e8 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -508,7 +508,7 @@ address_space_int_to_name (struct gdbarch *gdbarch, 
int space_flag)
     If STORAGE is non-NULL, create the new type instance there.
     STORAGE must be in the same obstack as TYPE.  */

-static struct type *
+struct type *
  make_qualified_type (struct type *type, int new_flags,
               struct type *storage)
  {
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 69f6b46..1192a4b 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1440,6 +1440,9 @@ extern int address_space_name_to_int (struct 
gdbarch *, char *);

  extern const char *address_space_int_to_name (struct gdbarch *, int);

+extern struct type * make_qualified_type (struct type *type, int new_flags,
+                        struct type *storage);
+
  extern struct type *make_type_with_address_space (struct type *type,
                            int space_identifier);

diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc 
b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..3622f3b
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -0,0 +1,184 @@
+/* Copyright 2011 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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti ptr {Base \*}
+    mi_var_rtti__check_derived_class_without_rtti constPtr {const Base \*}
+    mi_var_rtti__check_derived_class_without_rtti ptrConst {Base \* const}
+    mi_var_rtti__check_derived_class_without_rtti constPtrConst {const 
Base \* const}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti ptr {Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti constPtr {const Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti ptrConst {Derived \* const}
+    mi_var_rtti__check_derived_class_with_rtti constPtrConst {const 
Derived \* const}
+  :*/
+    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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti ref {Base \&}
+    mi_var_rtti__check_derived_class_without_rtti constRef {const Base \&}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti ref {Derived \&}
+    mi_var_rtti__check_derived_class_with_rtti constRef {const Derived \&}
+  :*/
+    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 );
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti s.ptr {Base \*}
+    mi_var_rtti__check_derived_class_without_rtti s.constPtr {const 
Base \*}
+    mi_var_rtti__check_derived_class_without_rtti s.ptrConst {Base \* 
const}
+    mi_var_rtti__check_derived_class_without_rtti s.constPtrConst 
{const Base \* const}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti s.ptr {Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti s.constPtr {const 
Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti s.ptrConst {Derived \* 
const}
+    mi_var_rtti__check_derived_class_with_rtti s.constPtrConst {const 
Derived \* const}
+  :*/
+    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 );
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti s.ref {Base \&}
+    mi_var_rtti__check_derived_class_without_rtti s.constRef {const 
Base \&}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti s.ref {Derived \&}
+    mi_var_rtti__check_derived_class_with_rtti s.constRef {const 
Derived \&}
+  :*/
+    return;
+  /*: END: use_rtti_for_ref_child :*/
+}
+
+void type_update_when_use_rtti_test ()
+{
+  /*: BEGIN: type_update_when_use_rtti :*/
+    Derived d;
+  /*:
+    mi_var_rtti__set_print_object on
+    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+  :*/
+
+    Base* ptr = &d;
+  /*:
+    mi_varobj_update_with_type_change VAR {Derived \*} 2 "update ptr"
+    mi_var_rtti__check_derived_children_with_rtti ptr
+    mi_var_rtti__check_derived_content_with_rtti ptr
+    mi_delete_varobj VAR "delete varobj for ptr"
+  :*/
+    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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+  :*/
+
+    Base* ptr = &d;
+  /*:
+    mi_varobj_update VAR {} "update ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+    mi_var_rtti__check_derived_content_without_rtti ptr
+    mi_delete_varobj VAR "delete varobj for ptr"
+  :*/
+    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();
+    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
index 0000000..2999e87
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -0,0 +1,108 @@
+# Copyright 2006, 2007, 2008, 2009, 2010, 2011 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 binfile $objdir/$subdir/$testfile
+
+if [get_compiler_info ${binfile} "c++"] {
+    return -1;
+}
+
+if {[gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug 
c++}] != ""} {
+  untested $testfile.exp
+  return -1
+}
+
+mi_gdb_load ${binfile}
+
+mi_prepare_inline_tests $srcfile
+
+# Enable using RTTI to determine real types of the objects
+proc mi_var_rtti__set_print_object {state} {
+  mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \
+    {\^done} \
+    "-interpreter-exec console \"set print object ${state}\""
+}
+
+proc mi_var_rtti__check_derived_children_without_rtti {var_name} {
+  mi_list_varobj_children VAR {
+     { VAR.public            public    1         }
+  } "list children of ${var_name} (without RTTI)"
+  mi_list_varobj_children "VAR.public" {
+     { VAR.public.A            A        0    int }
+  } "list children of ${var_name}.public (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_content_without_rtti {var_name} {
+  mi_check_varobj_value VAR.public.A        1 "check ${var_name}->A 
(without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_class_without_rtti {var_name var_type} {
+  mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj 
for ${var_name} (without RTTI)"
+  mi_var_rtti__check_derived_children_without_rtti ${var_name}
+  mi_var_rtti__check_derived_content_without_rtti ${var_name}
+  mi_delete_varobj VAR "delete varobj for ${var_name} (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_children_with_rtti {var_name} {
+    mi_list_varobj_children VAR {
+       { VAR.Base            Base    1    Base }
+       { VAR.public            public    2         }
+    } "list children of ${var_name} (with RTTI)"
+    mi_list_varobj_children "VAR.Base" {
+       { VAR.Base.public    public 1 }
+    } "list children of ${var_name}.Base (with RTTI)"
+    mi_list_varobj_children "VAR.Base.public" {
+       { VAR.Base.public.A    A        0    int    }
+    } "list children of ${var_name}.Base.public (with RTTI)"
+    mi_list_varobj_children "VAR.public" {
+       { VAR.public.B        B        0    int }
+       { VAR.public.C        C        0    int }
+    } "list children of ${var_name}.public (with RTTI)"
+}
+
+proc mi_var_rtti__check_derived_content_with_rtti {var_name} {
+    mi_check_varobj_value VAR.Base.public.A    1 "check ${var_name}->A 
(with RTTI)"
+    mi_check_varobj_value VAR.public.B        2 "check ${var_name}->B 
(with RTTI)"
+    mi_check_varobj_value VAR.public.C        3 "check ${var_name}->C 
(with RTTI)"
+}
+
+proc mi_var_rtti__check_derived_class_with_rtti {var_name var_type} {
+    mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj 
for ${var_name} (with RTTI)"
+    mi_var_rtti__check_derived_children_with_rtti ${var_name}
+    mi_var_rtti__check_derived_content_with_rtti ${var_name}
+    mi_delete_varobj VAR "delete varobj for ${var_name} (with RTTI)"
+}
+
+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 type_update_when_use_rtti
+mi_run_inline_test skip_type_update_when_not_use_rtti
+
+mi_gdb_exit
+return 0
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index cf4158d..8170e14 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
        if (((TYPE_CODE (type) == TYPE_CODE_PTR)
         || (TYPE_CODE (type) == TYPE_CODE_REF))
&& (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
-        {
-          real_type = value_rtti_target_type (val, &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);
-            }
-        }
+        real_type = value_rtti_target_type (val, &full, &top, &using_enc);
        else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
      real_type = value_rtti_type (val, &full, &top, &using_enc);
      }
diff --git a/gdb/valops.c b/gdb/valops.c
index cb39677..8f38cba 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -3528,8 +3528,7 @@ value_maybe_namespace_elt (const struct type *curtype,
    return result;
  }

-/* Given a pointer value V, find the real (RTTI) type of the object it
-   points to.
+/* Given a pointer or a reference value V, find its real (RTTI) type.

     Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
     and refer to the values computed for the object pointed to.  */
@@ -3539,12 +3538,35 @@ value_rtti_target_type (struct value *v, int *full,
              int *top, int *using_enc)
  {
    struct value *target;
+  struct type *type, *real_type;
+
+  type = value_type (v);
+  type = check_typedef (type);
+  if (TYPE_CODE(type) == TYPE_CODE_REF)
+    target = coerce_ref (v);
+  else if (TYPE_CODE(type) == TYPE_CODE_PTR)
+    target = value_ind (v);
+  else
+    return 0;
+
+  real_type = value_rtti_type (target, full, top, using_enc);

-  target = value_ind (v);
+  if (real_type)
+    {
+      // Copy qualifiers to the referenced object
+      real_type = make_qualified_type (real_type, TYPE_INSTANCE_FLAGS 
(value_type(target)), NULL);
+      if (TYPE_CODE(type) == TYPE_CODE_REF)
+        real_type = lookup_reference_type (real_type);
+      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+        real_type = lookup_pointer_type (real_type);
+      // Copy qualifiers to the pointer/reference
+      real_type = make_qualified_type (real_type, TYPE_INSTANCE_FLAGS 
(type), NULL);
+    }

-  return value_rtti_type (target, full, top, using_enc);
+  return real_type;
  }

+
  /* Given a value pointed to by ARGP, check its real run-time type, and
     if that is different from the enclosing type, create a new value
     using the real run-time type as the enclosing type (and of the same
diff --git a/gdb/value.c b/gdb/value.c
index d263d0c..a61df8e 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -821,6 +821,32 @@ value_enclosing_type (struct value *value)
    return value->enclosing_type;
  }

+struct type *
+actual_type (struct value *value, int resolve_simple_types)
+{
+  struct value_print_options opts;
+  struct value *target;
+  struct type *result;
+
+  get_user_print_options (&opts);
+
+  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_target_type ( value, 0, 0, 0 );
+      if (real_type)
+        result = real_type;
+    }
+    else if (resolve_simple_types)
+      result = value_enclosing_type (value);
+  }
+
+  return result;
+}
+
  static void
  require_not_optimized_out (const struct value *value)
  {
@@ -3114,6 +3140,7 @@ coerce_ref (struct value *arg)
  {
    struct type *value_type_arg_tmp = check_typedef (value_type (arg));
    struct value *retval;
+  struct type *enc_type;

    retval = coerce_ref_if_computed (arg);
    if (retval)
@@ -3122,9 +3149,23 @@ coerce_ref (struct value *arg)
    if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
      return arg;

-  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
+  enc_type = check_typedef (value_enclosing_type (arg));
+  enc_type = TYPE_TARGET_TYPE (enc_type);
+
+  retval = value_at_lazy (enc_type,
              unpack_pointer (value_type (arg),
                      value_contents (arg)));
+  /* Re-adjust type.  */
+  deprecated_set_value_type (retval, TYPE_TARGET_TYPE 
(value_type_arg_tmp));
+
+  /* Add embedding info.  */
+  set_value_enclosing_type (retval, enc_type);
+  set_value_embedded_offset (retval, value_pointed_to_offset (arg));
+
+  /* We may be pointing to an object of some derived type.  */
+  retval = value_full_object (retval, NULL, 0, 0, 0);
+
+  return retval;
  }

  struct value *
diff --git a/gdb/value.h b/gdb/value.h
index d2c58ec..57130e4 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -139,6 +139,15 @@ 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 also
+   all the types (e.g. for structures). This option is useful
+   to prevent retrieving enclosing type for the base classes fields */
+extern struct type *actual_type (struct value *value, int 
resolve_simple_types);
+
  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);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 7c68a93..22c045b 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -660,7 +660,16 @@ varobj_create (char *objname,
        var->type = value_type (type_only_value);
      }
        else
-    var->type = value_type (value);
+    {
+      struct type *enclosing_type;
+      var->type = value_type (value);
+      enclosing_type = actual_type(value, 0);
+      if (check_typedef (enclosing_type) != check_typedef (var->type))
+        {
+          var->type = enclosing_type;
+          value = value_cast (enclosing_type, value);
+        }
+    }

        install_new_value (var, value, 1 /* Initial assignment */);

@@ -2194,7 +2203,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 = actual_type (value, 0);
    else
      /* Otherwise, we must compute the type.  */
      child->type = (*child->root->lang->type_of_child) (child->parent,
@@ -2480,6 +2489,7 @@ static struct value *
  value_of_root (struct varobj **var_handle, int *type_changed)
  {
    struct varobj *var;
+  struct value_print_options opts;

    if (var_handle == NULL)
      return NULL;
@@ -2492,7 +2502,8 @@ value_of_root (struct varobj **var_handle, int 
*type_changed)
    if (!is_root_p (var))
      return NULL;

-  if (var->root->floating)
+  get_user_print_options (&opts);
+  if (var->root->floating || opts.objectprint)
      {
        struct varobj *tmp_var;
        char *old_type, *new_type;
@@ -2781,6 +2792,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
@@ -2792,8 +2807,10 @@ 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)
  {
+  struct type *enclosing_type;
    gdb_assert (type && *type);

    if (was_ptr)
@@ -2832,6 +2849,17 @@ 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)
+    {
+      enclosing_type = actual_type(*value, 1);
+      if (check_typedef (enclosing_type) != check_typedef (*type))
+        {
+          *type = enclosing_type;
+          *value = value_cast (enclosing_type, *value);
+        }
+    }
  }

  /* C */
@@ -2842,7 +2870,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))
@@ -2957,7 +2985,7 @@ c_describe_child (struct varobj *parent, int index,
        *cfull_expression = NULL;
        parent_expression = varobj_get_path_expr (parent);
      }
-  adjust_value_for_child_access (&value, &type, &was_ptr);
+  adjust_value_for_child_access (&value, &type, &was_ptr, 0);

    switch (TYPE_CODE (type))
      {
@@ -3223,16 +3251,27 @@ c_value_of_variable (struct varobj *var, enum 
varobj_display_formats format)
  static int
  cplus_number_of_children (struct varobj *var)
  {
+  struct value *value = 0;
    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))
@@ -3259,7 +3298,13 @@ 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)
+        {
+          value = var->parent->value;
+          lookup_actual_type = TYPE_CODE (var->parent->type) == 
TYPE_CODE_REF || TYPE_CODE (var->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)
@@ -3341,7 +3386,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;
@@ -3352,22 +3400,17 @@ 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 (parent->parent);
-    }
-  else
-    {
-      value = parent->value;
-      type = get_value_type (parent);
-      if (cfull_expression)
-    parent_expression = varobj_get_path_expr (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 (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)


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

* Re: set print object on should affect MI varobjs (PR 13393)
  2011-12-02 19:50 set print object on should affect MI varobjs (PR 13393) xgsa
@ 2011-12-08  8:15 ` xgsa
  2011-12-19 20:34   ` xgsa
  2011-12-20 17:47 ` Tom Tromey
  1 sibling, 1 reply; 47+ messages in thread
From: xgsa @ 2011-12-08  8:15 UTC (permalink / raw)
  To: gdb-patches

Hi,

I have sent my patch some time ago, but have not receive any response. 
Can somebody review and comment it? Are there any chances to get it in 
gdb 7.4?

Thanks,
Anton

-------- Original message --------
> Hi,
>
> (it seems that my previous message about this patch was lost somehow, 
> so I resend it again; sorry, if I sent it twice)
>
> The CLI "print" command shows user runtime type of C++ variable based 
> on RTTI if "set print object" is "on". So gdb can show "real" type 
> name for the objects that are stored by the interfaces and show their 
> internals. Unfortunately, this information is not available via MI, so 
> a lot of GUI tools that use it (e.g. Eclipse CDT) cann't access it.
>
> Here is an example that demonstrates the case described above:
>
> struct Base {
>     Base() : a(1) {}
>     virtual ~Base() {}  // Enforce type to have RTTI
>     int a;
> };
>
> struct Derived : public Base {
>     Derived() : b(2) {}
>     int b;
> };
>
> int main() {
>     Derived b;
>     Base* aPtr = &b;   // aPtr should has Derived* type
>     return 0;
> }
>
> This patch fixes this issue and also a few problems in gdb that are 
> directly connected to the described above:
>   - currently gdb loses cv-qualifiers after RTTI type access (e.g. if 
> aPtr in the example above will be declared as "const Base*" then 
> "print aPtr" in CLI with "set print object on" will return "Derived*" 
> instead of "const Derived*".
>   - "whatis" CLI command does not work for C++ references.
>
> See also more details here: 
> http://sourceware.org/bugzilla/show_bug.cgi?id=13393
>
> A few tests on this feature are also added to gdb.mi test suite.
> There is no regressions on gdb.mi & gdb.cp test suites (on 
> x86-ubuntu-linux platform).
>
>
> Thanks,
> Anton
>
>
> gdb/ChangeLog:
>
> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
>
>     PR 13393
>     * gdb/valops.c (value_rtti_target_type): add support for references.
>     Return also a reference or pointer type (because every caller do 
> it after call that leads to code duplication)
>     * gdb/c-valprint.c (c_value_print): updated for 
> value_rtti_target_type() change.
>     * gdb/eval.c (evaluate_subexp_standard): updated for 
> value_rtti_target_type() change.
>     * gdb/typeprint.c: updated for value_rtti_target_type() change.
>     * gdb/gdbtypes.c: make make_qualified_type() available for 
> value_rtti_target_type() from gdb/valops.c.
>     * gdb/gdbtypes.h: declaraion of make_qualified_type() was added.
>     * gdb/value.c(actual_type): new function.
>     (coerce_ref): support for enclosing type setting for references 
> (as it is done for pointers in value_ind())
>     * gdb/value.h(actual_type): add prototype.
>     * gdb/varobj.c(varobj_create): call actual_type() if necessary
>     (create_child_with_value): call actual_type().
>     (value_of_root): support for type change if the value changed and 
> RTTI is used to determine type.
>     (adjust_value_for_child_access): extended with a new parameter and 
> cast given value to enclosing type is necessary.
>     (c_number_of_children): update for extended 
> adjust_value_for_child_access()
>     (cplus_number_of_children): send a value as parameter if RTTI 
> should be used to determine type
>     (cplus_describe_child): determine whether RTTI type should be used
>
> gdb/testsuite/ChangeLog:
>
> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
>
>     PR 13393
>     * gdb.mi/mi-var-rtti.cc:: New file.
>     * gdb.mi/mi-var-rtti.exp:: New file.
>
>
> diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
> index 3461b08..bfb3227 100644
> --- a/gdb/c-valprint.c
> +++ b/gdb/c-valprint.c
> @@ -702,18 +702,8 @@ c_value_print (struct value *val, struct ui_file 
> *stream,
>            if (real_type)
>          {
>            /* RTTI entry found.  */
> -          if (TYPE_CODE (type) == TYPE_CODE_PTR)
> -            {
> -              /* Create a pointer type pointing to the real
> -             type.  */
> -              type = lookup_pointer_type (real_type);
> -            }
> -          else
> -            {
> -              /* Create a reference type referencing the real
> -             type.  */
> -              type = lookup_reference_type (real_type);
> -            }
> +          type = real_type;
> +
>            /* Need to adjust pointer value.  */
>            val = value_from_pointer (type, value_as_address (val) - top);
>
> diff --git a/gdb/eval.c b/gdb/eval.c
> index 5d758d1..7e6a6c5 100644
> --- a/gdb/eval.c
> +++ b/gdb/eval.c
> @@ -1992,14 +1992,7 @@ evaluate_subexp_standard (struct type 
> *expect_type,
>            {
>              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);
> -              }
>            }
>        }
>
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 614b813..52105e8 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -508,7 +508,7 @@ address_space_int_to_name (struct gdbarch 
> *gdbarch, int space_flag)
>     If STORAGE is non-NULL, create the new type instance there.
>     STORAGE must be in the same obstack as TYPE.  */
>
> -static struct type *
> +struct type *
>  make_qualified_type (struct type *type, int new_flags,
>               struct type *storage)
>  {
> diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
> index 69f6b46..1192a4b 100644
> --- a/gdb/gdbtypes.h
> +++ b/gdb/gdbtypes.h
> @@ -1440,6 +1440,9 @@ extern int address_space_name_to_int (struct 
> gdbarch *, char *);
>
>  extern const char *address_space_int_to_name (struct gdbarch *, int);
>
> +extern struct type * make_qualified_type (struct type *type, int 
> new_flags,
> +                        struct type *storage);
> +
>  extern struct type *make_type_with_address_space (struct type *type,
>                            int space_identifier);
>
> diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc 
> b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
> new file mode 100644
> index 0000000..3622f3b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
> @@ -0,0 +1,184 @@
> +/* Copyright 2011 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;
> +  /*:
> +    mi_var_rtti__set_print_object off
> +    mi_var_rtti__check_derived_class_without_rtti ptr {Base \*}
> +    mi_var_rtti__check_derived_class_without_rtti constPtr {const 
> Base \*}
> +    mi_var_rtti__check_derived_class_without_rtti ptrConst {Base \* 
> const}
> +    mi_var_rtti__check_derived_class_without_rtti constPtrConst 
> {const Base \* const}
> +
> +    mi_var_rtti__set_print_object on
> +    mi_var_rtti__check_derived_class_with_rtti ptr {Derived \*}
> +    mi_var_rtti__check_derived_class_with_rtti constPtr {const 
> Derived \*}
> +    mi_var_rtti__check_derived_class_with_rtti ptrConst {Derived \* 
> const}
> +    mi_var_rtti__check_derived_class_with_rtti constPtrConst {const 
> Derived \* const}
> +  :*/
> +    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;
> +  /*:
> +    mi_var_rtti__set_print_object off
> +    mi_var_rtti__check_derived_class_without_rtti ref {Base \&}
> +    mi_var_rtti__check_derived_class_without_rtti constRef {const 
> Base \&}
> +
> +    mi_var_rtti__set_print_object on
> +    mi_var_rtti__check_derived_class_with_rtti ref {Derived \&}
> +    mi_var_rtti__check_derived_class_with_rtti constRef {const 
> Derived \&}
> +  :*/
> +    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 );
> +  /*:
> +    mi_var_rtti__set_print_object off
> +    mi_var_rtti__check_derived_class_without_rtti s.ptr {Base \*}
> +    mi_var_rtti__check_derived_class_without_rtti s.constPtr {const 
> Base \*}
> +    mi_var_rtti__check_derived_class_without_rtti s.ptrConst {Base \* 
> const}
> +    mi_var_rtti__check_derived_class_without_rtti s.constPtrConst 
> {const Base \* const}
> +
> +    mi_var_rtti__set_print_object on
> +    mi_var_rtti__check_derived_class_with_rtti s.ptr {Derived \*}
> +    mi_var_rtti__check_derived_class_with_rtti s.constPtr {const 
> Derived \*}
> +    mi_var_rtti__check_derived_class_with_rtti s.ptrConst {Derived \* 
> const}
> +    mi_var_rtti__check_derived_class_with_rtti s.constPtrConst {const 
> Derived \* const}
> +  :*/
> +    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 );
> +  /*:
> +    mi_var_rtti__set_print_object off
> +    mi_var_rtti__check_derived_class_without_rtti s.ref {Base \&}
> +    mi_var_rtti__check_derived_class_without_rtti s.constRef {const 
> Base \&}
> +
> +    mi_var_rtti__set_print_object on
> +    mi_var_rtti__check_derived_class_with_rtti s.ref {Derived \&}
> +    mi_var_rtti__check_derived_class_with_rtti s.constRef {const 
> Derived \&}
> +  :*/
> +    return;
> +  /*: END: use_rtti_for_ref_child :*/
> +}
> +
> +void type_update_when_use_rtti_test ()
> +{
> +  /*: BEGIN: type_update_when_use_rtti :*/
> +    Derived d;
> +  /*:
> +    mi_var_rtti__set_print_object on
> +    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
> +    mi_var_rtti__check_derived_children_without_rtti ptr
> +  :*/
> +
> +    Base* ptr = &d;
> +  /*:
> +    mi_varobj_update_with_type_change VAR {Derived \*} 2 "update ptr"
> +    mi_var_rtti__check_derived_children_with_rtti ptr
> +    mi_var_rtti__check_derived_content_with_rtti ptr
> +    mi_delete_varobj VAR "delete varobj for ptr"
> +  :*/
> +    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;
> +  /*:
> +    mi_var_rtti__set_print_object off
> +    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
> +    mi_var_rtti__check_derived_children_without_rtti ptr
> +  :*/
> +
> +    Base* ptr = &d;
> +  /*:
> +    mi_varobj_update VAR {} "update ptr"
> +    mi_var_rtti__check_derived_children_without_rtti ptr
> +    mi_var_rtti__check_derived_content_without_rtti ptr
> +    mi_delete_varobj VAR "delete varobj for ptr"
> +  :*/
> +    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();
> +    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
> index 0000000..2999e87
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
> @@ -0,0 +1,108 @@
> +# Copyright 2006, 2007, 2008, 2009, 2010, 2011 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 binfile $objdir/$subdir/$testfile
> +
> +if [get_compiler_info ${binfile} "c++"] {
> +    return -1;
> +}
> +
> +if {[gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug 
> c++}] != ""} {
> +  untested $testfile.exp
> +  return -1
> +}
> +
> +mi_gdb_load ${binfile}
> +
> +mi_prepare_inline_tests $srcfile
> +
> +# Enable using RTTI to determine real types of the objects
> +proc mi_var_rtti__set_print_object {state} {
> +  mi_gdb_test "-interpreter-exec console \"set print object 
> ${state}\"" \
> +    {\^done} \
> +    "-interpreter-exec console \"set print object ${state}\""
> +}
> +
> +proc mi_var_rtti__check_derived_children_without_rtti {var_name} {
> +  mi_list_varobj_children VAR {
> +     { VAR.public            public    1         }
> +  } "list children of ${var_name} (without RTTI)"
> +  mi_list_varobj_children "VAR.public" {
> +     { VAR.public.A            A        0    int }
> +  } "list children of ${var_name}.public (without RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_content_without_rtti {var_name} {
> +  mi_check_varobj_value VAR.public.A        1 "check ${var_name}->A 
> (without RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_class_without_rtti {var_name var_type} {
> +  mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj 
> for ${var_name} (without RTTI)"
> +  mi_var_rtti__check_derived_children_without_rtti ${var_name}
> +  mi_var_rtti__check_derived_content_without_rtti ${var_name}
> +  mi_delete_varobj VAR "delete varobj for ${var_name} (without RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_children_with_rtti {var_name} {
> +    mi_list_varobj_children VAR {
> +       { VAR.Base            Base    1    Base }
> +       { VAR.public            public    2         }
> +    } "list children of ${var_name} (with RTTI)"
> +    mi_list_varobj_children "VAR.Base" {
> +       { VAR.Base.public    public 1 }
> +    } "list children of ${var_name}.Base (with RTTI)"
> +    mi_list_varobj_children "VAR.Base.public" {
> +       { VAR.Base.public.A    A        0    int    }
> +    } "list children of ${var_name}.Base.public (with RTTI)"
> +    mi_list_varobj_children "VAR.public" {
> +       { VAR.public.B        B        0    int }
> +       { VAR.public.C        C        0    int }
> +    } "list children of ${var_name}.public (with RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_content_with_rtti {var_name} {
> +    mi_check_varobj_value VAR.Base.public.A    1 "check 
> ${var_name}->A (with RTTI)"
> +    mi_check_varobj_value VAR.public.B        2 "check ${var_name}->B 
> (with RTTI)"
> +    mi_check_varobj_value VAR.public.C        3 "check ${var_name}->C 
> (with RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_class_with_rtti {var_name var_type} {
> +    mi_create_varobj_checked VAR ${var_name} ${var_type} "create 
> varobj for ${var_name} (with RTTI)"
> +    mi_var_rtti__check_derived_children_with_rtti ${var_name}
> +    mi_var_rtti__check_derived_content_with_rtti ${var_name}
> +    mi_delete_varobj VAR "delete varobj for ${var_name} (with RTTI)"
> +}
> +
> +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 type_update_when_use_rtti
> +mi_run_inline_test skip_type_update_when_not_use_rtti
> +
> +mi_gdb_exit
> +return 0
> diff --git a/gdb/typeprint.c b/gdb/typeprint.c
> index cf4158d..8170e14 100644
> --- a/gdb/typeprint.c
> +++ b/gdb/typeprint.c
> @@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
>        if (((TYPE_CODE (type) == TYPE_CODE_PTR)
>         || (TYPE_CODE (type) == TYPE_CODE_REF))
> && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
> -        {
> -          real_type = value_rtti_target_type (val, &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);
> -            }
> -        }
> +        real_type = value_rtti_target_type (val, &full, &top, 
> &using_enc);
>        else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
>      real_type = value_rtti_type (val, &full, &top, &using_enc);
>      }
> diff --git a/gdb/valops.c b/gdb/valops.c
> index cb39677..8f38cba 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -3528,8 +3528,7 @@ value_maybe_namespace_elt (const struct type 
> *curtype,
>    return result;
>  }
>
> -/* Given a pointer value V, find the real (RTTI) type of the object it
> -   points to.
> +/* Given a pointer or a reference value V, find its real (RTTI) type.
>
>     Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
>     and refer to the values computed for the object pointed to.  */
> @@ -3539,12 +3538,35 @@ value_rtti_target_type (struct value *v, int 
> *full,
>              int *top, int *using_enc)
>  {
>    struct value *target;
> +  struct type *type, *real_type;
> +
> +  type = value_type (v);
> +  type = check_typedef (type);
> +  if (TYPE_CODE(type) == TYPE_CODE_REF)
> +    target = coerce_ref (v);
> +  else if (TYPE_CODE(type) == TYPE_CODE_PTR)
> +    target = value_ind (v);
> +  else
> +    return 0;
> +
> +  real_type = value_rtti_type (target, full, top, using_enc);
>
> -  target = value_ind (v);
> +  if (real_type)
> +    {
> +      // Copy qualifiers to the referenced object
> +      real_type = make_qualified_type (real_type, TYPE_INSTANCE_FLAGS 
> (value_type(target)), NULL);
> +      if (TYPE_CODE(type) == TYPE_CODE_REF)
> +        real_type = lookup_reference_type (real_type);
> +      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
> +        real_type = lookup_pointer_type (real_type);
> +      // Copy qualifiers to the pointer/reference
> +      real_type = make_qualified_type (real_type, TYPE_INSTANCE_FLAGS 
> (type), NULL);
> +    }
>
> -  return value_rtti_type (target, full, top, using_enc);
> +  return real_type;
>  }
>
> +
>  /* Given a value pointed to by ARGP, check its real run-time type, and
>     if that is different from the enclosing type, create a new value
>     using the real run-time type as the enclosing type (and of the same
> diff --git a/gdb/value.c b/gdb/value.c
> index d263d0c..a61df8e 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -821,6 +821,32 @@ value_enclosing_type (struct value *value)
>    return value->enclosing_type;
>  }
>
> +struct type *
> +actual_type (struct value *value, int resolve_simple_types)
> +{
> +  struct value_print_options opts;
> +  struct value *target;
> +  struct type *result;
> +
> +  get_user_print_options (&opts);
> +
> +  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_target_type ( value, 0, 0, 0 );
> +      if (real_type)
> +        result = real_type;
> +    }
> +    else if (resolve_simple_types)
> +      result = value_enclosing_type (value);
> +  }
> +
> +  return result;
> +}
> +
>  static void
>  require_not_optimized_out (const struct value *value)
>  {
> @@ -3114,6 +3140,7 @@ coerce_ref (struct value *arg)
>  {
>    struct type *value_type_arg_tmp = check_typedef (value_type (arg));
>    struct value *retval;
> +  struct type *enc_type;
>
>    retval = coerce_ref_if_computed (arg);
>    if (retval)
> @@ -3122,9 +3149,23 @@ coerce_ref (struct value *arg)
>    if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
>      return arg;
>
> -  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
> +  enc_type = check_typedef (value_enclosing_type (arg));
> +  enc_type = TYPE_TARGET_TYPE (enc_type);
> +
> +  retval = value_at_lazy (enc_type,
>              unpack_pointer (value_type (arg),
>                      value_contents (arg)));
> +  /* Re-adjust type.  */
> +  deprecated_set_value_type (retval, TYPE_TARGET_TYPE 
> (value_type_arg_tmp));
> +
> +  /* Add embedding info.  */
> +  set_value_enclosing_type (retval, enc_type);
> +  set_value_embedded_offset (retval, value_pointed_to_offset (arg));
> +
> +  /* We may be pointing to an object of some derived type.  */
> +  retval = value_full_object (retval, NULL, 0, 0, 0);
> +
> +  return retval;
>  }
>
>  struct value *
> diff --git a/gdb/value.h b/gdb/value.h
> index d2c58ec..57130e4 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -139,6 +139,15 @@ 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 also
> +   all the types (e.g. for structures). This option is useful
> +   to prevent retrieving enclosing type for the base classes fields */
> +extern struct type *actual_type (struct value *value, int 
> resolve_simple_types);
> +
>  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);
> diff --git a/gdb/varobj.c b/gdb/varobj.c
> index 7c68a93..22c045b 100644
> --- a/gdb/varobj.c
> +++ b/gdb/varobj.c
> @@ -660,7 +660,16 @@ varobj_create (char *objname,
>        var->type = value_type (type_only_value);
>      }
>        else
> -    var->type = value_type (value);
> +    {
> +      struct type *enclosing_type;
> +      var->type = value_type (value);
> +      enclosing_type = actual_type(value, 0);
> +      if (check_typedef (enclosing_type) != check_typedef (var->type))
> +        {
> +          var->type = enclosing_type;
> +          value = value_cast (enclosing_type, value);
> +        }
> +    }
>
>        install_new_value (var, value, 1 /* Initial assignment */);
>
> @@ -2194,7 +2203,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 = actual_type (value, 0);
>    else
>      /* Otherwise, we must compute the type.  */
>      child->type = (*child->root->lang->type_of_child) (child->parent,
> @@ -2480,6 +2489,7 @@ static struct value *
>  value_of_root (struct varobj **var_handle, int *type_changed)
>  {
>    struct varobj *var;
> +  struct value_print_options opts;
>
>    if (var_handle == NULL)
>      return NULL;
> @@ -2492,7 +2502,8 @@ value_of_root (struct varobj **var_handle, int 
> *type_changed)
>    if (!is_root_p (var))
>      return NULL;
>
> -  if (var->root->floating)
> +  get_user_print_options (&opts);
> +  if (var->root->floating || opts.objectprint)
>      {
>        struct varobj *tmp_var;
>        char *old_type, *new_type;
> @@ -2781,6 +2792,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
> @@ -2792,8 +2807,10 @@ 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)
>  {
> +  struct type *enclosing_type;
>    gdb_assert (type && *type);
>
>    if (was_ptr)
> @@ -2832,6 +2849,17 @@ 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)
> +    {
> +      enclosing_type = actual_type(*value, 1);
> +      if (check_typedef (enclosing_type) != check_typedef (*type))
> +        {
> +          *type = enclosing_type;
> +          *value = value_cast (enclosing_type, *value);
> +        }
> +    }
>  }
>
>  /* C */
> @@ -2842,7 +2870,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))
> @@ -2957,7 +2985,7 @@ c_describe_child (struct varobj *parent, int index,
>        *cfull_expression = NULL;
>        parent_expression = varobj_get_path_expr (parent);
>      }
> -  adjust_value_for_child_access (&value, &type, &was_ptr);
> +  adjust_value_for_child_access (&value, &type, &was_ptr, 0);
>
>    switch (TYPE_CODE (type))
>      {
> @@ -3223,16 +3251,27 @@ c_value_of_variable (struct varobj *var, enum 
> varobj_display_formats format)
>  static int
>  cplus_number_of_children (struct varobj *var)
>  {
> +  struct value *value = 0;
>    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))
> @@ -3259,7 +3298,13 @@ 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)
> +        {
> +          value = var->parent->value;
> +          lookup_actual_type = TYPE_CODE (var->parent->type) == 
> TYPE_CODE_REF || TYPE_CODE (var->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)
> @@ -3341,7 +3386,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;
> @@ -3352,22 +3400,17 @@ 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 (parent->parent);
> -    }
> -  else
> -    {
> -      value = parent->value;
> -      type = get_value_type (parent);
> -      if (cfull_expression)
> -    parent_expression = varobj_get_path_expr (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 (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)
>
>
>
>


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

* Re: set print object on should affect MI varobjs (PR 13393)
  2011-12-08  8:15 ` xgsa
@ 2011-12-19 20:34   ` xgsa
  0 siblings, 0 replies; 47+ messages in thread
From: xgsa @ 2011-12-19 20:34 UTC (permalink / raw)
  To: gdb-patches

Just a reminder: please, review this patch.

Thanks,
Anton

-------- Original message --------
> Hi,
>
> I have sent my patch some time ago, but have not receive any response. 
> Can somebody review and comment it? Are there any chances to get it in 
> gdb 7.4?
>
> Thanks,
> Anton
>
> -------- Original message --------
>> Hi,
>>
>> (it seems that my previous message about this patch was lost somehow, 
>> so I resend it again; sorry, if I sent it twice)
>>
>> The CLI "print" command shows user runtime type of C++ variable based 
>> on RTTI if "set print object" is "on". So gdb can show "real" type 
>> name for the objects that are stored by the interfaces and show their 
>> internals. Unfortunately, this information is not available via MI, 
>> so a lot of GUI tools that use it (e.g. Eclipse CDT) cann't access it.
>>
>> Here is an example that demonstrates the case described above:
>>
>> struct Base {
>>     Base() : a(1) {}
>>     virtual ~Base() {}  // Enforce type to have RTTI
>>     int a;
>> };
>>
>> struct Derived : public Base {
>>     Derived() : b(2) {}
>>     int b;
>> };
>>
>> int main() {
>>     Derived b;
>>     Base* aPtr = &b;   // aPtr should has Derived* type
>>     return 0;
>> }
>>
>> This patch fixes this issue and also a few problems in gdb that are 
>> directly connected to the described above:
>>   - currently gdb loses cv-qualifiers after RTTI type access (e.g. if 
>> aPtr in the example above will be declared as "const Base*" then 
>> "print aPtr" in CLI with "set print object on" will return "Derived*" 
>> instead of "const Derived*".
>>   - "whatis" CLI command does not work for C++ references.
>>
>> See also more details here: 
>> http://sourceware.org/bugzilla/show_bug.cgi?id=13393
>>
>> A few tests on this feature are also added to gdb.mi test suite.
>> There is no regressions on gdb.mi & gdb.cp test suites (on 
>> x86-ubuntu-linux platform).
>>
>>
>> Thanks,
>> Anton
>>
>>
>> gdb/ChangeLog:
>>
>> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
>>
>>     PR 13393
>>     * gdb/valops.c (value_rtti_target_type): add support for references.
>>     Return also a reference or pointer type (because every caller do 
>> it after call that leads to code duplication)
>>     * gdb/c-valprint.c (c_value_print): updated for 
>> value_rtti_target_type() change.
>>     * gdb/eval.c (evaluate_subexp_standard): updated for 
>> value_rtti_target_type() change.
>>     * gdb/typeprint.c: updated for value_rtti_target_type() change.
>>     * gdb/gdbtypes.c: make make_qualified_type() available for 
>> value_rtti_target_type() from gdb/valops.c.
>>     * gdb/gdbtypes.h: declaraion of make_qualified_type() was added.
>>     * gdb/value.c(actual_type): new function.
>>     (coerce_ref): support for enclosing type setting for references 
>> (as it is done for pointers in value_ind())
>>     * gdb/value.h(actual_type): add prototype.
>>     * gdb/varobj.c(varobj_create): call actual_type() if necessary
>>     (create_child_with_value): call actual_type().
>>     (value_of_root): support for type change if the value changed and 
>> RTTI is used to determine type.
>>     (adjust_value_for_child_access): extended with a new parameter 
>> and cast given value to enclosing type is necessary.
>>     (c_number_of_children): update for extended 
>> adjust_value_for_child_access()
>>     (cplus_number_of_children): send a value as parameter if RTTI 
>> should be used to determine type
>>     (cplus_describe_child): determine whether RTTI type should be used
>>
>> gdb/testsuite/ChangeLog:
>>
>> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
>>
>>     PR 13393
>>     * gdb.mi/mi-var-rtti.cc:: New file.
>>     * gdb.mi/mi-var-rtti.exp:: New file.
>>
>>
>> diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
>> index 3461b08..bfb3227 100644
>> --- a/gdb/c-valprint.c
>> +++ b/gdb/c-valprint.c
>> @@ -702,18 +702,8 @@ c_value_print (struct value *val, struct ui_file 
>> *stream,
>>            if (real_type)
>>          {
>>            /* RTTI entry found.  */
>> -          if (TYPE_CODE (type) == TYPE_CODE_PTR)
>> -            {
>> -              /* Create a pointer type pointing to the real
>> -             type.  */
>> -              type = lookup_pointer_type (real_type);
>> -            }
>> -          else
>> -            {
>> -              /* Create a reference type referencing the real
>> -             type.  */
>> -              type = lookup_reference_type (real_type);
>> -            }
>> +          type = real_type;
>> +
>>            /* Need to adjust pointer value.  */
>>            val = value_from_pointer (type, value_as_address (val) - 
>> top);
>>
>> diff --git a/gdb/eval.c b/gdb/eval.c
>> index 5d758d1..7e6a6c5 100644
>> --- a/gdb/eval.c
>> +++ b/gdb/eval.c
>> @@ -1992,14 +1992,7 @@ evaluate_subexp_standard (struct type 
>> *expect_type,
>>            {
>>              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);
>> -              }
>>            }
>>        }
>>
>> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
>> index 614b813..52105e8 100644
>> --- a/gdb/gdbtypes.c
>> +++ b/gdb/gdbtypes.c
>> @@ -508,7 +508,7 @@ address_space_int_to_name (struct gdbarch 
>> *gdbarch, int space_flag)
>>     If STORAGE is non-NULL, create the new type instance there.
>>     STORAGE must be in the same obstack as TYPE.  */
>>
>> -static struct type *
>> +struct type *
>>  make_qualified_type (struct type *type, int new_flags,
>>               struct type *storage)
>>  {
>> diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
>> index 69f6b46..1192a4b 100644
>> --- a/gdb/gdbtypes.h
>> +++ b/gdb/gdbtypes.h
>> @@ -1440,6 +1440,9 @@ extern int address_space_name_to_int (struct 
>> gdbarch *, char *);
>>
>>  extern const char *address_space_int_to_name (struct gdbarch *, int);
>>
>> +extern struct type * make_qualified_type (struct type *type, int 
>> new_flags,
>> +                        struct type *storage);
>> +
>>  extern struct type *make_type_with_address_space (struct type *type,
>>                            int space_identifier);
>>
>> diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc 
>> b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
>> new file mode 100644
>> index 0000000..3622f3b
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
>> @@ -0,0 +1,184 @@
>> +/* Copyright 2011 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;
>> +  /*:
>> +    mi_var_rtti__set_print_object off
>> +    mi_var_rtti__check_derived_class_without_rtti ptr {Base \*}
>> +    mi_var_rtti__check_derived_class_without_rtti constPtr {const 
>> Base \*}
>> +    mi_var_rtti__check_derived_class_without_rtti ptrConst {Base \* 
>> const}
>> +    mi_var_rtti__check_derived_class_without_rtti constPtrConst 
>> {const Base \* const}
>> +
>> +    mi_var_rtti__set_print_object on
>> +    mi_var_rtti__check_derived_class_with_rtti ptr {Derived \*}
>> +    mi_var_rtti__check_derived_class_with_rtti constPtr {const 
>> Derived \*}
>> +    mi_var_rtti__check_derived_class_with_rtti ptrConst {Derived \* 
>> const}
>> +    mi_var_rtti__check_derived_class_with_rtti constPtrConst {const 
>> Derived \* const}
>> +  :*/
>> +    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;
>> +  /*:
>> +    mi_var_rtti__set_print_object off
>> +    mi_var_rtti__check_derived_class_without_rtti ref {Base \&}
>> +    mi_var_rtti__check_derived_class_without_rtti constRef {const 
>> Base \&}
>> +
>> +    mi_var_rtti__set_print_object on
>> +    mi_var_rtti__check_derived_class_with_rtti ref {Derived \&}
>> +    mi_var_rtti__check_derived_class_with_rtti constRef {const 
>> Derived \&}
>> +  :*/
>> +    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 );
>> +  /*:
>> +    mi_var_rtti__set_print_object off
>> +    mi_var_rtti__check_derived_class_without_rtti s.ptr {Base \*}
>> +    mi_var_rtti__check_derived_class_without_rtti s.constPtr {const 
>> Base \*}
>> +    mi_var_rtti__check_derived_class_without_rtti s.ptrConst {Base 
>> \* const}
>> +    mi_var_rtti__check_derived_class_without_rtti s.constPtrConst 
>> {const Base \* const}
>> +
>> +    mi_var_rtti__set_print_object on
>> +    mi_var_rtti__check_derived_class_with_rtti s.ptr {Derived \*}
>> +    mi_var_rtti__check_derived_class_with_rtti s.constPtr {const 
>> Derived \*}
>> +    mi_var_rtti__check_derived_class_with_rtti s.ptrConst {Derived 
>> \* const}
>> +    mi_var_rtti__check_derived_class_with_rtti s.constPtrConst 
>> {const Derived \* const}
>> +  :*/
>> +    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 );
>> +  /*:
>> +    mi_var_rtti__set_print_object off
>> +    mi_var_rtti__check_derived_class_without_rtti s.ref {Base \&}
>> +    mi_var_rtti__check_derived_class_without_rtti s.constRef {const 
>> Base \&}
>> +
>> +    mi_var_rtti__set_print_object on
>> +    mi_var_rtti__check_derived_class_with_rtti s.ref {Derived \&}
>> +    mi_var_rtti__check_derived_class_with_rtti s.constRef {const 
>> Derived \&}
>> +  :*/
>> +    return;
>> +  /*: END: use_rtti_for_ref_child :*/
>> +}
>> +
>> +void type_update_when_use_rtti_test ()
>> +{
>> +  /*: BEGIN: type_update_when_use_rtti :*/
>> +    Derived d;
>> +  /*:
>> +    mi_var_rtti__set_print_object on
>> +    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
>> +    mi_var_rtti__check_derived_children_without_rtti ptr
>> +  :*/
>> +
>> +    Base* ptr = &d;
>> +  /*:
>> +    mi_varobj_update_with_type_change VAR {Derived \*} 2 "update ptr"
>> +    mi_var_rtti__check_derived_children_with_rtti ptr
>> +    mi_var_rtti__check_derived_content_with_rtti ptr
>> +    mi_delete_varobj VAR "delete varobj for ptr"
>> +  :*/
>> +    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;
>> +  /*:
>> +    mi_var_rtti__set_print_object off
>> +    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
>> +    mi_var_rtti__check_derived_children_without_rtti ptr
>> +  :*/
>> +
>> +    Base* ptr = &d;
>> +  /*:
>> +    mi_varobj_update VAR {} "update ptr"
>> +    mi_var_rtti__check_derived_children_without_rtti ptr
>> +    mi_var_rtti__check_derived_content_without_rtti ptr
>> +    mi_delete_varobj VAR "delete varobj for ptr"
>> +  :*/
>> +    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();
>> +    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
>> index 0000000..2999e87
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
>> @@ -0,0 +1,108 @@
>> +# Copyright 2006, 2007, 2008, 2009, 2010, 2011 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 binfile $objdir/$subdir/$testfile
>> +
>> +if [get_compiler_info ${binfile} "c++"] {
>> +    return -1;
>> +}
>> +
>> +if {[gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug 
>> c++}] != ""} {
>> +  untested $testfile.exp
>> +  return -1
>> +}
>> +
>> +mi_gdb_load ${binfile}
>> +
>> +mi_prepare_inline_tests $srcfile
>> +
>> +# Enable using RTTI to determine real types of the objects
>> +proc mi_var_rtti__set_print_object {state} {
>> +  mi_gdb_test "-interpreter-exec console \"set print object 
>> ${state}\"" \
>> +    {\^done} \
>> +    "-interpreter-exec console \"set print object ${state}\""
>> +}
>> +
>> +proc mi_var_rtti__check_derived_children_without_rtti {var_name} {
>> +  mi_list_varobj_children VAR {
>> +     { VAR.public            public    1         }
>> +  } "list children of ${var_name} (without RTTI)"
>> +  mi_list_varobj_children "VAR.public" {
>> +     { VAR.public.A            A        0    int }
>> +  } "list children of ${var_name}.public (without RTTI)"
>> +}
>> +
>> +proc mi_var_rtti__check_derived_content_without_rtti {var_name} {
>> +  mi_check_varobj_value VAR.public.A        1 "check ${var_name}->A 
>> (without RTTI)"
>> +}
>> +
>> +proc mi_var_rtti__check_derived_class_without_rtti {var_name 
>> var_type} {
>> +  mi_create_varobj_checked VAR ${var_name} ${var_type} "create 
>> varobj for ${var_name} (without RTTI)"
>> +  mi_var_rtti__check_derived_children_without_rtti ${var_name}
>> +  mi_var_rtti__check_derived_content_without_rtti ${var_name}
>> +  mi_delete_varobj VAR "delete varobj for ${var_name} (without RTTI)"
>> +}
>> +
>> +proc mi_var_rtti__check_derived_children_with_rtti {var_name} {
>> +    mi_list_varobj_children VAR {
>> +       { VAR.Base            Base    1    Base }
>> +       { VAR.public            public    2         }
>> +    } "list children of ${var_name} (with RTTI)"
>> +    mi_list_varobj_children "VAR.Base" {
>> +       { VAR.Base.public    public 1 }
>> +    } "list children of ${var_name}.Base (with RTTI)"
>> +    mi_list_varobj_children "VAR.Base.public" {
>> +       { VAR.Base.public.A    A        0    int    }
>> +    } "list children of ${var_name}.Base.public (with RTTI)"
>> +    mi_list_varobj_children "VAR.public" {
>> +       { VAR.public.B        B        0    int }
>> +       { VAR.public.C        C        0    int }
>> +    } "list children of ${var_name}.public (with RTTI)"
>> +}
>> +
>> +proc mi_var_rtti__check_derived_content_with_rtti {var_name} {
>> +    mi_check_varobj_value VAR.Base.public.A    1 "check 
>> ${var_name}->A (with RTTI)"
>> +    mi_check_varobj_value VAR.public.B        2 "check 
>> ${var_name}->B (with RTTI)"
>> +    mi_check_varobj_value VAR.public.C        3 "check 
>> ${var_name}->C (with RTTI)"
>> +}
>> +
>> +proc mi_var_rtti__check_derived_class_with_rtti {var_name var_type} {
>> +    mi_create_varobj_checked VAR ${var_name} ${var_type} "create 
>> varobj for ${var_name} (with RTTI)"
>> +    mi_var_rtti__check_derived_children_with_rtti ${var_name}
>> +    mi_var_rtti__check_derived_content_with_rtti ${var_name}
>> +    mi_delete_varobj VAR "delete varobj for ${var_name} (with RTTI)"
>> +}
>> +
>> +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 type_update_when_use_rtti
>> +mi_run_inline_test skip_type_update_when_not_use_rtti
>> +
>> +mi_gdb_exit
>> +return 0
>> diff --git a/gdb/typeprint.c b/gdb/typeprint.c
>> index cf4158d..8170e14 100644
>> --- a/gdb/typeprint.c
>> +++ b/gdb/typeprint.c
>> @@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
>>        if (((TYPE_CODE (type) == TYPE_CODE_PTR)
>>         || (TYPE_CODE (type) == TYPE_CODE_REF))
>> && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
>> -        {
>> -          real_type = value_rtti_target_type (val, &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);
>> -            }
>> -        }
>> +        real_type = value_rtti_target_type (val, &full, &top, 
>> &using_enc);
>>        else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
>>      real_type = value_rtti_type (val, &full, &top, &using_enc);
>>      }
>> diff --git a/gdb/valops.c b/gdb/valops.c
>> index cb39677..8f38cba 100644
>> --- a/gdb/valops.c
>> +++ b/gdb/valops.c
>> @@ -3528,8 +3528,7 @@ value_maybe_namespace_elt (const struct type 
>> *curtype,
>>    return result;
>>  }
>>
>> -/* Given a pointer value V, find the real (RTTI) type of the object it
>> -   points to.
>> +/* Given a pointer or a reference value V, find its real (RTTI) type.
>>
>>     Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
>>     and refer to the values computed for the object pointed to.  */
>> @@ -3539,12 +3538,35 @@ value_rtti_target_type (struct value *v, int 
>> *full,
>>              int *top, int *using_enc)
>>  {
>>    struct value *target;
>> +  struct type *type, *real_type;
>> +
>> +  type = value_type (v);
>> +  type = check_typedef (type);
>> +  if (TYPE_CODE(type) == TYPE_CODE_REF)
>> +    target = coerce_ref (v);
>> +  else if (TYPE_CODE(type) == TYPE_CODE_PTR)
>> +    target = value_ind (v);
>> +  else
>> +    return 0;
>> +
>> +  real_type = value_rtti_type (target, full, top, using_enc);
>>
>> -  target = value_ind (v);
>> +  if (real_type)
>> +    {
>> +      // Copy qualifiers to the referenced object
>> +      real_type = make_qualified_type (real_type, 
>> TYPE_INSTANCE_FLAGS (value_type(target)), NULL);
>> +      if (TYPE_CODE(type) == TYPE_CODE_REF)
>> +        real_type = lookup_reference_type (real_type);
>> +      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
>> +        real_type = lookup_pointer_type (real_type);
>> +      // Copy qualifiers to the pointer/reference
>> +      real_type = make_qualified_type (real_type, 
>> TYPE_INSTANCE_FLAGS (type), NULL);
>> +    }
>>
>> -  return value_rtti_type (target, full, top, using_enc);
>> +  return real_type;
>>  }
>>
>> +
>>  /* Given a value pointed to by ARGP, check its real run-time type, and
>>     if that is different from the enclosing type, create a new value
>>     using the real run-time type as the enclosing type (and of the same
>> diff --git a/gdb/value.c b/gdb/value.c
>> index d263d0c..a61df8e 100644
>> --- a/gdb/value.c
>> +++ b/gdb/value.c
>> @@ -821,6 +821,32 @@ value_enclosing_type (struct value *value)
>>    return value->enclosing_type;
>>  }
>>
>> +struct type *
>> +actual_type (struct value *value, int resolve_simple_types)
>> +{
>> +  struct value_print_options opts;
>> +  struct value *target;
>> +  struct type *result;
>> +
>> +  get_user_print_options (&opts);
>> +
>> +  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_target_type ( value, 0, 0, 0 );
>> +      if (real_type)
>> +        result = real_type;
>> +    }
>> +    else if (resolve_simple_types)
>> +      result = value_enclosing_type (value);
>> +  }
>> +
>> +  return result;
>> +}
>> +
>>  static void
>>  require_not_optimized_out (const struct value *value)
>>  {
>> @@ -3114,6 +3140,7 @@ coerce_ref (struct value *arg)
>>  {
>>    struct type *value_type_arg_tmp = check_typedef (value_type (arg));
>>    struct value *retval;
>> +  struct type *enc_type;
>>
>>    retval = coerce_ref_if_computed (arg);
>>    if (retval)
>> @@ -3122,9 +3149,23 @@ coerce_ref (struct value *arg)
>>    if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
>>      return arg;
>>
>> -  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
>> +  enc_type = check_typedef (value_enclosing_type (arg));
>> +  enc_type = TYPE_TARGET_TYPE (enc_type);
>> +
>> +  retval = value_at_lazy (enc_type,
>>              unpack_pointer (value_type (arg),
>>                      value_contents (arg)));
>> +  /* Re-adjust type.  */
>> +  deprecated_set_value_type (retval, TYPE_TARGET_TYPE 
>> (value_type_arg_tmp));
>> +
>> +  /* Add embedding info.  */
>> +  set_value_enclosing_type (retval, enc_type);
>> +  set_value_embedded_offset (retval, value_pointed_to_offset (arg));
>> +
>> +  /* We may be pointing to an object of some derived type.  */
>> +  retval = value_full_object (retval, NULL, 0, 0, 0);
>> +
>> +  return retval;
>>  }
>>
>>  struct value *
>> diff --git a/gdb/value.h b/gdb/value.h
>> index d2c58ec..57130e4 100644
>> --- a/gdb/value.h
>> +++ b/gdb/value.h
>> @@ -139,6 +139,15 @@ 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 also
>> +   all the types (e.g. for structures). This option is useful
>> +   to prevent retrieving enclosing type for the base classes fields */
>> +extern struct type *actual_type (struct value *value, int 
>> resolve_simple_types);
>> +
>>  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);
>> diff --git a/gdb/varobj.c b/gdb/varobj.c
>> index 7c68a93..22c045b 100644
>> --- a/gdb/varobj.c
>> +++ b/gdb/varobj.c
>> @@ -660,7 +660,16 @@ varobj_create (char *objname,
>>        var->type = value_type (type_only_value);
>>      }
>>        else
>> -    var->type = value_type (value);
>> +    {
>> +      struct type *enclosing_type;
>> +      var->type = value_type (value);
>> +      enclosing_type = actual_type(value, 0);
>> +      if (check_typedef (enclosing_type) != check_typedef (var->type))
>> +        {
>> +          var->type = enclosing_type;
>> +          value = value_cast (enclosing_type, value);
>> +        }
>> +    }
>>
>>        install_new_value (var, value, 1 /* Initial assignment */);
>>
>> @@ -2194,7 +2203,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 = actual_type (value, 0);
>>    else
>>      /* Otherwise, we must compute the type.  */
>>      child->type = (*child->root->lang->type_of_child) (child->parent,
>> @@ -2480,6 +2489,7 @@ static struct value *
>>  value_of_root (struct varobj **var_handle, int *type_changed)
>>  {
>>    struct varobj *var;
>> +  struct value_print_options opts;
>>
>>    if (var_handle == NULL)
>>      return NULL;
>> @@ -2492,7 +2502,8 @@ value_of_root (struct varobj **var_handle, int 
>> *type_changed)
>>    if (!is_root_p (var))
>>      return NULL;
>>
>> -  if (var->root->floating)
>> +  get_user_print_options (&opts);
>> +  if (var->root->floating || opts.objectprint)
>>      {
>>        struct varobj *tmp_var;
>>        char *old_type, *new_type;
>> @@ -2781,6 +2792,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
>> @@ -2792,8 +2807,10 @@ 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)
>>  {
>> +  struct type *enclosing_type;
>>    gdb_assert (type && *type);
>>
>>    if (was_ptr)
>> @@ -2832,6 +2849,17 @@ 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)
>> +    {
>> +      enclosing_type = actual_type(*value, 1);
>> +      if (check_typedef (enclosing_type) != check_typedef (*type))
>> +        {
>> +          *type = enclosing_type;
>> +          *value = value_cast (enclosing_type, *value);
>> +        }
>> +    }
>>  }
>>
>>  /* C */
>> @@ -2842,7 +2870,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))
>> @@ -2957,7 +2985,7 @@ c_describe_child (struct varobj *parent, int 
>> index,
>>        *cfull_expression = NULL;
>>        parent_expression = varobj_get_path_expr (parent);
>>      }
>> -  adjust_value_for_child_access (&value, &type, &was_ptr);
>> +  adjust_value_for_child_access (&value, &type, &was_ptr, 0);
>>
>>    switch (TYPE_CODE (type))
>>      {
>> @@ -3223,16 +3251,27 @@ c_value_of_variable (struct varobj *var, enum 
>> varobj_display_formats format)
>>  static int
>>  cplus_number_of_children (struct varobj *var)
>>  {
>> +  struct value *value = 0;
>>    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))
>> @@ -3259,7 +3298,13 @@ 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)
>> +        {
>> +          value = var->parent->value;
>> +          lookup_actual_type = TYPE_CODE (var->parent->type) == 
>> TYPE_CODE_REF || TYPE_CODE (var->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)
>> @@ -3341,7 +3386,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;
>> @@ -3352,22 +3400,17 @@ 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 (parent->parent);
>> -    }
>> -  else
>> -    {
>> -      value = parent->value;
>> -      type = get_value_type (parent);
>> -      if (cfull_expression)
>> -    parent_expression = varobj_get_path_expr (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 (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)
>>
>>
>>
>>
>
>


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

* Re: set print object on should affect MI varobjs (PR 13393)
  2011-12-02 19:50 set print object on should affect MI varobjs (PR 13393) xgsa
  2011-12-08  8:15 ` xgsa
@ 2011-12-20 17:47 ` Tom Tromey
  2011-12-21 19:01   ` set print object on should affect MI varobjs (PR gdb/13393) xgsa
  1 sibling, 1 reply; 47+ messages in thread
From: Tom Tromey @ 2011-12-20 17:47 UTC (permalink / raw)
  To: xgsa; +Cc: gdb-patches

>>>>> ">" == xgsa  <xgsa@yandex.ru> writes:

>> (it seems that my previous message about this patch was lost somehow,
>> so I resend it again; sorry, if I sent it twice)

No problem.  Thanks for working on this.

>> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

>>     PR 13393

I think it has to mention the category for the commit->bz scanner to
work.

Your patch got wrapped by your mailer, making it harder to read.

>> -static struct type *
>> +struct type *
>>  make_qualified_type (struct type *type, int new_flags,
>>               struct type *storage)

I'd prefer not to export this.
I think you can just use make_cv_type instead.

>> +  else if (TYPE_CODE(type) == TYPE_CODE_PTR)

Missing space before the open paren here.  This occurs a few times.


>> +struct type *
>> +actual_type (struct value *value, int resolve_simple_types)
>> +{

This should have an introductory comment saying to look at value.h.

>> +      struct type *real_type;
>> +      real_type = value_rtti_target_type ( value, 0, 0, 0 );

Blank line between declaration and code.
This has an extra space after "(" and before ")".

>> +/* Returns value_type() or value_enclosing_type () depending on

Remove the '()'s.

>> +   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 also
>> +   all the types (e.g. for structures). This option is useful
>> +   to prevent retrieving enclosing type for the base classes fields */

Sentences should end with a period followed by 2 spaces.
The last sentence needs this too.

>> +      struct type *enclosing_type;
>> +      var->type = value_type (value);

Blank line.

>> +      enclosing_type = actual_type(value, 0);

Missing space.

>> +      if (check_typedef (enclosing_type) != check_typedef (var->type))
>> +        {
>> +          var->type = enclosing_type;
>> +          value = value_cast (enclosing_type, value);

Will this always do the right thing?
It seems questionable.

>> +  // Access a real type of the value (if necessary and possible)

GDB is C90 and can't use // comments.

>> +      enclosing_type = actual_type(*value, 1);

I don't understand why this one call has a '1' here.

>> +      // 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;

This line has to be reformatted per the GNU coding standards.

Do you have copyright assignment papers filed with the FSF?
If not, contact me off-list to get started with this.
We can't put anything in until the paperwork is finished.

Tom

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

* Re: set print object on should affect MI varobjs (PR gdb/13393)
  2011-12-20 17:47 ` Tom Tromey
@ 2011-12-21 19:01   ` xgsa
  2011-12-21 19:37     ` Jan Kratochvil
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2011-12-21 19:01 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Here is the patch with the corrections after your review.

 >>>> +struct type *
 >>>> +actual_type (struct value *value, int resolve_simple_types)
 >>>> +{
 >>
 >>This should have an introductory comment saying to look at value.h.

It seems that none of neighboring functions (e.g. value_type() & value_enclosing_type()) has such comment. I think it is better to be consistent and not to add the comment, but if you insist I can add it.

 >>>> +      if (check_typedef (enclosing_type) != check_typedef (var->type))
 >>>> +        {
 >>>> +          var->type = enclosing_type;
 >>>> +          value = value_cast (enclosing_type, value);
 >>
 >>Will this always do the right thing?
 >>It seems questionable.

It works fine for me. Can you give an example when it works wrong?

 >>>> +      enclosing_type = actual_type(*value, 1);
 >>
 >>I don't understand why this one call has a '1' here.

The C++ references are treated as a simple values in many places of varobj. E.g. they are dereferenced in install_new_value():
 >  /* We are not interested in the address of references, and given
 >     that in C++ a reference is not rebindable, it cannot
 >     meaningfully change.  So, get hold of the real value.  */
 >  if (value)
 >    value = coerce_ref (value);
So I need to ask real type not only on references & pointers but also on the values.

I have also renamed actual_type() => value_actual_type() (to be consistent with value_type() & value_enclosing_type()).


Thanks,
Anton


gdb/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

     PR gdb/13393
     * gdb/valops.c (value_rtti_target_type): add support for references.
     Return also a reference or pointer type (because every caller do it after call that leads to code duplication)
     * gdb/c-valprint.c (c_value_print): updated for value_rtti_target_type() change.
     * gdb/eval.c (evaluate_subexp_standard): updated for value_rtti_target_type() change.
     * gdb/typeprint.c: updated for value_rtti_target_type() change.
     * gdb/value.c(value_actual_type): new function.
     (coerce_ref): support for enclosing type setting for references (as it is done for pointers in value_ind())
     * gdb/value.h(value_actual_type): add prototype.
     * gdb/varobj.c(varobj_create): call value_actual_type() if necessary
     (create_child_with_value): call value_actual_type().
     (value_of_root): support for type change if the value changed and RTTI is used to determine type.
     (adjust_value_for_child_access): extended with a new parameter and cast given value to enclosing type is necessary.
     (c_number_of_children): update for extended adjust_value_for_child_access()
     (cplus_number_of_children): send a value as parameter if RTTI should be used to determine type
     (cplus_describe_child): determine whether RTTI type should be used

gdb/testsuite/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

     PR gdb/13393
     * gdb.mi/mi-var-rtti.cc:: New file.
     * gdb.mi/mi-var-rtti.exp:: New file.


diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 3461b08..bfb3227 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -702,18 +702,8 @@ c_value_print (struct value *val, struct ui_file *stream,
            if (real_type)
          {
            /* RTTI entry found.  */
-          if (TYPE_CODE (type) == TYPE_CODE_PTR)
-            {
-              /* Create a pointer type pointing to the real
-             type.  */
-              type = lookup_pointer_type (real_type);
-            }
-          else
-            {
-              /* Create a reference type referencing the real
-             type.  */
-              type = lookup_reference_type (real_type);
-            }
+          type = real_type;
+
            /* Need to adjust pointer value.  */
            val = value_from_pointer (type, value_as_address (val) - top);

diff --git a/gdb/eval.c b/gdb/eval.c
index 5d758d1..7e6a6c5 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1992,14 +1992,7 @@ evaluate_subexp_standard (struct type *expect_type,
            {
              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);
-              }
            }
        }

diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..3622f3b
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -0,0 +1,184 @@
+/* Copyright 2011 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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti ptr {Base \*}
+    mi_var_rtti__check_derived_class_without_rtti constPtr {const Base \*}
+    mi_var_rtti__check_derived_class_without_rtti ptrConst {Base \* const}
+    mi_var_rtti__check_derived_class_without_rtti constPtrConst {const Base \* const}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti ptr {Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti constPtr {const Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti ptrConst {Derived \* const}
+    mi_var_rtti__check_derived_class_with_rtti constPtrConst {const Derived \* const}
+  :*/
+    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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti ref {Base \&}
+    mi_var_rtti__check_derived_class_without_rtti constRef {const Base \&}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti ref {Derived \&}
+    mi_var_rtti__check_derived_class_with_rtti constRef {const Derived \&}
+  :*/
+    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 );
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti s.ptr {Base \*}
+    mi_var_rtti__check_derived_class_without_rtti s.constPtr {const Base \*}
+    mi_var_rtti__check_derived_class_without_rtti s.ptrConst {Base \* const}
+    mi_var_rtti__check_derived_class_without_rtti s.constPtrConst {const Base \* const}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti s.ptr {Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti s.constPtr {const Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti s.ptrConst {Derived \* const}
+    mi_var_rtti__check_derived_class_with_rtti s.constPtrConst {const Derived \* const}
+  :*/
+    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 );
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti s.ref {Base \&}
+    mi_var_rtti__check_derived_class_without_rtti s.constRef {const Base \&}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti s.ref {Derived \&}
+    mi_var_rtti__check_derived_class_with_rtti s.constRef {const Derived \&}
+  :*/
+    return;
+  /*: END: use_rtti_for_ref_child :*/
+}
+
+void type_update_when_use_rtti_test ()
+{
+  /*: BEGIN: type_update_when_use_rtti :*/
+    Derived d;
+  /*:
+    mi_var_rtti__set_print_object on
+    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+  :*/
+
+    Base* ptr = &d;
+  /*:
+    mi_varobj_update_with_type_change VAR {Derived \*} 2 "update ptr"
+    mi_var_rtti__check_derived_children_with_rtti ptr
+    mi_var_rtti__check_derived_content_with_rtti ptr
+    mi_delete_varobj VAR "delete varobj for ptr"
+  :*/
+    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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+  :*/
+
+    Base* ptr = &d;
+  /*:
+    mi_varobj_update VAR {} "update ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+    mi_var_rtti__check_derived_content_without_rtti ptr
+    mi_delete_varobj VAR "delete varobj for ptr"
+  :*/
+    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();
+    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
index 0000000..2999e87
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -0,0 +1,108 @@
+# Copyright 2006, 2007, 2008, 2009, 2010, 2011 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 binfile $objdir/$subdir/$testfile
+
+if [get_compiler_info ${binfile} "c++"] {
+    return -1;
+}
+
+if {[gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug c++}] != ""} {
+  untested $testfile.exp
+  return -1
+}
+
+mi_gdb_load ${binfile}
+
+mi_prepare_inline_tests $srcfile
+
+# Enable using RTTI to determine real types of the objects
+proc mi_var_rtti__set_print_object {state} {
+  mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \
+    {\^done} \
+    "-interpreter-exec console \"set print object ${state}\""
+}
+
+proc mi_var_rtti__check_derived_children_without_rtti {var_name} {
+  mi_list_varobj_children VAR {
+     { VAR.public            public    1         }
+  } "list children of ${var_name} (without RTTI)"
+  mi_list_varobj_children "VAR.public" {
+     { VAR.public.A            A        0    int }
+  } "list children of ${var_name}.public (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_content_without_rtti {var_name} {
+  mi_check_varobj_value VAR.public.A        1 "check ${var_name}->A (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_class_without_rtti {var_name var_type} {
+  mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj for ${var_name} (without RTTI)"
+  mi_var_rtti__check_derived_children_without_rtti ${var_name}
+  mi_var_rtti__check_derived_content_without_rtti ${var_name}
+  mi_delete_varobj VAR "delete varobj for ${var_name} (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_children_with_rtti {var_name} {
+    mi_list_varobj_children VAR {
+       { VAR.Base            Base    1    Base }
+       { VAR.public            public    2         }
+    } "list children of ${var_name} (with RTTI)"
+    mi_list_varobj_children "VAR.Base" {
+       { VAR.Base.public    public 1 }
+    } "list children of ${var_name}.Base (with RTTI)"
+    mi_list_varobj_children "VAR.Base.public" {
+       { VAR.Base.public.A    A        0    int    }
+    } "list children of ${var_name}.Base.public (with RTTI)"
+    mi_list_varobj_children "VAR.public" {
+       { VAR.public.B        B        0    int }
+       { VAR.public.C        C        0    int }
+    } "list children of ${var_name}.public (with RTTI)"
+}
+
+proc mi_var_rtti__check_derived_content_with_rtti {var_name} {
+    mi_check_varobj_value VAR.Base.public.A    1 "check ${var_name}->A (with RTTI)"
+    mi_check_varobj_value VAR.public.B        2 "check ${var_name}->B (with RTTI)"
+    mi_check_varobj_value VAR.public.C        3 "check ${var_name}->C (with RTTI)"
+}
+
+proc mi_var_rtti__check_derived_class_with_rtti {var_name var_type} {
+    mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj for ${var_name} (with RTTI)"
+    mi_var_rtti__check_derived_children_with_rtti ${var_name}
+    mi_var_rtti__check_derived_content_with_rtti ${var_name}
+    mi_delete_varobj VAR "delete varobj for ${var_name} (with RTTI)"
+}
+
+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 type_update_when_use_rtti
+mi_run_inline_test skip_type_update_when_not_use_rtti
+
+mi_gdb_exit
+return 0
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index cf4158d..8170e14 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
        if (((TYPE_CODE (type) == TYPE_CODE_PTR)
         || (TYPE_CODE (type) == TYPE_CODE_REF))
&& (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
-        {
-          real_type = value_rtti_target_type (val, &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);
-            }
-        }
+        real_type = value_rtti_target_type (val, &full, &top, &using_enc);
        else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
      real_type = value_rtti_type (val, &full, &top, &using_enc);
      }
diff --git a/gdb/valops.c b/gdb/valops.c
index cb39677..6a914b0 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -3528,8 +3528,7 @@ value_maybe_namespace_elt (const struct type *curtype,
    return result;
  }

-/* Given a pointer value V, find the real (RTTI) type of the object it
-   points to.
+/* Given a pointer or a reference value V, find its real (RTTI) type.

     Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
     and refer to the values computed for the object pointed to.  */
@@ -3539,12 +3538,37 @@ value_rtti_target_type (struct value *v, int *full,
              int *top, int *using_enc)
  {
    struct value *target;
+  struct type *type, *real_type;

-  target = value_ind (v);
+  type = value_type (v);
+  type = check_typedef (type);
+  if (TYPE_CODE (type) == TYPE_CODE_REF)
+    target = coerce_ref (v);
+  else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    target = value_ind (v);
+  else
+    return 0;

-  return value_rtti_type (target, full, top, using_enc);
+  real_type = value_rtti_type (target, full, top, using_enc);
+
+  if (real_type)
+    {
+      struct type *target_type = value_type (target);
+
+      /* Copy qualifiers to the referenced object.  */
+      real_type = make_cv_type (TYPE_CONST (target_type), TYPE_VOLATILE (target_type), real_type, NULL);
+      if (TYPE_CODE (type) == TYPE_CODE_REF)
+        real_type = lookup_reference_type (real_type);
+      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+        real_type = lookup_pointer_type (real_type);
+      /* Copy qualifiers to the pointer/reference.  */
+      real_type = make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type), real_type, NULL);
+    }
+
+  return real_type;
  }

+
  /* Given a value pointed to by ARGP, check its real run-time type, and
     if that is different from the enclosing type, create a new value
     using the real run-time type as the enclosing type (and of the same
diff --git a/gdb/value.c b/gdb/value.c
index d263d0c..7d9e5cc 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -821,6 +821,33 @@ value_enclosing_type (struct value *value)
    return value->enclosing_type;
  }

+struct type *
+value_actual_type (struct value *value, int resolve_simple_types)
+{
+  struct value_print_options opts;
+  struct value *target;
+  struct type *result;
+
+  get_user_print_options (&opts);
+
+  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_target_type (value, 0, 0, 0);
+      if (real_type)
+        result = real_type;
+    }
+    else if (resolve_simple_types)
+      result = value_enclosing_type (value);
+  }
+
+  return result;
+}
+
  static void
  require_not_optimized_out (const struct value *value)
  {
@@ -3114,6 +3141,7 @@ coerce_ref (struct value *arg)
  {
    struct type *value_type_arg_tmp = check_typedef (value_type (arg));
    struct value *retval;
+  struct type *enc_type;

    retval = coerce_ref_if_computed (arg);
    if (retval)
@@ -3122,9 +3150,23 @@ coerce_ref (struct value *arg)
    if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
      return arg;

-  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
+  enc_type = check_typedef (value_enclosing_type (arg));
+  enc_type = TYPE_TARGET_TYPE (enc_type);
+
+  retval = value_at_lazy (enc_type,
              unpack_pointer (value_type (arg),
                      value_contents (arg)));
+  /* Re-adjust type.  */
+  deprecated_set_value_type (retval, TYPE_TARGET_TYPE (value_type_arg_tmp));
+
+  /* Add embedding info.  */
+  set_value_enclosing_type (retval, enc_type);
+  set_value_embedded_offset (retval, value_pointed_to_offset (arg));
+
+  /* We may be pointing to an object of some derived type.  */
+  retval = value_full_object (retval, NULL, 0, 0, 0);
+
+  return retval;
  }

  struct value *
diff --git a/gdb/value.h b/gdb/value.h
index d2c58ec..c01da3e 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -139,6 +139,15 @@ 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.  */
+extern struct type *value_actual_type (struct value *value, int resolve_simple_types);
+
  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);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 7c68a93..47390cb 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -660,7 +660,17 @@ varobj_create (char *objname,
        var->type = value_type (type_only_value);
      }
        else
-    var->type = value_type (value);
+    {
+      struct type *enclosing_type;
+
+      var->type = value_type (value);
+      enclosing_type = value_actual_type (value, 0);
+      if (check_typedef (enclosing_type) != check_typedef (var->type))
+        {
+          var->type = enclosing_type;
+          value = value_cast (enclosing_type, value);
+        }
+    }

        install_new_value (var, value, 1 /* Initial assignment */);

@@ -2194,7 +2204,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);
    else
      /* Otherwise, we must compute the type.  */
      child->type = (*child->root->lang->type_of_child) (child->parent,
@@ -2480,6 +2490,7 @@ static struct value *
  value_of_root (struct varobj **var_handle, int *type_changed)
  {
    struct varobj *var;
+  struct value_print_options opts;

    if (var_handle == NULL)
      return NULL;
@@ -2492,7 +2503,8 @@ value_of_root (struct varobj **var_handle, int *type_changed)
    if (!is_root_p (var))
      return NULL;

-  if (var->root->floating)
+  get_user_print_options (&opts);
+  if (var->root->floating || opts.objectprint)
      {
        struct varobj *tmp_var;
        char *old_type, *new_type;
@@ -2781,6 +2793,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
@@ -2792,7 +2808,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);

@@ -2832,6 +2849,19 @@ 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;
+
+      enclosing_type = value_actual_type (*value, 1);
+      if (check_typedef (enclosing_type) != check_typedef (*type))
+        {
+          *type = enclosing_type;
+          *value = value_cast (enclosing_type, *value);
+        }
+    }
  }

  /* C */
@@ -2842,7 +2872,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))
@@ -2957,7 +2987,7 @@ c_describe_child (struct varobj *parent, int index,
        *cfull_expression = NULL;
        parent_expression = varobj_get_path_expr (parent);
      }
-  adjust_value_for_child_access (&value, &type, &was_ptr);
+  adjust_value_for_child_access (&value, &type, &was_ptr, 0);

    switch (TYPE_CODE (type))
      {
@@ -3223,16 +3253,28 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
  static int
  cplus_number_of_children (struct varobj *var)
  {
+  struct value *value = 0;
    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))
@@ -3259,7 +3301,14 @@ 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)
+        {
+          value = var->parent->value;
+          lookup_actual_type = (TYPE_CODE (var->parent->type) == TYPE_CODE_REF
+                                || TYPE_CODE (var->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)
@@ -3341,7 +3390,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;
@@ -3352,22 +3404,17 @@ 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 (parent->parent);
-    }
-  else
-    {
-      value = parent->value;
-      type = get_value_type (parent);
-      if (cfull_expression)
-    parent_expression = varobj_get_path_expr (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 (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)

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

* Re: set print object on should affect MI varobjs (PR gdb/13393)
  2011-12-21 19:01   ` set print object on should affect MI varobjs (PR gdb/13393) xgsa
@ 2011-12-21 19:37     ` Jan Kratochvil
  2011-12-22 10:17       ` set print object on should affect MI varobjs (PR mi/13393) xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2011-12-21 19:37 UTC (permalink / raw)
  To: xgsa; +Cc: Tom Tromey, gdb-patches

On Wed, 21 Dec 2011 19:49:49 +0100, xgsa wrote:
> It seems that none of neighboring functions (e.g. value_type()
> & value_enclosing_type()) has such comment. I think it is better to be
> consistent and not to add the comment, but if you insist I can add it.

Yes, the GDB codebase is in a worse state than what is accepted for new
patches.


I do not see there bugs, the comments below are just formatting fixes.


> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
> 
>     PR gdb/13393

This should be mi/13393.

>     * gdb/valops.c (value_rtti_target_type): add support for references.

Sentence starts with capital 'A'.

>     Return also a reference or pointer type (because every caller do it after call that leads to code duplication)

All the lines must be <= 80 characters (some people say 72 characters).

The same applies to all the code lines, they must be <= 80 characters.

Every sentece is terminated by '.'.


>     * gdb/c-valprint.c (c_value_print): updated for value_rtti_target_type() change.

GNU does not use () at the function names.

>     * gdb/eval.c (evaluate_subexp_standard): updated for value_rtti_target_type() change.
>     * gdb/typeprint.c: updated for value_rtti_target_type() change.
>     * gdb/value.c(value_actual_type): new function.

Space before '('.

>     (coerce_ref): support for enclosing type setting for references (as it is done for pointers in value_ind())
>     * gdb/value.h(value_actual_type): add prototype.
>     * gdb/varobj.c(varobj_create): call value_actual_type() if necessary
>     (create_child_with_value): call value_actual_type().
>     (value_of_root): support for type change if the value changed and RTTI is used to determine type.
>     (adjust_value_for_child_access): extended with a new parameter and cast given value to enclosing type is necessary.
>     (c_number_of_children): update for extended adjust_value_for_child_access()
>     (cplus_number_of_children): send a value as parameter if RTTI should be used to determine type
>     (cplus_describe_child): determine whether RTTI type should be used
> 
> gdb/testsuite/ChangeLog:
> 
> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
> 
>     PR gdb/13393

Likewise.

>     * gdb.mi/mi-var-rtti.cc:: New file.
>     * gdb.mi/mi-var-rtti.exp:: New file.

Single ':'.


> --- /dev/null
> +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
> @@ -0,0 +1,108 @@
> +# Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.

This is a new test (even if it is partially copied), 2011 is enough there.


> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -3528,8 +3528,7 @@ value_maybe_namespace_elt (const struct type *curtype,
>    return result;
>  }
> 
> -/* Given a pointer value V, find the real (RTTI) type of the object it
> -   points to.
> +/* Given a pointer or a reference value V, find its real (RTTI) type.
> 
>     Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
>     and refer to the values computed for the object pointed to.  */
> @@ -3539,12 +3538,37 @@ value_rtti_target_type (struct value *v, int *full,

You are changing the behavior of this function wrt. indirection.  I would find
best to rename it, this way you ensure all the callers are reviewed, incl.
possible callers in 3rd party patches which are common for GDB.


>              int *top, int *using_enc)
>  {
>    struct value *target;
> +  struct type *type, *real_type;
> 
> -  target = value_ind (v);
> +  type = value_type (v);
> +  type = check_typedef (type);
> +  if (TYPE_CODE (type) == TYPE_CODE_REF)
> +    target = coerce_ref (v);
> +  else if (TYPE_CODE (type) == TYPE_CODE_PTR)
> +    target = value_ind (v);
> +  else
> +    return 0;

return NULL, it is a pointer.

> 
> -  return value_rtti_type (target, full, top, using_enc);
> +  real_type = value_rtti_type (target, full, top, using_enc);
> +
> +  if (real_type)
> +    {
> +      struct type *target_type = value_type (target);
> +
> +      /* Copy qualifiers to the referenced object.  */
> +      real_type = make_cv_type (TYPE_CONST (target_type), TYPE_VOLATILE (target_type), real_type, NULL);
> +      if (TYPE_CODE (type) == TYPE_CODE_REF)
> +        real_type = lookup_reference_type (real_type);
> +      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
> +        real_type = lookup_pointer_type (real_type);

Empty line before comment.

> +      /* Copy qualifiers to the pointer/reference.  */
> +      real_type = make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type), real_type, NULL);
> +    }
> +
> +  return real_type;
>  }
> 
> +
>  /* Given a value pointed to by ARGP, check its real run-time type, and
>     if that is different from the enclosing type, create a new value
>     using the real run-time type as the enclosing type (and of the same
> diff --git a/gdb/value.c b/gdb/value.c
> index d263d0c..7d9e5cc 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -821,6 +821,33 @@ value_enclosing_type (struct value *value)
>    return value->enclosing_type;
>  }
> 
> +struct type *
> +value_actual_type (struct value *value, int resolve_simple_types)
> +{
> +  struct value_print_options opts;
> +  struct value *target;
> +  struct type *result;
> +
> +  get_user_print_options (&opts);
> +
> +  result = value_type (value);
> +  if (opts.objectprint)
> +  {
> +    if ((TYPE_CODE (result) == TYPE_CODE_PTR) || (TYPE_CODE (result) == TYPE_CODE_REF))

Those inner parens are excessive.
       if (TYPE_CODE (result) == TYPE_CODE_PTR || TYPE_CODE (result) == TYPE_CODE_REF)

> +    {
> +      struct type *real_type;
> +
> +      real_type = value_rtti_target_type (value, 0, 0, 0);
> +      if (real_type)
> +        result = real_type;
> +    }
> +    else if (resolve_simple_types)
> +      result = value_enclosing_type (value);
> +  }
> +
> +  return result;
> +}
> +
>  static void
>  require_not_optimized_out (const struct value *value)
>  {
> @@ -3114,6 +3141,7 @@ coerce_ref (struct value *arg)
>  {
>    struct type *value_type_arg_tmp = check_typedef (value_type (arg));
>    struct value *retval;
> +  struct type *enc_type;
> 
>    retval = coerce_ref_if_computed (arg);
>    if (retval)


> @@ -3122,9 +3150,23 @@ coerce_ref (struct value *arg)
>    if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
>      return arg;
> 
> -  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
> +  enc_type = check_typedef (value_enclosing_type (arg));
> +  enc_type = TYPE_TARGET_TYPE (enc_type);
> +
> +  retval = value_at_lazy (enc_type,
>              unpack_pointer (value_type (arg),
>                      value_contents (arg)));
> +  /* Re-adjust type.  */
> +  deprecated_set_value_type (retval, TYPE_TARGET_TYPE (value_type_arg_tmp));
> +
> +  /* Add embedding info.  */
> +  set_value_enclosing_type (retval, enc_type);
> +  set_value_embedded_offset (retval, value_pointed_to_offset (arg));
> +
> +  /* We may be pointing to an object of some derived type.  */
> +  retval = value_full_object (retval, NULL, 0, 0, 0);
> +
> +  return retval;
>  }

Please put this code into some function called also by value_ind, instead of
just copy-pasting it.


> 
>  struct value *
> diff --git a/gdb/value.h b/gdb/value.h
> index d2c58ec..c01da3e 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -139,6 +139,15 @@ 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.  */
> +extern struct type *value_actual_type (struct value *value, int resolve_simple_types);
> +
>  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);
> diff --git a/gdb/varobj.c b/gdb/varobj.c
> index 7c68a93..47390cb 100644
> --- a/gdb/varobj.c
> +++ b/gdb/varobj.c
> @@ -660,7 +660,17 @@ varobj_create (char *objname,
>        var->type = value_type (type_only_value);
>      }
>        else
> -    var->type = value_type (value);
> +    {

Here is some whitespace corruption, there should have been tab before
var->type.


> @@ -3259,7 +3301,14 @@ cplus_number_of_children (struct varobj *var)
>        int kids[3];
> 
>        type = get_value_type (var->parent);
> -      adjust_value_for_child_access (NULL, &type, NULL);

Empty line before a comment line.

> +      /* It is necessary to access a real type (via RTTI).  */
> +      if (opts.objectprint)
> +        {
> +          value = var->parent->value;
> +          lookup_actual_type = (TYPE_CODE (var->parent->type) == TYPE_CODE_REF
> +                                || TYPE_CODE (var->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)


Thanks,
Jan

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2011-12-21 19:37     ` Jan Kratochvil
@ 2011-12-22 10:17       ` xgsa
  2011-12-24  1:55         ` Jan Kratochvil
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2011-12-22 10:17 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches

The updated ChangeLog & patch after Jan's review fixture.


gdb/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

     PR mi/13393

     * gdb/valops.c (value_rtti_target_type): Replaced with
     value_rtti_indirect_type.
     (value_rtti_indirect_type): New function.  The same as
     value_rtti_target_type, but return a reference or pointer type (because
     every caller do it after call that leads to code duplication).
     * gdb/c-valprint.c (c_value_print): Use value_rtti_indirect_type
     instead of value_rtti_target_type.
     * gdb/eval.c (evaluate_subexp_standard): Use value_rtti_indirect_type
     instead of value_rtti_target_type.
     * gdb/typeprint.c: Use value_rtti_indirect_type instead of
     value_rtti_target_type.
     * gdb/value.c (value_actual_type): New function.
     (value_rtti_indirect_type): New function.
     (coerce_ref): Support for enclosing type setting for references
     with readjust_value_type.
     * gdb/value.h (value_actual_type): Add prototype.
     (readjust_value_type): Add prototype.
     * gdb/valops.c (value_ind): Extract value type and enclosing type setting
     to a separate function readjust_value_type.
     * gdb/varobj.c (varobj_create): Call value_actual_type if necessary.
     (create_child_with_value): Call value_actual_type.
     (value_of_root): Support for type change if the value changed and RTTI is
     used to determine type.
     (adjust_value_for_child_access): Extended with a new parameter and cast
     given value to enclosing type is necessary.
     (c_number_of_children): Update for extended adjust_value_for_child_access.
     (cplus_number_of_children): Send a value as parameter if RTTI should be
     used to determine type.
     (cplus_describe_child): Determine whether RTTI type should be used.

gdb/testsuite/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

     PR mi/13393

     * gdb.mi/mi-var-rtti.cc: New file.
     * gdb.mi/mi-var-rtti.exp: New file.


diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 3461b08..d81d07d 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -698,22 +698,12 @@ c_value_print (struct value *val, struct ui_file *stream,

        if (value_entirely_available (val))
           {
-          real_type = value_rtti_target_type (val, &full, &top, &using_enc);
+          real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);
            if (real_type)
          {
            /* RTTI entry found.  */
-          if (TYPE_CODE (type) == TYPE_CODE_PTR)
-            {
-              /* Create a pointer type pointing to the real
-             type.  */
-              type = lookup_pointer_type (real_type);
-            }
-          else
-            {
-              /* Create a reference type referencing the real
-             type.  */
-              type = lookup_reference_type (real_type);
-            }
+          type = real_type;
+
            /* Need to adjust pointer value.  */
            val = value_from_pointer (type, value_as_address (val) - top);

diff --git a/gdb/eval.c b/gdb/eval.c
index 5d758d1..3d23d0f 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1990,16 +1990,9 @@ evaluate_subexp_standard (struct type *expect_type,
          if (opts.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);
+            real_type = value_rtti_indirect_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);
-              }
            }
        }

diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..3622f3b
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -0,0 +1,184 @@
+/* Copyright 2011 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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti ptr {Base \*}
+    mi_var_rtti__check_derived_class_without_rtti constPtr {const Base \*}
+    mi_var_rtti__check_derived_class_without_rtti ptrConst {Base \* const}
+    mi_var_rtti__check_derived_class_without_rtti constPtrConst {const Base \* const}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti ptr {Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti constPtr {const Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti ptrConst {Derived \* const}
+    mi_var_rtti__check_derived_class_with_rtti constPtrConst {const Derived \* const}
+  :*/
+    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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti ref {Base \&}
+    mi_var_rtti__check_derived_class_without_rtti constRef {const Base \&}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti ref {Derived \&}
+    mi_var_rtti__check_derived_class_with_rtti constRef {const Derived \&}
+  :*/
+    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 );
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti s.ptr {Base \*}
+    mi_var_rtti__check_derived_class_without_rtti s.constPtr {const Base \*}
+    mi_var_rtti__check_derived_class_without_rtti s.ptrConst {Base \* const}
+    mi_var_rtti__check_derived_class_without_rtti s.constPtrConst {const Base \* const}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti s.ptr {Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti s.constPtr {const Derived \*}
+    mi_var_rtti__check_derived_class_with_rtti s.ptrConst {Derived \* const}
+    mi_var_rtti__check_derived_class_with_rtti s.constPtrConst {const Derived \* const}
+  :*/
+    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 );
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_var_rtti__check_derived_class_without_rtti s.ref {Base \&}
+    mi_var_rtti__check_derived_class_without_rtti s.constRef {const Base \&}
+
+    mi_var_rtti__set_print_object on
+    mi_var_rtti__check_derived_class_with_rtti s.ref {Derived \&}
+    mi_var_rtti__check_derived_class_with_rtti s.constRef {const Derived \&}
+  :*/
+    return;
+  /*: END: use_rtti_for_ref_child :*/
+}
+
+void type_update_when_use_rtti_test ()
+{
+  /*: BEGIN: type_update_when_use_rtti :*/
+    Derived d;
+  /*:
+    mi_var_rtti__set_print_object on
+    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+  :*/
+
+    Base* ptr = &d;
+  /*:
+    mi_varobj_update_with_type_change VAR {Derived \*} 2 "update ptr"
+    mi_var_rtti__check_derived_children_with_rtti ptr
+    mi_var_rtti__check_derived_content_with_rtti ptr
+    mi_delete_varobj VAR "delete varobj for ptr"
+  :*/
+    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;
+  /*:
+    mi_var_rtti__set_print_object off
+    mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+  :*/
+
+    Base* ptr = &d;
+  /*:
+    mi_varobj_update VAR {} "update ptr"
+    mi_var_rtti__check_derived_children_without_rtti ptr
+    mi_var_rtti__check_derived_content_without_rtti ptr
+    mi_delete_varobj VAR "delete varobj for ptr"
+  :*/
+    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();
+    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
index 0000000..177b63c
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -0,0 +1,108 @@
+# Copyright 2011 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 binfile $objdir/$subdir/$testfile
+
+if [get_compiler_info ${binfile} "c++"] {
+    return -1;
+}
+
+if {[gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug c++}] != ""} {
+  untested $testfile.exp
+  return -1
+}
+
+mi_gdb_load ${binfile}
+
+mi_prepare_inline_tests $srcfile
+
+# Enable using RTTI to determine real types of the objects
+proc mi_var_rtti__set_print_object {state} {
+  mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \
+    {\^done} \
+    "-interpreter-exec console \"set print object ${state}\""
+}
+
+proc mi_var_rtti__check_derived_children_without_rtti {var_name} {
+  mi_list_varobj_children VAR {
+     { VAR.public            public    1         }
+  } "list children of ${var_name} (without RTTI)"
+  mi_list_varobj_children "VAR.public" {
+     { VAR.public.A            A        0    int }
+  } "list children of ${var_name}.public (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_content_without_rtti {var_name} {
+  mi_check_varobj_value VAR.public.A        1 "check ${var_name}->A (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_class_without_rtti {var_name var_type} {
+  mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj for ${var_name} (without RTTI)"
+  mi_var_rtti__check_derived_children_without_rtti ${var_name}
+  mi_var_rtti__check_derived_content_without_rtti ${var_name}
+  mi_delete_varobj VAR "delete varobj for ${var_name} (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_children_with_rtti {var_name} {
+    mi_list_varobj_children VAR {
+       { VAR.Base            Base    1    Base }
+       { VAR.public            public    2         }
+    } "list children of ${var_name} (with RTTI)"
+    mi_list_varobj_children "VAR.Base" {
+       { VAR.Base.public    public 1 }
+    } "list children of ${var_name}.Base (with RTTI)"
+    mi_list_varobj_children "VAR.Base.public" {
+       { VAR.Base.public.A    A        0    int    }
+    } "list children of ${var_name}.Base.public (with RTTI)"
+    mi_list_varobj_children "VAR.public" {
+       { VAR.public.B        B        0    int }
+       { VAR.public.C        C        0    int }
+    } "list children of ${var_name}.public (with RTTI)"
+}
+
+proc mi_var_rtti__check_derived_content_with_rtti {var_name} {
+    mi_check_varobj_value VAR.Base.public.A    1 "check ${var_name}->A (with RTTI)"
+    mi_check_varobj_value VAR.public.B        2 "check ${var_name}->B (with RTTI)"
+    mi_check_varobj_value VAR.public.C        3 "check ${var_name}->C (with RTTI)"
+}
+
+proc mi_var_rtti__check_derived_class_with_rtti {var_name var_type} {
+    mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj for ${var_name} (with RTTI)"
+    mi_var_rtti__check_derived_children_with_rtti ${var_name}
+    mi_var_rtti__check_derived_content_with_rtti ${var_name}
+    mi_delete_varobj VAR "delete varobj for ${var_name} (with RTTI)"
+}
+
+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 type_update_when_use_rtti
+mi_run_inline_test skip_type_update_when_not_use_rtti
+
+mi_gdb_exit
+return 0
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index cf4158d..6546c98 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
        if (((TYPE_CODE (type) == TYPE_CODE_PTR)
         || (TYPE_CODE (type) == TYPE_CODE_REF))
&& (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
-        {
-          real_type = value_rtti_target_type (val, &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);
-            }
-        }
+        real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);
        else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
      real_type = value_rtti_type (val, &full, &top, &using_enc);
      }
diff --git a/gdb/valops.c b/gdb/valops.c
index cb39677..b4ebe36 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1774,15 +1774,7 @@ value_ind (struct value *arg1)
                    (value_as_address (arg1)
                     - value_pointed_to_offset (arg1)));

-      /* Re-adjust type.  */
-      deprecated_set_value_type (arg2, TYPE_TARGET_TYPE (base_type));
-      /* Add embedding info.  */
-      set_value_enclosing_type (arg2, enc_type);
-      set_value_embedded_offset (arg2, value_pointed_to_offset (arg1));
-
-      /* We may be pointing to an object of some derived type.  */
-      arg2 = value_full_object (arg2, NULL, 0, 0, 0);
-      return arg2;
+      return readjust_value_type (arg2, enc_type, base_type, arg1);
      }

    error (_("Attempt to take contents of a non-pointer value."));
@@ -3528,23 +3520,48 @@ value_maybe_namespace_elt (const struct type *curtype,
    return result;
  }

-/* Given a pointer value V, find the real (RTTI) type of the object it
-   points to.
+/* Given a pointer or a reference value V, find its real (RTTI) type.

     Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
     and refer to the values computed for the object pointed to.  */

  struct type *
-value_rtti_target_type (struct value *v, int *full,
-            int *top, int *using_enc)
+value_rtti_indirect_type (struct value *v, int *full,
+              int *top, int *using_enc)
  {
    struct value *target;
+  struct type *type, *real_type, *target_type;
+
+  type = value_type (v);
+  type = check_typedef (type);
+  if (TYPE_CODE (type) == TYPE_CODE_REF)
+    target = coerce_ref (v);
+  else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    target = value_ind (v);
+  else
+    return NULL;

-  target = value_ind (v);
+  real_type = value_rtti_type (target, full, top, using_enc);

-  return value_rtti_type (target, full, top, using_enc);
+  if (real_type)
+    {
+      /* Copy qualifiers to the referenced object.  */
+      target_type = value_type (target);
+      real_type = make_cv_type (TYPE_CONST (target_type),
+                                TYPE_VOLATILE (target_type), real_type, NULL);
+      if (TYPE_CODE (type) == TYPE_CODE_REF)
+        real_type = lookup_reference_type (real_type);
+      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+        real_type = lookup_pointer_type (real_type);
+      /* Copy qualifiers to the pointer/reference.  */
+      real_type = make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type),
+                                real_type, NULL);
+    }
+
+  return real_type;
  }

+
  /* Given a value pointed to by ARGP, check its real run-time type, and
     if that is different from the enclosing type, create a new value
     using the real run-time type as the enclosing type (and of the same
diff --git a/gdb/value.c b/gdb/value.c
index d263d0c..15726c0 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -821,6 +821,35 @@ 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)
+{
+  struct value_print_options opts;
+  struct value *target;
+  struct type *result;
+
+  get_user_print_options (&opts);
+
+  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, 0, 0, 0);
+      if (real_type)
+        result = real_type;
+    }
+    else if (resolve_simple_types)
+      result = value_enclosing_type (value);
+  }
+
+  return result;
+}
+
  static void
  require_not_optimized_out (const struct value *value)
  {
@@ -3110,10 +3139,26 @@ coerce_ref_if_computed (const struct value *arg)
  }

  struct value *
+readjust_value_type (struct value *value, struct type *enc_type,
+                     struct type *original_type, struct value *original_value)
+{
+  /* Re-adjust type.  */
+  deprecated_set_value_type (value, TYPE_TARGET_TYPE (original_type));
+
+  /* Add embedding info.  */
+  set_value_enclosing_type (value, enc_type);
+  set_value_embedded_offset (value, value_pointed_to_offset (original_value));
+
+  /* We may be pointing to an object of some derived type.  */
+  return value_full_object (value, NULL, 0, 0, 0);
+}
+
+struct value *
  coerce_ref (struct value *arg)
  {
    struct type *value_type_arg_tmp = check_typedef (value_type (arg));
    struct value *retval;
+  struct type *enc_type;

    retval = coerce_ref_if_computed (arg);
    if (retval)
@@ -3122,9 +3167,13 @@ coerce_ref (struct value *arg)
    if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
      return arg;

-  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
-            unpack_pointer (value_type (arg),
-                    value_contents (arg)));
+  enc_type = check_typedef (value_enclosing_type (arg));
+  enc_type = TYPE_TARGET_TYPE (enc_type);
+
+  retval = value_at_lazy (enc_type,
+                          unpack_pointer (value_type (arg),
+                                          value_contents (arg)));
+  return readjust_value_type (retval, enc_type, value_type_arg_tmp, arg);
  }

  struct value *
diff --git a/gdb/value.h b/gdb/value.h
index d2c58ec..7345c71 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -139,6 +139,16 @@ 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.  */
+
+extern struct type *value_actual_type (struct value *value, int resolve_simple_types);
+
  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);
@@ -353,6 +363,13 @@ extern short *deprecated_value_regnum_hack (struct value *);

  extern struct value *coerce_ref_if_computed (const struct value *arg);

+/* Setup a new value type and enclosing value type for dereferenced value.
+   It is a common implementation for coerce_ref and value_ind.  */
+
+extern struct value *
+readjust_value_type (struct value *value, struct type *enc_type,
+                     struct type *original_type, struct value *original_value);
+
  /* Convert a REF to the object referenced.  */

  extern struct value *coerce_ref (struct value *value);
@@ -617,8 +634,8 @@ extern struct value *value_primitive_field (struct value *arg1, int offset,
                          struct type *arg_type);


-extern struct type *value_rtti_target_type (struct value *, int *, int *,
-                        int *);
+extern struct type *value_rtti_indirect_type (struct value *, int *, int *,
+                          int *);

  extern struct value *value_full_object (struct value *, struct type *, int,
                      int, int);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 7c68a93..dfeb71b 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -659,8 +659,18 @@ varobj_create (char *objname,

        var->type = value_type (type_only_value);
      }
-      else
-    var->type = value_type (value);
+    else
+    {
+      struct type *enclosing_type;
+
+      var->type = value_type (value);
+      enclosing_type = value_actual_type (value, 0);
+      if (check_typedef (enclosing_type) != check_typedef (var->type))
+        {
+          var->type = enclosing_type;
+          value = value_cast (enclosing_type, value);
+        }
+    }

        install_new_value (var, value, 1 /* Initial assignment */);

@@ -2194,7 +2204,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);
    else
      /* Otherwise, we must compute the type.  */
      child->type = (*child->root->lang->type_of_child) (child->parent,
@@ -2480,6 +2490,7 @@ static struct value *
  value_of_root (struct varobj **var_handle, int *type_changed)
  {
    struct varobj *var;
+  struct value_print_options opts;

    if (var_handle == NULL)
      return NULL;
@@ -2492,7 +2503,8 @@ value_of_root (struct varobj **var_handle, int *type_changed)
    if (!is_root_p (var))
      return NULL;

-  if (var->root->floating)
+  get_user_print_options (&opts);
+  if (var->root->floating || opts.objectprint)
      {
        struct varobj *tmp_var;
        char *old_type, *new_type;
@@ -2781,6 +2793,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
@@ -2792,7 +2808,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);

@@ -2832,6 +2849,19 @@ 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;
+
+      enclosing_type = value_actual_type (*value, 1);
+      if (check_typedef (enclosing_type) != check_typedef (*type))
+        {
+          *type = enclosing_type;
+          *value = value_cast (enclosing_type, *value);
+        }
+    }
  }

  /* C */
@@ -2842,7 +2872,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))
@@ -2957,7 +2987,7 @@ c_describe_child (struct varobj *parent, int index,
        *cfull_expression = NULL;
        parent_expression = varobj_get_path_expr (parent);
      }
-  adjust_value_for_child_access (&value, &type, &was_ptr);
+  adjust_value_for_child_access (&value, &type, &was_ptr, 0);

    switch (TYPE_CODE (type))
      {
@@ -3223,16 +3253,28 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
  static int
  cplus_number_of_children (struct varobj *var)
  {
+  struct value *value = 0;
    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))
@@ -3259,7 +3301,15 @@ 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)
+        {
+          value = var->parent->value;
+          lookup_actual_type = (TYPE_CODE (var->parent->type) == TYPE_CODE_REF
+                                || TYPE_CODE (var->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)
@@ -3341,7 +3391,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;
@@ -3352,22 +3405,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 (parent->parent);
-    }
-  else
-    {
-      value = parent->value;
-      type = get_value_type (parent);
-      if (cfull_expression)
-    parent_expression = varobj_get_path_expr (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 (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)

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2011-12-22 10:17       ` set print object on should affect MI varobjs (PR mi/13393) xgsa
@ 2011-12-24  1:55         ` Jan Kratochvil
  2011-12-24 13:56           ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2011-12-24  1:55 UTC (permalink / raw)
  To: xgsa; +Cc: Tom Tromey, gdb-patches

On Thu, 22 Dec 2011 11:16:41 +0100, xgsa wrote:
> Content-Type: text/plain; charset=ISO-8859-1; format=flowed
> 
> The updated ChangeLog & patch after Jan's review fixture.

Could you please use either a different mail client or if not possible then at
least to attach the patch as file?

The "flowed" format corrupts it a lot, I do not know where are which spaces,
for example I guess your ChangeLog entry exceeds 80 characters as 8 initial
characters is tab.  And I cannot apply the patch, with both rfc822 text or
decoded body I get:
	patching file gdb/c-valprint.c
	Hunk #1 FAILED at 698.
	1 out of 1 hunk FAILED -- saving rejects to file gdb/c-valprint.c.rej
	patching file gdb/eval.c
	patch: **** malformed patch at line 86: && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))

Sorry for the hassle.


Thanks,
Jan

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2011-12-24  1:55         ` Jan Kratochvil
@ 2011-12-24 13:56           ` xgsa
  2012-01-02  2:22             ` Jan Kratochvil
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2011-12-24 13:56 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches

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

I have used 4 spaces for tabs in ChangeLog, sorry. Fixed.


Thanks,
Anton


gdb/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

         PR mi/13393

         * gdb/valops.c (value_rtti_target_type): Replaced with
         value_rtti_indirect_type.
         (value_rtti_indirect_type): New function.  The same as
         value_rtti_target_type, but return a reference or pointer type (because
         every caller do it after call that leads to code duplication).
         * gdb/c-valprint.c (c_value_print): Use value_rtti_indirect_type
         instead of value_rtti_target_type.
         * gdb/eval.c (evaluate_subexp_standard): Use value_rtti_indirect_type
         instead of value_rtti_target_type.
         * gdb/typeprint.c: Use value_rtti_indirect_type instead of
         value_rtti_target_type.
         * gdb/value.c (value_actual_type): New function.
         (value_rtti_indirect_type): New function.
         (coerce_ref): Support for enclosing type setting for references
         with readjust_value_type.
         * gdb/value.h (value_actual_type): Add prototype.
         (readjust_value_type): Add prototype.
         * gdb/valops.c (value_ind): Extract value type and enclosing type
         setting to a separate function readjust_value_type.
         * gdb/varobj.c (varobj_create): Call value_actual_type if necessary.
         (create_child_with_value): Call value_actual_type.
         (value_of_root): Support for type change if the value changed and RTTI
         is used to determine type.
         (adjust_value_for_child_access): Extended with a new parameter and cast
         given value to enclosing type is necessary.
         (c_number_of_children): Updated for extended
         adjust_value_for_child_access.
         (cplus_number_of_children): Send a value as parameter if RTTI should be
         used to determine type.
         (cplus_describe_child): Determine whether RTTI type should be used.

gdb/testsuite/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

         PR mi/13393

         * gdb.mi/mi-var-rtti.cc: New file.
         * gdb.mi/mi-var-rtti.exp: New file.


[-- Attachment #2: gdb_mi4.patch --]
[-- Type: text/x-diff, Size: 26366 bytes --]

diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 3461b08..d81d07d 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -698,22 +698,12 @@ c_value_print (struct value *val, struct ui_file *stream,
 
 	  if (value_entirely_available (val))
  	    {
-	      real_type = value_rtti_target_type (val, &full, &top, &using_enc);
+	      real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);
 	      if (real_type)
 		{
 		  /* RTTI entry found.  */
-		  if (TYPE_CODE (type) == TYPE_CODE_PTR)
-		    {
-		      /* Create a pointer type pointing to the real
-			 type.  */
-		      type = lookup_pointer_type (real_type);
-		    }
-		  else
-		    {
-		      /* Create a reference type referencing the real
-			 type.  */
-		      type = lookup_reference_type (real_type);
-		    }
+		  type = real_type;
+
 		  /* Need to adjust pointer value.  */
 		  val = value_from_pointer (type, value_as_address (val) - top);
 
diff --git a/gdb/eval.c b/gdb/eval.c
index 5d758d1..3d23d0f 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1990,16 +1990,9 @@ evaluate_subexp_standard (struct type *expect_type,
         if (opts.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);
+            real_type = value_rtti_indirect_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);
-              }
           }
       }
 
diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..3622f3b
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -0,0 +1,184 @@
+/* Copyright 2011 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;
+  /*: 
+	mi_var_rtti__set_print_object off
+	mi_var_rtti__check_derived_class_without_rtti ptr {Base \*}
+	mi_var_rtti__check_derived_class_without_rtti constPtr {const Base \*}
+	mi_var_rtti__check_derived_class_without_rtti ptrConst {Base \* const}
+	mi_var_rtti__check_derived_class_without_rtti constPtrConst {const Base \* const}
+
+	mi_var_rtti__set_print_object on
+	mi_var_rtti__check_derived_class_with_rtti ptr {Derived \*}
+	mi_var_rtti__check_derived_class_with_rtti constPtr {const Derived \*}
+	mi_var_rtti__check_derived_class_with_rtti ptrConst {Derived \* const}
+	mi_var_rtti__check_derived_class_with_rtti constPtrConst {const Derived \* const}
+  :*/
+	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;
+  /*: 
+	mi_var_rtti__set_print_object off
+	mi_var_rtti__check_derived_class_without_rtti ref {Base \&}
+	mi_var_rtti__check_derived_class_without_rtti constRef {const Base \&}
+
+	mi_var_rtti__set_print_object on
+	mi_var_rtti__check_derived_class_with_rtti ref {Derived \&}
+	mi_var_rtti__check_derived_class_with_rtti constRef {const Derived \&}
+  :*/
+	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 );
+  /*: 
+	mi_var_rtti__set_print_object off
+	mi_var_rtti__check_derived_class_without_rtti s.ptr {Base \*}
+	mi_var_rtti__check_derived_class_without_rtti s.constPtr {const Base \*}
+	mi_var_rtti__check_derived_class_without_rtti s.ptrConst {Base \* const}
+	mi_var_rtti__check_derived_class_without_rtti s.constPtrConst {const Base \* const}
+
+	mi_var_rtti__set_print_object on
+	mi_var_rtti__check_derived_class_with_rtti s.ptr {Derived \*}
+	mi_var_rtti__check_derived_class_with_rtti s.constPtr {const Derived \*}
+	mi_var_rtti__check_derived_class_with_rtti s.ptrConst {Derived \* const}
+	mi_var_rtti__check_derived_class_with_rtti s.constPtrConst {const Derived \* const}
+  :*/
+	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 );
+  /*: 
+	mi_var_rtti__set_print_object off
+	mi_var_rtti__check_derived_class_without_rtti s.ref {Base \&}
+	mi_var_rtti__check_derived_class_without_rtti s.constRef {const Base \&}
+
+	mi_var_rtti__set_print_object on
+	mi_var_rtti__check_derived_class_with_rtti s.ref {Derived \&}
+	mi_var_rtti__check_derived_class_with_rtti s.constRef {const Derived \&}
+  :*/
+	return;
+  /*: END: use_rtti_for_ref_child :*/
+}
+
+void type_update_when_use_rtti_test ()
+{
+  /*: BEGIN: type_update_when_use_rtti :*/
+	Derived d;
+  /*: 
+	mi_var_rtti__set_print_object on
+	mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
+	mi_var_rtti__check_derived_children_without_rtti ptr
+  :*/
+
+	Base* ptr = &d;
+  /*: 
+	mi_varobj_update_with_type_change VAR {Derived \*} 2 "update ptr"
+	mi_var_rtti__check_derived_children_with_rtti ptr
+	mi_var_rtti__check_derived_content_with_rtti ptr
+	mi_delete_varobj VAR "delete varobj for ptr"
+  :*/
+	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;
+  /*: 
+	mi_var_rtti__set_print_object off
+	mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
+	mi_var_rtti__check_derived_children_without_rtti ptr
+  :*/
+
+	Base* ptr = &d;
+  /*: 
+	mi_varobj_update VAR {} "update ptr"
+	mi_var_rtti__check_derived_children_without_rtti ptr
+	mi_var_rtti__check_derived_content_without_rtti ptr
+	mi_delete_varobj VAR "delete varobj for ptr"
+  :*/
+	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();
+	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
index 0000000..177b63c
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -0,0 +1,108 @@
+# Copyright 2011 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 binfile $objdir/$subdir/$testfile
+
+if [get_compiler_info ${binfile} "c++"] {
+    return -1;
+}
+
+if {[gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug c++}] != ""} {
+  untested $testfile.exp
+  return -1
+}
+
+mi_gdb_load ${binfile}
+
+mi_prepare_inline_tests $srcfile
+
+# Enable using RTTI to determine real types of the objects
+proc mi_var_rtti__set_print_object {state} {
+  mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \
+    {\^done} \
+    "-interpreter-exec console \"set print object ${state}\""
+}
+
+proc mi_var_rtti__check_derived_children_without_rtti {var_name} {
+  mi_list_varobj_children VAR {
+     { VAR.public			public	1		 }
+  } "list children of ${var_name} (without RTTI)"
+  mi_list_varobj_children "VAR.public" {
+     { VAR.public.A			A		0	int }
+  } "list children of ${var_name}.public (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_content_without_rtti {var_name} {
+  mi_check_varobj_value VAR.public.A		1 "check ${var_name}->A (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_class_without_rtti {var_name var_type} {
+  mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj for ${var_name} (without RTTI)"
+  mi_var_rtti__check_derived_children_without_rtti ${var_name}
+  mi_var_rtti__check_derived_content_without_rtti ${var_name}
+  mi_delete_varobj VAR "delete varobj for ${var_name} (without RTTI)"
+}
+
+proc mi_var_rtti__check_derived_children_with_rtti {var_name} {
+    mi_list_varobj_children VAR {
+       { VAR.Base			Base	1	Base }
+       { VAR.public			public	2		 }
+    } "list children of ${var_name} (with RTTI)"
+    mi_list_varobj_children "VAR.Base" {
+       { VAR.Base.public	public 1 }
+    } "list children of ${var_name}.Base (with RTTI)"
+    mi_list_varobj_children "VAR.Base.public" {
+       { VAR.Base.public.A	A		0	int	}
+    } "list children of ${var_name}.Base.public (with RTTI)"
+    mi_list_varobj_children "VAR.public" {
+       { VAR.public.B		B		0	int }
+       { VAR.public.C		C		0	int }
+    } "list children of ${var_name}.public (with RTTI)"
+}
+
+proc mi_var_rtti__check_derived_content_with_rtti {var_name} {
+    mi_check_varobj_value VAR.Base.public.A	1 "check ${var_name}->A (with RTTI)"
+    mi_check_varobj_value VAR.public.B		2 "check ${var_name}->B (with RTTI)"
+    mi_check_varobj_value VAR.public.C		3 "check ${var_name}->C (with RTTI)"
+}
+
+proc mi_var_rtti__check_derived_class_with_rtti {var_name var_type} {
+    mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj for ${var_name} (with RTTI)"
+	mi_var_rtti__check_derived_children_with_rtti ${var_name}
+	mi_var_rtti__check_derived_content_with_rtti ${var_name}
+    mi_delete_varobj VAR "delete varobj for ${var_name} (with RTTI)"
+}
+
+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 type_update_when_use_rtti
+mi_run_inline_test skip_type_update_when_not_use_rtti
+
+mi_gdb_exit
+return 0
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index cf4158d..6546c98 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
       if (((TYPE_CODE (type) == TYPE_CODE_PTR)
 	   || (TYPE_CODE (type) == TYPE_CODE_REF))
 	  && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
-        {
-          real_type = value_rtti_target_type (val, &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);
-            }
-        }
+        real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);
       else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
 	real_type = value_rtti_type (val, &full, &top, &using_enc);
     }
diff --git a/gdb/valops.c b/gdb/valops.c
index cb39677..b4ebe36 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1774,15 +1774,7 @@ value_ind (struct value *arg1)
 			      (value_as_address (arg1)
 			       - value_pointed_to_offset (arg1)));
 
-      /* Re-adjust type.  */
-      deprecated_set_value_type (arg2, TYPE_TARGET_TYPE (base_type));
-      /* Add embedding info.  */
-      set_value_enclosing_type (arg2, enc_type);
-      set_value_embedded_offset (arg2, value_pointed_to_offset (arg1));
-
-      /* We may be pointing to an object of some derived type.  */
-      arg2 = value_full_object (arg2, NULL, 0, 0, 0);
-      return arg2;
+      return readjust_value_type (arg2, enc_type, base_type, arg1);
     }
 
   error (_("Attempt to take contents of a non-pointer value."));
@@ -3528,23 +3520,48 @@ value_maybe_namespace_elt (const struct type *curtype,
   return result;
 }
 
-/* Given a pointer value V, find the real (RTTI) type of the object it
-   points to.
+/* Given a pointer or a reference value V, find its real (RTTI) type.
 
    Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
    and refer to the values computed for the object pointed to.  */
 
 struct type *
-value_rtti_target_type (struct value *v, int *full, 
-			int *top, int *using_enc)
+value_rtti_indirect_type (struct value *v, int *full, 
+			  int *top, int *using_enc)
 {
   struct value *target;
+  struct type *type, *real_type, *target_type;
+
+  type = value_type (v);
+  type = check_typedef (type);
+  if (TYPE_CODE (type) == TYPE_CODE_REF)
+    target = coerce_ref (v);
+  else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    target = value_ind (v);
+  else
+    return NULL;
 
-  target = value_ind (v);
+  real_type = value_rtti_type (target, full, top, using_enc);
 
-  return value_rtti_type (target, full, top, using_enc);
+  if (real_type)
+    {
+      /* Copy qualifiers to the referenced object.  */
+      target_type = value_type (target);
+      real_type = make_cv_type (TYPE_CONST (target_type),
+                                TYPE_VOLATILE (target_type), real_type, NULL);
+      if (TYPE_CODE (type) == TYPE_CODE_REF)
+        real_type = lookup_reference_type (real_type);
+      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+        real_type = lookup_pointer_type (real_type);
+      /* Copy qualifiers to the pointer/reference.  */
+      real_type = make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type),
+                                real_type, NULL);
+    }
+
+  return real_type;
 }
 
+
 /* Given a value pointed to by ARGP, check its real run-time type, and
    if that is different from the enclosing type, create a new value
    using the real run-time type as the enclosing type (and of the same
diff --git a/gdb/value.c b/gdb/value.c
index d263d0c..15726c0 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -821,6 +821,35 @@ 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)
+{
+  struct value_print_options opts;
+  struct value *target;
+  struct type *result;
+
+  get_user_print_options (&opts);
+
+  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, 0, 0, 0);
+      if (real_type)
+        result = real_type;
+    }
+    else if (resolve_simple_types)
+      result = value_enclosing_type (value);
+  }
+
+  return result;
+}
+
 static void
 require_not_optimized_out (const struct value *value)
 {
@@ -3110,10 +3139,26 @@ coerce_ref_if_computed (const struct value *arg)
 }
 
 struct value *
+readjust_value_type (struct value *value, struct type *enc_type,
+                     struct type *original_type, struct value *original_value)
+{
+  /* Re-adjust type.  */
+  deprecated_set_value_type (value, TYPE_TARGET_TYPE (original_type));
+
+  /* Add embedding info.  */
+  set_value_enclosing_type (value, enc_type);
+  set_value_embedded_offset (value, value_pointed_to_offset (original_value));
+
+  /* We may be pointing to an object of some derived type.  */
+  return value_full_object (value, NULL, 0, 0, 0);
+}
+
+struct value *
 coerce_ref (struct value *arg)
 {
   struct type *value_type_arg_tmp = check_typedef (value_type (arg));
   struct value *retval;
+  struct type *enc_type;
 
   retval = coerce_ref_if_computed (arg);
   if (retval)
@@ -3122,9 +3167,13 @@ coerce_ref (struct value *arg)
   if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
     return arg;
 
-  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
-			unpack_pointer (value_type (arg),
-					value_contents (arg)));
+  enc_type = check_typedef (value_enclosing_type (arg));
+  enc_type = TYPE_TARGET_TYPE (enc_type);
+
+  retval = value_at_lazy (enc_type,
+                          unpack_pointer (value_type (arg),
+                                          value_contents (arg)));
+  return readjust_value_type (retval, enc_type, value_type_arg_tmp, arg);
 }
 
 struct value *
diff --git a/gdb/value.h b/gdb/value.h
index d2c58ec..7345c71 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -139,6 +139,16 @@ 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.  */
+
+extern struct type *value_actual_type (struct value *value, int resolve_simple_types);
+
 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);
@@ -353,6 +363,13 @@ extern short *deprecated_value_regnum_hack (struct value *);
 
 extern struct value *coerce_ref_if_computed (const struct value *arg);
 
+/* Setup a new value type and enclosing value type for dereferenced value.
+   It is a common implementation for coerce_ref and value_ind.  */
+
+extern struct value *
+readjust_value_type (struct value *value, struct type *enc_type,
+                     struct type *original_type, struct value *original_value);
+
 /* Convert a REF to the object referenced.  */
 
 extern struct value *coerce_ref (struct value *value);
@@ -617,8 +634,8 @@ extern struct value *value_primitive_field (struct value *arg1, int offset,
 					    struct type *arg_type);
 
 
-extern struct type *value_rtti_target_type (struct value *, int *, int *,
-					    int *);
+extern struct type *value_rtti_indirect_type (struct value *, int *, int *,
+					      int *);
 
 extern struct value *value_full_object (struct value *, struct type *, int,
 					int, int);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 7c68a93..dfeb71b 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -659,8 +659,18 @@ varobj_create (char *objname,
 
 	  var->type = value_type (type_only_value);
 	}
-      else 
-	var->type = value_type (value);
+	else
+	{
+	  struct type *enclosing_type;
+
+	  var->type = value_type (value);
+	  enclosing_type = value_actual_type (value, 0);
+	  if (check_typedef (enclosing_type) != check_typedef (var->type))
+	    {
+	      var->type = enclosing_type;
+	      value = value_cast (enclosing_type, value);
+	    }
+	}
 
       install_new_value (var, value, 1 /* Initial assignment */);
 
@@ -2194,7 +2204,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);
   else
     /* Otherwise, we must compute the type.  */
     child->type = (*child->root->lang->type_of_child) (child->parent, 
@@ -2480,6 +2490,7 @@ static struct value *
 value_of_root (struct varobj **var_handle, int *type_changed)
 {
   struct varobj *var;
+  struct value_print_options opts;
 
   if (var_handle == NULL)
     return NULL;
@@ -2492,7 +2503,8 @@ value_of_root (struct varobj **var_handle, int *type_changed)
   if (!is_root_p (var))
     return NULL;
 
-  if (var->root->floating)
+  get_user_print_options (&opts);
+  if (var->root->floating || opts.objectprint)
     {
       struct varobj *tmp_var;
       char *old_type, *new_type;
@@ -2781,6 +2793,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
@@ -2792,7 +2808,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);
 
@@ -2832,6 +2849,19 @@ 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;
+
+      enclosing_type = value_actual_type (*value, 1);
+      if (check_typedef (enclosing_type) != check_typedef (*type))
+        {
+          *type = enclosing_type;
+          *value = value_cast (enclosing_type, *value);
+        }
+    }
 }
 
 /* C */
@@ -2842,7 +2872,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))
@@ -2957,7 +2987,7 @@ c_describe_child (struct varobj *parent, int index,
       *cfull_expression = NULL;
       parent_expression = varobj_get_path_expr (parent);
     }
-  adjust_value_for_child_access (&value, &type, &was_ptr);
+  adjust_value_for_child_access (&value, &type, &was_ptr, 0);
       
   switch (TYPE_CODE (type))
     {
@@ -3223,16 +3253,28 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
 static int
 cplus_number_of_children (struct varobj *var)
 {
+  struct value *value = 0;
   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))
@@ -3259,7 +3301,15 @@ 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)
+        {
+          value = var->parent->value;
+          lookup_actual_type = (TYPE_CODE (var->parent->type) == TYPE_CODE_REF
+                                || TYPE_CODE (var->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)
@@ -3341,7 +3391,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;
@@ -3352,22 +3405,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 (parent->parent);
-    }
-  else
-    {
-      value = parent->value;
-      type = get_value_type (parent);
-      if (cfull_expression)
-	parent_expression = varobj_get_path_expr (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 (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)

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2011-12-24 13:56           ` xgsa
@ 2012-01-02  2:22             ` Jan Kratochvil
  2012-01-06 15:47               ` RTTI type improvement for (was: "Re: set print object on should affect MI varobjs (PR mi/13393)") xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2012-01-02  2:22 UTC (permalink / raw)
  To: xgsa; +Cc: Tom Tromey, gdb-patches

On Sat, 24 Dec 2011 14:21:09 +0100, xgsa wrote:
> gdb/ChangeLog:

The ChangeLog order did not fully match the patch order, it is difficult to
follow it a bit.


> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
> 
>         PR mi/13393
> 

>         * gdb/valops.c (value_ind): Extract value type and enclosing type
>         setting to a separate function readjust_value_type.

valops.c already has an entry above (below after reordering it); but that
corresponds to the problem the entries are not in the patch order.

All the files are already in gdb/ChangeLog so they should be written as
valops.c, not gdb/valops.c.


>         * gdb/valops.c (value_rtti_target_type): Replaced with
>         value_rtti_indirect_type.
>         (value_rtti_indirect_type): New function.  The same as
>         value_rtti_target_type, but return a reference or pointer type (because
>         every caller do it after call that leads to code duplication).

http://www.gnu.org/prep/standards/standards.html#Change-Log-Concepts
"There’s no need to describe the full purpose of the changes or how they work
together."

Therefore:
	  (value_rtti_target_type): Rename to ...
	  (value_rtti_indirect_type): ... here.
is enough.

That change to value_rtti_indirect_type would be easier to read if it was
a separate patch.


>         * gdb/c-valprint.c (c_value_print): Use value_rtti_indirect_type
>         instead of value_rtti_target_type.
>         * gdb/eval.c (evaluate_subexp_standard): Use value_rtti_indirect_type
>         instead of value_rtti_target_type.
>         * gdb/typeprint.c: Use value_rtti_indirect_type instead of
>         value_rtti_target_type.
>         * gdb/value.c (value_actual_type): New function.

>         (value_rtti_indirect_type): New function.

Here probably should have been readjust_value_type, not
value_rtti_indirect_type.


>         (coerce_ref): Support for enclosing type setting for references
>         with readjust_value_type.
>         * gdb/value.h (value_actual_type): Add prototype.
>         (readjust_value_type): Add prototype.

Missing:
	  (value_rtti_target_type): Rename to ...
	  (value_rtti_indirect_type): ... here.


>         * gdb/varobj.c (varobj_create): Call value_actual_type if necessary.
>         (create_child_with_value): Call value_actual_type.
>         (value_of_root): Support for type change if the value changed and RTTI
>         is used to determine type.
>         (adjust_value_for_child_access): Extended with a new parameter and cast
>         given value to enclosing type is necessary.
>         (c_number_of_children): Updated for extended

Missing/adjust:
          (c_number_of_children, c_describe_child): Updated for extended

>         adjust_value_for_child_access.
>         (cplus_number_of_children): Send a value as parameter if RTTI should be
>         used to determine type.
>         (cplus_describe_child): Determine whether RTTI type should be used.
> 
> gdb/testsuite/ChangeLog:
> 
> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
> 
>         PR mi/13393
> 
>         * gdb.mi/mi-var-rtti.cc: New file.
>         * gdb.mi/mi-var-rtti.exp: New file.

The testcase names should be unique so that one can find one if some FAILs,
they are not unique:
      5 gdb.mi/mi-var-rtti.exp: -interpreter-exec console "set print object on"
      5 gdb.mi/mi-var-rtti.exp: -interpreter-exec console "set print object off"
      4 gdb.mi/mi-var-rtti.exp: list children of ptr.public (without RTTI)
      4 gdb.mi/mi-var-rtti.exp: list children of ptr (without RTTI)
      2 gdb.mi/mi-var-rtti.exp: update ptr
      2 gdb.mi/mi-var-rtti.exp: list children of ptr.public (with RTTI)
      2 gdb.mi/mi-var-rtti.exp: list children of ptr.Base.public (with RTTI)
      2 gdb.mi/mi-var-rtti.exp: list children of ptr.Base (with RTTI)
      2 gdb.mi/mi-var-rtti.exp: list children of ptr (with RTTI)
      2 gdb.mi/mi-var-rtti.exp: delete varobj for ptr
      2 gdb.mi/mi-var-rtti.exp: create varobj for ptr
      2 gdb.mi/mi-var-rtti.exp: check ptr->C (with RTTI)
      2 gdb.mi/mi-var-rtti.exp: check ptr->B (with RTTI)
      2 gdb.mi/mi-var-rtti.exp: check ptr->A (without RTTI)
      2 gdb.mi/mi-var-rtti.exp: check ptr->A (with RTTI) 


> 

> diff --git a/gdb/valops.c b/gdb/valops.c
> index cb39677..b4ebe36 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -1774,15 +1774,7 @@ value_ind (struct value *arg1)
>  			      (value_as_address (arg1)
>  			       - value_pointed_to_offset (arg1)));
>  
> -      /* Re-adjust type.  */
> -      deprecated_set_value_type (arg2, TYPE_TARGET_TYPE (base_type));
> -      /* Add embedding info.  */
> -      set_value_enclosing_type (arg2, enc_type);
> -      set_value_embedded_offset (arg2, value_pointed_to_offset (arg1));
> -
> -      /* We may be pointing to an object of some derived type.  */
> -      arg2 = value_full_object (arg2, NULL, 0, 0, 0);
> -      return arg2;
> +      return readjust_value_type (arg2, enc_type, base_type, arg1);
>      }
>  
>    error (_("Attempt to take contents of a non-pointer value."));
> @@ -3528,23 +3520,48 @@ value_maybe_namespace_elt (const struct type *curtype,
>    return result;
>  }
>  
> -/* Given a pointer value V, find the real (RTTI) type of the object it
> -   points to.
> +/* Given a pointer or a reference value V, find its real (RTTI) type.
>  
>     Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
>     and refer to the values computed for the object pointed to.  */
>  
>  struct type *
> -value_rtti_target_type (struct value *v, int *full, 
> -			int *top, int *using_enc)
> +value_rtti_indirect_type (struct value *v, int *full, 
> +			  int *top, int *using_enc)
>  {
>    struct value *target;
> +  struct type *type, *real_type, *target_type;
> +
> +  type = value_type (v);
> +  type = check_typedef (type);
> +  if (TYPE_CODE (type) == TYPE_CODE_REF)
> +    target = coerce_ref (v);
> +  else if (TYPE_CODE (type) == TYPE_CODE_PTR)
> +    target = value_ind (v);
> +  else
> +    return NULL;
>  
> -  target = value_ind (v);
> +  real_type = value_rtti_type (target, full, top, using_enc);
>  
> -  return value_rtti_type (target, full, top, using_enc);
> +  if (real_type)
> +    {
> +      /* Copy qualifiers to the referenced object.  */
> +      target_type = value_type (target);
> +      real_type = make_cv_type (TYPE_CONST (target_type),
> +                                TYPE_VOLATILE (target_type), real_type, NULL);

Use tabs, not spaces.
http://www.gnu.org/prep/standards/standards.html#Formatting
GNU indent options


> +      if (TYPE_CODE (type) == TYPE_CODE_REF)
> +        real_type = lookup_reference_type (real_type);
> +      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
> +        real_type = lookup_pointer_type (real_type);

Either remove "if (TYPE_CODE (type) == TYPE_CODE_PTR)" as it must be always
true here anyway, either
	else /* TYPE_CODE (type) == TYPE_CODE_PTR */
          real_type = lookup_pointer_type (real_type);
or:
	else if (TYPE_CODE (type) == TYPE_CODE_PTR)
          real_type = lookup_pointer_type (real_type);
	else
	  internal_error (...);


Empty line before a comment.

> +      /* Copy qualifiers to the pointer/reference.  */
> +      real_type = make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type),
> +                                real_type, NULL);
> +    }
> +
> +  return real_type;
>  }
>  
> +

Excessive newline.


>  /* Given a value pointed to by ARGP, check its real run-time type, and
>     if that is different from the enclosing type, create a new value
>     using the real run-time type as the enclosing type (and of the same
> diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
> index 3461b08..d81d07d 100644
> --- a/gdb/c-valprint.c
> +++ b/gdb/c-valprint.c
> @@ -698,22 +698,12 @@ c_value_print (struct value *val, struct ui_file *stream,
>  
>  	  if (value_entirely_available (val))
>   	    {
> -	      real_type = value_rtti_target_type (val, &full, &top, &using_enc);
> +	      real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);

More than 80 characters.

>  	      if (real_type)
>  		{
>  		  /* RTTI entry found.  */
> -		  if (TYPE_CODE (type) == TYPE_CODE_PTR)
> -		    {
> -		      /* Create a pointer type pointing to the real
> -			 type.  */
> -		      type = lookup_pointer_type (real_type);
> -		    }
> -		  else
> -		    {
> -		      /* Create a reference type referencing the real
> -			 type.  */
> -		      type = lookup_reference_type (real_type);
> -		    }
> +		  type = real_type;
> +
>  		  /* Need to adjust pointer value.  */
>  		  val = value_from_pointer (type, value_as_address (val) - top);
>  
> diff --git a/gdb/eval.c b/gdb/eval.c
> index 5d758d1..3d23d0f 100644
> --- a/gdb/eval.c
> +++ b/gdb/eval.c
> @@ -1990,16 +1990,9 @@ evaluate_subexp_standard (struct type *expect_type,
>          if (opts.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);
> +            real_type = value_rtti_indirect_type (arg1, &full, &top, &using_enc);

More than 80 characters.

>              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);
> -              }
>            }
>        }
>  
> diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
> new file mode 100644
> index 0000000..3622f3b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
> @@ -0,0 +1,184 @@
> +/* Copyright 2011 Free Software Foundation, Inc.

Just a reminder to update the year for the final commit.


> +
> +   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 {

It would be nice to test also multiple inheritance where non-zero
EMBEDDED_OFFSET gets involved with value_enclosing_type, that is some

	struct Derived : public First, public Base {

But your code probably works with it during some quick tests.


> +    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;
> +  /*: 
> +	mi_var_rtti__set_print_object off
> +	mi_var_rtti__check_derived_class_without_rtti ptr {Base \*}
> +	mi_var_rtti__check_derived_class_without_rtti constPtr {const Base \*}
> +	mi_var_rtti__check_derived_class_without_rtti ptrConst {Base \* const}
> +	mi_var_rtti__check_derived_class_without_rtti constPtrConst {const Base \* const}
> +
> +	mi_var_rtti__set_print_object on
> +	mi_var_rtti__check_derived_class_with_rtti ptr {Derived \*}
> +	mi_var_rtti__check_derived_class_with_rtti constPtr {const Derived \*}
> +	mi_var_rtti__check_derived_class_with_rtti ptrConst {Derived \* const}
> +	mi_var_rtti__check_derived_class_with_rtti constPtrConst {const Derived \* const}
> +  :*/
> +	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;
> +  /*: 
> +	mi_var_rtti__set_print_object off
> +	mi_var_rtti__check_derived_class_without_rtti ref {Base \&}
> +	mi_var_rtti__check_derived_class_without_rtti constRef {const Base \&}
> +
> +	mi_var_rtti__set_print_object on
> +	mi_var_rtti__check_derived_class_with_rtti ref {Derived \&}
> +	mi_var_rtti__check_derived_class_with_rtti constRef {const Derived \&}
> +  :*/
> +	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 );
> +  /*: 
> +	mi_var_rtti__set_print_object off
> +	mi_var_rtti__check_derived_class_without_rtti s.ptr {Base \*}
> +	mi_var_rtti__check_derived_class_without_rtti s.constPtr {const Base \*}
> +	mi_var_rtti__check_derived_class_without_rtti s.ptrConst {Base \* const}
> +	mi_var_rtti__check_derived_class_without_rtti s.constPtrConst {const Base \* const}
> +
> +	mi_var_rtti__set_print_object on
> +	mi_var_rtti__check_derived_class_with_rtti s.ptr {Derived \*}
> +	mi_var_rtti__check_derived_class_with_rtti s.constPtr {const Derived \*}
> +	mi_var_rtti__check_derived_class_with_rtti s.ptrConst {Derived \* const}
> +	mi_var_rtti__check_derived_class_with_rtti s.constPtrConst {const Derived \* const}
> +  :*/
> +	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 );
> +  /*: 
> +	mi_var_rtti__set_print_object off
> +	mi_var_rtti__check_derived_class_without_rtti s.ref {Base \&}
> +	mi_var_rtti__check_derived_class_without_rtti s.constRef {const Base \&}
> +
> +	mi_var_rtti__set_print_object on
> +	mi_var_rtti__check_derived_class_with_rtti s.ref {Derived \&}
> +	mi_var_rtti__check_derived_class_with_rtti s.constRef {const Derived \&}
> +  :*/
> +	return;
> +  /*: END: use_rtti_for_ref_child :*/
> +}
> +
> +void type_update_when_use_rtti_test ()
> +{
> +  /*: BEGIN: type_update_when_use_rtti :*/
> +	Derived d;
> +  /*: 
> +	mi_var_rtti__set_print_object on
> +	mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
> +	mi_var_rtti__check_derived_children_without_rtti ptr
> +  :*/
> +
> +	Base* ptr = &d;
> +  /*: 
> +	mi_varobj_update_with_type_change VAR {Derived \*} 2 "update ptr"
> +	mi_var_rtti__check_derived_children_with_rtti ptr
> +	mi_var_rtti__check_derived_content_with_rtti ptr
> +	mi_delete_varobj VAR "delete varobj for ptr"
> +  :*/
> +	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;
> +  /*: 
> +	mi_var_rtti__set_print_object off
> +	mi_create_varobj_checked VAR ptr {Base \*} "create varobj for ptr"
> +	mi_var_rtti__check_derived_children_without_rtti ptr
> +  :*/
> +
> +	Base* ptr = &d;
> +  /*: 
> +	mi_varobj_update VAR {} "update ptr"
> +	mi_var_rtti__check_derived_children_without_rtti ptr
> +	mi_var_rtti__check_derived_content_without_rtti ptr
> +	mi_delete_varobj VAR "delete varobj for ptr"
> +  :*/
> +	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();
> +	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
> index 0000000..177b63c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
> @@ -0,0 +1,108 @@
> +# Copyright 2011 Free Software Foundation, Inc.

Just a reminder to update the year for the final commit.

> +
> +# 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 binfile $objdir/$subdir/$testfile
> +
> +if [get_compiler_info ${binfile} "c++"] {
> +    return -1;
> +}
> +
> +if {[gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug c++}] != ""} {
> +  untested $testfile.exp
> +  return -1
> +}

build_executable is preferred nowadays.


> +
> +mi_gdb_load ${binfile}
> +
> +mi_prepare_inline_tests $srcfile
> +
> +# Enable using RTTI to determine real types of the objects
> +proc mi_var_rtti__set_print_object {state} {
> +  mi_gdb_test "-interpreter-exec console \"set print object ${state}\"" \
> +    {\^done} \
> +    "-interpreter-exec console \"set print object ${state}\""
> +}
> +
> +proc mi_var_rtti__check_derived_children_without_rtti {var_name} {
> +  mi_list_varobj_children VAR {
> +     { VAR.public			public	1		 }
> +  } "list children of ${var_name} (without RTTI)"
> +  mi_list_varobj_children "VAR.public" {
> +     { VAR.public.A			A		0	int }
> +  } "list children of ${var_name}.public (without RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_content_without_rtti {var_name} {
> +  mi_check_varobj_value VAR.public.A		1 "check ${var_name}->A (without RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_class_without_rtti {var_name var_type} {
> +  mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj for ${var_name} (without RTTI)"
> +  mi_var_rtti__check_derived_children_without_rtti ${var_name}
> +  mi_var_rtti__check_derived_content_without_rtti ${var_name}
> +  mi_delete_varobj VAR "delete varobj for ${var_name} (without RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_children_with_rtti {var_name} {
> +    mi_list_varobj_children VAR {
> +       { VAR.Base			Base	1	Base }
> +       { VAR.public			public	2		 }
> +    } "list children of ${var_name} (with RTTI)"
> +    mi_list_varobj_children "VAR.Base" {
> +       { VAR.Base.public	public 1 }
> +    } "list children of ${var_name}.Base (with RTTI)"
> +    mi_list_varobj_children "VAR.Base.public" {
> +       { VAR.Base.public.A	A		0	int	}
> +    } "list children of ${var_name}.Base.public (with RTTI)"
> +    mi_list_varobj_children "VAR.public" {
> +       { VAR.public.B		B		0	int }
> +       { VAR.public.C		C		0	int }
> +    } "list children of ${var_name}.public (with RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_content_with_rtti {var_name} {
> +    mi_check_varobj_value VAR.Base.public.A	1 "check ${var_name}->A (with RTTI)"
> +    mi_check_varobj_value VAR.public.B		2 "check ${var_name}->B (with RTTI)"
> +    mi_check_varobj_value VAR.public.C		3 "check ${var_name}->C (with RTTI)"
> +}
> +
> +proc mi_var_rtti__check_derived_class_with_rtti {var_name var_type} {
> +    mi_create_varobj_checked VAR ${var_name} ${var_type} "create varobj for ${var_name} (with RTTI)"
> +	mi_var_rtti__check_derived_children_with_rtti ${var_name}
> +	mi_var_rtti__check_derived_content_with_rtti ${var_name}
> +    mi_delete_varobj VAR "delete varobj for ${var_name} (with RTTI)"
> +}
> +
> +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 type_update_when_use_rtti
> +mi_run_inline_test skip_type_update_when_not_use_rtti
> +
> +mi_gdb_exit
> +return 0
> diff --git a/gdb/typeprint.c b/gdb/typeprint.c
> index cf4158d..6546c98 100644
> --- a/gdb/typeprint.c
> +++ b/gdb/typeprint.c
> @@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
>        if (((TYPE_CODE (type) == TYPE_CODE_PTR)
>  	   || (TYPE_CODE (type) == TYPE_CODE_REF))
>  	  && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
> -        {
> -          real_type = value_rtti_target_type (val, &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);
> -            }
> -        }
> +        real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);
>        else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
>  	real_type = value_rtti_type (val, &full, &top, &using_enc);
>      }
> diff --git a/gdb/value.c b/gdb/value.c
> index d263d0c..15726c0 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -821,6 +821,35 @@ value_enclosing_type (struct value *value)
>    return value->enclosing_type;
>  }
>  
> +/* Look at value.h for description.  */

Empty line after function comment.

> +struct type *
> +value_actual_type (struct value *value, int resolve_simple_types)
> +{
> +  struct value_print_options opts;
> +  struct value *target;
> +  struct type *result;
> +
> +  get_user_print_options (&opts);
> +
> +  result = value_type (value);
> +  if (opts.objectprint)
> +  {

This block should be indented by 2 more characters right.


> +    if (TYPE_CODE (result) == TYPE_CODE_PTR
> +        || TYPE_CODE (result) == TYPE_CODE_REF)

Use tabs, not spaces.


> +    {

This block should be indented by 2 more characters right.


> +      struct type *real_type;
> +
> +      real_type = value_rtti_indirect_type (value, 0, 0, 0);

         real_type = value_rtti_indirect_type (value, NULL, NULL, NULL);
(I am aware, it is compatible.)


> +      if (real_type)
> +        result = real_type;

Use tabs, not spaces.


> +    }
> +    else if (resolve_simple_types)
> +      result = value_enclosing_type (value);
> +  }
> +
> +  return result;
> +}
> +
>  static void
>  require_not_optimized_out (const struct value *value)
>  {
> @@ -3110,10 +3139,26 @@ coerce_ref_if_computed (const struct value *arg)
>  }
>  

Missing the comment:
	/* Look at value.h for description.  */

>  struct value *
> +readjust_value_type (struct value *value, struct type *enc_type,
> +                     struct type *original_type, struct value *original_value)
> +{
> +  /* Re-adjust type.  */
> +  deprecated_set_value_type (value, TYPE_TARGET_TYPE (original_type));
> +
> +  /* Add embedding info.  */
> +  set_value_enclosing_type (value, enc_type);
> +  set_value_embedded_offset (value, value_pointed_to_offset (original_value));
> +
> +  /* We may be pointing to an object of some derived type.  */
> +  return value_full_object (value, NULL, 0, 0, 0);
> +}
> +
> +struct value *
>  coerce_ref (struct value *arg)
>  {
>    struct type *value_type_arg_tmp = check_typedef (value_type (arg));
>    struct value *retval;
> +  struct type *enc_type;
>  
>    retval = coerce_ref_if_computed (arg);
>    if (retval)
> @@ -3122,9 +3167,13 @@ coerce_ref (struct value *arg)
>    if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
>      return arg;
>  
> -  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
> -			unpack_pointer (value_type (arg),
> -					value_contents (arg)));
> +  enc_type = check_typedef (value_enclosing_type (arg));
> +  enc_type = TYPE_TARGET_TYPE (enc_type);
> +
> +  retval = value_at_lazy (enc_type,
> +                          unpack_pointer (value_type (arg),
> +                                          value_contents (arg)));
> +  return readjust_value_type (retval, enc_type, value_type_arg_tmp, arg);
>  }
>  
>  struct value *
> diff --git a/gdb/value.h b/gdb/value.h
> index d2c58ec..7345c71 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -139,6 +139,16 @@ 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.  */
> +
> +extern struct type *value_actual_type (struct value *value, int resolve_simple_types);

More than 80 characters.

> +
>  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);
> @@ -353,6 +363,13 @@ extern short *deprecated_value_regnum_hack (struct value *);
>  
>  extern struct value *coerce_ref_if_computed (const struct value *arg);
>  
> +/* Setup a new value type and enclosing value type for dereferenced value.
> +   It is a common implementation for coerce_ref and value_ind.  */
> +
> +extern struct value *
> +readjust_value_type (struct value *value, struct type *enc_type,
> +                     struct type *original_type, struct value *original_value);

Use tabs, not spaces.  The function name should be more specific, such as
readjust_indirect_value_type.  Missing comment on the parameters.  Comment
that VALUE will will be modified by this function.


> +
>  /* Convert a REF to the object referenced.  */
>  
>  extern struct value *coerce_ref (struct value *value);
> @@ -617,8 +634,8 @@ extern struct value *value_primitive_field (struct value *arg1, int offset,
>  					    struct type *arg_type);
>  
>  
> -extern struct type *value_rtti_target_type (struct value *, int *, int *,
> -					    int *);
> +extern struct type *value_rtti_indirect_type (struct value *, int *, int *,
> +					      int *);
>  
>  extern struct value *value_full_object (struct value *, struct type *, int,
>  					int, int);
> diff --git a/gdb/varobj.c b/gdb/varobj.c
> index 7c68a93..dfeb71b 100644
> --- a/gdb/varobj.c
> +++ b/gdb/varobj.c
> @@ -659,8 +659,18 @@ varobj_create (char *objname,
>  
>  	  var->type = value_type (type_only_value);
>  	}
> -      else 
> -	var->type = value_type (value);
> +	else
> +	{

This block should be indented by 2 more characters right.

> +	  struct type *enclosing_type;
> +
> +	  var->type = value_type (value);
> +	  enclosing_type = value_actual_type (value, 0);
> +	  if (check_typedef (enclosing_type) != check_typedef (var->type))

As noted by Tom, I would extend it that maybe value_actual_type should return
whether it did any action as that check_typedef != check_typedef check is
fragile in general, the same type has multiple instances.


> +	    {
> +	      var->type = enclosing_type;
> +	      value = value_cast (enclosing_type, value);
> +	    }
> +	}
>  
>        install_new_value (var, value, 1 /* Initial assignment */);
>  
> @@ -2194,7 +2204,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);
>    else
>      /* Otherwise, we must compute the type.  */
>      child->type = (*child->root->lang->type_of_child) (child->parent, 
> @@ -2480,6 +2490,7 @@ static struct value *
>  value_of_root (struct varobj **var_handle, int *type_changed)
>  {
>    struct varobj *var;
> +  struct value_print_options opts;
>  
>    if (var_handle == NULL)
>      return NULL;
> @@ -2492,7 +2503,8 @@ value_of_root (struct varobj **var_handle, int *type_changed)
>    if (!is_root_p (var))
>      return NULL;
>  
> -  if (var->root->floating)
> +  get_user_print_options (&opts);
> +  if (var->root->floating || opts.objectprint)
>      {
>        struct varobj *tmp_var;
>        char *old_type, *new_type;
> @@ -2781,6 +2793,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
> @@ -2792,7 +2808,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);
>  
> @@ -2832,6 +2849,19 @@ 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;
> +
> +      enclosing_type = value_actual_type (*value, 1);
> +      if (check_typedef (enclosing_type) != check_typedef (*type))

The same check_typedef != check_typedef and value_actual_type comment like
above.

> +        {
> +          *type = enclosing_type;
> +          *value = value_cast (enclosing_type, *value);
> +        }
> +    }
>  }
>  
>  /* C */
> @@ -2842,7 +2872,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))
> @@ -2957,7 +2987,7 @@ c_describe_child (struct varobj *parent, int index,
>        *cfull_expression = NULL;
>        parent_expression = varobj_get_path_expr (parent);
>      }
> -  adjust_value_for_child_access (&value, &type, &was_ptr);
> +  adjust_value_for_child_access (&value, &type, &was_ptr, 0);
>        
>    switch (TYPE_CODE (type))
>      {
> @@ -3223,16 +3253,28 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
>  static int
>  cplus_number_of_children (struct varobj *var)
>  {
> +  struct value *value = 0;

Please use:
     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);

Empty line before comment.

> +      /* 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);

Use tabs, not spaces.


> +        }
> +      adjust_value_for_child_access (&value, &type, NULL, lookup_actual_type);
>  
>        if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
>  	  ((TYPE_CODE (type)) == TYPE_CODE_UNION))
> @@ -3259,7 +3301,15 @@ 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)
> +        {
> +          value = var->parent->value;
> +          lookup_actual_type = (TYPE_CODE (var->parent->type) == TYPE_CODE_REF
> +                                || TYPE_CODE (var->parent->type) == TYPE_CODE_PTR);

More than 80 characters.

> +        }
> +      adjust_value_for_child_access (&value, &type, NULL, lookup_actual_type);
>  
>        cplus_class_num_children (type, kids);
>        if (strcmp (var->name, "public") == 0)
> @@ -3341,7 +3391,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;
> @@ -3352,22 +3405,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 (parent->parent);
> -    }
> -  else
> -    {
> -      value = parent->value;
> -      type = get_value_type (parent);
> -      if (cfull_expression)
> -	parent_expression = varobj_get_path_expr (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 (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)



Thanks,
Jan

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

* RTTI type  improvement for (was: "Re: set print object on should affect MI varobjs (PR mi/13393)")
  2012-01-02  2:22             ` Jan Kratochvil
@ 2012-01-06 15:47               ` xgsa
  2012-01-09 14:41                 ` Jan Kratochvil
  2012-02-06 21:45                 ` Tom Tromey
  0 siblings, 2 replies; 47+ messages in thread
From: xgsa @ 2012-01-06 15:47 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches

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

> That change to value_rtti_indirect_type would be easier to read if it was
> a separate patch.

This is the first part of my previous patch that contains the change
to value_rtti_indirect_type. The second part requires this one to be
applied, so I'll provide it after commit.

Here is an example of what this patch fixes:
struct Base {
	virtual ~Base() {}
};

struct Derived: public Base {};

int main()
{
	Derived i;
	const Base& ri = i;
	const Base* pi = &i;
	return 0;   // <= run until this line
}

The "whatis ri" command fails with message:
  "Attempt to take contents of a non-pointer value.".
The "whatis pi" command does not respect cv-qualifiers:
  type = /* real type = Derived * */
  const Base *

This patch fixes these problems and takes into account the last Jan's review.


gdb/ChangeLog:

2012-01-06  Anton Gorenkov <xgsa@yandex.ru>

        * c-valprint.c (c_value_print): Use value_rtti_indirect_type
        instead of value_rtti_target_type.
        * eval.c (evaluate_subexp_standard): Use value_rtti_indirect_type
        instead of value_rtti_target_type.
        * typeprint.c (whatis_exp): Use value_rtti_indirect_type instead of
        value_rtti_target_type.
        * valops.c (value_ind): Extract function readjust_indirect_value_type.
        (value_rtti_indirect_type): The replacement for value_rtti_target_type.
        * value.c (readjust_indirect_value_type): New function.
        (coerce_ref): Support for enclosing type setting for references
        with readjust_indirect_value_type.
        * value.h (readjust_value_type): The replacement for
        value_rtti_target_type.



[-- Attachment #2: gdb_reference_rtti_fix1.patch --]
[-- Type: text/x-diff, Size: 8332 bytes --]

diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 3461b08..e2e2792 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -698,22 +698,13 @@ c_value_print (struct value *val, struct ui_file *stream,
 
 	  if (value_entirely_available (val))
  	    {
-	      real_type = value_rtti_target_type (val, &full, &top, &using_enc);
+	      real_type = value_rtti_indirect_type (val, &full, &top,
+						    &using_enc);
 	      if (real_type)
 		{
 		  /* RTTI entry found.  */
-		  if (TYPE_CODE (type) == TYPE_CODE_PTR)
-		    {
-		      /* Create a pointer type pointing to the real
-			 type.  */
-		      type = lookup_pointer_type (real_type);
-		    }
-		  else
-		    {
-		      /* Create a reference type referencing the real
-			 type.  */
-		      type = lookup_reference_type (real_type);
-		    }
+		  type = real_type;
+
 		  /* Need to adjust pointer value.  */
 		  val = value_from_pointer (type, value_as_address (val) - top);
 
diff --git a/gdb/eval.c b/gdb/eval.c
index 5d758d1..10606a8 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1990,16 +1990,10 @@ evaluate_subexp_standard (struct type *expect_type,
         if (opts.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);
+            real_type = value_rtti_indirect_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);
-              }
           }
       }
 
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index cf4158d..6546c98 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
       if (((TYPE_CODE (type) == TYPE_CODE_PTR)
 	   || (TYPE_CODE (type) == TYPE_CODE_REF))
 	  && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
-        {
-          real_type = value_rtti_target_type (val, &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);
-            }
-        }
+        real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);
       else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
 	real_type = value_rtti_type (val, &full, &top, &using_enc);
     }
diff --git a/gdb/valops.c b/gdb/valops.c
index cb39677..2bc02f3 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1774,15 +1774,7 @@ value_ind (struct value *arg1)
 			      (value_as_address (arg1)
 			       - value_pointed_to_offset (arg1)));
 
-      /* Re-adjust type.  */
-      deprecated_set_value_type (arg2, TYPE_TARGET_TYPE (base_type));
-      /* Add embedding info.  */
-      set_value_enclosing_type (arg2, enc_type);
-      set_value_embedded_offset (arg2, value_pointed_to_offset (arg1));
-
-      /* We may be pointing to an object of some derived type.  */
-      arg2 = value_full_object (arg2, NULL, 0, 0, 0);
-      return arg2;
+      return readjust_indirect_value_type (arg2, enc_type, base_type, arg1);
     }
 
   error (_("Attempt to take contents of a non-pointer value."));
@@ -3528,21 +3520,48 @@ value_maybe_namespace_elt (const struct type *curtype,
   return result;
 }
 
-/* Given a pointer value V, find the real (RTTI) type of the object it
-   points to.
+/* Given a pointer or a reference value V, find its real (RTTI) type.
 
    Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
    and refer to the values computed for the object pointed to.  */
 
 struct type *
-value_rtti_target_type (struct value *v, int *full, 
-			int *top, int *using_enc)
+value_rtti_indirect_type (struct value *v, int *full, 
+			  int *top, int *using_enc)
 {
   struct value *target;
+  struct type *type, *real_type, *target_type;
+
+  type = value_type (v);
+  type = check_typedef (type);
+  if (TYPE_CODE (type) == TYPE_CODE_REF)
+    target = coerce_ref (v);
+  else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    target = value_ind (v);
+  else
+    return NULL;
 
-  target = value_ind (v);
+  real_type = value_rtti_type (target, full, top, using_enc);
+
+  if (real_type)
+    {
+      /* Copy qualifiers to the referenced object.  */
+      target_type = value_type (target);
+      real_type = make_cv_type (TYPE_CONST (target_type),
+				TYPE_VOLATILE (target_type), real_type, NULL);
+      if (TYPE_CODE (type) == TYPE_CODE_REF)
+        real_type = lookup_reference_type (real_type);
+      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+        real_type = lookup_pointer_type (real_type);
+      else
+        internal_error (__FILE__, __LINE__, _("Unexpected value type."));
+
+      /* Copy qualifiers to the pointer/reference.  */
+      real_type = make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type),
+				real_type, NULL);
+    }
 
-  return value_rtti_type (target, full, top, using_enc);
+  return real_type;
 }
 
 /* Given a value pointed to by ARGP, check its real run-time type, and
diff --git a/gdb/value.c b/gdb/value.c
index d263d0c..c78e489 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -3109,11 +3109,30 @@ coerce_ref_if_computed (const struct value *arg)
   return funcs->coerce_ref (arg);
 }
 
+/* Look at value.h for description.  */
+
+struct value *
+readjust_indirect_value_type (struct value *value, struct type *enc_type,
+			      struct type *original_type,
+			      struct value *original_value)
+{
+  /* Re-adjust type.  */
+  deprecated_set_value_type (value, TYPE_TARGET_TYPE (original_type));
+
+  /* Add embedding info.  */
+  set_value_enclosing_type (value, enc_type);
+  set_value_embedded_offset (value, value_pointed_to_offset (original_value));
+
+  /* We may be pointing to an object of some derived type.  */
+  return value_full_object (value, NULL, 0, 0, 0);
+}
+
 struct value *
 coerce_ref (struct value *arg)
 {
   struct type *value_type_arg_tmp = check_typedef (value_type (arg));
   struct value *retval;
+  struct type *enc_type;
 
   retval = coerce_ref_if_computed (arg);
   if (retval)
@@ -3122,9 +3141,13 @@ coerce_ref (struct value *arg)
   if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
     return arg;
 
-  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
-			unpack_pointer (value_type (arg),
-					value_contents (arg)));
+  enc_type = check_typedef (value_enclosing_type (arg));
+  enc_type = TYPE_TARGET_TYPE (enc_type);
+
+  retval = value_at_lazy (enc_type,
+                          unpack_pointer (value_type (arg),
+                                          value_contents (arg)));
+  return readjust_indirect_value_type (retval, enc_type, value_type_arg_tmp, arg);
 }
 
 struct value *
diff --git a/gdb/value.h b/gdb/value.h
index d2c58ec..679192f 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -353,6 +353,19 @@ extern short *deprecated_value_regnum_hack (struct value *);
 
 extern struct value *coerce_ref_if_computed (const struct value *arg);
 
+/* Setup a new value type and enclosing value type for dereferenced value VALUE.
+   ENC_TYPE is the new enclosing type that should be set.  ORIGINAL_TYPE and
+   ORIGINAL_VALUE are the type and value of the original reference or pointer.
+
+   Note, that VALUE is modified by this function.
+
+   It is a common implementation for coerce_ref and value_ind.  */
+
+extern struct value *
+readjust_indirect_value_type (struct value *value, struct type *enc_type,
+			      struct type *original_type,
+			      struct value *original_value);
+
 /* Convert a REF to the object referenced.  */
 
 extern struct value *coerce_ref (struct value *value);
@@ -617,8 +630,8 @@ extern struct value *value_primitive_field (struct value *arg1, int offset,
 					    struct type *arg_type);
 
 
-extern struct type *value_rtti_target_type (struct value *, int *, int *,
-					    int *);
+extern struct type *value_rtti_indirect_type (struct value *, int *, int *,
+					      int *);
 
 extern struct value *value_full_object (struct value *, struct type *, int,
 					int, int);

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

* Re: RTTI type  improvement for (was: "Re: set print object on should affect MI varobjs (PR mi/13393)")
  2012-01-06 15:47               ` RTTI type improvement for (was: "Re: set print object on should affect MI varobjs (PR mi/13393)") xgsa
@ 2012-01-09 14:41                 ` Jan Kratochvil
  2012-01-11 21:58                   ` RTTI type improvement for Tom Tromey
  2012-02-06 21:45                 ` Tom Tromey
  1 sibling, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2012-01-09 14:41 UTC (permalink / raw)
  To: xgsa; +Cc: Tom Tromey, gdb-patches

Hello Anton,

On Fri, 06 Jan 2012 16:47:08 +0100, xgsa wrote:
> > That change to value_rtti_indirect_type would be easier to read if it was
> > a separate patch.
> 
> This is the first part of my previous patch that contains the change
> to value_rtti_indirect_type. The second part requires this one to be
> applied, so I'll provide it after commit.

Unfortunately we cannot yet check it in while waiting for the copyright
paperwork.  But sure you can base the other patch on top of this one.


> Here is an example of what this patch fixes:
[...]
> The "whatis ri" command fails with message:
>   "Attempt to take contents of a non-pointer value.".
> The "whatis pi" command does not respect cv-qualifiers:
>   type = /* real type = Derived * */
>   const Base *

I do not see any change with this patch in the results of your testcase
gdb.mi/mi-var-rtti.exp .  Regressions in the future are better evaluated when
one sees the testcase and associated code which it breaks.  A separate
testcase for this patch would be nice but I assume the full changes require
this functionality so it gets tested anyway.


> gdb/ChangeLog:
> 
> 2012-01-06  Anton Gorenkov <xgsa@yandex.ru>
> 
>         * c-valprint.c (c_value_print): Use value_rtti_indirect_type
>         instead of value_rtti_target_type.
>         * eval.c (evaluate_subexp_standard): Use value_rtti_indirect_type
>         instead of value_rtti_target_type.
>         * typeprint.c (whatis_exp): Use value_rtti_indirect_type instead of
>         value_rtti_target_type.
>         * valops.c (value_ind): Extract function readjust_indirect_value_type.
>         (value_rtti_indirect_type): The replacement for value_rtti_target_type.

Here really should be value_rtti_target_type in parens, like:
	  (value_rtti_target_type): Rename to ...
	  (value_rtti_indirect_type): ... here and make it indirect.  Update
	  function comment.


>         * value.c (readjust_indirect_value_type): New function.
>         (coerce_ref): Support for enclosing type setting for references
>         with readjust_indirect_value_type.


>         * value.h (readjust_value_type): The replacement for
>         value_rtti_target_type.

Use:
	  * value.h (readjust_value_type): New declaration.
	  (value_rtti_target_type): Rename to ...
	  (value_rtti_indirect_type): ... here.



> diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
> index 3461b08..e2e2792 100644
> --- a/gdb/c-valprint.c
> +++ b/gdb/c-valprint.c
> @@ -698,22 +698,13 @@ c_value_print (struct value *val, struct ui_file *stream,
>  
>  	  if (value_entirely_available (val))
>   	    {
> -	      real_type = value_rtti_target_type (val, &full, &top, &using_enc);
> +	      real_type = value_rtti_indirect_type (val, &full, &top,
> +						    &using_enc);
>  	      if (real_type)
>  		{
>  		  /* RTTI entry found.  */
> -		  if (TYPE_CODE (type) == TYPE_CODE_PTR)
> -		    {
> -		      /* Create a pointer type pointing to the real
> -			 type.  */
> -		      type = lookup_pointer_type (real_type);
> -		    }
> -		  else
> -		    {
> -		      /* Create a reference type referencing the real
> -			 type.  */
> -		      type = lookup_reference_type (real_type);
> -		    }
> +		  type = real_type;
> +
>  		  /* Need to adjust pointer value.  */
>  		  val = value_from_pointer (type, value_as_address (val) - top);
>  
> diff --git a/gdb/eval.c b/gdb/eval.c
> index 5d758d1..10606a8 100644
> --- a/gdb/eval.c
> +++ b/gdb/eval.c
> @@ -1990,16 +1990,10 @@ evaluate_subexp_standard (struct type *expect_type,
>          if (opts.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);
> +            real_type = value_rtti_indirect_type (arg1, &full, &top,

This line should indent by tabs, not spaces.  Sure a nitpick, no problem.
Do not care if the old code was wrongly using spaces.


> +						  &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);
> -              }
>            }
>        }
>  
> diff --git a/gdb/typeprint.c b/gdb/typeprint.c
> index cf4158d..6546c98 100644
> --- a/gdb/typeprint.c
> +++ b/gdb/typeprint.c
> @@ -140,16 +140,7 @@ whatis_exp (char *exp, int show)
>        if (((TYPE_CODE (type) == TYPE_CODE_PTR)
>  	   || (TYPE_CODE (type) == TYPE_CODE_REF))
>  	  && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
> -        {
> -          real_type = value_rtti_target_type (val, &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);
> -            }
> -        }
> +        real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);
>        else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
>  	real_type = value_rtti_type (val, &full, &top, &using_enc);
>      }
> diff --git a/gdb/valops.c b/gdb/valops.c
> index cb39677..2bc02f3 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -1774,15 +1774,7 @@ value_ind (struct value *arg1)
>  			      (value_as_address (arg1)
>  			       - value_pointed_to_offset (arg1)));
>  
> -      /* Re-adjust type.  */
> -      deprecated_set_value_type (arg2, TYPE_TARGET_TYPE (base_type));
> -      /* Add embedding info.  */
> -      set_value_enclosing_type (arg2, enc_type);
> -      set_value_embedded_offset (arg2, value_pointed_to_offset (arg1));
> -
> -      /* We may be pointing to an object of some derived type.  */
> -      arg2 = value_full_object (arg2, NULL, 0, 0, 0);
> -      return arg2;
> +      return readjust_indirect_value_type (arg2, enc_type, base_type, arg1);
>      }
>  
>    error (_("Attempt to take contents of a non-pointer value."));
> @@ -3528,21 +3520,48 @@ value_maybe_namespace_elt (const struct type *curtype,
>    return result;
>  }
>  
> -/* Given a pointer value V, find the real (RTTI) type of the object it
> -   points to.
> +/* Given a pointer or a reference value V, find its real (RTTI) type.
>  
>     Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
>     and refer to the values computed for the object pointed to.  */
>  
>  struct type *
> -value_rtti_target_type (struct value *v, int *full, 
> -			int *top, int *using_enc)
> +value_rtti_indirect_type (struct value *v, int *full, 
> +			  int *top, int *using_enc)
>  {
>    struct value *target;
> +  struct type *type, *real_type, *target_type;
> +
> +  type = value_type (v);
> +  type = check_typedef (type);
> +  if (TYPE_CODE (type) == TYPE_CODE_REF)
> +    target = coerce_ref (v);
> +  else if (TYPE_CODE (type) == TYPE_CODE_PTR)
> +    target = value_ind (v);
> +  else
> +    return NULL;
>  
> -  target = value_ind (v);
> +  real_type = value_rtti_type (target, full, top, using_enc);
> +
> +  if (real_type)
> +    {
> +      /* Copy qualifiers to the referenced object.  */
> +      target_type = value_type (target);
> +      real_type = make_cv_type (TYPE_CONST (target_type),
> +				TYPE_VOLATILE (target_type), real_type, NULL);
> +      if (TYPE_CODE (type) == TYPE_CODE_REF)
> +        real_type = lookup_reference_type (real_type);
> +      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
> +        real_type = lookup_pointer_type (real_type);
> +      else
> +        internal_error (__FILE__, __LINE__, _("Unexpected value type."));

Here should be tabs for indentation, 3 times.

> +
> +      /* Copy qualifiers to the pointer/reference.  */
> +      real_type = make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type),
> +				real_type, NULL);
> +    }
>  
> -  return value_rtti_type (target, full, top, using_enc);
> +  return real_type;
>  }
>  
>  /* Given a value pointed to by ARGP, check its real run-time type, and
> diff --git a/gdb/value.c b/gdb/value.c
> index d263d0c..c78e489 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -3109,11 +3109,30 @@ coerce_ref_if_computed (const struct value *arg)
>    return funcs->coerce_ref (arg);
>  }
>  
> +/* Look at value.h for description.  */
> +
> +struct value *
> +readjust_indirect_value_type (struct value *value, struct type *enc_type,
> +			      struct type *original_type,
> +			      struct value *original_value)
> +{
> +  /* Re-adjust type.  */
> +  deprecated_set_value_type (value, TYPE_TARGET_TYPE (original_type));
> +
> +  /* Add embedding info.  */
> +  set_value_enclosing_type (value, enc_type);
> +  set_value_embedded_offset (value, value_pointed_to_offset (original_value));
> +
> +  /* We may be pointing to an object of some derived type.  */
> +  return value_full_object (value, NULL, 0, 0, 0);
> +}
> +
>  struct value *
>  coerce_ref (struct value *arg)
>  {
>    struct type *value_type_arg_tmp = check_typedef (value_type (arg));
>    struct value *retval;
> +  struct type *enc_type;
>  
>    retval = coerce_ref_if_computed (arg);
>    if (retval)
> @@ -3122,9 +3141,13 @@ coerce_ref (struct value *arg)
>    if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
>      return arg;
>  
> -  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
> -			unpack_pointer (value_type (arg),
> -					value_contents (arg)));
> +  enc_type = check_typedef (value_enclosing_type (arg));
> +  enc_type = TYPE_TARGET_TYPE (enc_type);
> +
> +  retval = value_at_lazy (enc_type,
> +                          unpack_pointer (value_type (arg),
> +                                          value_contents (arg)));
> +  return readjust_indirect_value_type (retval, enc_type, value_type_arg_tmp, arg);

Line has more than 80 characters.


>  }
>  
>  struct value *
> diff --git a/gdb/value.h b/gdb/value.h
> index d2c58ec..679192f 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -353,6 +353,19 @@ extern short *deprecated_value_regnum_hack (struct value *);
>  
>  extern struct value *coerce_ref_if_computed (const struct value *arg);
>  
> +/* Setup a new value type and enclosing value type for dereferenced value VALUE.
> +   ENC_TYPE is the new enclosing type that should be set.  ORIGINAL_TYPE and
> +   ORIGINAL_VALUE are the type and value of the original reference or pointer.
> +
> +   Note, that VALUE is modified by this function.
> +
> +   It is a common implementation for coerce_ref and value_ind.  */
> +
> +extern struct value *
> +readjust_indirect_value_type (struct value *value, struct type *enc_type,
> +			      struct type *original_type,
> +			      struct value *original_value);
> +
>  /* Convert a REF to the object referenced.  */
>  
>  extern struct value *coerce_ref (struct value *value);
> @@ -617,8 +630,8 @@ extern struct value *value_primitive_field (struct value *arg1, int offset,
>  					    struct type *arg_type);
>  
>  
> -extern struct type *value_rtti_target_type (struct value *, int *, int *,
> -					    int *);
> +extern struct type *value_rtti_indirect_type (struct value *, int *, int *,
> +					      int *);
>  
>  extern struct value *value_full_object (struct value *, struct type *, int,
>  					int, int);


In general OK, prepared for a check-in.


Thanks,
Jan

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

* Re: RTTI type  improvement for
  2012-01-09 14:41                 ` Jan Kratochvil
@ 2012-01-11 21:58                   ` Tom Tromey
  2012-01-12 11:25                     ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Tom Tromey @ 2012-01-11 21:58 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: xgsa, gdb-patches

>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:

Jan> Unfortunately we cannot yet check it in while waiting for the copyright
Jan> paperwork.  But sure you can base the other patch on top of this one.

If this takes too long, please ping the FSF.

Tom

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

* Re: RTTI type  improvement for
  2012-01-11 21:58                   ` RTTI type improvement for Tom Tromey
@ 2012-01-12 11:25                     ` xgsa
  0 siblings, 0 replies; 47+ messages in thread
From: xgsa @ 2012-01-12 11:25 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Jan Kratochvil, gdb-patches


> If this takes too long, please ping the FSF.

There was a small delay on my side. The FSF should receive the form in the next few days. I'll notify you when it happens or if there are some problems or questions about it. Thanks.

Anton

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

* Re: RTTI type  improvement for
  2012-01-06 15:47               ` RTTI type improvement for (was: "Re: set print object on should affect MI varobjs (PR mi/13393)") xgsa
  2012-01-09 14:41                 ` Jan Kratochvil
@ 2012-02-06 21:45                 ` Tom Tromey
  2012-02-08 18:34                   ` xgsa
  1 sibling, 1 reply; 47+ messages in thread
From: Tom Tromey @ 2012-02-06 21:45 UTC (permalink / raw)
  To: xgsa; +Cc: Jan Kratochvil, gdb-patches

>>>>> "Anton" == xgsa  <xgsa@yandex.ru> writes:

Anton> The second part requires this one to be applied, so I'll provide
Anton> it after commit.

It is fine to pipeline patches.
Often it is even preferable to do this, but it depends on how
independent the individual patches actually are.

Anton> +struct value *
Anton> +readjust_indirect_value_type (struct value *value, struct type *enc_type,
Anton> +			      struct type *original_type,
Anton> +			      struct value *original_value)

I wonder if there is a cleaner way to do this same thing.
Say, a kind of value constructor as opposed to something that rewrites
an existing value?

If not, that is fine.

Anton> +extern struct value *
Anton> +readjust_indirect_value_type (struct value *value, struct type *enc_type,
Anton> +			      struct type *original_type,
Anton> +			      struct value *original_value);

If you're going to split the first line that way, I think you should
indent the subsequent lines by 4 or 5 spaces (not sure what the standard
is, if there is one).

Probably better to split before the open paren though (and still indent;
there are examples of this elsewhere).

Tom

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

* Re: RTTI type  improvement for
  2012-02-06 21:45                 ` Tom Tromey
@ 2012-02-08 18:34                   ` xgsa
  2012-02-10 20:13                     ` Tom Tromey
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-02-08 18:34 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

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

Hi,
> Anton>  +struct value *
> Anton>  +readjust_indirect_value_type (struct value *value, struct type *enc_type,
> Anton>  +			      struct type *original_type,
> Anton>  +			      struct value *original_value)
>
> I wonder if there is a cleaner way to do this same thing.
> Say, a kind of value constructor as opposed to something that rewrites
> an existing value?
>
> If not, that is fine.

I just extract that code from value_ind. I'd prefer to leave it as is.

> Anton>  +extern struct value *
> Anton>  +readjust_indirect_value_type (struct value *value, struct type *enc_type,
> Anton>  +			      struct type *original_type,
> Anton>  +			      struct value *original_value);
>
> If you're going to split the first line that way, I think you should
> indent the subsequent lines by 4 or 5 spaces (not sure what the standard
> is, if there is one).
>
> Probably better to split before the open paren though (and still indent;
> there are examples of this elsewhere).

Did not noticed it. Fixed.


Note, that the copyright paperwork is done.


gdb/ChangeLog:

2012-01-06  Anton Gorenkov <xgsa@yandex.ru>

     * c-valprint.c (c_value_print): Use value_rtti_indirect_type
     instead of value_rtti_target_type.
     * eval.c (evaluate_subexp_standard): Use value_rtti_indirect_type
     instead of value_rtti_target_type.
     * typeprint.c (whatis_exp): Use value_rtti_indirect_type instead of
     value_rtti_target_type.
     * valops.c (value_ind): Extract function readjust_indirect_value_type.
     (value_rtti_target_type): Rename to ...
     (value_rtti_indirect_type): ... here and make it indirect.  Update
     function comment.
     * value.c (readjust_indirect_value_type): New function.
     (coerce_ref): Support for enclosing type setting for references
     with readjust_indirect_value_type.
     * value.h (readjust_value_type): New declaration.
     (value_rtti_target_type): Rename to ...
     (value_rtti_indirect_type): ... here.



[-- Attachment #2: gdb_reference_rtti_fix2.patch --]
[-- Type: text/x-diff, Size: 8380 bytes --]

diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 82551e9..25c6688 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -728,22 +728,13 @@ c_value_print (struct value *val, struct ui_file *stream,
 
 	  if (value_entirely_available (val))
  	    {
-	      real_type = value_rtti_target_type (val, &full, &top, &using_enc);
+	      real_type = value_rtti_indirect_type (val, &full, &top,
+						    &using_enc);
 	      if (real_type)
 		{
 		  /* RTTI entry found.  */
-		  if (TYPE_CODE (type) == TYPE_CODE_PTR)
-		    {
-		      /* Create a pointer type pointing to the real
-			 type.  */
-		      type = lookup_pointer_type (real_type);
-		    }
-		  else
-		    {
-		      /* Create a reference type referencing the real
-			 type.  */
-		      type = lookup_reference_type (real_type);
-		    }
+		  type = real_type;
+
 		  /* Need to adjust pointer value.  */
 		  val = value_from_pointer (type, value_as_address (val) - top);
 
diff --git a/gdb/eval.c b/gdb/eval.c
index 9913a72..de1c4bd 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2001,16 +2001,10 @@ evaluate_subexp_standard (struct type *expect_type,
         if (opts.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);
+            real_type = value_rtti_indirect_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);
-              }
           }
       }
 
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 803d20b..f257f47 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -139,16 +139,7 @@ whatis_exp (char *exp, int show)
       if (((TYPE_CODE (type) == TYPE_CODE_PTR)
 	   || (TYPE_CODE (type) == TYPE_CODE_REF))
 	  && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
-        {
-          real_type = value_rtti_target_type (val, &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);
-            }
-        }
+        real_type = value_rtti_indirect_type (val, &full, &top, &using_enc);
       else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
 	real_type = value_rtti_type (val, &full, &top, &using_enc);
     }
diff --git a/gdb/valops.c b/gdb/valops.c
index fca601f..ee450e3 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1772,15 +1772,7 @@ value_ind (struct value *arg1)
 			      (value_as_address (arg1)
 			       - value_pointed_to_offset (arg1)));
 
-      /* Re-adjust type.  */
-      deprecated_set_value_type (arg2, TYPE_TARGET_TYPE (base_type));
-      /* Add embedding info.  */
-      set_value_enclosing_type (arg2, enc_type);
-      set_value_embedded_offset (arg2, value_pointed_to_offset (arg1));
-
-      /* We may be pointing to an object of some derived type.  */
-      arg2 = value_full_object (arg2, NULL, 0, 0, 0);
-      return arg2;
+      return readjust_indirect_value_type (arg2, enc_type, base_type, arg1);
     }
 
   error (_("Attempt to take contents of a non-pointer value."));
@@ -3526,21 +3518,48 @@ value_maybe_namespace_elt (const struct type *curtype,
   return result;
 }
 
-/* Given a pointer value V, find the real (RTTI) type of the object it
-   points to.
+/* Given a pointer or a reference value V, find its real (RTTI) type.
 
    Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
    and refer to the values computed for the object pointed to.  */
 
 struct type *
-value_rtti_target_type (struct value *v, int *full, 
-			int *top, int *using_enc)
+value_rtti_indirect_type (struct value *v, int *full, 
+			  int *top, int *using_enc)
 {
   struct value *target;
+  struct type *type, *real_type, *target_type;
+
+  type = value_type (v);
+  type = check_typedef (type);
+  if (TYPE_CODE (type) == TYPE_CODE_REF)
+    target = coerce_ref (v);
+  else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    target = value_ind (v);
+  else
+    return NULL;
 
-  target = value_ind (v);
+  real_type = value_rtti_type (target, full, top, using_enc);
+
+  if (real_type)
+    {
+      /* Copy qualifiers to the referenced object.  */
+      target_type = value_type (target);
+      real_type = make_cv_type (TYPE_CONST (target_type),
+				TYPE_VOLATILE (target_type), real_type, NULL);
+      if (TYPE_CODE (type) == TYPE_CODE_REF)
+        real_type = lookup_reference_type (real_type);
+      else if (TYPE_CODE (type) == TYPE_CODE_PTR)
+        real_type = lookup_pointer_type (real_type);
+      else
+        internal_error (__FILE__, __LINE__, _("Unexpected value type."));
+
+      /* Copy qualifiers to the pointer/reference.  */
+      real_type = make_cv_type (TYPE_CONST (type), TYPE_VOLATILE (type),
+				real_type, NULL);
+    }
 
-  return value_rtti_type (target, full, top, using_enc);
+  return real_type;
 }
 
 /* Given a value pointed to by ARGP, check its real run-time type, and
diff --git a/gdb/value.c b/gdb/value.c
index 583be33..85ea970 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -3134,11 +3134,30 @@ coerce_ref_if_computed (const struct value *arg)
   return funcs->coerce_ref (arg);
 }
 
+/* Look at value.h for description.  */
+
+struct value *
+readjust_indirect_value_type (struct value *value, struct type *enc_type,
+			      struct type *original_type,
+			      struct value *original_value)
+{
+  /* Re-adjust type.  */
+  deprecated_set_value_type (value, TYPE_TARGET_TYPE (original_type));
+
+  /* Add embedding info.  */
+  set_value_enclosing_type (value, enc_type);
+  set_value_embedded_offset (value, value_pointed_to_offset (original_value));
+
+  /* We may be pointing to an object of some derived type.  */
+  return value_full_object (value, NULL, 0, 0, 0);
+}
+
 struct value *
 coerce_ref (struct value *arg)
 {
   struct type *value_type_arg_tmp = check_typedef (value_type (arg));
   struct value *retval;
+  struct type *enc_type;
 
   retval = coerce_ref_if_computed (arg);
   if (retval)
@@ -3147,9 +3166,14 @@ coerce_ref (struct value *arg)
   if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
     return arg;
 
-  return value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
-			unpack_pointer (value_type (arg),
-					value_contents (arg)));
+  enc_type = check_typedef (value_enclosing_type (arg));
+  enc_type = TYPE_TARGET_TYPE (enc_type);
+
+  retval = value_at_lazy (enc_type,
+                          unpack_pointer (value_type (arg),
+                                          value_contents (arg)));
+  return readjust_indirect_value_type (retval, enc_type,
+                                       value_type_arg_tmp, arg);
 }
 
 struct value *
diff --git a/gdb/value.h b/gdb/value.h
index 2a2274d..d4c4a83 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -351,6 +351,19 @@ extern short *deprecated_value_regnum_hack (struct value *);
 
 extern struct value *coerce_ref_if_computed (const struct value *arg);
 
+/* Setup a new value type and enclosing value type for dereferenced value VALUE.
+   ENC_TYPE is the new enclosing type that should be set.  ORIGINAL_TYPE and
+   ORIGINAL_VAL are the type and value of the original reference or pointer.
+
+   Note, that VALUE is modified by this function.
+
+   It is a common implementation for coerce_ref and value_ind.  */
+
+extern struct value * readjust_indirect_value_type (struct value *value,
+						    struct type *enc_type,
+						    struct type *original_type,
+						    struct value *original_val);
+
 /* Convert a REF to the object referenced.  */
 
 extern struct value *coerce_ref (struct value *value);
@@ -615,8 +628,8 @@ extern struct value *value_primitive_field (struct value *arg1, int offset,
 					    struct type *arg_type);
 
 
-extern struct type *value_rtti_target_type (struct value *, int *, int *,
-					    int *);
+extern struct type *value_rtti_indirect_type (struct value *, int *, int *,
+					      int *);
 
 extern struct value *value_full_object (struct value *, struct type *, int,
 					int, int);

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

* Re: RTTI type  improvement for
  2012-02-08 18:34                   ` xgsa
@ 2012-02-10 20:13                     ` Tom Tromey
  2012-02-19 18:46                       ` set print object on should affect MI varobjs (PR mi/13393) xgsa
  2012-02-21 14:15                       ` RTTI type improvement for xgsa
  0 siblings, 2 replies; 47+ messages in thread
From: Tom Tromey @ 2012-02-10 20:13 UTC (permalink / raw)
  To: xgsa; +Cc: gdb-patches

>>>>> "xgsa" == xgsa  <xgsa@yandex.ru> writes:

xgsa> 2012-01-06  Anton Gorenkov <xgsa@yandex.ru>
xgsa>     * c-valprint.c (c_value_print): Use value_rtti_indirect_type
xgsa>     instead of value_rtti_target_type.
xgsa>     * eval.c (evaluate_subexp_standard): Use value_rtti_indirect_type
xgsa>     instead of value_rtti_target_type.
xgsa>     * typeprint.c (whatis_exp): Use value_rtti_indirect_type instead of
xgsa>     value_rtti_target_type.
xgsa>     * valops.c (value_ind): Extract function readjust_indirect_value_type.
xgsa>     (value_rtti_target_type): Rename to ...
xgsa>     (value_rtti_indirect_type): ... here and make it indirect.  Update
xgsa>     function comment.
xgsa>     * value.c (readjust_indirect_value_type): New function.
xgsa>     (coerce_ref): Support for enclosing type setting for references
xgsa>     with readjust_indirect_value_type.
xgsa>     * value.h (readjust_value_type): New declaration.
xgsa>     (value_rtti_target_type): Rename to ...
xgsa>     (value_rtti_indirect_type): ... here.

This is ok, thanks.

Contact me off-list for write-after-approval instructions if you
don't have that already set up.

Tom

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-02-10 20:13                     ` Tom Tromey
@ 2012-02-19 18:46                       ` xgsa
  2012-02-23  4:58                         ` xgsa
  2012-03-18 16:28                         ` xgsa
  2012-02-21 14:15                       ` RTTI type improvement for xgsa
  1 sibling, 2 replies; 47+ messages in thread
From: xgsa @ 2012-02-19 18:46 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

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

As the first patch was approved (not checked in though cause my account 
hasn't been created yet) here is the second part of the changes. Note, 
that this patch relies on changes from the previous one.


Thanks,
Anton


gdb/testsuite/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

         PR mi/13393

         * gdb.mi/mi-var-rtti.cc: New file.
         * gdb.mi/mi-var-rtti.exp: New file.

gdb/ChangeLog:

2011-12-02  Anton Gorenkov <xgsa@yandex.ru>

         PR mi/13393

         * value.c (value_actual_type): New function.
         * value.h (value_actual_type): New declaration.
         * varobj.c (varobj_create): Call value_actual_type instead of
         value_type.
         (create_child_with_value): Call value_actual_type instead of
         value_type.
         (value_of_root): Support for type change if the value changed 
and RTTI
         is used to determine the type.
         (adjust_value_for_child_access): Extended with a new parameter 
and cast
         given value to enclosing type if it is set.
         (c_number_of_children): Updated for extended
         adjust_value_for_child_access.
         (c_describe_child): Updated for extended
         adjust_value_for_child_access.
         (cplus_number_of_children): Updated for extended
         adjust_value_for_child_access.
         (cplus_describe_child): Updated for extended
         adjust_value_for_child_access.



[-- Attachment #2: gdb_varobj_rtti1.patch --]
[-- Type: text/x-diff, Size: 21283 bytes --]

diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..d85af37
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -0,0 +1,258 @@
+/* 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_test
+	set_print_object off $testname
+	check_derived_class_without_rtti ptr {Base \*} $testname
+	check_derived_class_without_rtti constPtr {const Base \*} $testname
+	check_derived_class_without_rtti ptrConst {Base \* const} $testname
+	check_derived_class_without_rtti constPtrConst {const Base \* const} \
+		$testname
+
+	set_print_object on $testname
+	check_derived_class_with_rtti ptr {Derived \*} $testname
+	check_derived_class_with_rtti constPtr {const Derived \*} $testname
+	check_derived_class_with_rtti ptrConst {Derived \* const} $testname
+	check_derived_class_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_test
+	set_print_object off $testname
+	check_derived_class_without_rtti ref {Base \&} $testname
+	check_derived_class_without_rtti constRef {const Base \&} $testname
+
+	set_print_object on $testname
+	check_derived_class_with_rtti ref {Derived \&} $testname
+	check_derived_class_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_test
+	set_print_object off $testname
+	check_derived_class_without_rtti s.ptr {Base \*} $testname
+	check_derived_class_without_rtti s.constPtr {const Base \*} $testname
+	check_derived_class_without_rtti s.ptrConst {Base \* const} $testname
+	check_derived_class_without_rtti s.constPtrConst {const Base \* const} \
+		$testname
+
+	set_print_object on $testname
+	check_derived_class_with_rtti s.ptr {Derived \*} $testname
+	check_derived_class_with_rtti s.constPtr {const Derived \*} $testname
+	check_derived_class_with_rtti s.ptrConst {Derived \* const} $testname
+	check_derived_class_with_rtti s.constPtrConst {const Derived \* const} \
+		$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_test
+	set_print_object off $testname
+	check_derived_class_without_rtti s.ref {Base \&} $testname
+	check_derived_class_without_rtti s.constRef {const Base \&} $testname
+
+	set_print_object on $testname
+	check_derived_class_with_rtti s.ref {Derived \&} $testname
+	check_derived_class_with_rtti s.constRef {const Derived \&} $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_derived_class_without_rtti ptr {Base \*} $testname
+	check_derived_class_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_test
+	set_print_object on $testname
+	mi_create_varobj_checked VAR ptr {Base \*} \
+		"create varobj for ptr in $testname"
+	check_derived_children_without_rtti ptr $testname
+  :*/
+
+	Base* ptr = &d;
+  /*: 
+	mi_varobj_update_with_type_change VAR {Derived \*} 2 \
+		"update ptr in $testname"
+	check_derived_children_with_rtti ptr $testname
+	check_derived_content_with_rtti ptr $testname
+	mi_delete_varobj VAR "delete varobj for ptr 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_test
+	set_print_object off $testname
+	mi_create_varobj_checked VAR ptr {Base \*} \
+		"create varobj for ptr in $testname"
+	check_derived_children_without_rtti ptr $testname
+  :*/
+
+	Base* ptr = &d;
+  /*: 
+	mi_varobj_update VAR {} "update ptr in $testname"
+	check_derived_children_without_rtti ptr $testname
+	check_derived_content_without_rtti ptr $testname
+	mi_delete_varobj VAR "delete varobj for ptr 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
index 0000000..c4597ce
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -0,0 +1,114 @@
+# 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 {var_name testname} {
+    mi_list_varobj_children VAR {
+        { VAR.public public 1 }
+    } "list children of ${var_name} (without RTTI) in $testname"
+    mi_list_varobj_children "VAR.public" {
+        { VAR.public.A A 0 int }
+    } "list children of ${var_name}.public (without RTTI) in $testname"
+}
+
+proc check_derived_content_without_rtti {var_name testname} {
+    mi_check_varobj_value VAR.public.A 1 \
+        "check ${var_name}->A (without RTTI) in $testname"
+}
+
+proc check_derived_class_without_rtti {var_name var_type testname} {
+    mi_create_varobj_checked VAR ${var_name} ${var_type} \
+        "create varobj for ${var_name} (without RTTI) in ${testname}"
+    check_derived_children_without_rtti ${var_name} ${testname}
+    check_derived_content_without_rtti ${var_name} ${testname}
+    mi_delete_varobj VAR \
+        "delete varobj for ${var_name} (without RTTI) in ${testname}"
+}
+
+proc check_derived_children_with_rtti {var_name testname} {
+    mi_list_varobj_children VAR {
+        { VAR.Base Base 1 Base }
+        { VAR.public public 2 }
+    } "list children of ${var_name} (with RTTI) in $testname"
+    mi_list_varobj_children "VAR.Base" {
+        { VAR.Base.public public 1 }
+    } "list children of ${var_name}.Base (with RTTI) in $testname"
+    mi_list_varobj_children "VAR.Base.public" {
+        { VAR.Base.public.A A 0 int }
+    } "list children of ${var_name}.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 ${var_name}.public (with RTTI) in $testname"
+}
+
+proc check_derived_content_with_rtti {var_name testname} {
+    mi_check_varobj_value VAR.Base.public.A 1 \
+        "check ${var_name}->A (with RTTI) in $testname"
+    mi_check_varobj_value VAR.public.B 2 \
+        "check ${var_name}->B (with RTTI) in $testname"
+    mi_check_varobj_value VAR.public.C 3 \
+        "check ${var_name}->C (with RTTI) in $testname"
+}
+
+proc check_derived_class_with_rtti {var_name var_type testname} {
+    mi_create_varobj_checked VAR ${var_name} ${var_type} \
+        "create varobj for ${var_name} (with RTTI) in $testname"
+    check_derived_children_with_rtti ${var_name} $testname
+    check_derived_content_with_rtti ${var_name} $testname
+    mi_delete_varobj VAR \
+        "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
diff --git a/gdb/value.c b/gdb/value.c
index 85ea970..77e547e 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -825,6 +825,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)
 {
diff --git a/gdb/value.h b/gdb/value.h
index d4c4a83..71b5140 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -137,6 +137,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);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 8855ce3..d55b082 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -672,8 +672,15 @@ 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);
+	  }
 
       install_new_value (var, value, 1 /* Initial assignment */);
 
@@ -2280,7 +2287,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, 
@@ -2566,6 +2573,7 @@ static struct value *
 value_of_root (struct varobj **var_handle, int *type_changed)
 {
   struct varobj *var;
+  struct value_print_options opts;
 
   if (var_handle == NULL)
     return NULL;
@@ -2578,7 +2586,8 @@ value_of_root (struct varobj **var_handle, int *type_changed)
   if (!is_root_p (var))
     return NULL;
 
-  if (var->root->floating)
+  get_user_print_options (&opts);
+  if (var->root->floating || opts.objectprint)
     {
       struct varobj *tmp_var;
       char *old_type, *new_type;
@@ -2867,6 +2876,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
@@ -2878,7 +2891,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);
 
@@ -2923,6 +2937,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);
+        }
+    }
 }
 
 /* C */
@@ -2933,7 +2961,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))
@@ -3049,7 +3077,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))
     {
@@ -3350,16 +3378,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))
@@ -3386,7 +3427,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)
@@ -3468,7 +3519,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;
@@ -3479,24 +3533,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)

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

* Re: RTTI type  improvement for
  2012-02-10 20:13                     ` Tom Tromey
  2012-02-19 18:46                       ` set print object on should affect MI varobjs (PR mi/13393) xgsa
@ 2012-02-21 14:15                       ` xgsa
  1 sibling, 0 replies; 47+ messages in thread
From: xgsa @ 2012-02-21 14:15 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Checked in.

Thank you for help, guys!
Anton

-------- Original message --------
> xgsa>  2012-01-06  Anton Gorenkov<xgsa@yandex.ru>
> xgsa>      * c-valprint.c (c_value_print): Use value_rtti_indirect_type
> xgsa>      instead of value_rtti_target_type.
> xgsa>      * eval.c (evaluate_subexp_standard): Use value_rtti_indirect_type
> xgsa>      instead of value_rtti_target_type.
> xgsa>      * typeprint.c (whatis_exp): Use value_rtti_indirect_type instead of
> xgsa>      value_rtti_target_type.
> xgsa>      * valops.c (value_ind): Extract function readjust_indirect_value_type.
> xgsa>      (value_rtti_target_type): Rename to ...
> xgsa>      (value_rtti_indirect_type): ... here and make it indirect.  Update
> xgsa>      function comment.
> xgsa>      * value.c (readjust_indirect_value_type): New function.
> xgsa>      (coerce_ref): Support for enclosing type setting for references
> xgsa>      with readjust_indirect_value_type.
> xgsa>      * value.h (readjust_value_type): New declaration.
> xgsa>      (value_rtti_target_type): Rename to ...
> xgsa>      (value_rtti_indirect_type): ... here.
>
> This is ok, thanks.
>
> Contact me off-list for write-after-approval instructions if you
> don't have that already set up.
>
> Tom

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-02-19 18:46                       ` set print object on should affect MI varobjs (PR mi/13393) xgsa
@ 2012-02-23  4:58                         ` xgsa
  2012-03-18 16:28                         ` xgsa
  1 sibling, 0 replies; 47+ messages in thread
From: xgsa @ 2012-02-23  4:58 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Ping. Can anybody look at this patch?

BTW, the first part has already been checked in, so this patch could be 
applied on HEAD.

And one more question connected to these changes. Should I update 
documentation somehow (e.g. add some notes to the "show/set print 
object" commands description or to MI interface chapter)?

Thanks,
Anton

-------- Original message --------
> As the first patch was approved (not checked in though cause my 
> account hasn't been created yet) here is the second part of the 
> changes. Note, that this patch relies on changes from the previous one.
>
>
> Thanks,
> Anton
>
>
> gdb/testsuite/ChangeLog:
>
> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
>
>         PR mi/13393
>
>         * gdb.mi/mi-var-rtti.cc: New file.
>         * gdb.mi/mi-var-rtti.exp: New file.
>
> gdb/ChangeLog:
>
> 2011-12-02  Anton Gorenkov <xgsa@yandex.ru>
>
>         PR mi/13393
>
>         * value.c (value_actual_type): New function.
>         * value.h (value_actual_type): New declaration.
>         * varobj.c (varobj_create): Call value_actual_type instead of
>         value_type.
>         (create_child_with_value): Call value_actual_type instead of
>         value_type.
>         (value_of_root): Support for type change if the value changed 
> and RTTI
>         is used to determine the type.
>         (adjust_value_for_child_access): Extended with a new parameter 
> and cast
>         given value to enclosing type if it is set.
>         (c_number_of_children): Updated for extended
>         adjust_value_for_child_access.
>         (c_describe_child): Updated for extended
>         adjust_value_for_child_access.
>         (cplus_number_of_children): Updated for extended
>         adjust_value_for_child_access.
>         (cplus_describe_child): Updated for extended
>         adjust_value_for_child_access.
>
>


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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-02-19 18:46                       ` set print object on should affect MI varobjs (PR mi/13393) xgsa
  2012-02-23  4:58                         ` xgsa
@ 2012-03-18 16:28                         ` xgsa
  2012-03-18 20:41                           ` Eli Zaretskii
  1 sibling, 1 reply; 47+ messages in thread
From: xgsa @ 2012-03-18 16:28 UTC (permalink / raw)
  To: gdb-patches

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

Hi,

While implementing the support for this patch in Eclipse I ran into a 
problem with type updates for child varobjs. This patch fixes the issue.

And I still have a question about the documentation update. What part of 
it should be updated (the "show/set print object" commands description 
or to MI interface chapter or something else)?


Thanks,
Anton

[-- Attachment #2: ChangeLog --]
[-- Type: text/plain, Size: 1486 bytes --]

gdb/testsuite/ChangeLog:

2012-03-18  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-03-18  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.
	(varobj_get_num_children): Likewise.
	(varobj_list_children): Likewise.
	(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.
	(c_number_of_children): Updated for extended
	adjust_value_for_child_access.
	(c_describe_child): Updated for extended
	adjust_value_for_child_access.
	(cplus_number_of_children): Updated for extended
	adjust_value_for_child_access.
	(cplus_describe_child): Updated for extended
	adjust_value_for_child_access.


[-- Attachment #3: gdb_varobj_rtti2.patch --]
[-- Type: text/x-diff, Size: 33739 bytes --]

diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..d05f660
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -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
index 0000000..5e43bae
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -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
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 7f8642f..401565d 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -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} {
diff --git a/gdb/value.c b/gdb/value.c
index c23803a..3611cf5 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -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)
 {
diff --git a/gdb/value.h b/gdb/value.h
index d501b52..e16e963 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -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);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index b6e67c6..24c0398 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -268,6 +268,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);
 
@@ -672,8 +675,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);
+	  }
 
       install_new_value (var, value, 1 /* Initial assignment */);
 
@@ -961,6 +970,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,
@@ -983,12 +993,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);
     }
 }
@@ -1011,6 +1027,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,
@@ -1146,6 +1163,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);
@@ -1201,7 +1219,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
@@ -1227,8 +1245,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;
     }
@@ -1575,6 +1593,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 
@@ -1880,8 +1935,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;
@@ -1920,6 +1976,8 @@ varobj_update (struct varobj **varp, int explicit)
       if (!r.value_installed)
 	{	  
 	  new = value_of_child (v->parent, v->index);
+	  if (update_type_if_necessary(v, new))
+	      r.type_changed = 1;
 	  if (install_new_value (v, new, 0 /* type not changed */))
 	    {
 	      r.changed = 1;
@@ -1932,7 +1990,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)
@@ -1950,7 +2009,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;
@@ -1964,8 +2023,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)
@@ -1977,6 +2036,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);
@@ -2003,9 +2074,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;
@@ -2280,7 +2352,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, 
@@ -2867,6 +2939,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
@@ -2878,7 +2954,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);
 
@@ -2923,6 +3000,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);
+        }
+    }
 }
 
 /* C */
@@ -2933,7 +3024,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))
@@ -3049,7 +3140,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))
     {
@@ -3345,16 +3436,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))
@@ -3381,7 +3485,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)
@@ -3463,7 +3577,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;
@@ -3474,24 +3591,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)

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-18 16:28                         ` xgsa
@ 2012-03-18 20:41                           ` Eli Zaretskii
  2012-03-19  7:10                             ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2012-03-18 20:41 UTC (permalink / raw)
  To: xgsa; +Cc: gdb-patches

> Date: Sun, 18 Mar 2012 18:27:34 +0200
> From: xgsa <xgsa@yandex.ru>
> 
> While implementing the support for this patch in Eclipse I ran into a 
> problem with type updates for child varobjs. This patch fixes the issue.
> 
> And I still have a question about the documentation update. What part of 
> it should be updated (the "show/set print object" commands description 
> or to MI interface chapter or something else)?

What exactly is the nature of the change, as will be visible by GDB
users?  With that information in hand, I could answer your questions.

Thanks.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-18 20:41                           ` Eli Zaretskii
@ 2012-03-19  7:10                             ` xgsa
  2012-03-19 17:41                               ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-03-19  7:10 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches


> What exactly is the nature of the change, as will be visible by GDB
> users?  With that information in hand, I could answer your questions.

That was the reply on the original patch, so I thought that I can omit 
the description, sorry.

That patch makes "set print object" option affect MI interface. Here is 
an example:

struct Base {
     Base() : a(1) {}
     virtual ~Base() {}  // Enforce type to have RTTI
     int a;
};

struct Derived : public Base {
     Derived() : b(2) {}
     int b;
};

int main() {
     Derived b;
     Base* aPtr = &b;
     return 0;                  // [1]
}


Start gdb in MI mode and run to line [1]. Make -var-create for aPtr. If 
"set print object" is "on" you will see the type Derived* for the 
created varobj.

See also more details here: 
http://sourceware.org/bugzilla/show_bug.cgi?id=13393


Thanks,
Anton

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-19  7:10                             ` xgsa
@ 2012-03-19 17:41                               ` Eli Zaretskii
  2012-03-23 17:09                                 ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2012-03-19 17:41 UTC (permalink / raw)
  To: xgsa; +Cc: gdb-patches

> Date: Mon, 19 Mar 2012 09:10:08 +0200
> From: xgsa <xgsa@yandex.ru>
> CC: gdb-patches@sourceware.org
> 
> Start gdb in MI mode and run to line [1]. Make -var-create for aPtr. If 
> "set print object" is "on" you will see the type Derived* for the 
> created varobj.

If "set print object" now affects MI as well, that should be mentioned
both where "set print object" is documented and where the relevant
varobj related MI commands are described.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-19 17:41                               ` Eli Zaretskii
@ 2012-03-23 17:09                                 ` xgsa
  2012-03-26 19:08                                   ` xgsa
                                                     ` (2 more replies)
  0 siblings, 3 replies; 47+ messages in thread
From: xgsa @ 2012-03-23 17:09 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

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

Hi,

> If "set print object" now affects MI as well, that should be mentioned
> both where "set print object" is documented and where the relevant
> varobj related MI commands are described.

Here is the previous patch with the documentation updated.


The original patch description:

That patch makes "set print object" option affect MI interface. Here is 
an example:

struct Base {
     Base() : a(1) {}
     virtual ~Base() {}  // Enforce type to have RTTI
     int a;
};

struct Derived : public Base {
     Derived() : b(2) {}
     int b;
};

int main() {
     Derived b;
     Base* aPtr = &b;
     return 0;                  // [1]
}

Start gdb in MI mode and run to line [1]. Make -var-create for aPtr. If 
"set print object" is "on" you will see the type Derived* for the 
created varobj.

See also more details here: 
http://sourceware.org/bugzilla/show_bug.cgi?id=13393


Waiting for your comments!

Thanks,
Anton.

[-- Attachment #2: ChangeLog --]
[-- Type: text/plain, Size: 1734 bytes --]

gdb/doc/ChangeLog:

2012-03-18  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-update.


gdb/testsuite/ChangeLog:

2012-03-18  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-03-18  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.
	(varobj_get_num_children): Likewise.
	(varobj_list_children): Likewise.
	(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.
	(c_number_of_children): Updated for extended
	adjust_value_for_child_access.
	(c_describe_child): Updated for extended
	adjust_value_for_child_access.
	(cplus_number_of_children): Updated for extended
	adjust_value_for_child_access.
	(cplus_describe_child): Updated for extended
	adjust_value_for_child_access.


[-- Attachment #3: gdb_varobj_rtti3.patch --]
[-- Type: text/x-diff, Size: 35242 bytes --]

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 56bf5d5..f0d133c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -8499,7 +8499,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
@@ -28861,7 +28862,9 @@ 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.  Note that if 
+@samp{set print object} setting is set the @emph{actual} (derived) type
+of the object is set rather than @emph{declared} one.
 
 @item thread-id
 If a variable object is bound to a specific thread, then this is the
@@ -29032,7 +29035,9 @@ 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. Note that if @samp{set print object} setting is
+set the @emph{actual} (derived) type of the object is set rather than
+@emph{declared} one.
 
 @item value
 If values were requested, this is the value.
diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..d05f660
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -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
index 0000000..5e43bae
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -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
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 7f8642f..401565d 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -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} {
diff --git a/gdb/value.c b/gdb/value.c
index c23803a..3611cf5 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -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)
 {
diff --git a/gdb/value.h b/gdb/value.h
index d501b52..e16e963 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -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);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index b6e67c6..24c0398 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -268,6 +268,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);
 
@@ -672,8 +675,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);
+	  }
 
       install_new_value (var, value, 1 /* Initial assignment */);
 
@@ -961,6 +970,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,
@@ -983,12 +993,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);
     }
 }
@@ -1011,6 +1027,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,
@@ -1146,6 +1163,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);
@@ -1201,7 +1219,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
@@ -1227,8 +1245,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;
     }
@@ -1575,6 +1593,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 
@@ -1880,8 +1935,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;
@@ -1920,6 +1976,8 @@ varobj_update (struct varobj **varp, int explicit)
       if (!r.value_installed)
 	{	  
 	  new = value_of_child (v->parent, v->index);
+	  if (update_type_if_necessary(v, new))
+	      r.type_changed = 1;
 	  if (install_new_value (v, new, 0 /* type not changed */))
 	    {
 	      r.changed = 1;
@@ -1932,7 +1990,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)
@@ -1950,7 +2009,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;
@@ -1964,8 +2023,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)
@@ -1977,6 +2036,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);
@@ -2003,9 +2074,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;
@@ -2280,7 +2352,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, 
@@ -2867,6 +2939,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
@@ -2878,7 +2954,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);
 
@@ -2923,6 +3000,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);
+        }
+    }
 }
 
 /* C */
@@ -2933,7 +3024,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))
@@ -3049,7 +3140,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))
     {
@@ -3345,16 +3436,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))
@@ -3381,7 +3485,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)
@@ -3463,7 +3577,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;
@@ -3474,24 +3591,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)

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-23 17:09                                 ` xgsa
@ 2012-03-26 19:08                                   ` xgsa
  2012-03-30 17:51                                   ` Tom Tromey
  2012-03-30 18:01                                   ` Eli Zaretskii
  2 siblings, 0 replies; 47+ messages in thread
From: xgsa @ 2012-03-26 19:08 UTC (permalink / raw)
  To: gdb-patches

Just a reminder: please, review this patch.

Thanks,
Anton

-------- Original message --------
> Hi,
>
>> If "set print object" now affects MI as well, that should be mentioned
>> both where "set print object" is documented and where the relevant
>> varobj related MI commands are described.
>
> Here is the previous patch with the documentation updated.
>
>
> The original patch description:
>
> That patch makes "set print object" option affect MI interface. Here 
> is an example:
>
> struct Base {
>     Base() : a(1) {}
>     virtual ~Base() {}  // Enforce type to have RTTI
>     int a;
> };
>
> struct Derived : public Base {
>     Derived() : b(2) {}
>     int b;
> };
>
> int main() {
>     Derived b;
>     Base* aPtr = &b;
>     return 0;                  // [1]
> }
>
> Start gdb in MI mode and run to line [1]. Make -var-create for aPtr. 
> If "set print object" is "on" you will see the type Derived* for the 
> created varobj.
>
> See also more details here: 
> http://sourceware.org/bugzilla/show_bug.cgi?id=13393
>
>
> Waiting for your comments!
>
> Thanks,
> Anton.


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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-23 17:09                                 ` xgsa
  2012-03-26 19:08                                   ` xgsa
@ 2012-03-30 17:51                                   ` Tom Tromey
  2012-03-30 18:01                                     ` Eli Zaretskii
  2012-03-30 20:11                                     ` xgsa
  2012-03-30 18:01                                   ` Eli Zaretskii
  2 siblings, 2 replies; 47+ messages in thread
From: Tom Tromey @ 2012-03-30 17:51 UTC (permalink / raw)
  To: xgsa; +Cc: Eli Zaretskii, gdb-patches

>>>>> "Anton" == xgsa  <xgsa@yandex.ru> writes:

Anton> Waiting for your comments!

Thanks for sending this.
I'm sorry about the delay, I have been quite behind on patch review :(

You didn't say whether you regression-tested this.

I have a few nits, but nothing serious.

AFAIK it still needs a doc review.

Anton> +  if (real_type_found)
Anton> +      *real_type_found = 0;

Too much indentation on the second line here.

Anton> +              if (real_type_found)
Anton> +                  *real_type_found = 1;

Here too.

Anton> +          if (real_type_found)
Anton> +              *real_type_found = 1;

Here too.

Anton> +   REAL_TYPE_FOUND is used to inform whether the real type was found
Anton> +   (or just static type was used). The NULL may be passed if it is not
Anton> +   necessary. */

Two spaces after periods.
Just write "NULL", not "The NULL".

Anton> +	    if (real_type_found)
Anton> +	        value = value_cast (var->type, value);

Too much indentation.

Anton> +      int type_updated = update_type_if_necessary(existing, value);

Space before open paren.

Anton> +	  curr_type_str = varobj_get_type(var);

Space before open paren.

Anton> +	  if (update_type_if_necessary(v, new))
Anton> +	      r.type_changed = 1;

Too much indentation.

Tom

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-30 17:51                                   ` Tom Tromey
@ 2012-03-30 18:01                                     ` Eli Zaretskii
  2012-03-30 20:11                                     ` xgsa
  1 sibling, 0 replies; 47+ messages in thread
From: Eli Zaretskii @ 2012-03-30 18:01 UTC (permalink / raw)
  To: Tom Tromey; +Cc: xgsa, gdb-patches

> From: Tom Tromey <tromey@redhat.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, gdb-patches@sourceware.org
> Date: Fri, 30 Mar 2012 11:50:44 -0600
> 
> AFAIK it still needs a doc review.

Just done, sorry for the delay.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-23 17:09                                 ` xgsa
  2012-03-26 19:08                                   ` xgsa
  2012-03-30 17:51                                   ` Tom Tromey
@ 2012-03-30 18:01                                   ` Eli Zaretskii
  2012-03-30 20:25                                     ` xgsa
  2 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2012-03-30 18:01 UTC (permalink / raw)
  To: xgsa; +Cc: gdb-patches

> Date: Fri, 23 Mar 2012 19:07:59 +0200
> From: xgsa <xgsa@yandex.ru>
> CC: gdb-patches@sourceware.org

Sorry for a long response time.

> +would be printed by the @value{GDBN} CLI.  Note that if 
> +@samp{set print object} setting is set the @emph{actual} (derived) type
> +of the object is set rather than @emph{declared} one.

"setting is set" is not right.  I actually don't understand what you
tried to say; if you explain your intent, I will suggest a better
wording.

> +The type of the child. Note that if @samp{set print object} setting is
                        ^^
Two spaces here, please.

> +set the @emph{actual} (derived) type of the object is set rather than
> +@emph{declared} one.

Here you have the same problem as above ("setting is set" and
generally unclear intent).

Thanks.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-30 17:51                                   ` Tom Tromey
  2012-03-30 18:01                                     ` Eli Zaretskii
@ 2012-03-30 20:11                                     ` xgsa
  1 sibling, 0 replies; 47+ messages in thread
From: xgsa @ 2012-03-30 20:11 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Eli Zaretskii, gdb-patches


> You didn't say whether you regression-tested this.
Yes, I didn't say it because I was not sure I have done it properly. I 
have run the gdb.mi tests but there were a few unexpected failures. 
However these failures are reproducible on gdb master branch without my 
changes, so it should be a problem with my environment setup. 
Unfortunately, I cannot figure out how to fix it. Moreover probably I 
should run all the tests (not only gdb.mi) with "make check" but I 
cannot found the overall statistics (only by every module), so it is 
quite hard to compare the results. I have read the Testsuite chapter[1] 
in gdb internals manual however that didn't help. Can you clarify me how 
the regression testing should be done or point me where to read about it?

[1] 
http://sourceware.org/gdb/current/onlinedocs/gdbint/Testsuite.html#Testsuite

> Anton>  +  if (real_type_found)
> Anton>  +      *real_type_found = 0;
Fixed
> Too much indentation on the second line here.
>
> Anton>  +              if (real_type_found)
> Anton>  +                  *real_type_found = 1;
>
> Here too.
Fixed
> Anton>  +          if (real_type_found)
> Anton>  +              *real_type_found = 1;
>
> Here too.
Fixed
> Anton>  +   REAL_TYPE_FOUND is used to inform whether the real type was found
> Anton>  +   (or just static type was used). The NULL may be passed if it is not
> Anton>  +   necessary. */
>
> Two spaces after periods.
> Just write "NULL", not "The NULL".
Fixed.
> Anton>  +	    if (real_type_found)
> Anton>  +	        value = value_cast (var->type, value);
>
> Too much indentation.
Fixed.
> Anton>  +      int type_updated = update_type_if_necessary(existing, value);
>
> Space before open paren.
Fixed.
> Anton>  +	  curr_type_str = varobj_get_type(var);
>
> Space before open paren.
Fixed.
> Anton>  +	  if (update_type_if_necessary(v, new))
> Anton>  +	      r.type_changed = 1;
>
> Too much indentation.
Fixed.


Anton.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-30 18:01                                   ` Eli Zaretskii
@ 2012-03-30 20:25                                     ` xgsa
  2012-03-30 20:52                                       ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-03-30 20:25 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches


>> +would be printed by the @value{GDBN} CLI.  Note that if
>> +@samp{set print object} setting is set the @emph{actual} (derived) type
>> +of the object is set rather than @emph{declared} one.
> "setting is set" is not right.  I actually don't understand what you
> tried to say; if you explain your intent, I will suggest a better
> wording.
I meant that "set print object on/off" will also affect the "type" field 
returned by -var-create and -var-list-children.
Probably, it should be an "option" not "setting". The result will look 
like this:

+would be printed by the @value{GDBN} CLI.  Note that if
+@samp{set print object} option is set the @emph{actual} (derived) type
+of the object is set rather than @emph{declared} one.


Is it ok?
>> +The type of the child. Note that if @samp{set print object} setting is
>                          ^^
> Two spaces here, please.
Fixed.


P.S. I have also found a mistake in my gdb/doc/Changelog. It should be 
"-var-create and -var-list-children" instead of "-var-create and 
-var-update". Fixed.


Anton.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-30 20:25                                     ` xgsa
@ 2012-03-30 20:52                                       ` Eli Zaretskii
  2012-03-30 21:26                                         ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2012-03-30 20:52 UTC (permalink / raw)
  To: xgsa; +Cc: gdb-patches

> Date: Fri, 30 Mar 2012 23:26:48 +0300
> From: xgsa <xgsa@yandex.ru>
> CC: gdb-patches@sourceware.org
> 
> >> +would be printed by the @value{GDBN} CLI.  Note that if
> >> +@samp{set print object} setting is set the @emph{actual} (derived) type
> >> +of the object is set rather than @emph{declared} one.
> > "setting is set" is not right.  I actually don't understand what you
> > tried to say; if you explain your intent, I will suggest a better
> > wording.
> I meant that "set print object on/off" will also affect the "type" field 
> returned by -var-create and -var-list-children.
> Probably, it should be an "option" not "setting". The result will look 
> like this:
> 
> +would be printed by the @value{GDBN} CLI.  Note that if
> +@samp{set print object} option is set the @emph{actual} (derived) type
> +of the object is set rather than @emph{declared} one.
> 
> 
> Is it ok?

Close, but not quite there yet.  The last piece we need to clarify is
the "actual (derived) type of the object is set" part.  What do you
mean by "type is set"?  This text describes the result returned by
'-var-create', so did you mean to say that the actual type is
mentioned in the tuple returned by this operation?  IOW, did you mean
to point out that the 'type=TYPE' part of -var-create's output will
mention the actual type as TYPE?

Thanks.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-30 20:52                                       ` Eli Zaretskii
@ 2012-03-30 21:26                                         ` xgsa
  2012-03-31  5:54                                           ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-03-30 21:26 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

31.03.2012, 00:52, "Eli Zaretskii" <eliz@gnu.org>:
> Close, but not quite there yet. б The last piece we need to clarify is
> the "actual (derived) type of the object is set" part. б What do you
> mean by "type is set"? б This text describes the result returned by
> '-var-create', so did you mean to say that the actual type is
> mentioned in the tuple returned by this operation? б IOW, did you mean
> to point out that the 'type=TYPE' part of -var-create's output will
> mention the actual type as TYPE?

Yes, it is exactly what I meant. Can you help me with the better wording?


Thanks,
Anton.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-30 21:26                                         ` xgsa
@ 2012-03-31  5:54                                           ` Eli Zaretskii
  2012-03-31  6:57                                             ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2012-03-31  5:54 UTC (permalink / raw)
  To: xgsa; +Cc: gdb-patches

> From: xgsa <xgsa@yandex.ru>
> Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
> Date: Sat, 31 Mar 2012 01:25:51 +0400
> 
> 31.03.2012, 00:52, "Eli Zaretskii" <eliz@gnu.org>:
> > Close, but not quite there yet. б The last piece we need to clarify is
> > the "actual (derived) type of the object is set" part. б What do you
> > mean by "type is set"? б This text describes the result returned by
> > '-var-create', so did you mean to say that the actual type is
> > mentioned in the tuple returned by this operation? б IOW, did you mean
> > to point out that the 'type=TYPE' part of -var-create's output will
> > mention the actual type as TYPE?
> 
> Yes, it is exactly what I meant. Can you help me with the better wording?

I suggest this:

  The varobj's type.  This is a string representation of the type, as
  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.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-31  5:54                                           ` Eli Zaretskii
@ 2012-03-31  6:57                                             ` xgsa
  2012-03-31  9:33                                               ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-03-31  6:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

31.03.2012, 09:53, "Eli Zaretskii" <eliz@gnu.org>:
> б б The varobj's type. б This is a string representation of the type, as
> б б 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.

Ok, thanks. I'll provide the updated patch soon.


Anton.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-31  6:57                                             ` xgsa
@ 2012-03-31  9:33                                               ` xgsa
  2012-04-03  0:54                                                 ` Doug Evans
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-03-31  9:33 UTC (permalink / raw)
  To: Eli Zaretskii, Tom Tromey; +Cc: gdb-patches

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

Hi,

Here is the previous patch with the Tom's and Eli's review comments fixed.


The original patch description:

That patch makes "set print object" option affect MI interface. Here is 
an example:

struct Base {
     Base() : a(1) {}
     virtual ~Base() {}  // Enforce type to have RTTI
     int a;
};

struct Derived : public Base {
     Derived() : b(2) {}
     int b;
};

int main() {
     Derived b;
     Base* aPtr = &b;
     return 0;                  // [1]
}

Start gdb in MI mode and run to line [1]. Make -var-create for aPtr. If 
"set print object" is "on" you will see the type Derived* for the 
created varobj.

See also more details here: 
http://sourceware.org/bugzilla/show_bug.cgi?id=13393


Thanks,
Anton.

[-- Attachment #2: gdb_varobj_rtti4.ChangeLog --]
[-- Type: text/plain, Size: 1741 bytes --]

gdb/doc/ChangeLog:

2012-03-18  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-03-18  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-03-18  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.
	(varobj_get_num_children): Likewise.
	(varobj_list_children): Likewise.
	(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.
	(c_number_of_children): Updated for extended
	adjust_value_for_child_access.
	(c_describe_child): Updated for extended
	adjust_value_for_child_access.
	(cplus_number_of_children): Updated for extended
	adjust_value_for_child_access.
	(cplus_describe_child): Updated for extended
	adjust_value_for_child_access.


[-- Attachment #3: gdb_varobj_rtti4.patch --]
[-- Type: text/x-diff, Size: 35321 bytes --]

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 56bf5d5..1b951df 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -8499,7 +8499,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
@@ -28861,7 +28862,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
@@ -29032,7 +29036,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.
diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..d05f660
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -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
index 0000000..5e43bae
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -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
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 7f8642f..401565d 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -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} {
diff --git a/gdb/value.c b/gdb/value.c
index c23803a..eae3e2d 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -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)
 {
diff --git a/gdb/value.h b/gdb/value.h
index d501b52..9de31a6 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -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);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index b6e67c6..5fce5f9 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -268,6 +268,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);
 
@@ -672,8 +675,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);
+	  }
 
       install_new_value (var, value, 1 /* Initial assignment */);
 
@@ -961,6 +970,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,
@@ -983,12 +993,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);
     }
 }
@@ -1011,6 +1027,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,
@@ -1146,6 +1163,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);
@@ -1201,7 +1219,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
@@ -1227,8 +1245,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;
     }
@@ -1575,6 +1593,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 
@@ -1880,8 +1935,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;
@@ -1920,6 +1976,8 @@ varobj_update (struct varobj **varp, int explicit)
       if (!r.value_installed)
 	{	  
 	  new = value_of_child (v->parent, v->index);
+	  if (update_type_if_necessary(v, new))
+	    r.type_changed = 1;
 	  if (install_new_value (v, new, 0 /* type not changed */))
 	    {
 	      r.changed = 1;
@@ -1932,7 +1990,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)
@@ -1950,7 +2009,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;
@@ -1964,8 +2023,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)
@@ -1977,6 +2036,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);
@@ -2003,9 +2074,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;
@@ -2280,7 +2352,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, 
@@ -2867,6 +2939,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
@@ -2878,7 +2954,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);
 
@@ -2923,6 +3000,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);
+        }
+    }
 }
 
 /* C */
@@ -2933,7 +3024,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))
@@ -3049,7 +3140,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))
     {
@@ -3345,16 +3436,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))
@@ -3381,7 +3485,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)
@@ -3463,7 +3577,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;
@@ -3474,24 +3591,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)

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-03-31  9:33                                               ` xgsa
@ 2012-04-03  0:54                                                 ` Doug Evans
  2012-04-03 13:27                                                   ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Doug Evans @ 2012-04-03  0:54 UTC (permalink / raw)
  To: xgsa; +Cc: Eli Zaretskii, Tom Tromey, gdb-patches

On Sat, Mar 31, 2012 at 2:34 AM, xgsa <xgsa@yandex.ru> wrote:
> Hi,
>
> Here is the previous patch with the Tom's and Eli's review comments fixed.

Hi.  ChangeLog nit:

To improve the S/N ratio of the ChangeLog entry, instead of:

	(adjust_value_for_child_access): Extended with a new parameter which
	specify whether the given value should be casted to enclosing type.
	(c_number_of_children): Updated for extended
	adjust_value_for_child_access.
	(c_describe_child): Updated for extended
	adjust_value_for_child_access.
	(cplus_number_of_children): Updated for extended
	adjust_value_for_child_access.
	(cplus_describe_child): Updated for extended
	adjust_value_for_child_access.

write this:

	(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.

and that's it.
I.e., don't write entries for each caller, just say "All callers updated."

[I know, a bit of a hassle this time, but next time you'll have less
to type. :-)]

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-03  0:54                                                 ` Doug Evans
@ 2012-04-03 13:27                                                   ` xgsa
  2012-04-06 17:11                                                     ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-04-03 13:27 UTC (permalink / raw)
  To: Doug Evans; +Cc: Eli Zaretskii, Tom Tromey, gdb-patches

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

Hi,
> Hi.  ChangeLog nit:
> ...
Thanks, the similar case with update_dynamic_varobj_children is fixed too.

The same patch and updated changelog are attached.


P.S. It seems the question with regression testing is left unanswered. 
Could someone clarify how it should be done or point me where I could 
read about it?


The original patch description:

That patch makes "set print object" option affect MI interface. Here is 
an example:

struct Base {
     Base() : a(1) {}
     virtual ~Base() {}  // Enforce type to have RTTI
     int a;
};

struct Derived : public Base {
     Derived() : b(2) {}
     int b;
};

int main() {
     Derived b;
     Base* aPtr = &b;
     return 0;                  // [1]
}

Start gdb in MI mode and run to line [1]. Make -var-create for aPtr. If 
"set print object" is "on" you will see the type Derived* for the 
created varobj.

See also more details here: 
http://sourceware.org/bugzilla/show_bug.cgi?id=13393


Thanks,
Anton.

[-- Attachment #2: gdb_varobj_rtti4.patch --]
[-- Type: text/x-diff, Size: 35321 bytes --]

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 56bf5d5..1b951df 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -8499,7 +8499,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
@@ -28861,7 +28862,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
@@ -29032,7 +29036,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.
diff --git a/gdb/testsuite/gdb.mi/mi-var-rtti.cc b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
new file mode 100644
index 0000000..d05f660
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.cc
@@ -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
index 0000000..5e43bae
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-var-rtti.exp
@@ -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
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 7f8642f..401565d 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -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} {
diff --git a/gdb/value.c b/gdb/value.c
index c23803a..eae3e2d 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -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)
 {
diff --git a/gdb/value.h b/gdb/value.h
index d501b52..9de31a6 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -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);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index b6e67c6..5fce5f9 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -268,6 +268,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);
 
@@ -672,8 +675,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);
+	  }
 
       install_new_value (var, value, 1 /* Initial assignment */);
 
@@ -961,6 +970,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,
@@ -983,12 +993,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);
     }
 }
@@ -1011,6 +1027,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,
@@ -1146,6 +1163,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);
@@ -1201,7 +1219,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
@@ -1227,8 +1245,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;
     }
@@ -1575,6 +1593,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 
@@ -1880,8 +1935,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;
@@ -1920,6 +1976,8 @@ varobj_update (struct varobj **varp, int explicit)
       if (!r.value_installed)
 	{	  
 	  new = value_of_child (v->parent, v->index);
+	  if (update_type_if_necessary(v, new))
+	    r.type_changed = 1;
 	  if (install_new_value (v, new, 0 /* type not changed */))
 	    {
 	      r.changed = 1;
@@ -1932,7 +1990,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)
@@ -1950,7 +2009,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;
@@ -1964,8 +2023,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)
@@ -1977,6 +2036,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);
@@ -2003,9 +2074,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;
@@ -2280,7 +2352,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, 
@@ -2867,6 +2939,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
@@ -2878,7 +2954,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);
 
@@ -2923,6 +3000,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);
+        }
+    }
 }
 
 /* C */
@@ -2933,7 +3024,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))
@@ -3049,7 +3140,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))
     {
@@ -3345,16 +3436,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))
@@ -3381,7 +3485,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)
@@ -3463,7 +3577,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;
@@ -3474,24 +3591,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)

[-- Attachment #3: gdb_varobj_rtti4_1.ChangeLog --]
[-- Type: text/plain, Size: 1400 bytes --]

gdb/doc/ChangeLog:

2012-03-18  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-03-18  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-03-18  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.


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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-03 13:27                                                   ` xgsa
@ 2012-04-06 17:11                                                     ` xgsa
  2012-04-13  8:07                                                       ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-04-06 17:11 UTC (permalink / raw)
  To: gdb-patches; +Cc: Doug Evans, Eli Zaretskii, Tom Tromey

I have run all the gdb test suites on my patch. There are no changes 
(except of my new group adding). Testing was done on Linux32. So is it 
ready for check in?


Thanks,
Anton

-------- Original message --------
> Hi,
>> Hi.  ChangeLog nit:
>> ...
> Thanks, the similar case with update_dynamic_varobj_children is fixed 
> too.
>
> The same patch and updated changelog are attached.
>
>
> P.S. It seems the question with regression testing is left unanswered. 
> Could someone clarify how it should be done or point me where I could 
> read about it?
>
>
> The original patch description:
>
> That patch makes "set print object" option affect MI interface. Here 
> is an example:
>
> struct Base {
>     Base() : a(1) {}
>     virtual ~Base() {}  // Enforce type to have RTTI
>     int a;
> };
>
> struct Derived : public Base {
>     Derived() : b(2) {}
>     int b;
> };
>
> int main() {
>     Derived b;
>     Base* aPtr = &b;
>     return 0;                  // [1]
> }
>
> Start gdb in MI mode and run to line [1]. Make -var-create for aPtr. 
> If "set print object" is "on" you will see the type Derived* for the 
> created varobj.
>
> See also more details here: 
> http://sourceware.org/bugzilla/show_bug.cgi?id=13393
>
>
> Thanks,
> Anton.


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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-06 17:11                                                     ` xgsa
@ 2012-04-13  8:07                                                       ` xgsa
  2012-04-13 12:22                                                         ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-04-13  8:07 UTC (permalink / raw)
  To: gdb-patches; +Cc: Doug Evans, Eli Zaretskii, Tom Tromey

Ping, guys! A few people reviewed this patch and said that it is ok in 
general, but there are a few minor comments. I have fixed them. Could 
somebody finally accept it?


Thanks,
Anton

-------- Original message --------
> I have run all the gdb test suites on my patch. There are no changes 
> (except of my new group adding). Testing was done on Linux32. So is it 
> ready for check in?
>
>
> Thanks,
> Anton
>
> -------- Original message --------
>> Hi,
>>> Hi.  ChangeLog nit:
>>> ...
>> Thanks, the similar case with update_dynamic_varobj_children is fixed 
>> too.
>>
>> The same patch and updated changelog are attached.
>>
>>
>> P.S. It seems the question with regression testing is left 
>> unanswered. Could someone clarify how it should be done or point me 
>> where I could read about it?
>>
>>
>> The original patch description:
>>
>> That patch makes "set print object" option affect MI interface. Here 
>> is an example:
>>
>> struct Base {
>>     Base() : a(1) {}
>>     virtual ~Base() {}  // Enforce type to have RTTI
>>     int a;
>> };
>>
>> struct Derived : public Base {
>>     Derived() : b(2) {}
>>     int b;
>> };
>>
>> int main() {
>>     Derived b;
>>     Base* aPtr = &b;
>>     return 0;                  // [1]
>> }
>>
>> Start gdb in MI mode and run to line [1]. Make -var-create for aPtr. 
>> If "set print object" is "on" you will see the type Derived* for the 
>> created varobj.
>>
>> See also more details here: 
>> http://sourceware.org/bugzilla/show_bug.cgi?id=13393
>>
>>
>> Thanks,
>> Anton.
>
>
>
>


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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-13  8:07                                                       ` xgsa
@ 2012-04-13 12:22                                                         ` Eli Zaretskii
  2012-04-13 12:34                                                           ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2012-04-13 12:22 UTC (permalink / raw)
  To: xgsa; +Cc: gdb-patches, dje, tromey

> Date: Fri, 13 Apr 2012 10:47:48 +0300
> From: xgsa <xgsa@yandex.ru>
> CC: Doug Evans <dje@google.com>, Eli Zaretskii <eliz@gnu.org>, 
>  Tom Tromey <tromey@redhat.com>
> 
> Ping, guys! A few people reviewed this patch and said that it is ok in 
> general, but there are a few minor comments. I have fixed them. Could 
> somebody finally accept it?

I didn't say "ok in general", I actually approved the documentation
part of the patch.

I don't know enough about MI or track its development to approve the
code parts, sorry.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-13 12:22                                                         ` Eli Zaretskii
@ 2012-04-13 12:34                                                           ` xgsa
  2012-04-13 17:23                                                             ` Tom Tromey
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-04-13 12:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, dje, tromey

-------- Original message --------
>> Date: Fri, 13 Apr 2012 10:47:48 +0300
>> From: xgsa<xgsa@yandex.ru>
>> CC: Doug Evans<dje@google.com>, Eli Zaretskii<eliz@gnu.org>,
>>   Tom Tromey<tromey@redhat.com>
>>
>> Ping, guys! A few people reviewed this patch and said that it is ok in
>> general, but there are a few minor comments. I have fixed them. Could
>> somebody finally accept it?
> I didn't say "ok in general", I actually approved the documentation
> part of the patch.
>
> I don't know enough about MI or track its development to approve the
> code parts, sorry.

I meant Tom Tromey saying:

> I have a few nits, but nothing serious.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-13 12:34                                                           ` xgsa
@ 2012-04-13 17:23                                                             ` Tom Tromey
  2012-04-14 23:35                                                               ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Tom Tromey @ 2012-04-13 17:23 UTC (permalink / raw)
  To: xgsa; +Cc: Eli Zaretskii, gdb-patches, dje

>>>>> "xgsa" == xgsa  <xgsa@yandex.ru> writes:

xgsa> I meant Tom Tromey saying:

Yeah.  I'm sorry about the delay.  The patch is ok, please check it in.

Tom

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-13 17:23                                                             ` Tom Tromey
@ 2012-04-14 23:35                                                               ` xgsa
  2012-04-16 18:35                                                                 ` Jan Kratochvil
  0 siblings, 1 reply; 47+ messages in thread
From: xgsa @ 2012-04-14 23:35 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> Yeah. I'm sorry about the delay. The patch is ok, please check it in.

Checked in.
The status of the PR mi/13393 
(http://sourceware.org/bugzilla/show_bug.cgi?id=13393) was changed to 
RESOLVED (FIXED).


Anton.

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-14 23:35                                                               ` xgsa
@ 2012-04-16 18:35                                                                 ` Jan Kratochvil
  2012-07-23 17:21                                                                   ` Ulrich Weigand
  0 siblings, 1 reply; 47+ messages in thread
From: Jan Kratochvil @ 2012-04-16 18:35 UTC (permalink / raw)
  To: xgsa; +Cc: Tom Tromey, gdb-patches

On Sat, 14 Apr 2012 14:28:26 +0200, xgsa wrote:
> >Yeah. I'm sorry about the delay. The patch is ok, please check it in.
> 
> Checked in.

Fedora 17 x86_64:
+FAIL: gdb.mi/mi-var-rtti.exp: list children of s.public in type_update_when_use_rtti
+FAIL: gdb.mi/mi-var-rtti.exp: list children of s.ptr (without RTTI) in type_update_when_use_rtti
+FAIL: gdb.mi/mi-var-rtti.exp: list children of s.ptr.public (without RTTI) in type_update_when_use_rtti


Thanks,
Jan


+Expecting: \^done,numchild=".*",children=\[child={name="S.public.ptr",exp="ptr",numchild="1",type="Base \*"(,thread-id="[0-9]+")?}.*\],has_more="0"
+Expecting: ^(-var-list-children  S\.public  [^M
+]+)?(\^done,numchild=".*",children=\[child={name="S.public.ptr",exp="ptr",numchild="1",type="Base \*"(,thread-id="[0-9]+")?}.*\],has_more="0"[^M
+]+[(]gdb[)] ^M
+[ ]*)
+-var-list-children  S.public  ^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+^done,numchild="1",children=[child={name="S.public.ptr",exp="ptr",numchild="1",type="Base *",thread-id="1"}],has_more="0"^M
+(gdb) ^M
+FAIL: gdb.mi/mi-var-rtti.exp: list children of s.public in type_update_when_use_rtti
+Expecting: \^done,numchild=".*",children=\[child={name="S.public.ptr.public",exp="public",numchild="1"(,thread-id="[0-9]+")?}.*\],has_more="0"
+Expecting: ^(-var-list-children  S\.public\.ptr  [^M
+]+)?(\^done,numchild=".*",children=\[child={name="S.public.ptr.public",exp="public",numchild="1"(,thread-id="[0-9]+")?}.*\],has_more="0"[^M
+]+[(]gdb[)] ^M
+[ ]*)
+-var-list-children  S.public.ptr  ^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+^done,numchild="1",children=[child={name="S.public.ptr.public",exp="public",numchild="1",thread-id="1"}],has_more="0"^M
+(gdb) ^M
+FAIL: gdb.mi/mi-var-rtti.exp: list children of s.ptr (without RTTI) in type_update_when_use_rtti

+Expecting: \^done,numchild=".*",children=\[child={name="S.public.ptr.public.A",exp="A",numchild="0",type="int"(,thread-id="[0-9]+")?}.*\],has_more="0"
+Expecting: ^(-var-list-children  S\.public\.ptr\.public  [^M
+]+)?(\^done,numchild=".*",children=\[child={name="S.public.ptr.public.A",exp="A",numchild="0",type="int"(,thread-id="[0-9]+")?}.*\],has_more="0"[^M
+]+[(]gdb[)] ^M
+[ ]*)
+-var-list-children  S.public.ptr.public  ^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+&"warning: can't find linker symbol for virtual table for `Base' value\n"^M
+&"warning:   found `Base::Base()' instead\n"^M
+^done,numchild="1",children=[child={name="S.public.ptr.public.A",exp="A",numchild="0",type="int",thread-id="1"}],has_more="0"^M
+(gdb) ^M
+FAIL: gdb.mi/mi-var-rtti.exp: list children of s.ptr.public (without RTTI) in type_update_when_use_rtti

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

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-04-16 18:35                                                                 ` Jan Kratochvil
@ 2012-07-23 17:21                                                                   ` Ulrich Weigand
  2012-08-06  7:26                                                                     ` xgsa
  0 siblings, 1 reply; 47+ messages in thread
From: Ulrich Weigand @ 2012-07-23 17:21 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: xgsa, Tom Tromey, gdb-patches

Jan Kratochvil wrote:
> On Sat, 14 Apr 2012 14:28:26 +0200, xgsa wrote:
> > >Yeah. I'm sorry about the delay. The patch is ok, please check it in.
> > 
> > Checked in.
> 
> Fedora 17 x86_64:
> +FAIL: gdb.mi/mi-var-rtti.exp: list children of s.public in type_update_when_use_rtti
> +FAIL: gdb.mi/mi-var-rtti.exp: list children of s.ptr (without RTTI) in type_update_when_use_rtti
> +FAIL: gdb.mi/mi-var-rtti.exp: list children of s.ptr.public (without RTTI) in type_update_when_use_rtti

Yes, I'm seeing similar failures on a number of platforms (arm, spu, s390x).

The reason seems to be that the test case is attempting to display local
variables that are not yet initialized, and thus their contents are random.
For C++ objects, this includes a random vtable pointer ...

Now, this particular sub-test appears to do this deliberately; all the other
sub-tests only create the varobj *after* their corresponding objects were
initialized.  I'm not quite sure what exactly the test is supposed to be
testing, but I guess it ought to be done differently ...

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] 47+ messages in thread

* Re: set print object on should affect MI varobjs (PR mi/13393)
  2012-07-23 17:21                                                                   ` Ulrich Weigand
@ 2012-08-06  7:26                                                                     ` xgsa
  0 siblings, 0 replies; 47+ messages in thread
From: xgsa @ 2012-08-06  7:26 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Jan Kratochvil, Tom Tromey, gdb-patches

Thanks for the note, Ulrich. Unfortunately, I have missed Jan's message 
about fails somehow. Moreover, I was in vacation for the last few weeks, 
so I read your message just now. I'll look at those tests and provide 
the fix.


Thanks,
Anton.

-------- Original message --------
> Jan Kratochvil wrote:
>> On Sat, 14 Apr 2012 14:28:26 +0200, xgsa wrote:
>>>> Yeah. I'm sorry about the delay. The patch is ok, please check it in.
>>> Checked in.
>> Fedora 17 x86_64:
>> +FAIL: gdb.mi/mi-var-rtti.exp: list children of s.public in type_update_when_use_rtti
>> +FAIL: gdb.mi/mi-var-rtti.exp: list children of s.ptr (without RTTI) in type_update_when_use_rtti
>> +FAIL: gdb.mi/mi-var-rtti.exp: list children of s.ptr.public (without RTTI) in type_update_when_use_rtti
> Yes, I'm seeing similar failures on a number of platforms (arm, spu, s390x).
>
> The reason seems to be that the test case is attempting to display local
> variables that are not yet initialized, and thus their contents are random.
> For C++ objects, this includes a random vtable pointer ...
>
> Now, this particular sub-test appears to do this deliberately; all the other
> sub-tests only create the varobj *after* their corresponding objects were
> initialized.  I'm not quite sure what exactly the test is supposed to be
> testing, but I guess it ought to be done differently ...
>
> Bye,
> Ulrich
>


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

end of thread, other threads:[~2012-08-06  7:26 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-02 19:50 set print object on should affect MI varobjs (PR 13393) xgsa
2011-12-08  8:15 ` xgsa
2011-12-19 20:34   ` xgsa
2011-12-20 17:47 ` Tom Tromey
2011-12-21 19:01   ` set print object on should affect MI varobjs (PR gdb/13393) xgsa
2011-12-21 19:37     ` Jan Kratochvil
2011-12-22 10:17       ` set print object on should affect MI varobjs (PR mi/13393) xgsa
2011-12-24  1:55         ` Jan Kratochvil
2011-12-24 13:56           ` xgsa
2012-01-02  2:22             ` Jan Kratochvil
2012-01-06 15:47               ` RTTI type improvement for (was: "Re: set print object on should affect MI varobjs (PR mi/13393)") xgsa
2012-01-09 14:41                 ` Jan Kratochvil
2012-01-11 21:58                   ` RTTI type improvement for Tom Tromey
2012-01-12 11:25                     ` xgsa
2012-02-06 21:45                 ` Tom Tromey
2012-02-08 18:34                   ` xgsa
2012-02-10 20:13                     ` Tom Tromey
2012-02-19 18:46                       ` set print object on should affect MI varobjs (PR mi/13393) xgsa
2012-02-23  4:58                         ` xgsa
2012-03-18 16:28                         ` xgsa
2012-03-18 20:41                           ` Eli Zaretskii
2012-03-19  7:10                             ` xgsa
2012-03-19 17:41                               ` Eli Zaretskii
2012-03-23 17:09                                 ` xgsa
2012-03-26 19:08                                   ` xgsa
2012-03-30 17:51                                   ` Tom Tromey
2012-03-30 18:01                                     ` Eli Zaretskii
2012-03-30 20:11                                     ` xgsa
2012-03-30 18:01                                   ` Eli Zaretskii
2012-03-30 20:25                                     ` xgsa
2012-03-30 20:52                                       ` Eli Zaretskii
2012-03-30 21:26                                         ` xgsa
2012-03-31  5:54                                           ` Eli Zaretskii
2012-03-31  6:57                                             ` xgsa
2012-03-31  9:33                                               ` xgsa
2012-04-03  0:54                                                 ` Doug Evans
2012-04-03 13:27                                                   ` xgsa
2012-04-06 17:11                                                     ` xgsa
2012-04-13  8:07                                                       ` xgsa
2012-04-13 12:22                                                         ` Eli Zaretskii
2012-04-13 12:34                                                           ` xgsa
2012-04-13 17:23                                                             ` Tom Tromey
2012-04-14 23:35                                                               ` xgsa
2012-04-16 18:35                                                                 ` Jan Kratochvil
2012-07-23 17:21                                                                   ` Ulrich Weigand
2012-08-06  7:26                                                                     ` xgsa
2012-02-21 14:15                       ` RTTI type improvement for xgsa

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