[c++] Pointer to member overhaul

Daniel Jacobowitz drow@false.org
Fri Dec 29 02:55:00 GMT 2006


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



More information about the Gdb-patches mailing list