OSDN Git Service

(struct function): Make frame_offset be HOST_WIDE_INT.
[pf3gnuchains/gcc-fork.git] / gcc / cp / sig.c
index 1426168..7e53de6 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions dealing with signatures and signature pointers/references.
-   Copyright (C) 1992 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93, 94, 95, 1996 Free Software Foundation, Inc.
    Contributed by Gerald Baumgartner (gb@cs.purdue.edu)
 
 This file is part of GNU CC.
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
@@ -143,7 +144,6 @@ build_signature_pointer_or_reference_type (to_type, constp, volatilep, refp)
        struct {
          void * optr;
         const s * sptr;
-        vtbl_type_node * vptr;
        };
 
      A `const' signature pointer/reference is a
@@ -151,17 +151,15 @@ build_signature_pointer_or_reference_type (to_type, constp, volatilep, refp)
        struct {
          const void * optr;
         const s * sptr;
-        vtbl_type_node * vptr;
        };
 
-     Similarly, for `volatile' and `const volatile'.
-   */
+     Similarly, for `volatile' and `const volatile'.  */
 
   t = make_lang_type (RECORD_TYPE);
   {
     tree obj_type = build_type_variant (void_type_node, constp, volatilep);
     tree optr_type = build_pointer_type (obj_type);
-    tree optr, sptr, vptr;
+    tree optr, sptr;
 
     optr = build_lang_field_decl (FIELD_DECL,
                                  get_identifier (SIGNATURE_OPTR_NAME),
@@ -170,35 +168,29 @@ build_signature_pointer_or_reference_type (to_type, constp, volatilep, refp)
     DECL_CLASS_CONTEXT (optr) = t;
 
     if (m)
-      {
-       /* We can share `sptr' and `vptr' among type variants.  */
-       sptr = TREE_CHAIN (TYPE_FIELDS (m));
-       vptr = TREE_CHAIN (sptr);
-      }
+      /* We can share the `sptr' field among type variants.  */
+      sptr = TREE_CHAIN (TYPE_FIELDS (m));
     else
       {
-       tree sig_tbl_type = c_build_type_variant (to_type, 1, 0);
+       tree sig_tbl_type = cp_build_type_variant (to_type, 1, 0);
        
        sptr = build_lang_field_decl (FIELD_DECL,
                                      get_identifier (SIGNATURE_SPTR_NAME),
                                      build_pointer_type (sig_tbl_type));
-       vptr = build_lang_field_decl (FIELD_DECL,
-                                     get_identifier (SIGNATURE_VPTR_NAME),
-                                     build_pointer_type (vtbl_type_node));
        DECL_FIELD_CONTEXT (sptr) = t;
        DECL_CLASS_CONTEXT (sptr) = t;
-       DECL_FIELD_CONTEXT (vptr) = t;
-       DECL_CLASS_CONTEXT (vptr) = t;
-       TREE_CHAIN (sptr) = vptr;
-       TREE_CHAIN (vptr) = NULL_TREE;
+       TREE_CHAIN (sptr) = NULL_TREE;
       }
 
     TREE_CHAIN (optr) = sptr;
     TYPE_FIELDS (t) = optr;
-    /* To make `build_vfn_ref' work when building a signature method call.  */
-    CLASSTYPE_VFIELD (t) = vptr;
-    DECL_FCONTEXT (CLASSTYPE_VFIELD (t)) = t;
-    TYPE_ALIGN (t) = TYPE_ALIGN (optr_type);
+    /* Allow signature pointers/references to be grabbed 2 words at a time.
+       For this to work on a Sparc, we need 8-byte alignment.  */
+    TYPE_ALIGN (t) = MAX (TYPE_ALIGN (double_type_node),
+                         TYPE_ALIGN (optr_type));
+
+    /* A signature pointer/reference type isn't a `real' class type.  */
+    IS_AGGR_TYPE (t) = 0;
   }
 
   {
@@ -236,7 +228,7 @@ build_signature_pointer_or_reference_type (to_type, constp, volatilep, refp)
   current_obstack = ambient_obstack;
   saveable_obstack = ambient_saveable_obstack;
 
-  /* Ouput debug information for this type.  */
+  /* Output debug information for this type.  */
   rest_of_type_compilation (t, 1);
 
   return t;
@@ -430,6 +422,7 @@ match_method_types (sig_mtype, class_mtype)
 }
 
 /* Undo casts of opaque type variables to the RHS types.  */
+
 static void
 undo_casts (sig_ty)
      tree sig_ty;
@@ -540,11 +533,11 @@ build_signature_table_constructor (sig_ty, rhs)
 
          if (rhs_method == NULL_TREE
              || (compute_access (basetypes, rhs_method)
-                 != access_public))
+                 != access_public_node))
            {
              error ("class `%s' does not contain a method conforming to `%s'",
                     TYPE_NAME_STRING (rhstype),
-                    fndecl_as_string (NULL, sig_method, 1));
+                    fndecl_as_string (sig_method, 1));
              undo_casts (sig_ty);
              return error_mark_node;
            }
@@ -569,36 +562,86 @@ build_signature_table_constructor (sig_ty, rhs)
        }
       else
        {
-         tree code, offset, pfn;
+         tree tag, vb_off, delta, idx, pfn, vt_off;
+         tree tag_decl, vb_off_decl, delta_decl, index_decl;
+         tree pfn_decl, vt_off_decl;
 
          if (rhs_method == sig_method)
            {
-             code = integer_two_node;
-             offset = integer_zero_node;
-             pfn = build_unary_op (ADDR_EXPR, rhs_method, 0);
+             /* default implementation */
+             tag = build_unary_op (NEGATE_EXPR, integer_one_node, 0);
+             vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0);
+             delta = integer_zero_node;
+             idx = integer_zero_node;
+             pfn = build_addr_func (rhs_method);
+             TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (rhs_method)) = 1;
              TREE_TYPE (pfn) = ptr_type_node;
+             TREE_ADDRESSABLE (rhs_method) = 1;
              offset_p = 0;     /* we can't offset the rhs sig table */
            }
          else if (DECL_VINDEX (rhs_method))
            {
-             code = integer_one_node;
-             offset = DECL_VINDEX (rhs_method);
-             pfn = null_pointer_node;
+             /* virtual member function */
+             tag = integer_one_node;
+             vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0);
+             if (flag_vtable_thunks)
+               delta = BINFO_OFFSET
+                 (get_binfo (DECL_CONTEXT (rhs_method), rhstype, 1));
+             else
+               delta = BINFO_OFFSET
+                 (get_binfo (DECL_CLASS_CONTEXT (rhs_method), rhstype, 1));
+             idx = DECL_VINDEX (rhs_method);
+             vt_off = get_vfield_offset (get_binfo (DECL_CONTEXT (rhs_method),
+                                                    rhstype, 0));
            }
          else
            {
-             code = integer_zero_node;
-             offset = integer_zero_node;
-             pfn = build_unary_op (ADDR_EXPR, rhs_method, 0);
+             /* non-virtual member function */
+             tag = integer_zero_node;
+             vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0);
+             delta = BINFO_OFFSET (get_binfo (DECL_CLASS_CONTEXT (rhs_method),
+                                              rhstype, 1));
+             idx = integer_zero_node;
+             pfn = build_addr_func (rhs_method);
+             TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (rhs_method)) = 1;
              TREE_TYPE (pfn) = ptr_type_node;
              TREE_ADDRESSABLE (rhs_method) = 1;
            }
 
-         tbl_entry = tree_cons (NULL_TREE, code,
-                                tree_cons (NULL_TREE, offset,
-                                           build_tree_list (NULL_TREE, pfn)));
-         tbl_entry = build_nt (CONSTRUCTOR, NULL_TREE, tbl_entry);
-         TREE_HAS_CONSTRUCTOR (tbl_entry) = 1;
+         /* Since digest_init doesn't handle initializing selected fields
+            of a struct (i.e., anonymous union), we build the constructor
+            by hand, without calling digest_init.  */
+         tag_decl = TYPE_FIELDS (sigtable_entry_type);
+         vb_off_decl = TREE_CHAIN (tag_decl);
+         delta_decl = TREE_CHAIN (vb_off_decl);
+         index_decl = TREE_CHAIN (delta_decl);
+         pfn_decl = TREE_CHAIN (index_decl);
+         vt_off_decl = TREE_CHAIN (pfn_decl);
+         
+         tag = convert (TREE_TYPE (tag_decl), tag);
+         vb_off = convert (TREE_TYPE (vb_off_decl), vb_off);
+         delta = convert (TREE_TYPE (delta_decl), delta);
+         idx = convert (TREE_TYPE (index_decl), idx);
+
+         if (DECL_VINDEX (rhs_method))
+           {
+             vt_off = convert (TREE_TYPE (vt_off_decl), vt_off);
+
+             tbl_entry = build_tree_list (vt_off_decl, vt_off);
+           }
+         else
+           {
+             pfn = convert (TREE_TYPE (pfn_decl), pfn);
+
+             tbl_entry = build_tree_list (pfn_decl, pfn);
+           }
+         tbl_entry = tree_cons (delta_decl, delta,
+                                tree_cons (index_decl, idx, tbl_entry));
+         tbl_entry = tree_cons (tag_decl, tag,
+                                tree_cons (vb_off_decl, vb_off, tbl_entry));
+         tbl_entry = build (CONSTRUCTOR, sigtable_entry_type,
+                            NULL_TREE, tbl_entry);
+
          TREE_CONSTANT (tbl_entry) = 1;
        }
 
@@ -647,7 +690,7 @@ build_signature_table_constructor (sig_ty, rhs)
    as initialization expression, we don't need a new signature table
    variable and just hand back the init expression.
 
-   The declaration processing is done by hand instead of using `finish_decl'
+   The declaration processing is done by hand instead of using `cp_finish_decl'
    so that we can make signature pointers global variables instead of
    static ones.  */
 
@@ -740,7 +783,7 @@ build_signature_pointer_constructor (lhs, rhs)
   tree lhstype = initp ? lhs : TREE_TYPE (lhs);
   tree rhstype = TREE_TYPE (rhs);
   tree sig_ty  = SIGNATURE_TYPE (lhstype);
-  tree sig_tbl, sptr_expr, optr_expr, vptr_expr;
+  tree sig_tbl, sptr_expr, optr_expr;
   tree result;
 
   if (! ((TREE_CODE (rhstype) == POINTER_TYPE
@@ -777,7 +820,6 @@ build_signature_pointer_constructor (lhs, rhs)
          /* LHS and RHS are signature pointers/refs of the same signature.  */
          optr_expr = build_optr_ref (rhs);
          sptr_expr = build_sptr_ref (rhs);
-         vptr_expr = build_vptr_ref (rhs);
        }
       else
        {
@@ -801,19 +843,10 @@ build_signature_pointer_constructor (lhs, rhs)
          else
            sptr_expr = build_unary_op (ADDR_EXPR, sig_tbl, 0);
          TREE_TYPE (sptr_expr) = build_pointer_type (sig_ty);
-         vptr_expr = build_vptr_ref (rhs);
        }
     }
   else
     {
-      tree rhs_vptr;
-
-      if (TYPE_USES_COMPLEX_INHERITANCE (TREE_TYPE (rhstype)))
-       {
-         sorry ("class with multiple inheritance as implementation of signature");
-         return error_mark_node;
-       }
-
       sig_tbl = build_sigtable (sig_ty, TREE_TYPE (rhstype), rhs);
       if (sig_tbl == error_mark_node)
        return error_mark_node;
@@ -828,22 +861,12 @@ build_signature_pointer_constructor (lhs, rhs)
        }
       else
        sptr_expr = build_unary_op (ADDR_EXPR, sig_tbl, 0);
-      if (CLASSTYPE_VFIELD (TREE_TYPE (rhstype)))
-       {
-         rhs_vptr = DECL_NAME (CLASSTYPE_VFIELD (TREE_TYPE (rhstype)));
-         vptr_expr = build_component_ref (build_indirect_ref (rhs, 0),
-                                          rhs_vptr, NULL_TREE, 0);
-       }
-      else
-       vptr_expr = copy_node (null_pointer_node);
-      TREE_TYPE (vptr_expr) = build_pointer_type (vtbl_type_node);
     }
 
   if (initp)
     {
       result = tree_cons (NULL_TREE, optr_expr,
-                         tree_cons (NULL_TREE, sptr_expr,
-                                    build_tree_list (NULL_TREE, vptr_expr)));
+                         build_tree_list (NULL_TREE, sptr_expr));
       result = build_nt (CONSTRUCTOR, NULL_TREE, result);
       TREE_HAS_CONSTRUCTOR (result) = 1;
       result = digest_init (lhstype, result, 0);
@@ -857,14 +880,10 @@ build_signature_pointer_constructor (lhs, rhs)
                                     optr_expr);
       sptr_expr = build_modify_expr (build_sptr_ref (lhs), NOP_EXPR,
                                     sptr_expr);
-      vptr_expr = build_modify_expr (build_vptr_ref (lhs), NOP_EXPR,
-                                    vptr_expr);
 
       result = tree_cons (NULL_TREE, optr_expr,
                          tree_cons (NULL_TREE, sptr_expr,
-                                    tree_cons (NULL_TREE, vptr_expr,
-                                               build_tree_list (NULL_TREE,
-                                                                lhs))));
+                                    build_tree_list (NULL_TREE, lhs)));
       result = build_compound_expr (result);
     }
 
@@ -900,53 +919,80 @@ save_this (instance)
 /* Build a signature member function call.  Looks up the signature table
    entry corresponding to FUNCTION.  Depending on the value of the CODE
    field, either call the function in PFN directly, or use OFFSET to
-   index INSTANCE's virtual function table.  */
+   index the object's virtual function table.  */
 
 tree
-build_signature_method_call (basetype, instance, function, parms)
-     tree basetype, instance, function, parms;
+build_signature_method_call (function, parms)
+     tree function, parms;
 {
+  tree instance = TREE_VALUE (parms);
   tree saved_instance = save_this (instance);  /* Create temp for `this'.  */
+  tree object_ptr = build_optr_ref (saved_instance);
+  tree new_object_ptr, new_parms;
   tree signature_tbl_ptr = build_sptr_ref (saved_instance);
   tree sig_field_name = DECL_NAME (DECL_MEMFUNC_POINTER_TO (function));
+  tree basetype = DECL_CONTEXT (function);
   tree basetype_path = TYPE_BINFO (basetype);
   tree tbl_entry = build_component_ref (build1 (INDIRECT_REF, basetype,
                                                signature_tbl_ptr),
                                        sig_field_name, basetype_path, 1);
-  tree code, offset, pfn, vfn;
+  tree tag, delta, pfn, vt_off, idx, vfn;
   tree deflt_call = NULL_TREE, direct_call, virtual_call, result;
 
-  code = build_component_ref (tbl_entry, get_identifier (SIGTABLE_CODE_NAME),
-                            NULL_TREE, 1);
-  offset = build_component_ref (tbl_entry,
-                               get_identifier (SIGTABLE_OFFSET_NAME),
-                            NULL_TREE, 1);
-  pfn = build_component_ref (tbl_entry, get_identifier (SIGTABLE_PFN_NAME),
-                            NULL_TREE, 1);
+  tbl_entry = save_expr (tbl_entry);
+  tag = build_component_ref (tbl_entry, tag_identifier, NULL_TREE, 1);
+  delta = build_component_ref (tbl_entry, delta_identifier, NULL_TREE, 1);
+  pfn = build_component_ref (tbl_entry, pfn_identifier, NULL_TREE, 1);
+  vt_off = build_component_ref (tbl_entry, vt_off_identifier, NULL_TREE, 1);
+  idx = build_component_ref (tbl_entry, index_identifier, NULL_TREE, 1);
   TREE_TYPE (pfn) = build_pointer_type (TREE_TYPE (function)); 
 
   if (IS_DEFAULT_IMPLEMENTATION (function))
     {
       pfn = save_expr (pfn);
-      deflt_call = build_function_call (pfn,
-                                       tree_cons (NULL_TREE, saved_instance,
-                                                  TREE_CHAIN (parms)));
+      deflt_call = build_function_call (pfn, parms);
     }
 
+  new_object_ptr = build (PLUS_EXPR, build_pointer_type (basetype),
+                         convert (ptrdiff_type_node, object_ptr),
+                         convert (ptrdiff_type_node, delta));
+
+  parms = tree_cons (NULL_TREE,
+                    convert (build_pointer_type (basetype), object_ptr),
+                    TREE_CHAIN (parms));
+  new_parms = tree_cons (NULL_TREE, new_object_ptr, TREE_CHAIN (parms));
+
   {
     /* Cast the signature method to have `this' of a normal pointer type.  */
     tree old_this = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn))));
 
     TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))) =
-      build_type_variant (TYPE_POINTER_TO (basetype),
+      build_type_variant (build_pointer_type (basetype),
                          TYPE_READONLY (old_this),
                          TYPE_VOLATILE (old_this));
 
-    direct_call = build_function_call (pfn, parms);
+    direct_call = build_function_call (pfn, new_parms);
+
+    {
+      tree vfld, vtbl, aref;
+
+      vfld = build (PLUS_EXPR,
+                   build_pointer_type (build_pointer_type (vtbl_type_node)),
+                   convert (ptrdiff_type_node, object_ptr),
+                   convert (ptrdiff_type_node, vt_off));
+      vtbl = build_indirect_ref (build_indirect_ref (vfld, NULL_PTR),
+                                NULL_PTR);
+      aref = build_array_ref (vtbl, idx);
+
+      if (flag_vtable_thunks)
+       vfn = aref;
+      else
+       vfn = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
+
+      TREE_TYPE (vfn) = build_pointer_type (TREE_TYPE (function));
 
-    vfn = build_vfn_ref (&TREE_VALUE (parms), saved_instance, offset);
-    TREE_TYPE (vfn) = build_pointer_type (TREE_TYPE (function));
-    virtual_call = build_function_call (vfn, parms);
+      virtual_call = build_function_call (vfn, new_parms);
+    }
 
     /* Undo the cast, make `this' a signature pointer again.  */
     TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))) = old_this;
@@ -960,22 +1006,22 @@ build_signature_method_call (basetype, instance, function, parms)
          && (!deflt_call || deflt_call == error_mark_node)))
     {
       compiler_error ("cannot build call of signature member function `%s'",
-                     fndecl_as_string (NULL, function, 1));
+                     fndecl_as_string (function, 1));
       return error_mark_node;
     }
 
   if (IS_DEFAULT_IMPLEMENTATION (function))
     {
-      tree test = build_binary_op_nodefault (EQ_EXPR, code, integer_one_node,
-                                            EQ_EXPR);
-      result = build_conditional_expr (code,
+      tree test = build_binary_op_nodefault (LT_EXPR, tag, integer_zero_node,
+                                            LT_EXPR);
+      result = build_conditional_expr (tag,
                                       build_conditional_expr (test,
-                                                              virtual_call,
-                                                              deflt_call),
+                                                              deflt_call,
+                                                              virtual_call),
                                       direct_call);
     }
   else
-    result = build_conditional_expr (code, virtual_call, direct_call);
+    result = build_conditional_expr (tag, virtual_call, direct_call);
 
   /* If we created a temporary variable for `this', initialize it first.  */
   if (instance != saved_instance)
@@ -1009,15 +1055,3 @@ build_sptr_ref (instance)
 
   return build_component_ref (instance, field, NULL_TREE, 1);
 }
-
-/* Create a COMPONENT_REF expression for referencing the VPTR field
-   of a signature pointer or reference.  */
-
-tree
-build_vptr_ref (instance)
-     tree instance;
-{
-  tree field = get_identifier (SIGNATURE_VPTR_NAME);
-
-  return build_component_ref (instance, field, NULL_TREE, 1);
-}