[c++] Pointer to member overhaul

Daniel Jacobowitz
2006-12-29T02:55:39Z

A bit of history: before I got sidetracked onto this patch, I was
working on support for ARM's compiler. This produces generally good
DWARF, but without several GNU extensions to DWARF that GCC generates
to make life easier for GDB's generally stabs-centric data structures.
So I was going through uses of various type information that aren't
available with that compiler. Among them: DW_AT_MIPS_linkage_name,
VPTR_FIELDNO, and FIELD_FCONTEXT. The first usage I picked turned
out to have a heavyweight mess under it.

GDB handles pointers to members in a way which only worked for some
older compilers (depending which bits of the code you're looking at,
I think it's either early GCC 2.x, or HP aCC, or both). Part of the
problem was the concept of a "reference to member" type, which doesn't
exist in C++.

Another problem was representational; some parts of GDB assumed
that TYPE_CODE_MEMBER was a pointer to member, and other bits assumed
that TYPE_CODE_PTR to a TYPE_CODE_MEMBER was.

Pointers to members, if you aren't familiar with them, describe some
data or function member of a class in terms of its signature. You can
write something like this:

int (A::*a_pmf) (int) = &A::func;

Later you can call it by applying it to an object. You can't do
anything with one without an object except cast them around; g++
lets you convert a pointer to data member (represented as an
offset) into the offset via a cast. GDB supports decoding the
pointer to member into a generally readable form; I've improved
that ability to handle a lot more cases.

Pointers to data members, pointers to function members, and pointers
to normal variables are essentially three different things. I decided
that representing them using TYPE_CODE_PTR was a mistake; they aren't
much like pointers. So this class replaces the confused
TYPE_CODE_MEMBER with TYPE_CODE_MEMBERPTR and TYPE_CODE_METHODPTR.

Then I moved the ABI specific bits for function member pointers to
cp-abi.h and implemented them for G++, and corrected everything I could
think of to test along the way. Lots of new testcases.

I know a great deal more about member pointers than I did when I
started, including several more things we don't get right, but I don't
think I'm going to take it much farther than this. Extensive
conversations with Mark Mitchell, my official C++ guru, have convinced
me that unless we link GDB with G++ there's no practical way we're
going to get expression evaluation, and in particular overload
resolution, 100% right. But we can do a heck of a lot better than we
do now.

So here's what that gave me, after six months. I separated out the
separable parts of this patch back in August, so I'm left with a big
lump. I've tested the final version on ia64-linux and x86_64-linux.
Near-final versions were also tested on arm-eabi, i686-linux, and
powerpc64-linux.

This patch is limited to C++ support and the surrounding value / type
machinery. I suspect it's too big for anyone to review usefully, but
in case anyone is willing to look at it, I will wait until 2007 to
commit it. I'm confident that it is strictly an improvement.

--
Daniel Jacobowitz
CodeSourcery

2006-12-28 Daniel Jacobowitz <dan@codesourcery.com>

* NEWS: Mention pointer to member improvements.
* Makefile.in (gnu-v3-abi.o): Delete special rule.
(eval.o, gnu-v3-abi.o, ia64-tdep.o): Update.
* ada-valprint.c (ada_print_scalar): Update for new type codes.
* c-typeprint.c (c_print_type): Update for new type codes.
(c_type_print_varspec_prefix, c_type_print_varspec_suffix)
(c_type_print_base): Likewise.
(c_type_print_args): Rewrite.
* c-valprint.c (c_val_print): Update for new type codes. Remove
support for references to members. Treat methods like functions.
* cp-abi.c (cplus_print_method_ptr, cplus_method_ptr_size)
(cplus_make_method_ptr, cplus_method_ptr_to_value): New.
* cp-abi.h (cplus_print_method_ptr, cplus_method_ptr_size)
(cplus_make_method_ptr, cplus_method_ptr_to_value): New prototypes.
(struct cp_abi_ops): Add corresponding members.
* cp-valprint.c (cp_print_class_method): Delete.
(cp_find_class_member): New function.
(cp_print_class_member): Use it. Simplify support for bogus
member pointers.
* dwarf2read.c (quirk_gcc_member_function_pointer): Use
lookup_methodptr_type.
(read_tag_ptr_to_member_type): Likewise, and lookup_memberptr_type.
* eval.c (evaluate_subexp_standard): Implement EVAL_SKIP for
OP_SCOPE. Update call to value_aggregate_elt. Rewrite member
pointer support.
(evaluate_subexp_for_address): Handle OP_SCOPE explicitly. Handle
references returned by user defined operators.
* f-typeprint.c (f_print_type, f_type_print_varspec_prefix)
(f_type_print_varspec_suffix): Remove support for member pointers.
* gdbtypes.c (lookup_memberptr_type): Renamed from lookup_member_type
and adjusted.
(smash_to_memberptr_type): Likewise, from smash_to_member_type.
(lookup_methodptr_type): New.
(rank_one_type): Adjust for TYPE_CODE_MEMBERPTR.
(recursive_dump_type): Update for new types.
* gdbtypes.h (enum type_code): Replace TYPE_CODE_MEMBER with
TYPE_CODE_MEMBERPTR and TYPE_CODE_METHODPTR.
(lookup_memberptr_type, lookup_methodptr_type)
(smash_to_memberptr_type): New prototypes.
(smash_to_method_type): Formatting fix.
(lookup_member_type, smash_to_member_type): Delete prototypes.
* gnu-v3-abi.c (gnuv3_get_vtable, gnuv3_get_virtual_fn): New.
Do not rely on debug information for the vptr or the method's
enclosing type. Handle function descriptors for IA64.
(gnuv3_virtual_fn_field): Rewrite using the new functions.
(gnuv3_find_method_in, gnuv3_print_method_ptr)
(gnuv3_method_ptr_size, gnuv3_make_method_ptr)
(gnuv3_method_ptr_to_value): New.
(init_gnuv3_ops): Set new members of gnu_v3_abi_ops.
* hpread.c (hpread_type_lookup): Update for new types.
* infcall.c (value_arg_coerce): Likewise.
* m2-typeprint.c (m2_print_type): Remove explicit support
for member pointers.
* m2-valprint.c (m2_val_print): Likewise.
* p-typeprint.c (pascal_type_print_varspec_prefix)
(pascal_type_print_varspec_suffix, pascal_type_print_base): Likewise.
* p-valprint.c (pascal_val_print): Likewise.
(pascal_object_print_class_method, pascal_object_print_class_member):
Delete.
* p-lang.h (pascal_object_print_class_method)
(pascal_object_print_class_member): Delete prototypes.
* stabsread.c (read_type): Update for new types.
* typeprint.c (print_type_scalar): Likewise.
* valops.c (value_struct_elt_for_reference, value_namespace_elt)
(value_maybe_namespace_elt, value_aggregate_elt): Add want_address
argument. Construct a pointer to member if the address of a
function or data member is requested.
(value_cast_pointers): Don't modify the input value.
(value_cast): Adjust pointer to member handling for new types.
Allow null pointer to member constants. Don't modify the input
value.
(value_ind): Remove pointer to member check. Handle function
descriptors for function pointers.
(value_struct_elt, value_find_oload_method_list, check_field):
Remove pointer to member checks.
* value.c (unpack_long): Allow pointers to data members.
(value_from_longest): Allow member pointers.
* value.h (value_aggregate_elt): Add want_address.
* varobj.c (c_variable_editable): Remove check for members.
* gdbarch.sh: Add vtable_function_descriptors and vbit_in_delta.
* ia64-tdep.c (ia64_convert_from_func_ptr_addr): Handle descriptors
in virtual tables.
(ia64_gdbarch_init): Call set_gdbarch_vtable_function_descriptors.
* c-lang.h (cp_print_class_method): Delete prototype.
* arm-tdep.c (arm_gdbarch_init): Call set_gdbarch_vbit_in_delta.
* mips-tdep.c (mips_gdbarch_init): Likewise.
* gdbarch.c, gdbarch.h: Regenerated.

2006-12-28 Daniel Jacobowitz <dan@codesourcery.com>

* gdb.cp/classes.exp (test_pointers_to_class_members): Update expected
output. Test the types of members and member pointers.
* gdb.cp/inherit.exp (test_print_mi_member_types): Remove KFAILs for
gdb/2092.
* gdb.cp/member-ptr.exp: Search for a comment instead of a
statement. Enable for GCC. Update expected output for some tests
and add new tests. Remove obsolete GCC KFAILs. Allow GCC's class
layout.
* gdb.cp/member-ptr.cc (Padding, Padding::vspacer, Base, Base::get_x)
(Base::vget_base, Left, Left::vget, Right, Right::vget, Diamond)
(Diamond::vget_base): New.
(main): Add new tests.
* gdb.cp/printmethod.exp: Update expected output for member functions.
* gdb.cp/virtfunc.exp (test_virtual_calls): Add a KFAIL for
print pEe->D::vg().

Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.861
diff -u -p -r1.861 Makefile.in
--- gdb/Makefile.in 17 Dec 2006 13:30:43 -0000 1.861
+++ gdb/Makefile.in 29 Dec 2006 00:13:20 -0000
@@ -1527,13 +1527,6 @@ main.o: main.c
$(CC) -c $(INTERNAL_CFLAGS) $(TARGET_SYSTEM_ROOT_DEFINE) \
-DBINDIR=\"$(bindir)\" $(srcdir)/main.c

-# FIXME: cagney/2004-09-16: "gnu-v3-abi.c", with a GCC 3.4 compiler,
-# gets a "assignment from incompatible pointer type" warning. The
-# return types - "enum gnu_v3_dtor_kinds" vs "enum ctor_kinds" -
-# conflict.
-gnu-v3-abi.o: $(srcdir)/gnu-v3-abi.c
- $(CC) -c $(INTERNAL_WARN_CFLAGS) $(srcdir)/gnu-v3-abi.c
-
# FIXME: cagney/2003-08-10: "monitor.c" gets -Wformat-nonliteral
# errors. It turns out that that is the least of monitor.c's
# problems. The function print_vsprintf appears to be using
@@ -1973,7 +1966,7 @@ environ.o: environ.c $(defs_h) $(environ
eval.o: eval.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
$(value_h) $(expression_h) $(target_h) $(frame_h) $(language_h) \
$(f_lang_h) $(cp_abi_h) $(infcall_h) $(objc_lang_h) $(block_h) \
- $(parser_defs_h) $(cp_support_h)
+ $(parser_defs_h) $(cp_support_h) $(gdb_assert_h)
event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
$(gdb_string_h) $(exceptions_h) $(gdb_assert_h) $(gdb_select_h)
event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
@@ -2052,7 +2045,7 @@ gnu-v2-abi.o: gnu-v2-abi.c $(defs_h) $(g
$(gdbtypes_h) $(value_h) $(demangle_h) $(cp_abi_h) $(cp_support_h) \
$(gnu_v2_abi_h)
gnu-v3-abi.o: gnu-v3-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(cp_support_h) \
- $(demangle_h) $(gdb_assert_h) $(gdb_string_h)
+ $(demangle_h) $(valprint_h) $(gdb_assert_h) $(gdb_string_h)
go32-nat.o: go32-nat.c $(defs_h) $(inferior_h) $(gdb_wait_h) $(gdbcore_h) \
$(command_h) $(gdbcmd_h) $(floatformat_h) $(buildsym_h) \
$(i387_tdep_h) $(i386_tdep_h) $(value_h) $(regcache_h) \
@@ -2168,7 +2161,8 @@ ia64-tdep.o: ia64-tdep.c $(defs_h) $(inf
$(frame_h) $(frame_base_h) $(frame_unwind_h) $(doublest_h) \
$(value_h) $(gdb_assert_h) $(objfiles_h) $(elf_common_h) \
$(elf_bfd_h) $(dis_asm_h) $(infcall_h) $(osabi_h) $(ia64_tdep_h) \
- $(elf_ia64_h) $(libunwind_frame_h) $(libunwind_ia64_h)
+ $(elf_ia64_h) $(libunwind_frame_h) $(libunwind_ia64_h) \
+ $(cp_abi_h)
infcall.o: infcall.c $(defs_h) $(breakpoint_h) $(target_h) $(regcache_h) \
$(inferior_h) $(gdb_assert_h) $(block_h) $(gdbcore_h) $(language_h) \
$(objfiles_h) $(gdbcmd_h) $(command_h) $(gdb_string_h) $(infcall_h) \
Index: gdb/ada-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/ada-valprint.c,v
retrieving revision 1.28
diff -u -p -r1.28 ada-valprint.c
--- gdb/ada-valprint.c 18 Jan 2006 21:24:19 -0000 1.28
+++ gdb/ada-valprint.c 29 Dec 2006 00:13:20 -0000
@@ -420,7 +420,8 @@ ada_print_scalar (struct type *type, LON
case TYPE_CODE_SET:
case TYPE_CODE_STRING:
case TYPE_CODE_ERROR:
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
+ case TYPE_CODE_METHODPTR:
case TYPE_CODE_METHOD:
case TYPE_CODE_REF:
warning (_("internal error: unhandled type in ada_print_scalar"));
Index: gdb/arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.217
diff -u -p -r1.217 arm-tdep.c
--- gdb/arm-tdep.c 22 Nov 2006 18:51:58 -0000 1.217
+++ gdb/arm-tdep.c 29 Dec 2006 00:13:21 -0000
@@ -2816,6 +2816,9 @@ arm_gdbarch_init (struct gdbarch_info in
set_gdbarch_coff_make_msymbol_special (gdbarch,
arm_coff_make_msymbol_special);

+ /* Virtual tables. */
+ set_gdbarch_vbit_in_delta (gdbarch, 1);
+
/* Hook in the ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);

Index: gdb/c-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.h,v
retrieving revision 1.13
diff -u -p -r1.13 c-lang.h
--- gdb/c-lang.h 17 Dec 2005 22:33:59 -0000 1.13
+++ gdb/c-lang.h 29 Dec 2006 00:13:21 -0000
@@ -1,7 +1,7 @@
/* C language support definitions for GDB, the GNU debugger.

- Copyright (C) 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2005 Free
- Software Foundation, Inc.
+ Copyright (C) 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2005, 2006
+ Free Software Foundation, Inc.

This file is part of GDB.

@@ -79,9 +79,6 @@ extern int static_field_print;
extern void cp_print_class_member (const gdb_byte *, struct type *,
struct ui_file *, char *);

-extern void cp_print_class_method (const gdb_byte *, struct type *,
- struct ui_file *);
-
extern void cp_print_value_fields (struct type *, struct type *,
const gdb_byte *, int, CORE_ADDR,
struct ui_file *, int,
Index: gdb/c-typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-typeprint.c,v
retrieving revision 1.33
diff -u -p -r1.33 c-typeprint.c
--- gdb/c-typeprint.c 17 Dec 2005 22:33:59 -0000 1.33
+++ gdb/c-typeprint.c 29 Dec 2006 00:13:21 -0000
@@ -1,6 +1,6 @@
/* Support for printing C and C++ types for GDB, the GNU debugger.
Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
- 1999, 2000, 2001, 2002, 2003
+ 1999, 2000, 2001, 2002, 2003, 2006
Free Software Foundation, Inc.

This file is part of GDB.
@@ -80,7 +80,8 @@ c_print_type (struct type *type, char *v
(code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
|| code == TYPE_CODE_METHOD
|| code == TYPE_CODE_ARRAY
- || code == TYPE_CODE_MEMBER
+ || code == TYPE_CODE_MEMBERPTR
+ || code == TYPE_CODE_METHODPTR
|| code == TYPE_CODE_REF)))
fputs_filtered (" ", stream);
need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
@@ -218,29 +219,25 @@ c_type_print_varspec_prefix (struct type
c_type_print_modifier (type, stream, 1, need_post_space);
break;

- case TYPE_CODE_MEMBER:
- if (passed_a_ptr)
- fprintf_filtered (stream, "(");
+ case TYPE_CODE_MEMBERPTR:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
- fprintf_filtered (stream, " ");
name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
if (name)
fputs_filtered (name, stream);
else
c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
- fprintf_filtered (stream, "::");
+ fprintf_filtered (stream, "::*");
break;

- case TYPE_CODE_METHOD:
- if (passed_a_ptr)
- fprintf_filtered (stream, "(");
+ case TYPE_CODE_METHODPTR:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
- if (passed_a_ptr)
- {
- fprintf_filtered (stream, " ");
- c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
- fprintf_filtered (stream, "::");
- }
+ fprintf_filtered (stream, "(");
+ name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
+ if (name)
+ fputs_filtered (name, stream);
+ else
+ c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
+ fprintf_filtered (stream, "::*");
break;

case TYPE_CODE_REF:
@@ -249,6 +246,7 @@ c_type_print_varspec_prefix (struct type
c_type_print_modifier (type, stream, 1, need_post_space);
break;

+ case TYPE_CODE_METHOD:
case TYPE_CODE_FUNC:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
if (passed_a_ptr)
@@ -337,42 +335,49 @@ c_type_print_modifier (struct type *type
}

-
+/* Print out the arguments of TYPE, which should have TYPE_CODE_METHOD
+ or TYPE_CODE_FUNC, to STREAM. Artificial arguments, such as "this"
+ in non-static methods, are displayed. */

static void
c_type_print_args (struct type *type, struct ui_file *stream)
{
- int i;
+ int i, len;
struct field *args;
+ int printed_any = 0;

fprintf_filtered (stream, "(");
args = TYPE_FIELDS (type);
- if (args != NULL)
- {
- int i;
-
- /* FIXME drow/2002-05-31: Always skips the first argument,
- should we be checking for static members? */
+ len = TYPE_NFIELDS (type);

- for (i = 1; i < TYPE_NFIELDS (type); i++)
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ if (printed_any)
{
- c_print_type (args[i].type, "", stream, -1, 0);
- if (i != TYPE_NFIELDS (type))
- {
- fprintf_filtered (stream, ",");
- wrap_here (" ");
- }
+ fprintf_filtered (stream, ", ");
+ wrap_here (" ");
}
- if (TYPE_VARARGS (type))
- fprintf_filtered (stream, "...");
- else if (i == 1
- && (current_language->la_language == language_cplus))
- fprintf_filtered (stream, "void");
+
+ c_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0);
+ printed_any = 1;
}
- else if (current_language->la_language == language_cplus)
+
+ if (printed_any && TYPE_VARARGS (type))
{
- fprintf_filtered (stream, "void");
+ /* Print out a trailing ellipsis for varargs functions. Ignore
+ TYPE_VARARGS if the function has no named arguments; that
+ represents unprototyped (K&R style) C functions. */
+ if (printed_any && TYPE_VARARGS (type))
+ {
+ fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+ fprintf_filtered (stream, "...");
+ }
}
+ else if (!printed_any
+ && (TYPE_PROTOTYPED (type)
+ || current_language->la_language == language_cplus))
+ fprintf_filtered (stream, "void");

fprintf_filtered (stream, ")");
}
@@ -548,22 +553,15 @@ c_type_print_varspec_suffix (struct type
0, 0);
break;

- case TYPE_CODE_MEMBER:
- if (passed_a_ptr)
- fprintf_filtered (stream, ")");
+ case TYPE_CODE_MEMBERPTR:
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
0, 0);
break;

- case TYPE_CODE_METHOD:
- if (passed_a_ptr)
- fprintf_filtered (stream, ")");
+ case TYPE_CODE_METHODPTR:
+ fprintf_filtered (stream, ")");
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
0, 0);
- if (passed_a_ptr)
- {
- c_type_print_args (type, stream);
- }
break;

case TYPE_CODE_PTR:
@@ -572,31 +570,12 @@ c_type_print_varspec_suffix (struct type
1, 0);
break;

+ case TYPE_CODE_METHOD:
case TYPE_CODE_FUNC:
if (passed_a_ptr)
fprintf_filtered (stream, ")");
if (!demangled_args)
- {
- int i, len = TYPE_NFIELDS (type);
- fprintf_filtered (stream, "(");
- if (len == 0
- && (TYPE_PROTOTYPED (type)
- || current_language->la_language == language_cplus))
- {
- fprintf_filtered (stream, "void");
- }
- else
- for (i = 0; i < len; i++)
- {
- if (i > 0)
- {
- fputs_filtered (", ", stream);
- wrap_here (" ");
- }
- c_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0);
- }
- fprintf_filtered (stream, ")");
- }
+ c_type_print_args (type, stream);
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
passed_a_ptr, 0);
break;
@@ -696,10 +675,11 @@ c_type_print_base (struct type *type, st
case TYPE_CODE_TYPEDEF:
case TYPE_CODE_ARRAY:
case TYPE_CODE_PTR:
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
case TYPE_CODE_REF:
case TYPE_CODE_FUNC:
case TYPE_CODE_METHOD:
+ case TYPE_CODE_METHODPTR:
c_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
break;

Index: gdb/c-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-valprint.c,v
retrieving revision 1.39
diff -u -p -r1.39 c-valprint.c
--- gdb/c-valprint.c 18 Jan 2006 21:24:19 -0000 1.39
+++ gdb/c-valprint.c 29 Dec 2006 00:13:21 -0000
@@ -142,6 +142,21 @@ c_val_print (struct type *type, const gd
addr = address;
goto print_unpacked_pointer;

+ case TYPE_CODE_MEMBERPTR:
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ break;
+ }
+ cp_print_class_member (valaddr + embedded_offset,
+ TYPE_DOMAIN_TYPE (type),
+ stream, "&");
+ break;
+
+ case TYPE_CODE_METHODPTR:
+ cplus_print_method_ptr (valaddr + embedded_offset, type, stream);
+ break;
+
case TYPE_CODE_PTR:
if (format && format != 's')
{
@@ -159,17 +174,6 @@ c_val_print (struct type *type, const gd
break;
}
elttype = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (elttype) == TYPE_CODE_METHOD)
- {
- cp_print_class_method (valaddr + embedded_offset, type, stream);
- }
- else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
- {
- cp_print_class_member (valaddr + embedded_offset,
- TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
- stream, "&");
- }
- else
{
addr = unpack_pointer (type, valaddr + embedded_offset);
print_unpacked_pointer:
@@ -250,19 +254,8 @@ c_val_print (struct type *type, const gd
}
break;

- case TYPE_CODE_MEMBER:
- error (_("not implemented: member type in c_val_print"));
- break;
-
case TYPE_CODE_REF:
elttype = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
- {
- cp_print_class_member (valaddr + embedded_offset,
- TYPE_DOMAIN_TYPE (elttype),
- stream, "");
- break;
- }
if (addressprint)
{
CORE_ADDR addr
@@ -351,6 +344,7 @@ c_val_print (struct type *type, const gd
break;

case TYPE_CODE_FUNC:
+ case TYPE_CODE_METHOD:
if (format)
{
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
@@ -442,14 +436,6 @@ c_val_print (struct type *type, const gd
}
break;

- case TYPE_CODE_METHOD:
- {
- struct value *v = value_at (type, address);
- cp_print_class_method (value_contents (value_addr (v)),
- lookup_pointer_type (type), stream);
- break;
- }
-
case TYPE_CODE_VOID:
fprintf_filtered (stream, "void");
break;
Index: gdb/cp-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-abi.c,v
retrieving revision 1.13
diff -u -p -r1.13 cp-abi.c
--- gdb/cp-abi.c 17 Dec 2005 22:33:59 -0000 1.13
+++ gdb/cp-abi.c 29 Dec 2006 00:13:21 -0000
@@ -1,6 +1,6 @@
/* Generic code for supporting multiple C++ ABI's

- Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.

This file is part of GDB.

@@ -95,6 +95,39 @@ value_rtti_type (struct value *v, int *f
return (*current_cp_abi.rtti_type) (v, full, top, using_enc);
}

+void
+cplus_print_method_ptr (const gdb_byte *contents, struct type *type,
+ struct ui_file *stream)
+{
+ if (current_cp_abi.print_method_ptr == NULL)
+ error (_("GDB does not support pointers to methods on this target"));
+ (*current_cp_abi.print_method_ptr) (contents, type, stream);
+}
+
+int
+cplus_method_ptr_size (void)
+{
+ if (current_cp_abi.method_ptr_size == NULL)
+ error (_("GDB does not support pointers to methods on this target"));
+ return (*current_cp_abi.method_ptr_size) ();
+}
+
+void
+cplus_make_method_ptr (gdb_byte *contents, CORE_ADDR value, int is_virtual)
+{
+ if (current_cp_abi.make_method_ptr == NULL)
+ error (_("GDB does not support pointers to methods on this target"));
+ (*current_cp_abi.make_method_ptr) (contents, value, is_virtual);
+}
+
+struct value *
+cplus_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
+{
+ if (current_cp_abi.method_ptr_to_value == NULL)
+ error (_("GDB does not support pointers to methods on this target"));
+ return (*current_cp_abi.method_ptr_to_value) (this_p, method_ptr);
+}
+
/* Set the current C++ ABI to SHORT_NAME. */

static int
Index: gdb/cp-abi.h
===================================================================
RCS file: /cvs/src/src/gdb/cp-abi.h,v
retrieving revision 1.9
diff -u -p -r1.9 cp-abi.h
--- gdb/cp-abi.h 17 Dec 2005 22:33:59 -0000 1.9
+++ gdb/cp-abi.h 29 Dec 2006 00:13:21 -0000
@@ -3,7 +3,7 @@

Contributed by Daniel Berlin <dberlin@redhat.com>

- Copyright (C) 2001, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2005, 2006 Free Software Foundation, Inc.

This file is part of GDB.

@@ -30,6 +30,7 @@
struct fn_field;
struct type;
struct value;
+struct ui_file;

/* The functions here that attempt to determine what sort of thing a
mangled name refers to may well be revised in the future. It would
@@ -147,6 +148,28 @@ extern struct type *value_rtti_type (str
extern int baseclass_offset (struct type *type, int index,
const bfd_byte *valaddr, CORE_ADDR address);

+/* Describe the target of a pointer to method. CONTENTS is the
+ bytes forming the pointer to method. TYPE is the pointer
+ to method type. STREAM is the stream to print it to. */
+void cplus_print_method_ptr (const gdb_byte *contents, struct type *type,
+ struct ui_file *stream);
+
+/* Return the size of a pointer to member function for the current
+ architecture. */
+int cplus_method_ptr_size (void);
+
+/* Return the method which should be called by applying METHOD_PTR
+ to *THIS_P, and adjust *THIS_P if necessary. */
+struct value *cplus_method_ptr_to_value (struct value **this_p,
+ struct value *method_ptr);
+
+/* Create the byte pattern in CONTENTS representing a pointer to
+ member function at ADDRESS (if IS_VIRTUAL is 0) or with virtual
+ table offset ADDRESS (if IS_VIRTUAL is 1). This is the opposite
+ of cplus_method_ptr_to_target. */
+void cplus_make_method_ptr (gdb_byte *CONTENTS, CORE_ADDR address,
+ int is_virtual);
+
struct cp_abi_ops
{
const char *shortname;
@@ -164,6 +187,11 @@ struct cp_abi_ops
int *using_enc);
int (*baseclass_offset) (struct type *type, int index,
const bfd_byte *valaddr, CORE_ADDR address);
+ void (*print_method_ptr) (const gdb_byte *contents, struct type *type,
+ struct ui_file *stream);
+ int (*method_ptr_size) (void);
+ void (*make_method_ptr) (gdb_byte *, CORE_ADDR, int);
+ struct value * (*method_ptr_to_value) (struct value **, struct value *);
};

Index: gdb/cp-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-valprint.c,v
retrieving revision 1.45
diff -u -p -r1.45 cp-valprint.c
--- gdb/cp-valprint.c 5 Dec 2006 23:57:53 -0000 1.45
+++ gdb/cp-valprint.c 29 Dec 2006 00:13:21 -0000
@@ -1,7 +1,8 @@
/* Support for printing C++ values for GDB, the GNU debugger.

Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ 1997, 2000, 2001, 2002, 2003, 2005, 2006
+ Free Software Foundation, Inc.

This file is part of GDB.

@@ -92,104 +93,6 @@ static void cp_print_hpacc_virtual_table
enum val_prettyprint);

-void
-cp_print_class_method (const gdb_byte *valaddr,
- struct type *type,
- struct ui_file *stream)
-{
- struct type *domain;
- struct fn_field *f = NULL;
- int j = 0;
- int len2;
- int offset;
- char *kind = "";
- CORE_ADDR addr;
- struct symbol *sym;
- unsigned len;
- unsigned int i;
- struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
-
- domain = TYPE_DOMAIN_TYPE (target_type);
- if (domain == (struct type *) NULL)
- {
- fprintf_filtered (stream, "<unknown>");
- return;
- }
- addr = unpack_pointer (type, valaddr);
- if (METHOD_PTR_IS_VIRTUAL (addr))
- {
- offset = METHOD_PTR_TO_VOFFSET (addr);
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- f = TYPE_FN_FIELDLIST1 (domain, i);
- len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
-
- check_stub_method_group (domain, i);
- for (j = 0; j < len2; j++)
- {
- if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
- {
- kind = "virtual ";
- goto common;
- }
- }
- }
- }
- else
- {
- sym = find_pc_function (addr);
- if (sym == 0)
- {
- /* 1997-08-01 Currently unsupported with HP aCC */
- if (deprecated_hp_som_som_object_present)
- {
- fputs_filtered ("?? <not supported with HP aCC>", stream);
- return;
- }
- error (_("invalid pointer to member function"));
- }
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- f = TYPE_FN_FIELDLIST1 (domain, i);
- len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
-
- check_stub_method_group (domain, i);
- for (j = 0; j < len2; j++)
- {
- if (strcmp (DEPRECATED_SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j))
- == 0)
- goto common;
- }
- }
- }
- common:
- if (i < len)
- {
- char *demangled_name;
-
- fprintf_filtered (stream, "&");
- fputs_filtered (kind, stream);
- demangled_name = cplus_demangle (TYPE_FN_FIELD_PHYSNAME (f, j),
- DMGL_ANSI | DMGL_PARAMS);
- if (demangled_name == NULL)
- fprintf_filtered (stream, "<badly mangled name %s>",
- TYPE_FN_FIELD_PHYSNAME (f, j));
- else
- {
- fputs_filtered (demangled_name, stream);
- xfree (demangled_name);
- }
- }
- else
- {
- fprintf_filtered (stream, "(");
- type_print (type, "", stream, -1);
- fprintf_filtered (stream, ") %d", (int) addr >> 3);
- }
-}
-
/* GCC versions after 2.4.5 use this. */
const char vtbl_ptr_name[] = "__vtbl_ptr_type";

@@ -703,48 +606,82 @@ cp_print_static_field (struct type *type
stream, format, 0, recurse, pretty);
}

+
+/* Find the field in *DOMAIN, or its non-virtual base classes, with bit offset
+ OFFSET. Set *DOMAIN to the containing type and *FIELDNO to the containing
+ field number. If OFFSET is not exactly at the start of some field, set
+ *DOMAIN to NULL. */
+
+void
+cp_find_class_member (struct type **domain_p, int *fieldno,
+ LONGEST offset)
+{
+ struct type *domain;
+ unsigned int i;
+ unsigned len;
+
+ *domain_p = check_typedef (*domain_p);
+ domain = *domain_p;
+ len = TYPE_NFIELDS (domain);
+
+ for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
+ {
+ LONGEST bitpos = TYPE_FIELD_BITPOS (domain, i);
+
+ QUIT;
+ if (offset == bitpos)
+ {
+ *fieldno = i;
+ return;
+ }
+ }
+
+ for (i = 0; i < TYPE_N_BASECLASSES (domain); i++)
+ {
+ LONGEST bitpos = TYPE_FIELD_BITPOS (domain, i);
+ LONGEST bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (domain, i));
+
+ if (offset >= bitpos && offset < bitpos + bitsize)
+ {
+ *domain_p = TYPE_FIELD_TYPE (domain, i);
+ cp_find_class_member (domain_p, fieldno, offset - bitpos);
+ return;
+ }
+ }
+
+ *domain_p = NULL;
+}
+
void
cp_print_class_member (const gdb_byte *valaddr, struct type *domain,
struct ui_file *stream, char *prefix)
{
-
/* VAL is a byte offset into the structure type DOMAIN.
Find the name of the field for that offset and
print it. */
- int extra = 0;
- int bits = 0;
- unsigned int i;
- unsigned len = TYPE_NFIELDS (domain);
-
- /* @@ Make VAL into bit offset */
+ unsigned int fieldno;

- /* Note: HP aCC generates offsets that are the real byte offsets added
- to a constant bias 0x20000000 (1 << 29). This constant bias gets
- shifted out in the code below -- joyous happenstance! */
+ LONGEST val = unpack_long (builtin_type_long, valaddr);

- /* Note: HP cfront uses a constant bias of 1; if we support this
- compiler ever, we will have to adjust the computation below */
+ /* Pointers to data members are usually byte offsets into an object.
+ Because a data member can have offset zero, and a NULL pointer to
+ member must be distinct from any valid non-NULL pointer to
+ member, either the value is biased or the NULL value has a
+ special representation; both are permitted by ISO C++. HP aCC
+ used a bias of 0x20000000; HP cfront used a bias of 1; g++ 3.x
+ and other compilers which use the Itanium ABI use -1 as the NULL
+ value. GDB only supports that last form; to add support for
+ another form, make this into a cp-abi hook. */

- LONGEST val = unpack_long (builtin_type_int, valaddr) << 3;
- for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
+ if (val == -1)
{
- int bitpos = TYPE_FIELD_BITPOS (domain, i);
- QUIT;
- if (val == bitpos)
- break;
- if (val < bitpos && i != 0)
- {
- /* Somehow pointing into a field. */
- i -= 1;
- extra = (val - TYPE_FIELD_BITPOS (domain, i));
- if (extra & 0x7)
- bits = 1;
- else
- extra >>= 3;
- break;
- }
+ fprintf_filtered (stream, "NULL");
+ return;
}
- if (i < len)
+
+ cp_find_class_member (&domain, &fieldno, val << 3);
+
+ if (domain != NULL)
{
char *name;
fputs_filtered (prefix, stream);
@@ -754,14 +691,10 @@ cp_print_class_member (const gdb_byte *v
else
c_type_print_base (domain, stream, 0, 0);
fprintf_filtered (stream, "::");
- fputs_filtered (TYPE_FIELD_NAME (domain, i), stream);
- if (extra)
- fprintf_filtered (stream, " + %d bytes", extra);
- if (bits)
- fprintf_filtered (stream, " (offset in bits)");
+ fputs_filtered (TYPE_FIELD_NAME (domain, fieldno), stream);
}
else
- fprintf_filtered (stream, "%ld", (long) (val >> 3));
+ fprintf_filtered (stream, "%ld", (long) val);
}

Index: gdb/dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.207
diff -u -p -r1.207 dwarf2read.c
--- gdb/dwarf2read.c 27 Dec 2006 22:38:57 -0000 1.207
+++ gdb/dwarf2read.c 29 Dec 2006 00:13:22 -0000
@@ -3699,7 +3699,6 @@ dwarf2_attach_fn_fields_to_type (struct
TYPE_NFN_FIELDS_TOTAL (type) = total_length;
}

-
/* Returns non-zero if NAME is the name of a vtable member in CU's
language, zero otherwise. */
static int
@@ -3779,7 +3778,7 @@ quirk_gcc_member_function_pointer (struc
smash_to_method_type (type, domain_type, TYPE_TARGET_TYPE (pfn_type),
TYPE_FIELDS (pfn_type), TYPE_NFIELDS (pfn_type),
TYPE_VARARGS (pfn_type));
- type = lookup_pointer_type (type);
+ type = lookup_methodptr_type (type);
set_die_type (die, type, cu);

return 1;
@@ -4561,10 +4560,13 @@ read_tag_ptr_to_member_type (struct die_
return;
}

- type = alloc_type (objfile);
to_type = die_type (die, cu);
domain = die_containing_type (die, cu);
- smash_to_member_type (type, domain, to_type);
+
+ if (TYPE_CODE (check_typedef (to_type)) == TYPE_CODE_METHOD)
+ type = lookup_methodptr_type (to_type);
+ else
+ type = lookup_memberptr_type (to_type, domain);

set_die_type (die, type, cu);
}
Index: gdb/eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.64
diff -u -p -r1.64 eval.c
--- gdb/eval.c 10 Oct 2006 03:17:53 -0000 1.64
+++ gdb/eval.c 29 Dec 2006 00:13:22 -0000
@@ -1,8 +1,8 @@
/* Evaluate expressions for GDB.

Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free
- Software Foundation, Inc.
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006
+ Free Software Foundation, Inc.

This file is part of GDB.

@@ -38,6 +38,8 @@
#include "parser-defs.h"
#include "cp-support.h"

+#include "gdb_assert.h"
+
/* This is defined in valops.c */
extern int overload_resolution;

@@ -434,9 +436,11 @@ evaluate_subexp_standard (struct type *e
case OP_SCOPE:
tem = longest_to_int (exp->elts[pc + 2].longconst);
(*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
arg1 = value_aggregate_elt (exp->elts[pc + 1].type,
&exp->elts[pc + 3].string,
- noside);
+ 0, noside);
if (arg1 == NULL)
error (_("There is no field named %s"), &exp->elts[pc + 3].string);
return arg1;
@@ -993,8 +997,6 @@ evaluate_subexp_standard (struct type *e
argvec = (struct value **) alloca (sizeof (struct value *) * (nargs + 3));
if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
{
- LONGEST fnptr;
-
/* 1997-08-01 Currently we do not support function invocation
via pointers-to-methods with HP aCC. Pointer does not point
to the function, but possibly to some thunk. */
@@ -1027,41 +1029,18 @@ evaluate_subexp_standard (struct type *e

arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);

- fnptr = value_as_long (arg1);
+ if (TYPE_CODE (check_typedef (value_type (arg1)))
+ != TYPE_CODE_METHODPTR)
+ error (_("Non-pointer-to-member value used in pointer-to-member "
+ "construct"));

- if (METHOD_PTR_IS_VIRTUAL (fnptr))
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
{
- int fnoffset = METHOD_PTR_TO_VOFFSET (fnptr);
- struct type *basetype;
- struct type *domain_type =
- TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (value_type (arg1)));
- int i, j;
- basetype = TYPE_TARGET_TYPE (value_type (arg2));
- if (domain_type != basetype)
- arg2 = value_cast (lookup_pointer_type (domain_type), arg2);
- basetype = TYPE_VPTR_BASETYPE (domain_type);
- for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--)
- {
- struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i);
- /* If one is virtual, then all are virtual. */
- if (TYPE_FN_FIELD_VIRTUAL_P (f, 0))
- for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j)
- if ((int) TYPE_FN_FIELD_VOFFSET (f, j) == fnoffset)
- {
- struct value *temp = value_ind (arg2);
- arg1 = value_virtual_fn_field (&temp, f, j, domain_type, 0);
- arg2 = value_addr (temp);
- goto got_it;
- }
- }
- if (i < 0)
- error (_("virtual function at index %d not found"), fnoffset);
+ struct type *method_type = check_typedef (value_type (arg1));
+ arg1 = value_zero (method_type, not_lval);
}
else
- {
- deprecated_set_value_type (arg1, lookup_pointer_type (TYPE_TARGET_TYPE (value_type (arg1))));
- }
- got_it:
+ arg1 = cplus_method_ptr_to_value (&arg2, arg1);

/* Now, say which argument to start evaluating from */
tem = 2;
@@ -1396,57 +1375,60 @@ evaluate_subexp_standard (struct type *e
}

case STRUCTOP_MEMBER:
- arg1 = evaluate_subexp_for_address (exp, pos, noside);
- arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
-
- /* With HP aCC, pointers to methods do not point to the function code */
- if (deprecated_hp_som_som_object_present &&
- (TYPE_CODE (value_type (arg2)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg2))) == TYPE_CODE_METHOD))
- error (_("Pointers to methods not supported with HP aCC")); /* 1997-08-19 */
-
- mem_offset = value_as_long (arg2);
- goto handle_pointer_to_member;
-
case STRUCTOP_MPTR:
- arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (op == STRUCTOP_MEMBER)
+ arg1 = evaluate_subexp_for_address (exp, pos, noside);
+ else
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);

- /* With HP aCC, pointers to methods do not point to the function code */
- if (deprecated_hp_som_som_object_present &&
- (TYPE_CODE (value_type (arg2)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg2))) == TYPE_CODE_METHOD))
- error (_("Pointers to methods not supported with HP aCC")); /* 1997-08-19 */
-
- mem_offset = value_as_long (arg2);
-
- handle_pointer_to_member:
- /* HP aCC generates offsets that have bit #29 set; turn it off to get
- a real offset to the member. */
- if (deprecated_hp_som_som_object_present)
- {
- if (!mem_offset) /* no bias -> really null */
- error (_("Attempted dereference of null pointer-to-member"));
- mem_offset &= ~0x20000000;
- }
if (noside == EVAL_SKIP)
goto nosideret;
+
type = check_typedef (value_type (arg2));
- if (TYPE_CODE (type) != TYPE_CODE_PTR)
- goto bad_pointer_to_member;
- type = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (type) == TYPE_CODE_METHOD)
- error (_("not implemented: pointer-to-method in pointer-to-member construct"));
- if (TYPE_CODE (type) != TYPE_CODE_MEMBER)
- goto bad_pointer_to_member;
- /* Now, convert these values to an address. */
- arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
- arg1);
- arg3 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
- value_as_long (arg1) + mem_offset);
- return value_ind (arg3);
- bad_pointer_to_member:
- error (_("non-pointer-to-member value used in pointer-to-member construct"));
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_METHODPTR:
+ if (deprecated_hp_som_som_object_present)
+ {
+ /* With HP aCC, pointers to methods do not point to the
+ function code. */
+ /* 1997-08-19 */
+ error (_("Pointers to methods not supported with HP aCC"));
+ }
+
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (TYPE_TARGET_TYPE (type), not_lval);
+ else
+ {
+ arg2 = cplus_method_ptr_to_value (&arg1, arg2);
+ gdb_assert (TYPE_CODE (value_type (arg2)) == TYPE_CODE_PTR);
+ return value_ind (arg2);
+ }
+
+ case TYPE_CODE_MEMBERPTR:
+ /* Now, convert these values to an address. */
+ arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
+ arg1);
+
+ mem_offset = value_as_long (arg2);
+ if (deprecated_hp_som_som_object_present)
+ {
+ /* HP aCC generates offsets that have bit #29 set; turn it off to get
+ a real offset to the member. */
+ if (!mem_offset) /* no bias -> really null */
+ error (_("Attempted dereference of null pointer-to-member"));
+ mem_offset &= ~0x20000000;
+ }
+
+ arg3 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ value_as_long (arg1) + mem_offset);
+ return value_ind (arg3);
+
+ default:
+ error (_("non-pointer-to-member value used in pointer-to-member construct"));
+ }

case BINOP_CONCAT:
arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
@@ -1469,13 +1451,11 @@ evaluate_subexp_standard (struct type *e
the implementation yet; but the pointer appears to point to a code
sequence (thunk) in memory -- in any case it is *not* the address
of the function as it would be in a naive implementation. */
- if ((TYPE_CODE (value_type (arg1)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg1))) == TYPE_CODE_METHOD))
+ if (TYPE_CODE (value_type (arg1)) == TYPE_CODE_METHODPTR)
error (_("Assignment to pointers to methods not implemented with HP aCC"));

- /* HP aCC pointers to data members require a constant bias */
- if ((TYPE_CODE (value_type (arg1)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg1))) == TYPE_CODE_MEMBER))
+ /* HP aCC pointers to data members require a constant bias. */
+ if (TYPE_CODE (value_type (arg1)) == TYPE_CODE_MEMBERPTR)
{
unsigned int *ptr = (unsigned int *) value_contents (arg2); /* forces evaluation */
*ptr |= 0x20000000; /* set 29th bit */
@@ -1934,9 +1914,9 @@ evaluate_subexp_standard (struct type *e
if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
arg1 = evaluate_subexp (expect_type, exp, pos, noside);
- if ((TYPE_TARGET_TYPE (value_type (arg1))) &&
- ((TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg1))) == TYPE_CODE_METHOD) ||
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg1))) == TYPE_CODE_MEMBER)))
+ type = check_typedef (value_type (arg1));
+ if (TYPE_CODE (type) == TYPE_CODE_METHODPTR
+ || TYPE_CODE (type) == TYPE_CODE_MEMBERPTR)
error (_("Attempt to dereference pointer to member without an object"));
if (noside == EVAL_SKIP)
goto nosideret;
@@ -1967,22 +1947,15 @@ evaluate_subexp_standard (struct type *e

if (noside == EVAL_SKIP)
{
- if (op == OP_SCOPE)
- {
- int temm = longest_to_int (exp->elts[pc + 3].longconst);
- (*pos) += 3 + BYTES_TO_EXP_ELEM (temm + 1);
- }
- else
- evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
goto nosideret;
}
else
{
struct value *retvalp = evaluate_subexp_for_address (exp, pos, noside);
/* If HP aCC object, use bias for pointers to members */
- if (deprecated_hp_som_som_object_present &&
- (TYPE_CODE (value_type (retvalp)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (retvalp))) == TYPE_CODE_MEMBER))
+ if (deprecated_hp_som_som_object_present
+ && TYPE_CODE (value_type (retvalp)) == TYPE_CODE_MEMBERPTR)
{
unsigned int *ptr = (unsigned int *) value_contents (retvalp); /* forces evaluation */
*ptr |= 0x20000000; /* set 29th bit */
@@ -2148,6 +2121,7 @@ evaluate_subexp_for_address (struct expr
int pc;
struct symbol *var;
struct value *x;
+ int tem;

pc = (*pos);
op = exp->elts[pc].opcode;
@@ -2162,15 +2136,7 @@ evaluate_subexp_for_address (struct expr
if (unop_user_defined_p (op, x))
{
x = value_x_unop (x, op, noside);
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- {
- if (VALUE_LVAL (x) == lval_memory)
- return value_zero (lookup_pointer_type (value_type (x)),
- not_lval);
- else
- error (_("Attempt to take address of non-lval"));
- }
- return value_addr (x);
+ goto default_case_after_eval;
}

return x;
@@ -2210,14 +2176,30 @@ evaluate_subexp_for_address (struct expr
(var,
block_innermost_frame (exp->elts[pc + 1].block));

+ case OP_SCOPE:
+ tem = longest_to_int (exp->elts[pc + 2].longconst);
+ (*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1);
+ x = value_aggregate_elt (exp->elts[pc + 1].type,
+ &exp->elts[pc + 3].string,
+ 1, noside);
+ if (x == NULL)
+ error (_("There is no field named %s"), &exp->elts[pc + 3].string);
+ return x;
+
default:
default_case:
x = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ default_case_after_eval:
if (noside == EVAL_AVOID_SIDE_EFFECTS)
{
+ struct type *type = check_typedef (value_type (x));
+
if (VALUE_LVAL (x) == lval_memory)
return value_zero (lookup_pointer_type (value_type (x)),
not_lval);
+ else if (TYPE_CODE (type) == TYPE_CODE_REF)
+ return value_zero (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ not_lval);
else
error (_("Attempt to take address of non-lval"));
}
Index: gdb/f-typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/f-typeprint.c,v
retrieving revision 1.16
diff -u -p -r1.16 f-typeprint.c
--- gdb/f-typeprint.c 1 Mar 2006 01:37:26 -0000 1.16
+++ gdb/f-typeprint.c 29 Dec 2006 00:13:22 -0000
@@ -73,7 +73,6 @@ f_print_type (struct type *type, char *v
(code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
|| code == TYPE_CODE_METHOD
|| code == TYPE_CODE_ARRAY
- || code == TYPE_CODE_MEMBER
|| code == TYPE_CODE_REF)))
fputs_filtered (" ", stream);
f_type_print_varspec_prefix (type, stream, show, 0);
@@ -138,7 +137,6 @@ f_type_print_varspec_prefix (struct type
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
case TYPE_CODE_METHOD:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_REF:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TYPEDEF:
@@ -250,7 +248,6 @@ f_type_print_varspec_suffix (struct type
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
case TYPE_CODE_METHOD:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TYPEDEF:
/* These types do not need a suffix. They are listed so that
Index: gdb/gdbarch.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.c,v
retrieving revision 1.332
diff -u -p -r1.332 gdbarch.c
--- gdb/gdbarch.c 28 Nov 2006 22:10:26 -0000 1.332
+++ gdb/gdbarch.c 29 Dec 2006 00:13:22 -0000
@@ -235,6 +235,8 @@ struct gdbarch
gdbarch_register_reggroup_p_ftype *register_reggroup_p;
gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
gdbarch_regset_from_core_section_ftype *regset_from_core_section;
+ int vtable_function_descriptors;
+ int vbit_in_delta;
};

@@ -361,6 +363,8 @@ struct gdbarch startup_gdbarch =
default_register_reggroup_p, /* register_reggroup_p */
0, /* fetch_pointer_argument */
0, /* regset_from_core_section */
+ 0, /* vtable_function_descriptors */
+ 0, /* vbit_in_delta */
/* startup_gdbarch() */
};

@@ -615,6 +619,8 @@ verify_gdbarch (struct gdbarch *current_
/* Skip verify of register_reggroup_p, invalid_p == 0 */
/* Skip verify of fetch_pointer_argument, has predicate */
/* Skip verify of regset_from_core_section, has predicate */
+ /* Skip verify of vtable_function_descriptors, invalid_p == 0 */
+ /* Skip verify of vbit_in_delta, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
if (strlen (buf) > 0)
@@ -1595,6 +1601,9 @@ gdbarch_dump (struct gdbarch *current_gd
fprintf_unfiltered (file,
"gdbarch_dump: value_to_register = <0x%lx>\n",
(long) current_gdbarch->value_to_register);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: vbit_in_delta = %s\n",
+ paddr_d (current_gdbarch->vbit_in_delta));
#ifdef TARGET_VIRTUAL_FRAME_POINTER
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
@@ -1604,6 +1613,9 @@ gdbarch_dump (struct gdbarch *current_gd
fprintf_unfiltered (file,
"gdbarch_dump: virtual_frame_pointer = <0x%lx>\n",
(long) current_gdbarch->virtual_frame_pointer);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: vtable_function_descriptors = %s\n",
+ paddr_d (current_gdbarch->vtable_function_descriptors));
#ifdef TARGET_WRITE_PC
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
@@ -3653,6 +3665,40 @@ set_gdbarch_regset_from_core_section (st
gdbarch->regset_from_core_section = regset_from_core_section;
}

+int
+gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of vtable_function_descriptors, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_vtable_function_descriptors called\n");
+ return gdbarch->vtable_function_descriptors;
+}
+
+void
+set_gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch,
+ int vtable_function_descriptors)
+{
+ gdbarch->vtable_function_descriptors = vtable_function_descriptors;
+}
+
+int
+gdbarch_vbit_in_delta (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of vbit_in_delta, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_vbit_in_delta called\n");
+ return gdbarch->vbit_in_delta;
+}
+
+void
+set_gdbarch_vbit_in_delta (struct gdbarch *gdbarch,
+ int vbit_in_delta)
+{
+ gdbarch->vbit_in_delta = vbit_in_delta;
+}
+

/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
Index: gdb/gdbarch.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.h,v
retrieving revision 1.288
diff -u -p -r1.288 gdbarch.h
--- gdb/gdbarch.h 28 Nov 2006 22:10:26 -0000 1.288
+++ gdb/gdbarch.h 29 Dec 2006 00:13:23 -0000
@@ -1383,6 +1383,19 @@ typedef const struct regset * (gdbarch_r
extern const struct regset * gdbarch_regset_from_core_section (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size);
extern void set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch, gdbarch_regset_from_core_section_ftype *regset_from_core_section);

+/* If the elements of C++ vtables are in-place function descriptors rather
+ than normal function pointers (which may point to code or a descriptor),
+ set this to one. */
+
+extern int gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch);
+extern void set_gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch, int vtable_function_descriptors);
+
+/* Set if the least significant bit of the delta is used instead of the least
+ significant bit of the pfn for pointers to virtual member functions. */
+
+extern int gdbarch_vbit_in_delta (struct gdbarch *gdbarch);
+extern void set_gdbarch_vbit_in_delta (struct gdbarch *gdbarch, int vbit_in_delta);
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);

Index: gdb/gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.368
diff -u -p -r1.368 gdbarch.sh
--- gdb/gdbarch.sh 28 Nov 2006 22:10:26 -0000 1.368
+++ gdb/gdbarch.sh 29 Dec 2006 00:13:23 -0000
@@ -663,6 +663,15 @@ F:=:CORE_ADDR:fetch_pointer_argument:str
# Return the appropriate register set for a core file section with
# name SECT_NAME and size SECT_SIZE.
M::const struct regset *:regset_from_core_section:const char *sect_name, size_t sect_size:sect_name, sect_size
+
+# If the elements of C++ vtables are in-place function descriptors rather
+# than normal function pointers (which may point to code or a descriptor),
+# set this to one.
+v::int:vtable_function_descriptors:::0:0::0
+
+# Set if the least significant bit of the delta is used instead of the least
+# significant bit of the pfn for pointers to virtual member functions.
+v::int:vbit_in_delta:::0:0::0
EOF
}

Index: gdb/gdbtypes.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.c,v
retrieving revision 1.108
diff -u -p -r1.108 gdbtypes.c
--- gdb/gdbtypes.c 6 Dec 2006 20:15:19 -0000 1.108
+++ gdb/gdbtypes.c 29 Dec 2006 00:13:23 -0000
@@ -621,15 +621,30 @@ replace_type (struct type *ntype, struct
of the aggregate that the member belongs to. */

struct type *
-lookup_member_type (struct type *type, struct type *domain)
+lookup_memberptr_type (struct type *type, struct type *domain)
{
struct type *mtype;

mtype = alloc_type (TYPE_OBJFILE (type));
- smash_to_member_type (mtype, domain, type);
+ smash_to_memberptr_type (mtype, domain, type);
return (mtype);
}

+/* Return a pointer-to-method type, for a method of type TO_TYPE. */
+
+struct type *
+lookup_methodptr_type (struct type *to_type)
+{
+ struct type *mtype;
+
+ mtype = alloc_type (TYPE_OBJFILE (to_type));
+ TYPE_TARGET_TYPE (mtype) = to_type;
+ TYPE_DOMAIN_TYPE (mtype) = TYPE_DOMAIN_TYPE (to_type);
+ TYPE_LENGTH (mtype) = cplus_method_ptr_size ();
+ TYPE_CODE (mtype) = TYPE_CODE_METHODPTR;
+ return mtype;
+}
+
/* Allocate a stub method whose return type is TYPE.
This apparently happens for speed of symbol reading, since parsing
out the arguments to the method is cpu-intensive, the way we are doing
@@ -981,19 +996,20 @@ build_builtin_type_vec128 (void)
return t;
}

-/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE.
- A MEMBER is a wierd thing -- it amounts to a typed offset into
- a struct, e.g. "an int at offset 8". A MEMBER TYPE doesn't
- include the offset (that's the value of the MEMBER itself), but does
- include the structure type into which it points (for some reason).
+/* Smash TYPE to be a type of pointers to members of DOMAIN with type
+ TO_TYPE. A member pointer is a wierd thing -- it amounts to a
+ typed offset into a struct, e.g. "an int at offset 8". A MEMBER
+ TYPE doesn't include the offset (that's the value of the MEMBER
+ itself), but does include the structure type into which it points
+ (for some reason).

When "smashing" the type, we preserve the objfile that the
old type pointed to, since we aren't changing where the type is actually
allocated. */

void
-smash_to_member_type (struct type *type, struct type *domain,
- struct type *to_type)
+smash_to_memberptr_type (struct type *type, struct type *domain,
+ struct type *to_type)
{
struct objfile *objfile;

@@ -1003,8 +1019,10 @@ smash_to_member_type (struct type *type,
TYPE_OBJFILE (type) = objfile;
TYPE_TARGET_TYPE (type) = to_type;
TYPE_DOMAIN_TYPE (type) = domain;
- TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */
- TYPE_CODE (type) = TYPE_CODE_MEMBER;
+ /* Assume that a data member pointer is the same size as a normal
+ pointer. */
+ TYPE_LENGTH (type) = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ TYPE_CODE (type) = TYPE_CODE_MEMBERPTR;
}

/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE.
@@ -2643,7 +2661,7 @@ rank_one_type (struct type *parm, struct
return INCOMPATIBLE_TYPE_BADNESS;
}
break;
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
switch (TYPE_CODE (arg))
{
default:
@@ -2957,8 +2975,11 @@ recursive_dump_type (struct type *type,
case TYPE_CODE_ERROR:
printf_filtered ("(TYPE_CODE_ERROR)");
break;
- case TYPE_CODE_MEMBER:
- printf_filtered ("(TYPE_CODE_MEMBER)");
+ case TYPE_CODE_MEMBERPTR:
+ printf_filtered ("(TYPE_CODE_MEMBERPTR)");
+ break;
+ case TYPE_CODE_METHODPTR:
+ printf_filtered ("(TYPE_CODE_METHODPTR)");
break;
case TYPE_CODE_METHOD:
printf_filtered ("(TYPE_CODE_METHOD)");
Index: gdb/gdbtypes.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.h,v
retrieving revision 1.65
diff -u -p -r1.65 gdbtypes.h
--- gdb/gdbtypes.h 1 Feb 2006 23:14:10 -0000 1.65
+++ gdb/gdbtypes.h 29 Dec 2006 00:13:23 -0000
@@ -142,8 +142,16 @@ enum type_code
TYPE_CODE_ERROR,

/* C++ */
- TYPE_CODE_MEMBER, /* Member type */
TYPE_CODE_METHOD, /* Method type */
+
+ /* Pointer-to-member-function type. This describes how to access a
+ particular member function of a class (possibly virtual). */
+ TYPE_CODE_METHODPTR,
+
+ /* Pointer-to-member type. This is the offset within a class to some
+ particular data member. */
+ TYPE_CODE_MEMBERPTR,
+
TYPE_CODE_REF, /* C++ Reference types */

TYPE_CODE_CHAR, /* *real* character type */
@@ -464,8 +472,9 @@ struct main_type
/* For types with virtual functions (TYPE_CODE_STRUCT), VPTR_BASETYPE
is the base class which defined the virtual function table pointer.

- For types that are pointer to member types (TYPE_CODE_MEMBER),
- VPTR_BASETYPE is the type that this pointer is a member of.
+ For types that are pointer to member types (TYPE_CODE_METHODPTR,
+ TYPE_CODE_MEMBERPTR), VPTR_BASETYPE is the type that this pointer
+ is a member of.

For method types (TYPE_CODE_METHOD), VPTR_BASETYPE is the aggregate
type that contains the method.
@@ -1220,14 +1229,16 @@ extern const char *address_space_int_to_
extern struct type *make_type_with_address_space (struct type *type,
int space_identifier);

-extern struct type *lookup_member_type (struct type *, struct type *);
+extern struct type *lookup_memberptr_type (struct type *, struct type *);
+
+extern struct type *lookup_methodptr_type (struct type *);

-extern void
-smash_to_method_type (struct type *type, struct type *domain,
- struct type *to_type, struct field *args,
- int nargs, int varargs);
+extern void smash_to_method_type (struct type *type, struct type *domain,
+ struct type *to_type, struct field *args,
+ int nargs, int varargs);

-extern void smash_to_member_type (struct type *, struct type *, struct type *);
+extern void smash_to_memberptr_type (struct type *, struct type *,
+ struct type *);

extern struct type *allocate_stub_method (struct type *);

Index: gdb/gnu-v3-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/gnu-v3-abi.c,v
retrieving revision 1.29
diff -u -p -r1.29 gnu-v3-abi.c
--- gdb/gnu-v3-abi.c 17 Dec 2005 22:34:00 -0000 1.29
+++ gdb/gnu-v3-abi.c 29 Dec 2006 00:13:23 -0000
@@ -1,7 +1,8 @@
/* Abstraction of GNU v3 abi.
Contributed by Jim Blandy <jimb@redhat.com>

- Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2005, 2006
+ Free Software Foundation, Inc.

This file is part of GDB.

@@ -25,6 +26,8 @@
#include "cp-abi.h"
#include "cp-support.h"
#include "demangle.h"
+#include "valprint.h"
+
#include "gdb_assert.h"
#include "gdb_string.h"

@@ -274,79 +277,94 @@ gnuv3_rtti_type (struct value *value,
return run_time_type;
}

+/* Find the vtable for CONTAINER and return a value of the correct
+ vtable type for this architecture. */

static struct value *
-gnuv3_virtual_fn_field (struct value **value_p,
- struct fn_field *f, int j,
- struct type *type, int offset)
+gnuv3_get_vtable (struct value *container)
{
struct type *vtable_type = gdbarch_data (current_gdbarch,
vtable_type_gdbarch_data);
- struct value *value = *value_p;
- struct type *values_type = check_typedef (value_type (value));
- struct type *vfn_base;
- CORE_ADDR vtable_address;
- struct value *vtable;
- struct value *vfn;
-
- /* Some simple sanity checks. */
- if (TYPE_CODE (values_type) != TYPE_CODE_CLASS)
- error (_("Only classes can have virtual functions."));
-
- /* Find the base class that defines this virtual function. */
- vfn_base = TYPE_FN_FIELD_FCONTEXT (f, j);
- if (! vfn_base)
- /* In programs compiled with G++ version 1, the debug info doesn't
- say which base class defined the virtual function. We'll guess
- it's the same base class that has our vtable; this is wrong for
- multiple inheritance, but it's better than nothing. */
- vfn_base = TYPE_VPTR_BASETYPE (type);
-
- /* This type may have been defined before its virtual function table
- was. If so, fill in the virtual function table entry for the
- type now. */
- if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
- fill_in_vptr_fieldno (vfn_base);
- if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
- error (_("Could not find virtual table pointer for class \"%s\"."),
- TYPE_TAG_NAME (vfn_base) ? TYPE_TAG_NAME (vfn_base) : "<unknown>");
-
- /* Now that we know which base class is defining our virtual
- function, cast our value to that baseclass. This takes care of
- any necessary `this' adjustments. */
- if (vfn_base != values_type)
- value = value_cast (vfn_base, value);
+ struct type *vtable_pointer_type;
+ struct value *vtable_pointer;
+ CORE_ADDR vtable_pointer_address, vtable_address;
+
+ /* We do not consult the debug information to find the virtual table.
+ The ABI specifies that it is always at offset zero in any class,
+ and debug information may not represent it. We won't issue an
+ error if there's a class with virtual functions but no virtual table
+ pointer, but something's already gone seriously wrong if that
+ happens.
+
+ We avoid using value_contents on principle, because the object might
+ be large. */
+
+ /* Find the type "pointer to virtual table". */
+ vtable_pointer_type = lookup_pointer_type (vtable_type);
+
+ /* Load it from the start of the class. */
+ vtable_pointer_address = value_as_address (value_addr (container));
+ vtable_pointer = value_at (vtable_pointer_type, vtable_pointer_address);
+ vtable_address = value_as_address (vtable_pointer);
+
+ /* Correct it to point at the start of the virtual table, rather
+ than the address point. */
+ return value_at_lazy (vtable_type,
+ vtable_address - vtable_address_point_offset ());
+}

- /* Now value is an object of the appropriate base type. Fetch its
- virtual table. */
- /* It might be possible to do this cast at the same time as the above.
- Does multiple inheritance affect this?
- Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent?
- */
- if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base)
- value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value);
- vtable_address
- = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
+/* Return a function pointer for CONTAINER's VTABLE_INDEX'th virtual
+ function, of type FNTYPE. */

- vtable = value_at_lazy (vtable_type,
- vtable_address - vtable_address_point_offset ());
+static struct value *
+gnuv3_get_virtual_fn (struct value *container, struct type *fntype,
+ int vtable_index)
+{
+ struct value *vtable = gnuv3_get_vtable (container);
+ struct value *vfn;

/* Fetch the appropriate function pointer from the vtable. */
vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
- value_from_longest (builtin_type_int,
- TYPE_FN_FIELD_VOFFSET (f, j)));
+ value_from_longest (builtin_type_int, vtable_index));

- /* Cast the function pointer to the appropriate type. */
- vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)),
- vfn);
+ /* If this architecture uses function descriptors directly in the vtable,
+ then the address of the vtable entry is actually a "function pointer"
+ (i.e. points to the descriptor). We don't need to scale the index
+ by the size of a function descriptor; GCC does that before outputing
+ debug information. */
+ if (gdbarch_vtable_function_descriptors (current_gdbarch))
+ vfn = value_addr (vfn);

- /* Is (type)value always numerically the same as (vfn_base)value?
- If so we can spare this cast and use one of the ones above. */
- *value_p = value_addr (value_cast (type, *value_p));
+ /* Cast the function pointer to the appropriate type. */
+ vfn = value_cast (lookup_pointer_type (fntype), vfn);

return vfn;
}

+/* GNU v3 implementation of value_virtual_fn_field. See cp-abi.h
+ for a description of the arguments. */
+
+static struct value *
+gnuv3_virtual_fn_field (struct value **value_p,
+ struct fn_field *f, int j,
+ struct type *vfn_base, int offset)
+{
+ struct type *values_type = check_typedef (value_type (*value_p));
+
+ /* Some simple sanity checks. */
+ if (TYPE_CODE (values_type) != TYPE_CODE_CLASS)
+ error (_("Only classes can have virtual functions."));
+
+ /* Cast our value to the base class which defines this virtual
+ function. This takes care of any necessary `this'
+ adjustments. */
+ if (vfn_base != values_type)
+ *value_p = value_cast (vfn_base, *value_p);
+
+ return gnuv3_get_virtual_fn (*value_p, TYPE_FN_FIELD_TYPE (f, j),
+ TYPE_FN_FIELD_VOFFSET (f, j));
+}
+
/* Compute the offset of the baseclass which is
the INDEXth baseclass of class TYPE,
for value at VALADDR (in host) at ADDRESS (in target).
@@ -416,6 +434,245 @@ gnuv3_baseclass_offset (struct type *typ
return base_offset;
}

+/* Locate a virtual method in DOMAIN or its non-virtual base classes
+ which has virtual table index VOFFSET. The method has an associated
+ "this" adjustment of ADJUSTMENT bytes. */
+
+const char *
+gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset,
+ LONGEST adjustment)
+{
+ int i;
+ const char *physname;
+
+ /* Search this class first. */
+ physname = NULL;
+ if (adjustment == 0)
+ {
+ int len;
+
+ len = TYPE_NFN_FIELDS (domain);
+ for (i = 0; i < len; i++)
+ {
+ int len2, j;
+ struct fn_field *f;
+
+ f = TYPE_FN_FIELDLIST1 (domain, i);
+ len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+ check_stub_method_group (domain, i);
+ for (j = 0; j < len2; j++)
+ if (TYPE_FN_FIELD_VOFFSET (f, j) == voffset)
+ return TYPE_FN_FIELD_PHYSNAME (f, j);
+ }
+ }
+
+ /* Next search non-virtual bases. If it's in a virtual base,
+ we're out of luck. */
+ for (i = 0; i < TYPE_N_BASECLASSES (domain); i++)
+ {
+ int pos;
+ struct type *basetype;
+
+ if (BASETYPE_VIA_VIRTUAL (domain, i))
+ continue;
+
+ pos = TYPE_BASECLASS_BITPOS (domain, i) / 8;
+ basetype = TYPE_FIELD_TYPE (domain, i);
+ /* Recurse with a modified adjustment. We don't need to adjust
+ voffset. */
+ if (adjustment >= pos && adjustment < pos + TYPE_LENGTH (basetype))
+ return gnuv3_find_method_in (basetype, voffset, adjustment - pos);
+ }
+
+ return NULL;
+}
+
+/* GNU v3 implementation of cplus_print_method_ptr. */
+
+static void
+gnuv3_print_method_ptr (const gdb_byte *contents,
+ struct type *type,
+ struct ui_file *stream)
+{
+ CORE_ADDR ptr_value;
+ LONGEST adjustment;
+ struct type *domain;
+ int vbit;
+
+ domain = TYPE_DOMAIN_TYPE (type);
+
+ /* Extract the pointer to member. */
+ ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr);
+ contents += TYPE_LENGTH (builtin_type_void_func_ptr);
+ adjustment = extract_signed_integer (contents,
+ TYPE_LENGTH (builtin_type_long));
+
+ if (!gdbarch_vbit_in_delta (current_gdbarch))
+ {
+ vbit = ptr_value & 1;
+ ptr_value = ptr_value ^ vbit;
+ }
+ else
+ {
+ vbit = adjustment & 1;
+ adjustment = adjustment >> 1;
+ }
+
+ /* Check for NULL. */
+ if (ptr_value == 0 && vbit == 0)
+ {
+ fprintf_filtered (stream, "NULL");
+ return;
+ }
+
+ /* Search for a virtual method. */
+ if (vbit)
+ {
+ CORE_ADDR voffset;
+ const char *physname;
+
+ /* It's a virtual table offset, maybe in this class. Search
+ for a field with the correct vtable offset. First convert it
+ to an index, as used in TYPE_FN_FIELD_VOFFSET. */
+ voffset = ptr_value / TYPE_LENGTH (builtin_type_long);
+
+ physname = gnuv3_find_method_in (domain, voffset, adjustment);
+
+ /* If we found a method, print that. We don't bother to disambiguate
+ possible paths to the method based on the adjustment. */
+ if (physname)
+ {
+ char *demangled_name = cplus_demangle (physname,
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name != NULL)
+ {
+ fprintf_filtered (stream, "&virtual ");
+ fputs_filtered (demangled_name, stream);
+ xfree (demangled_name);
+ return;
+ }
+ }
+ }
+
+ /* We didn't find it; print the raw data. */
+ if (vbit)
+ {
+ fprintf_filtered (stream, "&virtual table offset ");
+ print_longest (stream, 'd', 1, ptr_value);
+ }
+ else
+ print_address_demangle (ptr_value, stream, demangle);
+
+ if (adjustment)
+ {
+ fprintf_filtered (stream, ", this adjustment ");
+ print_longest (stream, 'd', 1, adjustment);
+ }
+}
+
+/* GNU v3 implementation of cplus_method_ptr_size. */
+
+static int
+gnuv3_method_ptr_size (void)
+{
+ return 2 * TYPE_LENGTH (builtin_type_void_data_ptr);
+}
+
+/* GNU v3 implementation of cplus_make_method_ptr. */
+
+static void
+gnuv3_make_method_ptr (gdb_byte *contents, CORE_ADDR value, int is_virtual)
+{
+ int size = TYPE_LENGTH (builtin_type_void_data_ptr);
+
+ /* FIXME drow/2006-12-24: The adjustment of "this" is currently
+ always zero, since the method pointer is of the correct type.
+ But if the method pointer came from a base class, this is
+ incorrect - it should be the offset to the base. The best
+ fix might be to create the pointer to member pointing at the
+ base class and cast it to the derived class, but that requires
+ support for adjusting pointers to members when casting them -
+ not currently supported by GDB. */
+
+ if (!gdbarch_vbit_in_delta (current_gdbarch))
+ {
+ store_unsigned_integer (contents, size, value | is_virtual);
+ store_unsigned_integer (contents + size, size, 0);
+ }
+ else
+ {
+ store_unsigned_integer (contents, size, value);
+ store_unsigned_integer (contents + size, size, is_virtual);
+ }
+}
+
+/* GNU v3 implementation of cplus_method_ptr_to_value. */
+
+static struct value *
+gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
+{
+ const gdb_byte *contents = value_contents (method_ptr);
+ CORE_ADDR ptr_value;
+ struct type *final_type, *method_type;
+ LONGEST adjustment;
+ struct value *adjval;
+ int vbit;
+
+ final_type = TYPE_DOMAIN_TYPE (check_typedef (value_type (method_ptr)));
+ final_type = lookup_pointer_type (final_type);
+
+ method_type = TYPE_TARGET_TYPE (check_typedef (value_type (method_ptr)));
+
+ ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr);
+ contents += TYPE_LENGTH (builtin_type_void_func_ptr);
+ adjustment = extract_signed_integer (contents,
+ TYPE_LENGTH (builtin_type_long));
+
+ if (!gdbarch_vbit_in_delta (current_gdbarch))
+ {
+ vbit = ptr_value & 1;
+ ptr_value = ptr_value ^ vbit;
+ }
+ else
+ {
+ vbit = adjustment & 1;
+ adjustment = adjustment >> 1;
+ }
+
+ /* First convert THIS to match the containing type of the pointer to
+ member. This cast may adjust the value of THIS. */
+ *this_p = value_cast (final_type, *this_p);
+
+ /* Then apply whatever adjustment is necessary. This creates a somewhat
+ strange pointer: it claims to have type FINAL_TYPE, but in fact it
+ might not be a valid FINAL_TYPE. For instance, it might be a
+ base class of FINAL_TYPE. And if it's not the primary base class,
+ then printing it out as a FINAL_TYPE object would produce some pretty
+ garbage.
+
+ But we don't really know the type of the first argument in
+ METHOD_TYPE either, which is why this happens. We can't
+ dereference this later as a FINAL_TYPE, but once we arrive in the
+ called method we'll have debugging information for the type of
+ "this" - and that'll match the value we produce here.
+
+ You can provoke this case by casting a Base::* to a Derived::*, for
+ instance. */
+ *this_p = value_cast (builtin_type_void_data_ptr, *this_p);
+ adjval = value_from_longest (builtin_type_long, adjustment);
+ *this_p = value_add (*this_p, adjval);
+ *this_p = value_cast (final_type, *this_p);
+
+ if (vbit)
+ {
+ LONGEST voffset = ptr_value / TYPE_LENGTH (builtin_type_long);
+ return gnuv3_get_virtual_fn (value_ind (*this_p), method_type, voffset);
+ }
+ else
+ return value_from_pointer (lookup_pointer_type (method_type), ptr_value);
+}
+
static void
init_gnuv3_ops (void)
{
@@ -433,6 +690,10 @@ init_gnuv3_ops (void)
gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type;
gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field;
gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset;
+ gnu_v3_abi_ops.print_method_ptr = gnuv3_print_method_ptr;
+ gnu_v3_abi_ops.method_ptr_size = gnuv3_method_ptr_size;
+ gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr;
+ gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value;
}

extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */
Index: gdb/hpread.c
===================================================================
RCS file: /cvs/src/src/gdb/hpread.c,v
retrieving revision 1.58
diff -u -p -r1.58 hpread.c
--- gdb/hpread.c 17 Dec 2005 22:34:01 -0000 1.58
+++ gdb/hpread.c 29 Dec 2006 00:13:24 -0000
@@ -1,6 +1,6 @@
/* Read hp debug symbols and convert to internal format, for GDB.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2006 Free Software Foundation, Inc.

This file is part of GDB.

@@ -4875,9 +4875,7 @@ hpread_type_lookup (dnttpointer hp_type,
objfile),
class_type = hpread_type_lookup (dn_bufp->dptrmem.pointsto,
objfile),
- ptrmemtype = alloc_type (objfile);
- smash_to_member_type (ptrmemtype, class_type, memtype);
- return make_pointer_type (ptrmemtype, NULL);
+ return lookup_memberptr_type (memtype, class_type);
}
break;

@@ -4905,7 +4903,7 @@ hpread_type_lookup (dnttpointer hp_type,
TYPE_FIELDS (functype),
TYPE_NFIELDS (functype),
0);
- return make_pointer_type (ptrmemtype, NULL);
+ return lookup_methodptr_type (ptrmemtype);
}
break;

Index: gdb/ia64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
retrieving revision 1.141
diff -u -p -r1.141 ia64-tdep.c
--- gdb/ia64-tdep.c 28 Dec 2006 23:48:51 -0000 1.141
+++ gdb/ia64-tdep.c 29 Dec 2006 00:13:25 -0000
@@ -40,6 +40,7 @@
#include "infcall.h"
#include "osabi.h"
#include "ia64-tdep.h"
+#include "cp-abi.h"

#ifdef HAVE_LIBUNWIND_IA64_H
#include "elf/ia64.h" /* for PT_IA_64_UNWIND value */
@@ -3306,6 +3307,17 @@ ia64_convert_from_func_ptr_addr (struct
if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
return read_memory_unsigned_integer (addr, 8);

+ /* There are also descriptors embedded in vtables. */
+ if (s)
+ {
+ struct minimal_symbol *minsym;
+
+ minsym = lookup_minimal_symbol_by_pc (addr);
+
+ if (minsym && is_vtable_name (SYMBOL_LINKAGE_NAME (minsym)))
+ return read_memory_unsigned_integer (addr, 8);
+ }
+
return addr;
}

@@ -3640,6 +3652,10 @@ ia64_gdbarch_init (struct gdbarch_info i
set_gdbarch_print_insn (gdbarch, ia64_print_insn);
set_gdbarch_convert_from_func_ptr_addr (gdbarch, ia64_convert_from_func_ptr_addr);

+ /* The virtual table contains 16-byte descriptors, not pointers to
+ descriptors. */
+ set_gdbarch_vtable_function_descriptors (gdbarch, 1);
+
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);

Index: gdb/infcall.c
===================================================================
RCS file: /cvs/src/src/gdb/infcall.c,v
retrieving revision 1.76
diff -u -p -r1.76 infcall.c
--- gdb/infcall.c 10 Sep 2006 15:44:36 -0000 1.76
+++ gdb/infcall.c 29 Dec 2006 00:13:25 -0000
@@ -1,7 +1,7 @@
/* Perform an inferior function call, for GDB, the GNU debugger.

Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.

This file is part of GDB.
@@ -169,7 +169,8 @@ value_arg_coerce (struct value *arg, str
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
case TYPE_CODE_ERROR:
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
+ case TYPE_CODE_METHODPTR:
case TYPE_CODE_METHOD:
case TYPE_CODE_COMPLEX:
default:
Index: gdb/m2-typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-typeprint.c,v
retrieving revision 1.8
diff -u -p -r1.8 m2-typeprint.c
--- gdb/m2-typeprint.c 27 May 2006 17:39:28 -0000 1.8
+++ gdb/m2-typeprint.c 29 Dec 2006 00:13:25 -0000
@@ -112,10 +112,6 @@ m2_print_type (struct type *type, char *
m2_ref (type, stream, show, level);
break;

- case TYPE_CODE_MEMBER:
- m2_unknown (_("member"), type, stream, show, level);
- break;
-
case TYPE_CODE_METHOD:
m2_unknown (_("method"), type, stream, show, level);
break;
Index: gdb/m2-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-valprint.c,v
retrieving revision 1.10
diff -u -p -r1.10 m2-valprint.c
--- gdb/m2-valprint.c 13 May 2006 15:46:38 -0000 1.10
+++ gdb/m2-valprint.c 29 Dec 2006 00:13:25 -0000
@@ -327,10 +327,6 @@ m2_val_print (struct type *type, const g
}
break;

- case TYPE_CODE_MEMBER:
- error (_("not implemented: member type in m2_val_print"));
- break;
-
case TYPE_CODE_REF:
elttype = check_typedef (TYPE_TARGET_TYPE (type));
if (addressprint)
Index: gdb/mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.399
diff -u -p -r1.399 mips-tdep.c
--- gdb/mips-tdep.c 28 Nov 2006 22:14:31 -0000 1.399
+++ gdb/mips-tdep.c 29 Dec 2006 00:13:25 -0000
@@ -5231,6 +5231,9 @@ mips_gdbarch_init (struct gdbarch_info i

set_gdbarch_single_step_through_delay (gdbarch, mips_single_step_through_delay);

+ /* Virtual tables. */
+ set_gdbarch_vbit_in_delta (gdbarch, 1);
+
mips_register_g_packet_guesses (gdbarch);

/* Hook in OS ABI-specific overrides, if they have been registered. */
Index: gdb/p-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/p-lang.h,v
retrieving revision 1.9
diff -u -p -r1.9 p-lang.h
--- gdb/p-lang.h 17 Dec 2005 22:34:01 -0000 1.9
+++ gdb/p-lang.h 29 Dec 2006 00:13:25 -0000
@@ -1,6 +1,6 @@
/* Pascal language support definitions for GDB, the GNU debugger.

- Copyright (C) 2000, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2005, 2006 Free Software Foundation, Inc.

This file is part of GDB.

@@ -67,12 +67,6 @@ extern int vtblprint; /* Controls print

extern int static_field_print;

-extern void pascal_object_print_class_member (const gdb_byte *, struct type *,
- struct ui_file *, char *);
-
-extern void pascal_object_print_class_method (const gdb_byte *, struct type *,
- struct ui_file *);
-
extern void pascal_object_print_value_fields (struct type *, const gdb_byte *,
CORE_ADDR, struct ui_file *,
int, int, enum val_prettyprint,
Index: gdb/p-typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/p-typeprint.c,v
retrieving revision 1.15
diff -u -p -r1.15 p-typeprint.c
--- gdb/p-typeprint.c 17 Dec 2005 22:34:01 -0000 1.15
+++ gdb/p-typeprint.c 29 Dec 2006 00:13:26 -0000
@@ -1,5 +1,5 @@
/* Support for printing Pascal types for GDB, the GNU debugger.
- Copyright (C) 2000, 2001, 2002
+ Copyright (C) 2000, 2001, 2002, 2006
Free Software Foundation, Inc.

This file is part of GDB.
@@ -208,19 +208,6 @@ pascal_type_print_varspec_prefix (struct
pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
break; /* pointer should be handled normally in pascal */

- case TYPE_CODE_MEMBER:
- if (passed_a_ptr)
- fprintf_filtered (stream, "(");
- pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
- fprintf_filtered (stream, " ");
- name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
- if (name)
- fputs_filtered (name, stream);
- else
- pascal_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
- fprintf_filtered (stream, "::");
- break;
-
case TYPE_CODE_METHOD:
if (passed_a_ptr)
fprintf_filtered (stream, "(");
@@ -353,12 +340,6 @@ pascal_type_print_varspec_suffix (struct
fprintf_filtered (stream, ")");
break;

- case TYPE_CODE_MEMBER:
- if (passed_a_ptr)
- fprintf_filtered (stream, ")");
- pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
- break;
-
case TYPE_CODE_METHOD:
if (passed_a_ptr)
fprintf_filtered (stream, ")");
@@ -481,7 +462,6 @@ pascal_type_print_base (struct type *typ
{
case TYPE_CODE_TYPEDEF:
case TYPE_CODE_PTR:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_REF:
/* case TYPE_CODE_FUNC:
case TYPE_CODE_METHOD: */
Index: gdb/p-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/p-valprint.c,v
retrieving revision 1.44
diff -u -p -r1.44 p-valprint.c
--- gdb/p-valprint.c 5 Dec 2006 23:57:53 -0000 1.44
+++ gdb/p-valprint.c 29 Dec 2006 00:13:26 -0000
@@ -151,17 +151,6 @@ pascal_val_print (struct type *type, con
break;
}
elttype = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (elttype) == TYPE_CODE_METHOD)
- {
- pascal_object_print_class_method (valaddr + embedded_offset, type, stream);
- }
- else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
- {
- pascal_object_print_class_member (valaddr + embedded_offset,
- TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
- stream, "&");
- }
- else
{
addr = unpack_pointer (type, valaddr + embedded_offset);
print_unpacked_pointer:
@@ -259,19 +248,8 @@ pascal_val_print (struct type *type, con
}
break;

- case TYPE_CODE_MEMBER:
- error (_("not implemented: member type in pascal_val_print"));
- break;
-
case TYPE_CODE_REF:
elttype = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
- {
- pascal_object_print_class_member (valaddr + embedded_offset,
- TYPE_DOMAIN_TYPE (elttype),
- stream, "");
- break;
- }
if (addressprint)
{
fprintf_filtered (stream, "@");
@@ -604,96 +582,6 @@ static void pascal_object_print_value (s
int, int, enum val_prettyprint,
struct type **);

-void
-pascal_object_print_class_method (const gdb_byte *valaddr, struct type *type,
- struct ui_file *stream)
-{
- struct type *domain;
- struct fn_field *f = NULL;
- int j = 0;
- int len2;
- int offset;
- char *kind = "";
- CORE_ADDR addr;
- struct symbol *sym;
- unsigned len;
- unsigned int i;
- struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
-
- domain = TYPE_DOMAIN_TYPE (target_type);
- if (domain == (struct type *) NULL)
- {
- fprintf_filtered (stream, "<unknown>");
- return;
- }
- addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr);
- if (METHOD_PTR_IS_VIRTUAL (addr))
- {
- offset = METHOD_PTR_TO_VOFFSET (addr);
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- f = TYPE_FN_FIELDLIST1 (domain, i);
- len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
-
- check_stub_method_group (domain, i);
- for (j = 0; j < len2; j++)
- {
- if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
- {
- kind = "virtual ";
- goto common;
- }
- }
- }
- }
- else
- {
- sym = find_pc_function (addr);
- if (sym == 0)
- {
- error (_("invalid pointer to member function"));
- }
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- f = TYPE_FN_FIELDLIST1 (domain, i);
- len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
-
- check_stub_method_group (domain, i);
- for (j = 0; j < len2; j++)
- {
- if (DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
- goto common;
- }
- }
- }
-common:
- if (i < len)
- {
- char *demangled_name;
-
- fprintf_filtered (stream, "&");
- fputs_filtered (kind, stream);
- demangled_name = cplus_demangle (TYPE_FN_FIELD_PHYSNAME (f, j),
- DMGL_ANSI | DMGL_PARAMS);
- if (demangled_name == NULL)
- fprintf_filtered (stream, "<badly mangled name %s>",
- TYPE_FN_FIELD_PHYSNAME (f, j));
- else
- {
- fputs_filtered (demangled_name, stream);
- xfree (demangled_name);
- }
- }
- else
- {
- fprintf_filtered (stream, "(");
- type_print (type, "", stream, -1);
- fprintf_filtered (stream, ") %d", (int) addr >> 3);
- }
-}
-
/* It was changed to this after 2.4.5. */
const char pascal_vtbl_ptr_name[] =
{'_', '_', 'v', 't', 'b', 'l', '_', 'p', 't', 'r', '_', 't', 'y', 'p', 'e', 0};
@@ -1060,58 +948,6 @@ pascal_object_print_static_field (struct
common_val_print (val, stream, format, 0, recurse, pretty);
}

-void
-pascal_object_print_class_member (const gdb_byte *valaddr, struct type *domain,
- struct ui_file *stream, char *prefix)
-{
-
- /* VAL is a byte offset into the structure type DOMAIN.
- Find the name of the field for that offset and
- print it. */
- int extra = 0;
- int bits = 0;
- unsigned int i;
- unsigned len = TYPE_NFIELDS (domain);
- /* @@ Make VAL into bit offset */
- LONGEST val = unpack_long (builtin_type_int, valaddr) << 3;
- for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
- {
- int bitpos = TYPE_FIELD_BITPOS (domain, i);
- QUIT;
- if (val == bitpos)
- break;
- if (val < bitpos && i != 0)
- {
- /* Somehow pointing into a field. */
- i -= 1;
- extra = (val - TYPE_FIELD_BITPOS (domain, i));
- if (extra & 0x7)
- bits = 1;
- else
- extra >>= 3;
- break;
- }
- }
- if (i < len)
- {
- char *name;
- fputs_filtered (prefix, stream);
- name = type_name_no_tag (domain);
- if (name)
- fputs_filtered (name, stream);
- else
- pascal_type_print_base (domain, stream, 0, 0);
- fprintf_filtered (stream, "::");
- fputs_filtered (TYPE_FIELD_NAME (domain, i), stream);
- if (extra)
- fprintf_filtered (stream, " + %d bytes", extra);
- if (bits)
- fprintf_filtered (stream, " (offset in bits)");
- }
- else
- fprintf_filtered (stream, "%ld", (long int) (val >> 3));
-}
-
extern initialize_file_ftype _initialize_pascal_valprint; /* -Wmissing-prototypes */

void
Index: gdb/stabsread.c
===================================================================
RCS file: /cvs/src/src/gdb/stabsread.c,v
retrieving revision 1.84
diff -u -p -r1.84 stabsread.c
--- gdb/stabsread.c 17 Jan 2006 22:30:29 -0000 1.84
+++ gdb/stabsread.c 29 Dec 2006 00:13:26 -0000
@@ -1,7 +1,7 @@
/* Support routines for decoding "stabs" debugging information format.

Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.

This file is part of GDB.
@@ -1731,7 +1731,7 @@ again:

memtype = read_type (pp, objfile);
type = dbx_alloc_type (typenums, objfile);
- smash_to_member_type (type, domain, memtype);
+ smash_to_memberptr_type (type, domain, memtype);
}
else
/* type attribute */
Index: gdb/typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/typeprint.c,v
retrieving revision 1.26
diff -u -p -r1.26 typeprint.c
--- gdb/typeprint.c 18 Feb 2006 20:47:54 -0000 1.26
+++ gdb/typeprint.c 29 Dec 2006 00:13:26 -0000
@@ -1,7 +1,7 @@
/* Language independent support for printing types for GDB, the GNU debugger.

Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1998,
- 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2003, 2006 Free Software Foundation, Inc.

This file is part of GDB.

@@ -257,7 +257,8 @@ print_type_scalar (struct type *type, LO
case TYPE_CODE_SET:
case TYPE_CODE_STRING:
case TYPE_CODE_ERROR:
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
+ case TYPE_CODE_METHODPTR:
case TYPE_CODE_METHOD:
case TYPE_CODE_REF:
case TYPE_CODE_NAMESPACE:
Index: gdb/valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.165
diff -u -p -r1.165 valops.c
--- gdb/valops.c 9 Oct 2006 19:28:14 -0000 1.165
+++ gdb/valops.c 29 Dec 2006 00:13:26 -0000
@@ -1,7 +1,8 @@
/* Perform non-arithmetic operations on values, for GDB.

Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006
Free Software Foundation, Inc.

This file is part of GDB.
@@ -97,14 +98,15 @@ static struct value *value_struct_elt_fo
struct type *curtype,
char *name,
struct type *intype,
+ int want_address,
enum noside noside);

static struct value *value_namespace_elt (const struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside);

static struct value *value_maybe_namespace_elt (const struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside);

static CORE_ADDR allocate_space_in_inferior (int);
@@ -259,6 +261,7 @@ value_cast_pointers (struct type *type,
}

/* No superclass found, just change the pointer type. */
+ arg2 = value_copy (arg2);
deprecated_set_value_type (arg2, type);
arg2 = value_change_enclosing_type (arg2, type);
set_value_pointed_to_offset (arg2, 0); /* pai: chk_val */
@@ -366,33 +369,24 @@ value_cast (struct type *type, struct va
return value_from_double (type, value_as_double (arg2));
else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM
|| code1 == TYPE_CODE_RANGE)
- && (scalar || code2 == TYPE_CODE_PTR))
+ && (scalar || code2 == TYPE_CODE_PTR
+ || code2 == TYPE_CODE_MEMBERPTR))
{
LONGEST longest;

- if (deprecated_hp_som_som_object_present /* if target compiled by HP aCC */
- && (code2 == TYPE_CODE_PTR))
+ /* If target compiled by HP aCC. */
+ if (deprecated_hp_som_som_object_present
+ && code2 == TYPE_CODE_MEMBERPTR)
{
unsigned int *ptr;
struct value *retvalp;

- switch (TYPE_CODE (TYPE_TARGET_TYPE (type2)))
- {
- /* With HP aCC, pointers to data members have a bias */
- case TYPE_CODE_MEMBER:
- retvalp = value_from_longest (type, value_as_long (arg2));
- /* force evaluation */
- ptr = (unsigned int *) value_contents (retvalp);
- *ptr &= ~0x20000000; /* zap 29th bit to remove bias */
- return retvalp;
-
- /* While pointers to methods don't really point to a function */
- case TYPE_CODE_METHOD:
- error (_("Pointers to methods not supported with HP aCC"));
-
- default:
- break; /* fall out and go to normal handling */
- }
+ /* With HP aCC, pointers to data members have a bias. */
+ retvalp = value_from_longest (type, value_as_long (arg2));
+ /* force evaluation */
+ ptr = (unsigned int *) value_contents (retvalp);
+ *ptr &= ~0x20000000; /* zap 29th bit to remove bias */
+ return retvalp;
}

/* When we cast pointers to integers, we mustn't use
@@ -434,11 +428,26 @@ value_cast (struct type *type, struct va
}
return value_from_longest (type, longest);
}
+ else if (code1 == TYPE_CODE_METHODPTR && code2 == TYPE_CODE_INT
+ && value_as_long (arg2) == 0)
+ {
+ struct value *result = allocate_value (type);
+ cplus_make_method_ptr (value_contents_writeable (result), 0, 0);
+ return result;
+ }
+ else if (code1 == TYPE_CODE_MEMBERPTR && code2 == TYPE_CODE_INT
+ && value_as_long (arg2) == 0)
+ {
+ /* The Itanium C++ ABI represents NULL pointers to members as
+ minus one, instead of biasing the normal case. */
+ return value_from_longest (type, -1);
+ }
else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2))
{
if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
return value_cast_pointers (type, arg2);

+ arg2 = value_copy (arg2);
deprecated_set_value_type (arg2, type);
arg2 = value_change_enclosing_type (arg2, type);
set_value_pointed_to_offset (arg2, 0); /* pai: chk_val */
@@ -940,9 +949,6 @@ value_ind (struct value *arg1)

base_type = check_typedef (value_type (arg1));

- if (TYPE_CODE (base_type) == TYPE_CODE_MEMBER)
- error (_("not implemented: member types in value_ind"));
-
/* Allow * on an integer so we can cast it to whatever we want.
This returns an int, which seems like the most C-like thing
to do. "long long" variables are rare enough that
@@ -957,9 +963,17 @@ value_ind (struct value *arg1)
/* Get the real type of the enclosing object */
enc_type = check_typedef (value_enclosing_type (arg1));
enc_type = TYPE_TARGET_TYPE (enc_type);
- /* Retrieve the enclosing object pointed to */
- arg2 = value_at_lazy (enc_type, (value_as_address (arg1)
- - value_pointed_to_offset (arg1)));
+
+ if (TYPE_CODE (check_typedef (enc_type)) == TYPE_CODE_FUNC
+ || TYPE_CODE (check_typedef (enc_type)) == TYPE_CODE_METHOD)
+ /* For functions, go through find_function_addr, which knows
+ how to handle function descriptors. */
+ arg2 = value_at_lazy (enc_type, find_function_addr (arg1, NULL));
+ else
+ /* Retrieve the enclosing object pointed to */
+ arg2 = value_at_lazy (enc_type, (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 */
@@ -1599,9 +1613,6 @@ value_struct_elt (struct value **argp, s
t = check_typedef (value_type (*argp));
}

- if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
- error (_("not implemented: member type in value_struct_elt"));
-
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
error (_("Attempt to extract a component of a value that is not a %s."), err);
@@ -1798,9 +1809,6 @@ value_find_oload_method_list (struct val
t = check_typedef (value_type (*argp));
}

- if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
- error (_("Not implemented: member type in value_find_oload_lis"));
-
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
error (_("Attempt to extract a component of a value that is not a struct or union"));
@@ -2334,9 +2342,6 @@ check_field (struct value *arg1, const c
t = TYPE_TARGET_TYPE (t);
}

- if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
- error (_("not implemented: member type in check_field"));
-
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
error (_("Internal error: `this' is not an aggregate"));
@@ -2345,14 +2350,14 @@ check_field (struct value *arg1, const c
}

/* C++: Given an aggregate type CURTYPE, and a member name NAME,
- return the appropriate member. This function is used to resolve
- user expressions of the form "DOMAIN::NAME". For more details on
- what happens, see the comment before
- value_struct_elt_for_reference. */
+ return the appropriate member (or the address of the member, if
+ WANT_ADDRESS). This function is used to resolve user expressions
+ of the form "DOMAIN::NAME". For more details on what happens, see
+ the comment before value_struct_elt_for_reference. */

struct value *
value_aggregate_elt (struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside)
{
switch (TYPE_CODE (curtype))
@@ -2360,9 +2365,9 @@ value_aggregate_elt (struct type *curtyp
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
return value_struct_elt_for_reference (curtype, 0, curtype, name, NULL,
- noside);
+ want_address, noside);
case TYPE_CODE_NAMESPACE:
- return value_namespace_elt (curtype, name, noside);
+ return value_namespace_elt (curtype, name, want_address, noside);
default:
internal_error (__FILE__, __LINE__,
_("non-aggregate type in value_aggregate_elt"));
@@ -2379,12 +2384,12 @@ value_aggregate_elt (struct type *curtyp
static struct value *
value_struct_elt_for_reference (struct type *domain, int offset,
struct type *curtype, char *name,
- struct type *intype,
+ struct type *intype, int want_address,
enum noside noside)
{
struct type *t = curtype;
int i;
- struct value *v;
+ struct value *v, *result;

if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
@@ -2402,15 +2407,21 @@ value_struct_elt_for_reference (struct t
if (v == NULL)
error (_("static field %s has been optimized out"),
name);
+ if (want_address)
+ v = value_addr (v);
return v;
}
if (TYPE_FIELD_PACKED (t, i))
error (_("pointers to bitfield members not allowed"));

- return value_from_longest
- (lookup_reference_type (lookup_member_type (TYPE_FIELD_TYPE (t, i),
- domain)),
- offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+ if (want_address)
+ return value_from_longest
+ (lookup_memberptr_type (TYPE_FIELD_TYPE (t, i), domain),
+ offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_value (TYPE_FIELD_TYPE (t, i));
+ else
+ error (_("Cannot reference non-static field \"%s\""), name);
}
}

@@ -2461,33 +2472,52 @@ value_struct_elt_for_reference (struct t
else
j = 0;

+ if (TYPE_FN_FIELD_STATIC_P (f, j))
+ {
+ struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+ 0, VAR_DOMAIN, 0, NULL);
+ if (s == NULL)
+ return NULL;
+
+ if (want_address)
+ return value_addr (read_var_value (s, 0));
+ else
+ return read_var_value (s, 0);
+ }
+
if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
{
- return value_from_longest
- (lookup_reference_type
- (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
- domain)),
- (LONGEST) METHOD_PTR_FROM_VOFFSET (TYPE_FN_FIELD_VOFFSET (f, j)));
+ if (want_address)
+ {
+ result = allocate_value
+ (lookup_methodptr_type (TYPE_FN_FIELD_TYPE (f, j)));
+ cplus_make_method_ptr (value_contents_writeable (result),
+ TYPE_FN_FIELD_VOFFSET (f, j), 1);
+ }
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_value (TYPE_FN_FIELD_TYPE (f, j));
+ else
+ error (_("Cannot reference virtual member function \"%s\""),
+ name);
}
else
{
struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
0, VAR_DOMAIN, 0, NULL);
if (s == NULL)
- {
- v = 0;
- }
+ return NULL;
+
+ v = read_var_value (s, 0);
+ if (!want_address)
+ result = v;
else
{
- v = read_var_value (s, 0);
-#if 0
- VALUE_TYPE (v) = lookup_reference_type
- (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
- domain));
-#endif
+ result = allocate_value (lookup_methodptr_type (TYPE_FN_FIELD_TYPE (f, j)));
+ cplus_make_method_ptr (value_contents_writeable (result),
+ VALUE_ADDRESS (v), 0);
}
- return v;
}
+ return result;
}
}
for (i = TYPE_N_BASECLASSES (t) - 1; i >= 0; i--)
@@ -2503,7 +2533,7 @@ value_struct_elt_for_reference (struct t
offset + base_offset,
TYPE_BASECLASS (t, i),
name,
- intype,
+ intype, want_address,
noside);
if (v)
return v;
@@ -2513,7 +2543,7 @@ value_struct_elt_for_reference (struct t
it up that way; this (frequently) works for types nested inside
classes. */

- return value_maybe_namespace_elt (curtype, name, noside);
+ return value_maybe_namespace_elt (curtype, name, want_address, noside);
}

/* C++: Return the member NAME of the namespace given by the type
@@ -2521,11 +2551,11 @@ value_struct_elt_for_reference (struct t

static struct value *
value_namespace_elt (const struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside)
{
struct value *retval = value_maybe_namespace_elt (curtype, name,
- noside);
+ want_address, noside);

if (retval == NULL)
error (_("No symbol \"%s\" in namespace \"%s\"."), name,
@@ -2542,11 +2572,12 @@ value_namespace_elt (const struct type *

static struct value *
value_maybe_namespace_elt (const struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside)
{
const char *namespace_name = TYPE_TAG_NAME (curtype);
struct symbol *sym;
+ struct value *result;

sym = cp_lookup_symbol_namespace (namespace_name, name, NULL,
get_selected_block (0), VAR_DOMAIN,
@@ -2556,9 +2587,14 @@ value_maybe_namespace_elt (const struct
return NULL;
else if ((noside == EVAL_AVOID_SIDE_EFFECTS)
&& (SYMBOL_CLASS (sym) == LOC_TYPEDEF))
- return allocate_value (SYMBOL_TYPE (sym));
+ result = allocate_value (SYMBOL_TYPE (sym));
else
- return value_of_variable (sym, get_selected_block (0));
+ result = value_of_variable (sym, get_selected_block (0));
+
+ if (result && want_address)
+ result = value_addr (result);
+
+ return result;
}

/* Given a pointer value V, find the real (RTTI) type
Index: gdb/value.c
===================================================================
RCS file: /cvs/src/src/gdb/value.c,v
retrieving revision 1.37
diff -u -p -r1.37 value.c
--- gdb/value.c 13 Dec 2006 22:36:48 -0000 1.37
+++ gdb/value.c 29 Dec 2006 00:13:27 -0000
@@ -1090,6 +1090,7 @@ unpack_long (struct type *type, const gd
case TYPE_CODE_INT:
case TYPE_CODE_CHAR:
case TYPE_CODE_RANGE:
+ case TYPE_CODE_MEMBERPTR:
if (nosign)
return extract_unsigned_integer (valaddr, len);
else
@@ -1104,9 +1105,6 @@ unpack_long (struct type *type, const gd
whether we want this to be true eventually. */
return extract_typed_address (valaddr, type);

- case TYPE_CODE_MEMBER:
- error (_("not implemented: member types in unpack_long"));
-
default:
error (_("Value can't be converted to integer."));
}
@@ -1537,6 +1535,7 @@ retry:
case TYPE_CODE_FLAGS:
case TYPE_CODE_BOOL:
case TYPE_CODE_RANGE:
+ case TYPE_CODE_MEMBERPTR:
store_signed_integer (value_contents_raw (val), len, num);
break;

Index: gdb/value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.93
diff -u -p -r1.93 value.h
--- gdb/value.h 22 Nov 2006 13:44:45 -0000 1.93
+++ gdb/value.h 29 Dec 2006 00:13:27 -0000
@@ -1,7 +1,8 @@
/* Definitions for values of C expressions, for GDB.

Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006
Free Software Foundation, Inc.

This file is part of GDB.
@@ -345,7 +346,9 @@ extern struct value *value_struct_elt (s
char *err);

extern struct value *value_aggregate_elt (struct type *curtype,
- char *name, enum noside noside);
+ char *name,
+ int want_address,
+ enum noside noside);

extern struct value *value_static_field (struct type *type, int fieldno);

Index: gdb/varobj.c
===================================================================
RCS file: /cvs/src/src/gdb/varobj.c,v
retrieving revision 1.65
diff -u -p -r1.65 varobj.c
--- gdb/varobj.c 8 Dec 2006 22:06:04 -0000 1.65
+++ gdb/varobj.c 29 Dec 2006 00:13:27 -0000
@@ -2099,7 +2099,6 @@ c_variable_editable (struct varobj *var)
case TYPE_CODE_UNION:
case TYPE_CODE_ARRAY:
case TYPE_CODE_FUNC:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_METHOD:
return 0;
break;
Index: gdb/testsuite/gdb.cp/classes.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/classes.exp,v
retrieving revision 1.14
diff -u -p -r1.14 classes.exp
--- gdb/testsuite/gdb.cp/classes.exp 10 Aug 2006 05:27:20 -0000 1.14
+++ gdb/testsuite/gdb.cp/classes.exp 29 Dec 2006 00:13:27 -0000
@@ -1,5 +1,5 @@
# Copyright 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004 Free Software Foundation, Inc.
+# 2003, 2004, 2006 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
@@ -498,11 +498,14 @@ proc test_enums {} {
# Pointers to class members

proc test_pointers_to_class_members {} {
- gdb_test "print Bar::z" "\\$\[0-9\]+ = \\(int ?\\( ?Bar::& ?\\) ?\\) ?Bar::z"
- gdb_test "print &Foo::x" "\\$\[0-9\]+ = \\(int ?\\( ?Foo::\\* ?\\) ?\\) ?&Foo::x"
+ gdb_test "print Bar::z" "Cannot reference non-static field \"z\""
+ gdb_test "print &Foo::x" "\\$\[0-9\]+ = &Foo::x"
gdb_test "print (int)&Foo::x" "\\$\[0-9\]+ = 0"
gdb_test "print (int)&Bar::y == 2*sizeof(int)" "\\$\[0-9\]+ = true"

+ gdb_test "ptype Bar::z" "type = int"
+ gdb_test "ptype &Bar::z" "type = int Bar::\\*"
+
# TODO: this is a bogus test. It's looking at a variable that
# has not even been declared yet, so it's accessing random junk
# on the stack and comparing that it's NOT equal to a specific
Index: gdb/testsuite/gdb.cp/inherit.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/inherit.exp,v
retrieving revision 1.9
diff -u -p -r1.9 inherit.exp
--- gdb/testsuite/gdb.cp/inherit.exp 10 Aug 2006 05:27:20 -0000 1.9
+++ gdb/testsuite/gdb.cp/inherit.exp 29 Dec 2006 00:13:27 -0000
@@ -389,29 +389,19 @@ proc test_print_mi_member_types {} {
# Print the types of qualified members; none of these tests pass today.

# Print all members of g_A.
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_A.A::a" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_A.A::x" "type = int"

# Print all members of g_B.
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_B.A::a" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_B.A::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_B.B::b" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_B.B::x" "type = int"

# Print all members of g_C.
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_C.A::a" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_C.A::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_C.C::c" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_C.C::x" "type = int"

# Print all members of g_D.
@@ -423,9 +413,6 @@ proc test_print_mi_member_types {} {

set name "ptype g_D.A::a"
gdb_test_multiple "ptype g_D.A::a" $name {
- -re "Attempt to take address of non-lval$nl$gdb_prompt $" {
- kfail "gdb/2092" "$name"
- }
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_D.A::a"
}
@@ -433,25 +420,16 @@ proc test_print_mi_member_types {} {

set name "ptype g_D.A::x"
gdb_test_multiple "ptype g_D.A::x" $name {
- -re "Attempt to take address of non-lval$nl$gdb_prompt $" {
- kfail "gdb/2092" "$name"
- }
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_D.A::x"
}
}

- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.B::b" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.B::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.C::c" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.C::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.D::d" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.D::x" "type = int"

# Print all members of g_E.
@@ -459,9 +437,6 @@ proc test_print_mi_member_types {} {

set name "ptype g_E.A::a"
gdb_test_multiple "ptype g_E.A::a" $name {
- -re "Attempt to take address of non-lval$nl$gdb_prompt $" {
- kfail "gdb/2092" "$name"
- }
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_E.A::a"
}
@@ -469,29 +444,18 @@ proc test_print_mi_member_types {} {

set name "ptype g_E.A::x"
gdb_test_multiple "ptype g_E.A::x" $name {
- -re "Attempt to take address of non-lval$nl$gdb_prompt $" {
- kfail "gdb/2092" "$name"
- }
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_E.A::x"
}
}

- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.B::b" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.B::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.C::c" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.C::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.D::d" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.D::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.E::e" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.E::x" "type = int"
}

Index: gdb/testsuite/gdb.cp/member-ptr.cc
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/member-ptr.cc,v
retrieving revision 1.3
diff -u -p -r1.3 member-ptr.cc
--- gdb/testsuite/gdb.cp/member-ptr.cc 11 Feb 2004 14:01:25 -0000 1.3
+++ gdb/testsuite/gdb.cp/member-ptr.cc 29 Dec 2006 00:13:27 -0000
@@ -1,6 +1,6 @@
/* This testcase is part of GDB, the GNU debugger.

- Copyright 1998, 1999, 2004 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2004, 2006 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
@@ -81,6 +81,69 @@ typedef int (A::*PMF)(int);

typedef int A::*PMI;

+/* This class is in front of the other base classes of Diamond, so
+ that we can detect if the offset for Left or the first Base is
+ added twice - otherwise it would be 2 * 0 == 0. */
+class Padding
+{
+ int spacer;
+ virtual int vspacer();
+};
+
+int Padding::vspacer()
+{
+ return this->spacer;
+}
+
+class Base
+{
+public:
+ int x;
+ int get_x();
+ virtual int vget_base ();
+};
+
+int Base::get_x ()
+{
+ return this->x;
+}
+
+int Base::vget_base ()
+{
+ return this->x + 1000;
+}
+
+class Left : public Base {
+public:
+ virtual int vget ();
+};
+
+int Left::vget ()
+{
+ return this->x + 100;
+}
+
+class Right : public Base {
+public:
+ virtual int vget ();
+};
+
+int Right::vget ()
+{
+ return this->x + 200;
+}
+
+class Diamond : public Padding, public Left, public Right
+{
+public:
+ virtual int vget_base ();
+};
+
+int Diamond::vget_base ()
+{
+ return this->Left::x + 2000;
+}
+
int main ()
{
A a;
@@ -90,6 +153,18 @@ int main ()
PMF * pmf_p;
PMI pmi;

+ Diamond diamond;
+ int (Diamond::*left_pmf) ();
+ int (Diamond::*right_pmf) ();
+ int (Diamond::*left_vpmf) ();
+ int (Diamond::*left_base_vpmf) ();
+ int (Diamond::*right_vpmf) ();
+ int (Base::*base_vpmf) ();
+ int Diamond::*diamond_pmi;
+
+ PMI null_pmi;
+ PMF null_pmf;
+
a.j = 121;
a.jj = 1331;

@@ -101,8 +176,27 @@ int main ()
pmf = &A::bar;
pmf_p = &pmf;

- pmi = NULL;
-
+ diamond.Left::x = 77;
+ diamond.Right::x = 88;
+
+ /* Some valid pointer to members from a base class. */
+ left_pmf = (int (Diamond::*) ()) (int (Left::*) ()) (&Base::get_x);
+ right_pmf = (int (Diamond::*) ()) (int (Right::*) ()) (&Base::get_x);
+ left_vpmf = &Left::vget;
+ left_base_vpmf = (int (Diamond::*) ()) (int (Left::*) ()) (&Base::vget_base);
+ right_vpmf = &Right::vget;
+
+ /* An unspecified, value preserving pointer to member cast. */
+ base_vpmf = (int (Base::*) ()) (int (Left::*) ()) &Diamond::vget_base;
+
+ /* A pointer to data member from a base class. */
+ diamond_pmi = (int Diamond::*) (int Left::*) &Base::x;
+
+ null_pmi = NULL;
+ null_pmf = NULL;
+
+ pmi = NULL; /* Breakpoint 1 here. */
+
k = (a.*pmf)(3);

pmi = &A::jj;
Index: gdb/testsuite/gdb.cp/member-ptr.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/member-ptr.exp,v
retrieving revision 1.5
diff -u -p -r1.5 member-ptr.exp
--- gdb/testsuite/gdb.cp/member-ptr.exp 10 Aug 2006 05:27:20 -0000 1.5
+++ gdb/testsuite/gdb.cp/member-ptr.exp 29 Dec 2006 00:13:27 -0000
@@ -1,4 +1,4 @@
-# Copyright 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
+# Copyright 1998, 1999, 2003, 2004, 2006 Free Software Foundation, Inc.

# This file is part of the gdb testsuite

@@ -20,8 +20,6 @@
# Written by Satish Pai <pai@apollo.hp.com> 1997-08-19
# Rewritten by Michael Chastain <mec.gnu@mindspring.com> 2004-01-11

-# TODO: copyright notice for member-ptr.cc
-
set vhn "\\$\[0-9\]+"

if $tracelevel then {
@@ -56,16 +54,9 @@ if ![runto_main] then {
continue
}

-gdb_breakpoint [gdb_get_line_number "pmi = NULL"]
+gdb_breakpoint [gdb_get_line_number "Breakpoint 1 here"]
gdb_continue_to_breakpoint "continue to pmi = NULL"

-# gcc is not ready for production
-# -- chastain 2004-01-12
-
-if { [test_compiler_info "gcc-*"] } {
- continue
-}
-
# ======================
# pointer to member data
# ======================
@@ -74,14 +65,9 @@ if { [test_compiler_info "gcc-*"] } {

set name "ptype pmi (A::j)"
gdb_test_multiple "ptype pmi" $name {
- -re "type = int *\\( ?A::\\*\\)\r\n$gdb_prompt $" {
+ -re "type = int A::\\*\r\n$gdb_prompt $" {
pass $name
}
- -re "type = int *A::\r\n$gdb_prompt $" {
- # gcc HEAD 2004-01-10 -gdwarf-2
- # gcc HEAD 2004-01-10 -gstabs+
- kfail "gdb/NNNN" $name
- }
}

# print pointer to data member
@@ -390,7 +376,7 @@ gdb_test_multiple "ptype *pmi" $name {

set name "print (int) pmi"
gdb_test_multiple "print (int) pmi" $name {
- -re "$vhn = (4|8)\r\n$gdb_prompt" {
+ -re "$vhn = (4|8|12)\r\n$gdb_prompt" {
pass $name
}
}
@@ -412,7 +398,7 @@ gdb_test_multiple "print ((int) pmi) ==

set name "ptype pmf"
gdb_test_multiple "ptype pmf" $name {
- -re "type = int \\( ?A::\\*\\)\\(int\\)\r\n$gdb_prompt $" {
+ -re "type = int \\( ?A::\\*\\)\\(A \\*, int\\)\r\n$gdb_prompt $" {
pass $name
}
-re "type = int \\( ?A::\\*\\)\\(void\\)\r\n$gdb_prompt $" {
@@ -434,7 +420,7 @@ gdb_test_multiple "ptype pmf" $name {

set name "print pmf"
gdb_test_multiple "print pmf" $name {
- -re "$vhn = &A::bar\r\n$gdb_prompt $" {
+ -re "$vhn = $hex <A::bar\\(int\\)>\r\n$gdb_prompt $" {
pass $name
}
-re "$vhn = .*not supported with HP aCC.*\r\n$gdb_prompt $" {
@@ -456,7 +442,7 @@ gdb_test_multiple "print pmf" $name {

set name "ptype pmf_p"
gdb_test_multiple "ptype pmf_p" $name {
- -re "type = int \\( ?A::\\*\\*\\)\\(int\\)\r\n$gdb_prompt $" {
+ -re "type = int \\( ?A::\\*\\*\\)\\(A \\*, int\\)\r\n$gdb_prompt $" {
pass $name
}
-re "type = int \\( ?A::\\*\\*\\)\\(void\\)\r\n$gdb_prompt $" {
@@ -498,7 +484,7 @@ gdb_test_multiple "print pmf_p" $name {

set name "print a.*pmf"
gdb_test_multiple "print a.*pmf" $name {
- -re "$vhn = \\(int \\(\\*\\)\\(int\\)\\) $hex <A::bar\\(int\\)>\r\n$gdb_prompt$ " {
+ -re "$vhn = {int \\(A \\*, int\\)} $hex <A::bar\\(int\\)>\r\n$gdb_prompt $" {
pass $name
}
-re "Pointers to methods not supported with HP aCC\r\n$gdb_prompt $" {
@@ -520,7 +506,7 @@ gdb_test_multiple "print a.*pmf" $name {

set name "print a_p->*pmf"
gdb_test_multiple "print a_p->*pmf" $name {
- -re "$vhn = \\(int \\(\\*\\)\\(int\\)\\) $hex <A::bar\\(int\\)>\r\n$gdb_prompt$ " {
+ -re "$vhn = {int \\(A \\*, int\\)} $hex <A::bar\\(int\\)>\r\n$gdb_prompt $" {
pass $name
}
-re "Pointers to methods not supported with HP aCC\r\n$gdb_prompt $" {
@@ -621,3 +607,56 @@ gdb_test_multiple "print (a.*pmf)(3)" $n
kfail "gdb/NNNN" $name
}
}
+
+# Print out a pointer to data member which requires looking into
+# a base class.
+gdb_test "print diamond_pmi" "$vhn = &Base::x"
+gdb_test "print diamond.*diamond_pmi" "$vhn = 77"
+
+# Examine some more complicated pmfs, which require adjusting "this"
+# and looking through virtual tables.
+
+# These two have a different object adjustment, but call the same method.
+gdb_test "print diamond.*left_pmf" \
+ "$vhn = {int \\(Diamond \\*\\)} $hex <Base::get_x\\((void|)\\)>"
+gdb_test "print diamond.*right_pmf" \
+ "$vhn = {int \\(Diamond \\*\\)} $hex <Base::get_x\\((void|)\\)>"
+
+gdb_test "print (diamond.*left_pmf) ()" "$vhn = 77"
+gdb_test "print (diamond.*right_pmf) ()" "$vhn = 88"
+
+# These two point to different methods, although they have the same
+# virtual table offsets.
+gdb_test "print diamond.*left_vpmf" \
+ "$vhn = {int \\(Diamond \\*\\)} $hex <Left::vget\\((void|)\\)>"
+gdb_test "print diamond.*right_vpmf" \
+ "$vhn = {int \\(Diamond \\*\\)} $hex <Right::vget\\((void|)\\)>"
+
+gdb_test "print (diamond.*left_vpmf) ()" "$vhn = 177"
+gdb_test "print (diamond.*left_base_vpmf) ()" "$vhn = 2077"
+gdb_test "print (diamond.*right_vpmf) ()" "$vhn = 288"
+
+# We should be able to figure out left_vpmf even without an object,
+# because it comes from a non-virtual base. The same for right_vpmf.
+gdb_test "print left_vpmf" "$vhn = &virtual Left::vget\\(\\)"
+gdb_test "print right_vpmf" "$vhn = &virtual Right::vget\\(\\)"
+
+# But we should gracefully fail to figure out base_vpmf, because
+# its runtime type is more derived than its static type. This
+# is a valid but unspecified cast (it is value preserving, i.e.
+# can be casted back to the correct type and used).
+gdb_test "print base_vpmf" \
+ "$vhn = &virtual table offset \[0-9\]*, this adjustment -\[0-9\]*"
+
+# Make sure we parse this correctly; it's invalid.
+gdb_test "print diamond.*left_vpmf ()" \
+ "Invalid data type for function to be called\\."
+
+# NULL pointer to member tests.
+gdb_test "print null_pmi" "$vhn = NULL"
+gdb_test "print null_pmi = &A::j" "$vhn = &A::j"
+gdb_test "print null_pmi = 0" "$vhn = NULL"
+
+gdb_test "print null_pmf" "$vhn = NULL"
+gdb_test "print null_pmf = &A::foo" "$vhn = $hex <A::foo ?\\(int\\)>"
+gdb_test "print null_pmf = 0" "$vhn = NULL"
Index: gdb/testsuite/gdb.cp/printmethod.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/printmethod.exp,v
retrieving revision 1.3
diff -u -p -r1.3 printmethod.exp
--- gdb/testsuite/gdb.cp/printmethod.exp 10 Aug 2006 05:27:20 -0000 1.3
+++ gdb/testsuite/gdb.cp/printmethod.exp 29 Dec 2006 00:13:27 -0000
@@ -1,4 +1,4 @@
-# Copyright 2002, 2003, 2005 Free Software Foundation, Inc.
+# Copyright 2002, 2003, 2005, 2006 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
@@ -63,8 +63,12 @@ gdb_continue_to_breakpoint "end of const

# The first of these is for PR gdb/653.

-gdb_test "print theA->virt" "\\$\[0-9\]* = &A::virt\\((void|)\\)" "print virtual method."
-gdb_test "print theA->nonvirt" "\\$\[0-9\]* = &A::nonvirt\\((void|)\\)" "print nonvirtual method."
+gdb_test "print theA->virt" \
+ "\\$\[0-9\]* = {void \\(A \\*\\)} $hex <A::virt\\((void|)\\)>" \
+ "print virtual method."
+gdb_test "print theA->nonvirt" \
+ "\\$\[0-9\]* = {void \\(A \\*\\)} $hex <A::nonvirt\\((void|)\\)>" \
+ "print nonvirtual method."

gdb_exit
return 0
Index: gdb/testsuite/gdb.cp/virtfunc.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/virtfunc.exp,v
retrieving revision 1.12
diff -u -p -r1.12 virtfunc.exp
--- gdb/testsuite/gdb.cp/virtfunc.exp 10 Aug 2006 05:27:20 -0000 1.12
+++ gdb/testsuite/gdb.cp/virtfunc.exp 29 Dec 2006 00:13:27 -0000
@@ -1,4 +1,5 @@
-# Copyright 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004
+# Copyright 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004,
+# 2006
# Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
@@ -217,6 +218,14 @@ proc test_virtual_calls {} {
-re "\\$\[0-9]+ = 102$nl$gdb_prompt $" {
pass "print pEe->D::vg()"
}
+ -re "\\$\[0-9]+ = 202$nl$gdb_prompt $" {
+ # To get this result, we have called pEe->*(&D::vg) ().
+ # That's how GDB interprets this, but it's wrong; in fact
+ # the explicit D:: means to bypass virtual function lookup,
+ # and call D::vg as if it were non-virtual. We still have
+ # to e.g. adjust "this", though.
+ kfail "gdb/1064" "print pEe->D::vg()"
+ }
-re "Attempt to take address of value not located in memory.$nl$gdb_prompt $" {
kfail "gdb/1064" "print pEe->D::vg()"
}
Index: gdb/NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.206
diff -u -p -r1.206 NEWS
--- gdb/NEWS 15 Dec 2006 23:57:35 -0000 1.206
+++ gdb/NEWS 29 Dec 2006 00:19:32 -0000
@@ -9,6 +9,8 @@ frequency signals (e.g. SIGALRM) via the
* GDB for MIPS targets now autodetects whether a remote target provides
32-bit or 64-bit register values.

+* Support for C++ member pointers has been improved.
+
* New commands

set mem inaccessible-by-default