* cp-tree.h (CPTI_VTABLE_INDEX_TYPE): New macro.
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 22 Feb 2000 02:30:54 +0000 (02:30 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 22 Feb 2000 02:30:54 +0000 (02:30 +0000)
(CPTI_CLASS_STAR_TYPE): Remove.
(vtable_index_type): Likewise.
(class_star_type_node): Remove.
(TYPE_PTRMEMFUNC_FN_TYPE): Adjust for the new ABI.
(build_binary_op_nodefault): Remove.
* call.c (build_new_op): Use build_binary_op instead of
build_binary_op_nodefault.
* decl.c (init_decl_processing): Remove class_star_type_node
initialization.  Make delta_type_node ptrdiff_type_node under the
new ABI.  Initialize vtable_index_type.
(build_ptrmemfunc_type): Build different structures for the new
ABI.
(build_enumerator): Use build_binary_op instead of
build_binary_op_nodefault.
* method.c (build_overload_value): Mangle pointers-to-members
appropriately under the new ABI.
* typeck.c (build_array_ref): Use build_binary_op instead of
build_binary_op_nodefault.
(get_member_function_from_ptrfunc): Adjust for the new ABI.
(build_binary_op_nodefault): Rename to ...
(build_binary_op): ... this.  Remove old version.  Adjust for
pointer-to-member comparisons under the new ABI.
(build_ptrmemfunc1): Remove dead code.  Adjust for the new ABI.
(build_ptrmemfunc): Adjust for the new ABI.
(expand_ptrmemfunc_cst): Likewise.
(delta2_from_ptrmemfunc): Assert that we're not using the new ABI.
(pfn_from_ptrmemfunc): Adjust for the new ABI.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32099 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/method.c
gcc/cp/typeck.c

index 045902c..346123d 100644 (file)
@@ -1,3 +1,34 @@
+2000-02-21  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (CPTI_VTABLE_INDEX_TYPE): New macro.
+       (CPTI_CLASS_STAR_TYPE): Remove.
+       (vtable_index_type): Likewise.
+       (class_star_type_node): Remove.
+       (TYPE_PTRMEMFUNC_FN_TYPE): Adjust for the new ABI.
+       (build_binary_op_nodefault): Remove.
+       * call.c (build_new_op): Use build_binary_op instead of
+       build_binary_op_nodefault.
+       * decl.c (init_decl_processing): Remove class_star_type_node
+       initialization.  Make delta_type_node ptrdiff_type_node under the
+       new ABI.  Initialize vtable_index_type.
+       (build_ptrmemfunc_type): Build different structures for the new
+       ABI.
+       (build_enumerator): Use build_binary_op instead of
+       build_binary_op_nodefault.
+       * method.c (build_overload_value): Mangle pointers-to-members
+       appropriately under the new ABI.
+       * typeck.c (build_array_ref): Use build_binary_op instead of
+       build_binary_op_nodefault.
+       (get_member_function_from_ptrfunc): Adjust for the new ABI.
+       (build_binary_op_nodefault): Rename to ...
+       (build_binary_op): ... this.  Remove old version.  Adjust for
+       pointer-to-member comparisons under the new ABI.
+       (build_ptrmemfunc1): Remove dead code.  Adjust for the new ABI.
+       (build_ptrmemfunc): Adjust for the new ABI.
+       (expand_ptrmemfunc_cst): Likewise.
+       (delta2_from_ptrmemfunc): Assert that we're not using the new ABI.
+       (pfn_from_ptrmemfunc): Adjust for the new ABI.
+       
 2000-02-21  Gabriel Dos Reis  <gdr@codesourcery.com>
 
        * call.c (build_object_call): Compress consecutive calls to
index e996b59..887e2df 100644 (file)
@@ -3407,7 +3407,7 @@ builtin:
     case BIT_XOR_EXPR:
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
-      return build_binary_op_nodefault (code, arg1, arg2, code);
+      return build_binary_op (code, arg1, arg2);
 
     case CONVERT_EXPR:
     case NEGATE_EXPR:
index 500937b..5337ed3 100644 (file)
@@ -517,6 +517,7 @@ enum cp_tree_index
     CPTI_WCHAR_DECL,
     CPTI_VTABLE_ENTRY_TYPE,
     CPTI_DELTA_TYPE,
+    CPTI_VTABLE_INDEX_TYPE,
     CPTI_CLEANUP_TYPE,
 
     CPTI_TI_DESC_TYPE,
@@ -532,7 +533,6 @@ enum cp_tree_index
     CPTI_PTMD_DESC_TYPE,
     CPTI_BASE_DESC_TYPE,
     
-    CPTI_CLASS_STAR_TYPE,
     CPTI_CLASS_TYPE,
     CPTI_RECORD_TYPE,
     CPTI_UNION_TYPE,
@@ -601,7 +601,12 @@ extern tree cp_global_trees[CPTI_MAX];
 #define void_zero_node                 cp_global_trees[CPTI_VOID_ZERO]
 #define wchar_decl_node                        cp_global_trees[CPTI_WCHAR_DECL]
 #define vtable_entry_type              cp_global_trees[CPTI_VTABLE_ENTRY_TYPE]
+/* The type used to represent an offset by which to adjust the `this'
+   pointer in pointer-to-member types and, when not using vtable
+   thunks, in vtables.  */
 #define delta_type_node                        cp_global_trees[CPTI_DELTA_TYPE]
+/* The type used to represent an index into the vtable.  */
+#define vtable_index_type               cp_global_trees[CPTI_VTABLE_INDEX_TYPE]
 
 #define ti_desc_type_node              cp_global_trees[CPTI_TI_DESC_TYPE]
 #define bltn_desc_type_node            cp_global_trees[CPTI_BLTN_DESC_TYPE]
@@ -616,7 +621,6 @@ extern tree cp_global_trees[CPTI_MAX];
 #define ptmd_desc_type_node            cp_global_trees[CPTI_PTMD_DESC_TYPE]
 #define base_desc_type_node            cp_global_trees[CPTI_BASE_DESC_TYPE]
 
-#define class_star_type_node           cp_global_trees[CPTI_CLASS_STAR_TYPE]
 #define class_type_node                        cp_global_trees[CPTI_CLASS_TYPE]
 #define record_type_node               cp_global_trees[CPTI_RECORD_TYPE]
 #define union_type_node                        cp_global_trees[CPTI_UNION_TYPE]
@@ -2498,12 +2502,27 @@ extern int flag_new_for_scope;
    function.
 
    (Of course, the exact values may differ depending on the mangling
-   scheme, sizes of types, and such.).  */
+   scheme, sizes of types, and such.).  
+
+   Under the new ABI, we do:
+
+     struct {
+       __P __pfn;
+       ptrdiff_t __delta;
+     };
+
+   (We don't need DELTA2, because the vtable is always the first thing
+   in the object.)  If the function is virtual, then PFN is one plus
+   twice the index into the vtable; otherwise, it is just a pointer to
+   the function.  */
      
 /* 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.  */
-#define TYPE_PTRMEMFUNC_FN_TYPE(NODE) (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (NODE)))))))
+#define TYPE_PTRMEMFUNC_FN_TYPE(NODE) \
+  (flag_new_abi                       \
+   ? (TREE_TYPE (TYPE_FIELDS (NODE))) \
+   : (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (NODE))))))))
 
 /* Returns `A' for a type like `int (A::*)(double)' */
 #define TYPE_PTRMEMFUNC_OBJECT_TYPE(NODE) \
@@ -4341,7 +4360,6 @@ extern tree build_function_call_maybe             PARAMS ((tree, tree));
 extern tree convert_arguments                  PARAMS ((tree, tree, tree, int));
 extern tree build_x_binary_op                  PARAMS ((enum tree_code, tree, tree));
 extern tree build_binary_op                    PARAMS ((enum tree_code, tree, tree));
-extern tree build_binary_op_nodefault          PARAMS ((enum tree_code, tree, tree, enum tree_code));
 extern tree build_x_unary_op                   PARAMS ((enum tree_code, tree));
 extern tree build_unary_op                     PARAMS ((enum tree_code, tree, int));
 extern tree unary_complex_lvalue               PARAMS ((enum tree_code, tree));
index 4551509..cb9ec29 100644 (file)
@@ -222,7 +222,6 @@ tree error_mark_list;
        tree __ptmf_desc_array_type, __ptmd_desc_array_type;
 #endif
 
-       tree class_star_type_node;
        tree class_type_node, record_type_node, union_type_node, enum_type_node;
        tree unknown_type_node;
 
@@ -6207,15 +6206,18 @@ init_decl_processing ()
   int_array_type_node
     = build_array_type (integer_type_node, array_domain_type);
 
-  /* This is just some anonymous class type.  Nobody should ever
-     need to look inside this envelope.  */
-  class_star_type_node = build_pointer_type (make_aggr_type (RECORD_TYPE));
-
-  if (flag_huge_objects)
+  if (flag_new_abi)
+    delta_type_node = ptrdiff_type_node;
+  else if (flag_huge_objects)
     delta_type_node = long_integer_type_node;
   else
     delta_type_node = short_integer_type_node;
 
+  if (flag_new_abi)
+    vtable_index_type = ptrdiff_type_node;
+  else
+    vtable_index_type = delta_type_node;
+
   default_function_type
     = build_function_type (integer_type_node, NULL_TREE);
 
@@ -8804,27 +8806,36 @@ build_ptrmemfunc_type (type)
     unqualified_variant
       = build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type));
 
-  u = make_aggr_type (UNION_TYPE);
-  SET_IS_AGGR_TYPE (u, 0);
-  fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
-  fields[1] = build_lang_decl (FIELD_DECL, delta2_identifier,
-                              delta_type_node);
-  finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node);
-  TYPE_NAME (u) = NULL_TREE;
-
   t = make_aggr_type (RECORD_TYPE);
-
   /* Let the front-end know this is a pointer to member function...  */
   TYPE_PTRMEMFUNC_FLAG (t) = 1;
   /* ... and not really an aggregate.  */
   SET_IS_AGGR_TYPE (t, 0);
 
-  fields[0] = build_lang_decl (FIELD_DECL, delta_identifier,
-                              delta_type_node);
-  fields[1] = build_lang_decl (FIELD_DECL, index_identifier,
-                              delta_type_node);
-  fields[2] = build_lang_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
-  finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
+  if (!flag_new_abi)
+    {
+      u = make_aggr_type (UNION_TYPE);
+      SET_IS_AGGR_TYPE (u, 0);
+      fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
+      fields[1] = build_lang_decl (FIELD_DECL, delta2_identifier,
+                                  delta_type_node);
+      finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node);
+      TYPE_NAME (u) = NULL_TREE;
+
+      fields[0] = build_lang_decl (FIELD_DECL, delta_identifier,
+                                  delta_type_node);
+      fields[1] = build_lang_decl (FIELD_DECL, index_identifier,
+                                  delta_type_node);
+      fields[2] = build_lang_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
+      finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
+    }
+  else
+    {
+      fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
+      fields[1] = build_lang_decl (FIELD_DECL, delta_identifier,
+                                  delta_type_node);
+      finish_builtin_type (t, "__ptrmemfunc_type", fields, 1, ptr_type_node);
+    }
 
   /* Zap out the name so that the back-end will give us the debugging
      information for this anonymous RECORD_TYPE.  */
@@ -12777,10 +12788,9 @@ build_enumerator (name, value, enumtype)
              /* The next value is the previous value ... */
              prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES (enumtype)));
              /* ... plus one.  */
-             value = build_binary_op_nodefault (PLUS_EXPR,
-                                                prev_value,
-                                                integer_one_node,
-                                                PLUS_EXPR);
+             value = build_binary_op (PLUS_EXPR,
+                                      prev_value,
+                                      integer_one_node);
 
              if (tree_int_cst_lt (value, prev_value))
                cp_error ("overflow in enumeration values at `%D'", name);
index b48e80e..6a12868 100644 (file)
@@ -851,6 +851,7 @@ build_overload_value (type, value, flags)
        tree idx;
        tree pfn;
        tree delta2;
+       tree fn;
 
        my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0);
 
@@ -872,17 +873,26 @@ build_overload_value (type, value, flags)
        my_friendly_assert (TREE_CODE (value) == PTRMEM_CST, 0);
 
        expand_ptrmemfunc_cst (value, &delta, &idx, &pfn, &delta2);
+       fn = PTRMEM_CST_MEMBER (value);
        build_overload_int (delta, flags);
        OB_PUTC ('_');
-       build_overload_int (idx, flags);
-       OB_PUTC ('_');
-       if (pfn)
+       if (!flag_new_abi)
+         {
+           build_overload_int (idx, flags);
+           OB_PUTC ('_');
+         }
+       else if (DECL_VIRTUAL_P (fn))
+         {
+           build_overload_int (DECL_VINDEX (fn), flags);
+           OB_PUTC ('_');
+         }
+
+       if (!DECL_VIRTUAL_P (fn))
          {
            numeric_output_need_bar = 0;
-           build_overload_identifier (DECL_ASSEMBLER_NAME
-                                      (PTRMEM_CST_MEMBER (value)));
+           build_overload_identifier (DECL_ASSEMBLER_NAME (fn));
          }
-       else
+       else if (!flag_new_abi)
          {
            OB_PUTC ('i');
            build_overload_int (delta2, flags);
index 8264ede..346eb83 100644 (file)
@@ -2509,8 +2509,7 @@ build_array_ref (array, idx)
        return error_mark_node;
       }
 
-    return build_indirect_ref (build_binary_op_nodefault (PLUS_EXPR, ar,
-                                                         ind, PLUS_EXPR),
+    return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, ind),
                               "array indexing");
   }
 }
@@ -2836,9 +2835,11 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
       basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
 
-      delta = cp_convert (ptrdiff_type_node,
-                         build_component_ref (function, delta_identifier,
-                                              NULL_TREE, 0));
+      /* Convert down to the right base, before using the instance.  */
+      instance = convert_pointer_to_real (basetype, instance_ptr);
+      if (instance == error_mark_node && instance_ptr != error_mark_node)
+       return instance;
+
       e3 = PFN_FROM_PTRMEMFUNC (function);
 
       /* This used to avoid checking for virtual functions if basetype
@@ -2853,27 +2854,42 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
         load-with-sign-extend, while the second used normal load then
         shift to sign-extend.  An optimizer flaw, perhaps, but it's
         easier to make this change.  */
-      idx = save_expr (default_conversion
+      if (flag_new_abi)
+       {
+         idx = build_binary_op (TRUNC_DIV_EXPR, 
+                                build1 (NOP_EXPR, vtable_index_type, e3),
+                                integer_two_node);
+         e1 = build_binary_op (BIT_AND_EXPR,
+                               build1 (NOP_EXPR, vtable_index_type, e3),
+                               integer_one_node);
+       }
+      else
+       {
+         idx = save_expr (default_conversion
                       (build_component_ref (function,
                                             index_identifier,
                                             NULL_TREE, 0)));
-      e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
-
-      /* Convert down to the right base, before using the instance.  */
-      instance = convert_pointer_to_real (basetype, instance_ptr);
-      if (instance == error_mark_node && instance_ptr != error_mark_node)
-       return instance;
+         e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
+         idx = build_binary_op (MINUS_EXPR, idx, integer_one_node);
+       }
 
       vtbl = convert_pointer_to (ptr_type_node, instance);
-      delta2 = DELTA2_FROM_PTRMEMFUNC (function);
+      delta = cp_convert (ptrdiff_type_node,
+                         build_component_ref (function, delta_identifier,
+                                              NULL_TREE, 0));
+      if (flag_new_abi)
+       /* DELTA2 is the amount by which to adjust the `this' pointer
+          to find the vtbl.  */
+       delta2 = delta;
+      else
+       delta2 = DELTA2_FROM_PTRMEMFUNC (function);
       vtbl = build
        (PLUS_EXPR,
         build_pointer_type (build_pointer_type (vtable_entry_type)),
         vtbl, cp_convert (ptrdiff_type_node, delta2));
       vtbl = build_indirect_ref (vtbl, NULL_PTR);
-      aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
-                                                    idx,
-                                                    integer_one_node));
+      aref = build_array_ref (vtbl, idx);
+
       if (! flag_vtable_thunks)
        {
          aref = save_expr (aref);
@@ -3237,14 +3253,6 @@ build_x_binary_op (code, arg1, arg2)
   return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
 }
 
-tree
-build_binary_op (code, arg1, arg2)
-     enum tree_code code;
-     tree arg1, arg2;
-{
-  return build_binary_op_nodefault (code, arg1, arg2, code);
-}
-
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    This function differs from `build' in several ways:
@@ -3255,9 +3263,6 @@ build_binary_op (code, arg1, arg2)
    are done in the narrower type when that gives the same result).
    Constant folding is also done before the result is returned.
 
-   ERROR_CODE is the code that determines what to say in error messages.
-   It is usually, but not always, the same as CODE.
-
    Note that the operands will never have enumeral types
    because either they have just had the default conversions performed
    or they have both just been converted to some other type in which
@@ -3267,10 +3272,9 @@ build_binary_op (code, arg1, arg2)
    multiple inheritance, and deal with pointer to member functions.  */
 
 tree
-build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
+build_binary_op (code, orig_op0, orig_op1)
      enum tree_code code;
      tree orig_op0, orig_op1;
-     enum tree_code error_code;
 {
   tree op0, op1;
   register enum tree_code code0, code1;
@@ -3626,102 +3630,98 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
        }
       else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
        {
-         op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
-         op1 = integer_zero_node;
+         if (flag_new_abi)
+           {
+             op0 = build_component_ref (op0, pfn_identifier, NULL_TREE, 0);
+             op1 = cp_convert (TREE_TYPE (op0), integer_zero_node);
+           }
+         else
+           {
+             op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
+             op1 = integer_zero_node;
+           }
          result_type = TREE_TYPE (op0);
        }
       else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
-       {
-         op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
-         op1 = integer_zero_node;
-         result_type = TREE_TYPE (op0);
-       }
+       return build_binary_op (code, op1, op0);
       else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
               && same_type_p (type0, type1))
        {
-         /* The code we generate for the test is:
-
-         (op0.index == op1.index
-          && ((op1.index != -1 && op0.delta2 == op1.delta2)
-              || op0.pfn == op1.pfn)) */
-
-         tree index0 = build_component_ref (op0, index_identifier,
-                                            NULL_TREE, 0);
-         tree index1 = save_expr (build_component_ref (op1, index_identifier,
-                                                       NULL_TREE, 0));
-         tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
-         tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
-         tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
-         tree delta21 = DELTA2_FROM_PTRMEMFUNC (op1);
-         tree e1, e2, e3;
-         tree integer_neg_one_node
-           = build_binary_op (MINUS_EXPR, integer_zero_node,
-                              integer_one_node);
-         e1 = build_binary_op (EQ_EXPR, index0, index1);
-         e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
-         e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
-                               build_binary_op (EQ_EXPR, delta20, delta21));
-         /* We can't use build_binary_op for this cmp because it would get
-            confused by the ptr to method types and think we want pmfs.  */
-         e3 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
-         e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
-         e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
-         if (code == EQ_EXPR)
-           return e2;
-         return build_binary_op (EQ_EXPR, e2, integer_zero_node);
-       }
-      else if (TYPE_PTRMEMFUNC_P (type0)
-              && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0), type1))
-       {
-         tree index0 = build_component_ref (op0, index_identifier,
-                                            NULL_TREE, 0);
-         tree index1;
-         tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
-         tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
-         tree delta21 = integer_zero_node;
-         tree e1, e2, e3;
-         tree integer_neg_one_node
-           = build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node);
-         if (TREE_CODE (TREE_OPERAND (op1, 0)) == FUNCTION_DECL
-             && DECL_VINDEX (TREE_OPERAND (op1, 0)))
+         /* E will be the final comparison.  */
+         tree e;
+         /* E1 and E2 are for scratch.  */
+         tree e1;
+         tree e2;
+
+         if (flag_new_abi)
            {
-             /* Map everything down one to make room for
-                the null pointer to member.  */
-             index1 = size_binop (PLUS_EXPR,
-                                  DECL_VINDEX (TREE_OPERAND (op1, 0)),
-                                  integer_one_node);
-             op1 = integer_zero_node;
-             delta21 = TYPE_VFIELD (TYPE_METHOD_BASETYPE
-                                    (TREE_TYPE (type1)));
-             delta21 = DECL_FIELD_BITPOS (delta21);
-             delta21 = size_binop (FLOOR_DIV_EXPR, delta21,
-                                   size_int (BITS_PER_UNIT));
-             delta21 = convert (sizetype, delta21);
+             /* We generate:
+
+                  (op0.pfn == op1.pfn 
+                    && (!op0.pfn || op0.delta == op1.delta))
+                   
+                The reason for the `!op0.pfn' bit is that a NULL
+                pointer-to-member is any member with a zero PFN; the
+                DELTA field is unspecified.  */
+             tree pfn0;
+             tree pfn1;
+             tree delta0;
+             tree delta1;
+
+             pfn0 = pfn_from_ptrmemfunc (op0);
+             pfn1 = pfn_from_ptrmemfunc (op1);
+             delta0 = build_component_ref (op0, delta_identifier,
+                                           NULL_TREE, 0);
+             delta1 = build_component_ref (op1, delta_identifier,
+                                           NULL_TREE, 0);
+             e1 = build_binary_op (EQ_EXPR, delta0, delta1);
+             e2 = build_binary_op (NE_EXPR, 
+                                   pfn0,
+                                   cp_convert (TREE_TYPE (pfn0),
+                                               integer_zero_node));
+             e1 = build_binary_op (TRUTH_ORIF_EXPR, e1, e2);
+             e2 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
+             e = build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
            }
          else
-           index1 = integer_neg_one_node;
-         {
-           tree nop1 = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type0),
-                               op1);
-           TREE_CONSTANT (nop1) = TREE_CONSTANT (op1);
-           op1 = nop1;
-         }
-         e1 = build_binary_op (EQ_EXPR, index0, index1);
-         e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
-         e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
-                               build_binary_op (EQ_EXPR, delta20, delta21));
-         /* We can't use build_binary_op for this cmp because it would get
+           {
+             /* The code we generate for the test is:
+
+                (op0.index == op1.index
+                 && ((op1.index != -1 && op0.delta2 == op1.delta2)
+                     || op0.pfn == op1.pfn)) */
+
+             tree index0 = build_component_ref (op0, index_identifier,
+                                                NULL_TREE, 0);
+             tree index1 = save_expr (build_component_ref (op1, index_identifier,
+                                                           NULL_TREE, 0));
+             tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
+             tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
+             tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
+             tree delta21 = DELTA2_FROM_PTRMEMFUNC (op1);
+             tree e3;
+             tree integer_neg_one_node
+               = build_binary_op (MINUS_EXPR, integer_zero_node,
+                                  integer_one_node);
+             e1 = build_binary_op (EQ_EXPR, index0, index1);
+             e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
+             e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
+                                   build_binary_op (EQ_EXPR, delta20, delta21));
+             /* We can't use build_binary_op for this cmp because it would get
             confused by the ptr to method types and think we want pmfs.  */
-         e3 = build (EQ_EXPR, boolean_type_node, pfn0, op1);
-         e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
-         e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
+             e3 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
+             e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
+             e = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
+           }
          if (code == EQ_EXPR)
-           return e2;
-         return build_binary_op (EQ_EXPR, e2, integer_zero_node);
-       }
-      else if (TYPE_PTRMEMFUNC_P (type1)
-              && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1), type0))
-       return build_binary_op (code, op1, op0);
+           return e;
+         return build_binary_op (EQ_EXPR, e, integer_zero_node);
+       }
+      else if ((TYPE_PTRMEMFUNC_P (type0)
+               && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0), type1))
+              || (TYPE_PTRMEMFUNC_P (type1)
+                  && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1), type0)))
+       my_friendly_abort (20000221);
       break;
 
     case MAX_EXPR:
@@ -4059,7 +4059,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
   if (!result_type)
     {
       cp_error ("invalid operands of types `%T' and `%T' to binary `%O'",
-               TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), error_code);
+               TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
       return error_mark_node;
     }
 
@@ -6071,77 +6071,101 @@ get_delta_difference (from, to, force)
   return BINFO_OFFSET (binfo);
 }
 
+/* Return a constructor for the pointer-to-member-function TYPE using
+   the other components as specified.  */
+
 tree
 build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
      tree type, delta, idx, pfn, delta2;
 {
   tree u;
+  tree delta_field;
+  tree idx_field;
+  tree pfn_or_delta2_field;
+  tree pfn_field;
+  tree delta2_field;
+  tree subtype;
+  int allconstant, allsimple;
 
-#if 0
-  /* This is the old way we did it.  We want to avoid calling
-     digest_init, so that it can give an error if we use { } when
-     initializing a pointer to member function.  */
-
-  if (pfn)
+  /* Pull the FIELD_DECLs out of the type.  */
+  if (flag_new_abi)
     {
-      u = build_nt (CONSTRUCTOR, NULL_TREE,
-                   tree_cons (pfn_identifier, pfn, NULL_TREE));
+      pfn_field = TYPE_FIELDS (type);
+      delta_field = TREE_CHAIN (pfn_field);
+      idx_field = NULL_TREE;
+      pfn_or_delta2_field = NULL_TREE;
+      delta2_field = NULL_TREE;
+      subtype = NULL_TREE;
     }
   else
     {
-      u = build_nt (CONSTRUCTOR, NULL_TREE,
-                   tree_cons (delta2_identifier, delta2, NULL_TREE));
+      delta_field = TYPE_FIELDS (type);
+      idx_field = TREE_CHAIN (delta_field);
+      pfn_or_delta2_field = TREE_CHAIN (idx_field);
+      subtype = TREE_TYPE (pfn_or_delta2_field);
+      pfn_field = TYPE_FIELDS (subtype);
+      delta2_field = TREE_CHAIN (pfn_field);
     }
 
-  u = build_nt (CONSTRUCTOR, NULL_TREE,
-               tree_cons (NULL_TREE, delta,
-                          tree_cons (NULL_TREE, idx,
-                                     tree_cons (NULL_TREE, u, NULL_TREE))));
-
-  return digest_init (type, u, (tree*)0);
-#else
-  tree delta_field, idx_field, pfn_or_delta2_field, pfn_field, delta2_field;
-  tree subtype;
-  int allconstant, allsimple;
+  /* Make sure DELTA has the type we want.  */
+  delta = convert_and_check (delta_type_node, delta);
 
-  delta_field = TYPE_FIELDS (type);
-  idx_field = TREE_CHAIN (delta_field);
-  pfn_or_delta2_field = TREE_CHAIN (idx_field);
-  subtype = TREE_TYPE (pfn_or_delta2_field);
-  pfn_field = TYPE_FIELDS (subtype);
-  delta2_field = TREE_CHAIN (pfn_field);
+  /* Keep track of whether the initializer is a) constant, and b) can
+     be done statically.  */
+  allconstant = TREE_CONSTANT (delta);
+  allsimple = (initializer_constant_valid_p (delta, TREE_TYPE (delta)) 
+              != NULL_TREE);
 
   if (pfn)
     {
-      allconstant = TREE_CONSTANT (pfn);
-      allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
-      u = tree_cons (pfn_field, pfn, NULL_TREE);
+      /* A non-virtual function.  */
+      if (!flag_new_abi)
+       u = build_tree_list (pfn_field, pfn);
+
+      allconstant &= TREE_CONSTANT (pfn);
+      allsimple &= (initializer_constant_valid_p (pfn, TREE_TYPE (pfn)) 
+                   != NULL_TREE);
     }
   else
     {
-      delta2 = convert_and_check (delta_type_node, delta2);
-      allconstant = TREE_CONSTANT (delta2);
-      allsimple = !! initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
-      u = tree_cons (delta2_field, delta2, NULL_TREE);
-    }
-
-  delta = convert_and_check (delta_type_node, delta);
-  idx = convert_and_check (delta_type_node, idx);
+      /* A virtual function.  */
+      if (flag_new_abi)
+       {
+         allconstant &= TREE_CONSTANT (pfn);
+         allsimple &= (initializer_constant_valid_p (pfn, TREE_TYPE (pfn)) 
+                       != NULL_TREE);
+       }
+      else
+       {
+         idx = convert_and_check (delta_type_node, idx);
+         u = build_tree_list (delta2_field, delta2);
 
-  allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx);
-  allsimple = allsimple
-    && initializer_constant_valid_p (delta, TREE_TYPE (delta))
-      && initializer_constant_valid_p (idx, TREE_TYPE (idx));
+         allconstant &= TREE_CONSTANT (idx) && TREE_CONSTANT (delta2);
+         allsimple &= ((initializer_constant_valid_p (idx, TREE_TYPE (idx)) 
+                        != NULL_TREE)
+                       && (initializer_constant_valid_p (delta2,
+                                                         TREE_TYPE (delta2))
+                           != NULL_TREE));
+       }
+    }
 
-  u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
-  u = tree_cons (delta_field, delta,
-                tree_cons (idx_field, idx,
-                           tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
+  /* Finish creating the initializer.  */
+  if (flag_new_abi)
+    u = tree_cons (pfn_field, pfn,
+                  build_tree_list (delta_field, delta));
+  else
+    {
+      u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
+      u = tree_cons (delta_field, delta,
+                    tree_cons (idx_field, 
+                               idx,
+                               build_tree_list (pfn_or_delta2_field,
+                                                u)));
+    }
   u = build (CONSTRUCTOR, type, NULL_TREE, u);
   TREE_CONSTANT (u) = allconstant;
   TREE_STATIC (u) = allconstant && allsimple;
   return u;
-#endif
 }
 
 /* Build a constructor for a pointer to member function.  It can be
@@ -6179,15 +6203,33 @@ build_ptrmemfunc (type, pfn, force)
        cp_error ("invalid conversion to type `%T' from type `%T'", 
                  to_type, pfn_type);
 
+      /* We don't have to do any conversion to convert a
+        pointer-to-member to its own type.  But, we don't want to
+        just return a PTRMEM_CST if there's an explicit cast; that
+        cast should make the expression an invalid template argument.  */
+      if (TREE_CODE (pfn) != PTRMEM_CST && same_type_p (to_type, pfn_type))
+       return pfn;
+
+      if (flag_new_abi)
+       {
+         /* Under the new ABI, the conversion is easy.  Just adjust
+            the DELTA field.  */
+         npfn = build_component_ref (pfn, pfn_identifier, NULL_TREE, 0);
+         delta = build_component_ref (pfn, delta_identifier, NULL_TREE, 0);
+         delta = cp_convert (ptrdiff_type_node, delta);
+         n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
+                                   TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
+                                   force);
+         delta = build_binary_op (PLUS_EXPR, delta, n);
+         return build_ptrmemfunc1 (to_type, delta, NULL_TREE, npfn,
+                                   NULL_TREE);
+       }
+
       if (TREE_CODE (pfn) == PTRMEM_CST)
        {
          /* We could just build the resulting CONSTRUCTOR now, but we
             don't, relying on the general machinery below, together
-            with constant-folding, to do the right thing.  We don't
-            want to return a PTRMEM_CST here, since a
-            pointer-to-member constant is no longer a valid template
-            argument once it is cast to any type, including its
-            original type.  */
+            with constant-folding, to do the right thing.  */
          expand_ptrmemfunc_cst (pfn, &ndelta, &idx, &npfn, &ndelta2);
          if (npfn)
            /* This constant points to a non-virtual function.
@@ -6195,12 +6237,6 @@ build_ptrmemfunc (type, pfn, force)
               matter since we won't use it anyhow.  */
            ndelta2 = integer_zero_node;
        }
-      else if (same_type_p (to_type, pfn_type))
-       /* We don't have to do any conversion.  Note that we do this
-          after checking for a PTRMEM_CST so that a PTRMEM_CST, cast
-          to its own type, will not be considered a legal non-type
-          template argument.  */
-       return pfn;
       else
        {
          ndelta = cp_convert (ptrdiff_type_node, 
@@ -6220,8 +6256,7 @@ build_ptrmemfunc (type, pfn, force)
       e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
          
       /* If it's a virtual function, this is what we want.  */
-      e2 = build_ptrmemfunc1 (to_type, delta, idx,
-                             NULL_TREE, delta2);
+      e2 = build_ptrmemfunc1 (to_type, delta, idx, NULL_TREE, delta2);
 
       pfn = PFN_FROM_PTRMEMFUNC (pfn);
       npfn = build1 (NOP_EXPR, type, pfn);
@@ -6229,8 +6264,7 @@ build_ptrmemfunc (type, pfn, force)
 
       /* But if it's a non-virtual function, or NULL, we use this
         instead.  */
-      e3 = build_ptrmemfunc1 (to_type, delta,
-                             idx, npfn, NULL_TREE);
+      e3 = build_ptrmemfunc1 (to_type, delta, idx, npfn, NULL_TREE);
       return build_conditional_expr (e1, e2, e3);
     }
 
@@ -6279,7 +6313,10 @@ expand_ptrmemfunc_cst (cst, delta, idx, pfn, delta2)
 
   if (!DECL_VIRTUAL_P (fn))
     {
-      *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+      if (!flag_new_abi)
+       *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+      else
+       *idx = NULL_TREE;
       *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
       *delta2 = NULL_TREE;
     }
@@ -6292,9 +6329,21 @@ expand_ptrmemfunc_cst (cst, delta, idx, pfn, delta2)
       tree binfo = binfo_or_else (orig_class, fn_class);
       *delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
 
-      /* Map everything down one to make room for the null PMF.  */
-      *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
-      *pfn = NULL_TREE;
+      if (!flag_new_abi)
+       {
+         /* Map everything down one to make room for the null PMF.  */
+         *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
+         *pfn = NULL_TREE;
+       }
+      else
+       {
+         /* Under the new ABI, we set PFN to twice the index, plus
+            one.  */
+         *idx = NULL_TREE;
+         *pfn = size_binop (MULT_EXPR, DECL_VINDEX (fn), integer_two_node);
+         *pfn = size_binop (PLUS_EXPR, *pfn, integer_one_node);
+         *pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
+       }
 
       /* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS.  */
       *delta2 = size_binop (PLUS_EXPR, *delta,
@@ -6309,6 +6358,8 @@ tree
 delta2_from_ptrmemfunc (t)
      tree t;
 {
+  my_friendly_assert (!flag_new_abi, 20000221);
+
   if (TREE_CODE (t) == PTRMEM_CST)
     {
       tree delta;
@@ -6347,11 +6398,14 @@ pfn_from_ptrmemfunc (t)
        return pfn;
     }
 
-  return (build_component_ref 
-         (build_component_ref (t,
-                               pfn_or_delta2_identifier, NULL_TREE,
-                               0), 
-          pfn_identifier, NULL_TREE, 0)); 
+  if (flag_new_abi)
+    return build_component_ref (t, pfn_identifier, NULL_TREE, 0);
+  else
+    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 to