cp-tree.h (TYPE_PTRMEMFUNC_P): Use TYPE_PTRMEMFUNC_FLAG.
authorMark Mitchell <mark@codesourcery.com>
Tue, 23 Mar 1999 00:01:48 +0000 (00:01 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Tue, 23 Mar 1999 00:01:48 +0000 (00:01 +0000)
* cp-tree.h (TYPE_PTRMEMFUNC_P): Use TYPE_PTRMEMFUNC_FLAG.
Document internals of pointer-to-member-functions.
(DELTA2_FROM_PTRMEMFUNC): Make it call delta2_from_ptrmemfunc.
(PFN_FROM_PTRMEMFUNC): Similarly.
(build_type_conversion): Remove unused parameter.
(build_ptrmemfunc1): Declare.
(expand_ptrmemfunc_cst): New function.
(delta2_from_ptrmemfunc): Likewise.
(pfn_from_ptrmemfunc): Likewise.
* cvt.c (cp_convert_to_pointer): Remove unused parameter to
build_type_conversion.  Use TYPE_PTRMEM_P for readability.
(convert_to_reference): Remove unused parameter to
build_type_conversion.
(ocp_convert): Likewise.
(build_user_type_conversion): Likewise.
* error.c (dump_expr): Handle NULL pointer-to-member functions.
* expr.c (cplus_expand_expr): Handle PTRMEM_CSTs for functions.
* method.c (build_overload_value): Don't go splitting CONSTRUCTORs
open when handling pointer-to-member functions.
* pt.c (convert_nontype_argument): Clean up error messages.  Be
more stringent with pointers-to-members.
* typeck.c (build_ptrmemfunc1): Don't declare.  Make it global.
(build_unary_op): Tidy ever-so-slightly.
(build_conditional_expr): Remove extra parameter to
build_type_conversion.
(build_ptrmemfunc): Build PTRMEM_CSTs if we know what function
we're using.
(expand_ptrmemfunc_cst): Define.
(delta2_from_ptrmemfunc): Likewise.
(pfn_from_ptrmemfunc): Likewise.

From-SVN: r25913

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/error.c
gcc/cp/expr.c
gcc/cp/method.c
gcc/cp/pt.c
gcc/cp/typeck.c
gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C [new file with mode: 0644]

index 384e3e9..3dd84a8 100644 (file)
@@ -1,3 +1,36 @@
+1999-03-22  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (TYPE_PTRMEMFUNC_P): Use TYPE_PTRMEMFUNC_FLAG.
+       Document internals of pointer-to-member-functions.
+       (DELTA2_FROM_PTRMEMFUNC): Make it call delta2_from_ptrmemfunc.
+       (PFN_FROM_PTRMEMFUNC): Similarly.
+       (build_type_conversion): Remove unused parameter.
+       (build_ptrmemfunc1): Declare.
+       (expand_ptrmemfunc_cst): New function.
+       (delta2_from_ptrmemfunc): Likewise.
+       (pfn_from_ptrmemfunc): Likewise.
+       * cvt.c (cp_convert_to_pointer): Remove unused parameter to
+       build_type_conversion.  Use TYPE_PTRMEM_P for readability.
+       (convert_to_reference): Remove unused parameter to
+       build_type_conversion.
+       (ocp_convert): Likewise.
+       (build_user_type_conversion): Likewise.
+       * error.c (dump_expr): Handle NULL pointer-to-member functions.
+       * expr.c (cplus_expand_expr): Handle PTRMEM_CSTs for functions.
+       * method.c (build_overload_value): Don't go splitting CONSTRUCTORs
+       open when handling pointer-to-member functions.
+       * pt.c (convert_nontype_argument): Clean up error messages.  Be
+       more stringent with pointers-to-members.
+       * typeck.c (build_ptrmemfunc1): Don't declare.  Make it global.
+       (build_unary_op): Tidy ever-so-slightly.
+       (build_conditional_expr): Remove extra parameter to
+       build_type_conversion.
+       (build_ptrmemfunc): Build PTRMEM_CSTs if we know what function
+       we're using.
+       (expand_ptrmemfunc_cst): Define.
+       (delta2_from_ptrmemfunc): Likewise.
+       (pfn_from_ptrmemfunc): Likewise.
+       
 1999-03-19  Mark Mitchell  <mark@codesourcery.com>
 
        * init.c (build_member_call): Handle template-id expressions
index 551803b..59f3e30 100644 (file)
@@ -1682,8 +1682,63 @@ extern int flag_new_for_scope;
 
 /* Nonzero for _TYPE node means that this type is a pointer to member
    function type.  */
-#define TYPE_PTRMEMFUNC_P(NODE) (TREE_CODE(NODE) == RECORD_TYPE && TYPE_LANG_SPECIFIC(NODE)->type_flags.ptrmemfunc_flag)
-#define TYPE_PTRMEMFUNC_FLAG(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.ptrmemfunc_flag)
+#define TYPE_PTRMEMFUNC_P(NODE) \
+  (TREE_CODE(NODE) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (NODE))
+#define TYPE_PTRMEMFUNC_FLAG(NODE) \
+  (TYPE_LANG_SPECIFIC(NODE)->type_flags.ptrmemfunc_flag)
+
+/* A pointer-to-function member type looks like:
+
+   struct {
+     short __delta;
+     short __index;
+     union {
+       P __pfn;
+       short __delta2;
+     } __pfn_or_delta2;
+   };
+
+   where P is a POINTER_TYPE to a METHOD_TYPE appropriate for the
+   pointer to member.  The fields are used as follows:
+
+     If __INDEX is -1, then the function to call is non-virtual, and
+     is located at the address given by __PFN.
+
+     If __INDEX is zero, then this a NULL pointer-to-member.
+
+     Otherwise, the function to call is virtual.  Then, __DELTA2 gives
+     the offset from an instance of the object to the virtual function
+     table, and __INDEX - 1 is the index into the vtable to use to
+     find the function.
+
+     The value to use for the THIS parameter is the address of the
+     object plus __DELTA.
+
+   For example, given:
+
+     struct B1 {
+       int i;
+     };
+
+     struct B2 {
+       double d;
+       void f();
+     };
+
+     struct S : public B1, B2 {};
+
+   the pointer-to-member for `&S::f' looks like:
+
+     { 4, -1, { &f__2B2 } };
+
+   The `4' means that given an `S*' you have to add 4 bytes to get to
+   the address of the `B2*'.  Then, the -1 indicates that this is a
+   non-virtual function.  Of course, `&f__2B2' is the name of that
+   function.
+
+   (Of course, the exactl values may differ depending on the mangling
+   scheme, sizes of types, and such.).  */
+     
 /* Get the POINTER_TYPE to the METHOD_TYPE associated with this
    pointer to member function.  TYPE_PTRMEMFUNC_P _must_ be true,
    before using this macro.  */
@@ -1698,8 +1753,8 @@ extern int flag_new_for_scope;
 #define TYPE_GET_PTRMEMFUNC_TYPE(NODE) ((tree)TYPE_LANG_SPECIFIC(NODE))
 #define TYPE_SET_PTRMEMFUNC_TYPE(NODE, VALUE) (TYPE_LANG_SPECIFIC(NODE) = ((struct lang_type *)(void*)(VALUE)))
 /* These are to get the delta2 and pfn fields from a TYPE_PTRMEMFUNC_P.  */
-#define DELTA2_FROM_PTRMEMFUNC(NODE) (build_component_ref (build_component_ref ((NODE), pfn_or_delta2_identifier, NULL_TREE, 0), delta2_identifier, NULL_TREE, 0))
-#define PFN_FROM_PTRMEMFUNC(NODE) (build_component_ref (build_component_ref ((NODE), pfn_or_delta2_identifier, NULL_TREE, 0), pfn_identifier, NULL_TREE, 0))
+#define DELTA2_FROM_PTRMEMFUNC(NODE) delta2_from_ptrmemfunc ((NODE))
+#define PFN_FROM_PTRMEMFUNC(NODE) pfn_from_ptrmemfunc ((NODE))
 
 /* For a pointer-to-member constant `X::Y' this is the RECORD_TYPE for
    `X'.  */
@@ -2711,7 +2766,7 @@ extern tree ocp_convert                           PROTO((tree, tree, int, int));
 extern tree cp_convert                         PROTO((tree, tree));
 extern tree convert                            PROTO((tree, tree));
 extern tree convert_force                      PROTO((tree, tree, int));
-extern tree build_type_conversion              PROTO((enum tree_code, tree, tree, int));
+extern tree build_type_conversion              PROTO((tree, tree, int));
 extern tree build_expr_type_conversion         PROTO((int, tree, int));
 extern tree type_promotes_to                   PROTO((tree));
 extern tree perform_qualification_conversions   PROTO((tree, tree));
@@ -3417,6 +3472,10 @@ extern int cp_type_quals                        PROTO((tree));
 extern int cp_has_mutable_p                     PROTO((tree));
 extern int at_least_as_qualified_p              PROTO((tree, tree));
 extern int more_qualified_p                     PROTO((tree, tree));
+extern tree build_ptrmemfunc1                   PROTO((tree, tree, tree, tree, tree));
+extern void expand_ptrmemfunc_cst               PROTO((tree, tree *, tree *, tree *, tree *));
+extern tree delta2_from_ptrmemfunc              PROTO((tree));
+extern tree pfn_from_ptrmemfunc                 PROTO((tree));
 
 /* in typeck2.c */
 extern tree error_not_base_type                        PROTO((tree, tree));
index 9f29c65..72721ce 100644 (file)
@@ -85,7 +85,7 @@ cp_convert_to_pointer (type, expr)
          return error_mark_node;
        }
 
-      rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
+      rval = build_type_conversion (type, expr, 1);
       if (rval)
        {
          if (rval == error_mark_node)
@@ -177,9 +177,7 @@ cp_convert_to_pointer (type, expr)
            }
        }
 
-      if (TREE_CODE (type) == POINTER_TYPE
-         && TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
-         && TREE_CODE (TREE_TYPE (intype)) == OFFSET_TYPE)
+      if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
        {
          tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
          tree b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
@@ -432,7 +430,7 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
       /* Look for a user-defined conversion to lvalue that we can use.  */
 
       rval_as_conversion
-       = build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
+       = build_type_conversion (reftype, expr, 1);
 
       if (rval_as_conversion && rval_as_conversion != error_mark_node
          && real_lvalue_p (rval_as_conversion))
@@ -735,7 +733,7 @@ ocp_convert (type, expr, convtype, flags)
       if (IS_AGGR_TYPE (intype))
        {
          tree rval;
-         rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
+         rval = build_type_conversion (type, e, 1);
          if (rval)
            return rval;
          if (flags & LOOKUP_COMPLAIN)
@@ -762,7 +760,7 @@ ocp_convert (type, expr, convtype, flags)
       if (IS_AGGR_TYPE (TREE_TYPE (e)))
        {
          tree rval;
-         rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
+         rval = build_type_conversion (type, e, 1);
          if (rval)
            return rval;
          else
@@ -948,8 +946,7 @@ convert_force (type, expr, convtype)
    (jason 8/9/95)  */
 
 tree
-build_type_conversion (code, xtype, expr, for_sure)
-     enum tree_code code ATTRIBUTE_UNUSED;
+build_type_conversion (xtype, expr, for_sure)
      tree xtype, expr;
      int for_sure;
 {
index 7ca6409..90f0a36 100644 (file)
@@ -1621,8 +1621,17 @@ dump_expr (t, nop)
              dump_unary_op ("&", pfn, 0);
              break;
            }
-         if (TREE_CODE (idx) == INTEGER_CST
-             && TREE_INT_CST_HIGH (idx) == 0)
+         else if (TREE_CODE (idx) == INTEGER_CST
+                  && tree_int_cst_equal (idx, integer_zero_node))
+           {
+             /* A NULL pointer-to-member constant.  */
+             OB_PUTS ("((");
+             dump_type (TREE_TYPE (t), 0);
+             OB_PUTS (") 0)");
+             break;
+           }
+         else if (TREE_CODE (idx) == INTEGER_CST
+                  && TREE_INT_CST_HIGH (idx) == 0)
            {
              tree virtuals;
              unsigned HOST_WIDE_INT n;
index 3dc8eae..22dd075 100644 (file)
@@ -188,10 +188,16 @@ cplus_expand_expr (exp, target, tmode, modifier)
          }
        else
          {
-           /* We don't yet handle pointer-to-member functions this
-              way.  */
-           my_friendly_abort (0);
-           return 0;
+           tree delta;
+           tree idx;
+           tree pfn;
+           tree delta2;
+
+           expand_ptrmemfunc_cst (exp, &delta, &idx, &pfn, &delta2);
+
+           return expand_expr (build_ptrmemfunc1 (type, delta, idx,
+                                                  pfn, delta2),
+                               target, tmode, modifier);
          }
       }
 
index 096d662..ecfa82c 100644 (file)
@@ -739,9 +739,6 @@ build_overload_value (type, value, in_template)
       return;
     }
 
-  if (TYPE_PTRMEMFUNC_P (type))
-    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
-
   switch (TREE_CODE (type))
     {
     case INTEGER_TYPE:
@@ -818,46 +815,6 @@ build_overload_value (type, value, in_template)
        return;
       }
     case POINTER_TYPE:
-      if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
-         && TREE_CODE (value) != ADDR_EXPR)
-       {
-         if (TREE_CODE (value) == CONSTRUCTOR)
-           {
-             /* This is dangerous code, crack built up pointer to members.  */
-             tree args = CONSTRUCTOR_ELTS (value);
-             tree a1 = TREE_VALUE (args);
-             tree a2 = TREE_VALUE (TREE_CHAIN (args));
-             tree a3 = CONSTRUCTOR_ELTS (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))));
-             a3 = TREE_VALUE (a3);
-             STRIP_NOPS (a3);
-             if (TREE_CODE (a1) == INTEGER_CST
-                 && TREE_CODE (a2) == INTEGER_CST)
-               {
-                 build_overload_int (a1, in_template);
-                 OB_PUTC ('_');
-                 build_overload_int (a2, in_template);
-                 OB_PUTC ('_');
-                 if (TREE_CODE (a3) == ADDR_EXPR)
-                   {
-                     a3 = TREE_OPERAND (a3, 0);
-                     if (TREE_CODE (a3) == FUNCTION_DECL)
-                       {
-                         numeric_output_need_bar = 0;
-                         build_overload_identifier (DECL_ASSEMBLER_NAME (a3));
-                         return;
-                       }
-                   }
-                 else if (TREE_CODE (a3) == INTEGER_CST)
-                   {
-                     OB_PUTC ('i');
-                     build_overload_int (a3, in_template);
-                     return;
-                   }
-               }
-           }
-         sorry ("template instantiation with pointer to method that is too complex");
-         return;
-       }
       if (TREE_CODE (value) == INTEGER_CST)
        {
          build_overload_int (value, in_template);
@@ -893,6 +850,35 @@ build_overload_value (type, value, in_template)
        my_friendly_abort (71);
       break; /* not really needed */
 
+    case RECORD_TYPE:
+      {
+       tree delta;
+       tree idx;
+       tree pfn;
+       tree delta2;
+
+       my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0);
+       my_friendly_assert (TREE_CODE (value) == PTRMEM_CST, 0);
+
+       expand_ptrmemfunc_cst (value, &delta, &idx, &pfn, &delta2);
+       build_overload_int (delta, in_template);
+       OB_PUTC ('_');
+       build_overload_int (idx, in_template);
+       OB_PUTC ('_');
+       if (pfn)
+         {
+           numeric_output_need_bar = 0;
+           build_overload_identifier (DECL_ASSEMBLER_NAME
+                                      (PTRMEM_CST_MEMBER (value)));
+         }
+       else
+         {
+           OB_PUTC ('i');
+           build_overload_int (delta2, in_template);
+         }
+      }
+      break;
+      
     default:
       sorry ("conversion of %s as template parameter",
             tree_code_name [(int) TREE_CODE (type)]);
index 4e9c52f..38e317c 100644 (file)
@@ -2577,7 +2577,14 @@ convert_nontype_argument (type, expr)
        Check this first since if expr_type is the unknown_type_node
        we would otherwise complain below.  */
     ;
+  else if (TYPE_PTRMEM_P (expr_type)
+          || TYPE_PTRMEMFUNC_P (expr_type))
+    {
+      if (TREE_CODE (expr) != PTRMEM_CST)
+       goto bad_argument;
+    }
   else if (TYPE_PTR_P (expr_type)
+          || TYPE_PTRMEM_P (expr_type)
           || TREE_CODE (expr_type) == ARRAY_TYPE
           || TREE_CODE (type) == REFERENCE_TYPE
           /* If expr is the address of an overloaded function, we
@@ -2597,11 +2604,17 @@ convert_nontype_argument (type, expr)
            {
            bad_argument:
              cp_error ("`%E' is not a valid template argument", expr);
-             error ("it must be %s%s with external linkage",
-                    TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
-                    ? "a pointer to " : "",
-                    TREE_CODE (TREE_TYPE (TREE_TYPE (expr))) == FUNCTION_TYPE
-                    ? "a function" : "an object");
+             if (TYPE_PTR_P (expr_type))
+               {
+                 if (TREE_CODE (TREE_TYPE (expr_type)) == FUNCTION_TYPE)
+                   cp_error ("it must be the address of a function with external linkage");
+                 else
+                   cp_error ("it must be the address of an object with external linkage");
+               }
+             else if (TYPE_PTRMEM_P (expr_type)
+                      || TYPE_PTRMEMFUNC_P (expr_type))
+               cp_error ("it must be a pointer-to-member of the form `&X::Y'");
+
              return NULL_TREE;
            }
 
@@ -2829,7 +2842,7 @@ convert_nontype_argument (type, expr)
            expr_type != unknown_type_node)
          return error_mark_node;
 
-       if (TREE_CODE (expr) == CONSTRUCTOR)
+       if (TREE_CODE (expr) == PTRMEM_CST)
          {
            /* A ptr-to-member constant.  */
            if (!same_type_p (type, expr_type))
index cfd9319..c1aa214 100644 (file)
@@ -51,7 +51,6 @@ static int comp_ptr_ttypes_const PROTO((tree, tree));
 static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
 static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
                                   tree, int));
-static tree build_ptrmemfunc1 PROTO((tree, tree, tree, tree, tree));
 static tree common_base_type PROTO((tree, tree));
 #if 0
 static tree convert_sequence PROTO((tree, tree));
@@ -4705,7 +4704,7 @@ build_unary_op (code, xarg, noconvert)
            (arg, argtype,
             "attempt to take address of bit-field structure member `%s'");
        else
-         addr = build1 (code, argtype, arg);
+         addr = build1 (ADDR_EXPR, argtype, arg);
 
        /* Address of a static or external variable or
           function counts as a constant */
@@ -5247,7 +5246,7 @@ build_conditional_expr (ifexp, op1, op2)
                                          | TYPE_QUAL_RESTRICT));
          else
            tmp = type2;
-         tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0);
+         tmp = build_type_conversion (tmp, op1, 0);
          if (tmp == NULL_TREE)
            {
              cp_error ("incompatible types `%T' and `%T' in `?:'",
@@ -5273,7 +5272,7 @@ build_conditional_expr (ifexp, op1, op2)
          else
            tmp = type1;
 
-         tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0);
+         tmp = build_type_conversion (tmp, op2, 0);
          if (tmp == NULL_TREE)
            {
              cp_error ("incompatible types `%T' and `%T' in `?:'",
@@ -6352,7 +6351,7 @@ get_delta_difference (from, to, force)
   return BINFO_OFFSET (binfo);
 }
 
-static tree
+tree
 build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
      tree type, delta, idx, pfn, delta2;
 {
@@ -6444,9 +6443,9 @@ build_ptrmemfunc (type, pfn, force)
   tree idx = integer_zero_node;
   tree delta = integer_zero_node;
   tree delta2 = integer_zero_node;
-  tree vfield_offset;
   tree npfn = NULL_TREE;
-
+  tree fn;
+  
   /* Handle multiple conversions of pointer to member functions.  */
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
     {
@@ -6499,50 +6498,113 @@ build_ptrmemfunc (type, pfn, force)
   if (type_unknown_p (pfn))
     return instantiate_type (type, pfn, 1);
 
-  if (!force 
-      && comp_target_types (type, TREE_TYPE (pfn), 0) != 1)
-    cp_error ("conversion to `%T' from `%T'", type, TREE_TYPE (pfn));
-
-  /* Allow pointer to member conversions here.  */
-  delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
-                               TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
-                               force);
-  delta2 = build_binary_op (PLUS_EXPR, delta2, delta, 1);
+  fn = TREE_OPERAND (pfn, 0);
+  my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
+  npfn = make_node (PTRMEM_CST);
+  TREE_TYPE (npfn) = build_ptrmemfunc_type (type);
+  PTRMEM_CST_MEMBER (npfn) = fn;
+  return npfn;
+}
 
-  if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
-    warning ("assuming pointer to member function is non-virtual");
+/* Return the DELTA, IDX, PFN, and DELTA2 values for the PTRMEM_CST
+   given by CST.  */
 
-  if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL
-      && DECL_VINDEX (TREE_OPERAND (pfn, 0)))
-    {
-      /* Find the offset to the vfield pointer in the object.  */
-      vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)),
-                                DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)),
-                                0);
-      vfield_offset = get_vfield_offset (vfield_offset);
-      delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2);
+void
+expand_ptrmemfunc_cst (cst, delta, idx, pfn, delta2)
+     tree cst;
+     tree *delta;
+     tree *idx;
+     tree *pfn;
+     tree *delta2;
+{
+  tree type = TREE_TYPE (cst);
+  tree fn = PTRMEM_CST_MEMBER (cst);
 
-      /* Map everything down one to make room for the null pointer to member.  */
-      idx = size_binop (PLUS_EXPR,
-                       DECL_VINDEX (TREE_OPERAND (pfn, 0)),
-                       integer_one_node);
+  my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
+  
+  *delta 
+    = get_delta_difference (TYPE_METHOD_BASETYPE 
+                           (TREE_TYPE (fn)),
+                           TYPE_PTRMEMFUNC_OBJECT_TYPE (type),
+                           /*force=*/0);
+  if (!DECL_VIRTUAL_P (fn))
+    {
+      *idx = size_binop (MINUS_EXPR, integer_zero_node,
+                        integer_one_node);
+      *pfn = build_addr_func (fn);
+      if (!same_type_p (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)),
+                       TYPE_PTRMEMFUNC_OBJECT_TYPE (type)))
+       *pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type), 
+                      *pfn);
+      *delta2 = NULL_TREE;
     }
   else
     {
-      idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+      *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), 
+                        integer_one_node);
+      *pfn = NULL_TREE;
+      *delta2 = get_binfo (DECL_CONTEXT (fn),
+                         DECL_CLASS_CONTEXT (fn),
+                         0);
+      *delta2 = get_vfield_offset (*delta2);
+      *delta2 = size_binop (PLUS_EXPR, *delta2,
+                          build_binary_op (PLUS_EXPR,
+                                           *delta, 
+                                           integer_zero_node,
+                                           1));
+    }
+}
 
-      if (type == TREE_TYPE (pfn))
-       {
-         npfn = pfn;
-       }
-      else
-       {
-         npfn = build1 (NOP_EXPR, type, pfn);
-         TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
-       }
+/* Return an expression for DELTA2 from the pointer-to-member function
+   given by T.  */
+
+tree
+delta2_from_ptrmemfunc (t)
+     tree t;
+{
+  if (TREE_CODE (t) == PTRMEM_CST)
+    {
+      tree delta;
+      tree idx;
+      tree pfn;
+      tree delta2;
+      
+      expand_ptrmemfunc_cst (t, &delta, &idx, &pfn, &delta2);
+      if (delta2)
+       return delta2;
+    }
+
+  return (build_component_ref 
+         (build_component_ref (t,
+                               pfn_or_delta2_identifier, NULL_TREE,
+                               0), 
+          delta2_identifier, NULL_TREE, 0)); 
+}
+
+/* Return an expression for PFN from the pointer-to-member function
+   given by T.  */
+
+tree
+pfn_from_ptrmemfunc (t)
+     tree t;
+{
+  if (TREE_CODE (t) == PTRMEM_CST)
+    {
+      tree delta;
+      tree idx;
+      tree pfn;
+      tree delta2;
+      
+      expand_ptrmemfunc_cst (t, &delta, &idx, &pfn, &delta2);
+      if (pfn)
+       return pfn;
     }
 
-  return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2);
+  return (build_component_ref 
+         (build_component_ref (t,
+                               pfn_or_delta2_identifier, NULL_TREE,
+                               0), 
+          pfn_identifier, NULL_TREE, 0)); 
 }
 
 /* Convert value RHS to type TYPE as preparation for an assignment
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
new file mode 100644 (file)
index 0000000..946e624
--- /dev/null
@@ -0,0 +1,34 @@
+// Build don't link:
+
+class A {
+public:
+  virtual void f();
+  int i;
+};
+
+class B : public A {
+public:
+  void f();
+  int j;
+};
+
+template <void (A::*)() >
+void g() {}
+template <int A::*>
+void h() {}
+
+
+int main() {
+  g<&A::f>();
+  h<&A::i>();
+  g<&B::f>(); // ERROR - 
+  h<&B::j>(); // ERROR - 
+  g<(void (A::*)()) &A::f>(); // ERROR - XFAIL *-*-*
+  h<(int A::*) &A::i>(); // ERROR - 
+  g<(void (A::*)()) &B::f>(); // ERROR - 
+  h<(int A::*) &B::j>(); // ERROR - 
+  g<(void (A::*)()) 0>(); // ERROR - 
+  h<(int A::*) 0>(); // ERROR - 
+
+  return 0;
+}