]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cp-tree.h (CPTI_VTABLE_INDEX_TYPE): New macro.
authorMark Mitchell <mark@codesourcery.com>
Tue, 22 Feb 2000 02:30:54 +0000 (02:30 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Tue, 22 Feb 2000 02:30:54 +0000 (02:30 +0000)
* 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.

From-SVN: r32099

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 045902c3352d1a6b42ab47badc8bd8633c2b019a..346123d7de8488864d899bd6e0a267ae51cc6a36 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 e996b59393a6aeda1d040aad3175aae9029a7c61..887e2dfd4cb32b0372e0b61c89cb31872707c0fe 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 500937b0ed1c9255d60b4974c33c3da601e8246b..5337ed3dc08c43e245902f2951b20362e34e47a7 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 45515098470d861a5e326e0a4f916841c89119ca..cb9ec294ce178072c11bd70a43090dba2f7a7998 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 b48e80ef1d82f1e7112b135b30dd97f26bc53e33..6a12868d989e17e332ac6b3b6e1ffc91fa5189db 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 8264ede49366f5c329076115c32a415158770993..346eb83312305074d7090585396eccce4237fecc 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