Enabled linkonce support for Darwin.
[platform/upstream/gcc.git] / gcc / cp / method.c
index fd61d20..10dfaca 100644 (file)
@@ -1,7 +1,7 @@
 /* Handle the hair of processing (but not expanding) inline functions.
    Also manage function and variable name overloading.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
@@ -62,6 +62,9 @@ static tree synthesize_exception_spec (tree, tree (*) (tree, void *), void *);
 static tree locate_dtor (tree, void *);
 static tree locate_ctor (tree, void *);
 static tree locate_copy (tree, void *);
+#ifdef ASM_OUTPUT_DEF
+static tree make_alias_for_thunk (tree);
+#endif
 
 /* Called once to initialize method.c.  */
 
@@ -85,119 +88,6 @@ set_mangled_name_for_decl (tree decl)
 }
 
 \f
-/* This function takes an identifier, ID, and attempts to figure out what
-   it means. There are a number of possible scenarios, presented in increasing
-   order of hair:
-
-   1) not in a class's scope
-   2) in class's scope, member name of the class's method
-   3) in class's scope, but not a member name of the class
-   4) in class's scope, member name of a class's variable
-
-   NAME is $1 from the bison rule. It is an IDENTIFIER_NODE.
-   VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1)
-
-   As a last ditch, try to look up the name as a label and return that
-   address.
-
-   Values which are declared as being of REFERENCE_TYPE are
-   automatically dereferenced here (as a hack to make the
-   compiler faster).  */
-
-tree
-hack_identifier (tree value, tree name)
-{
-  tree type;
-
-  if (value == error_mark_node)
-    return error_mark_node;
-
-  type = TREE_TYPE (value);
-  if (TREE_CODE (value) == FIELD_DECL)
-    value = finish_non_static_data_member (value, 
-                                          /*qualifying_scope=*/NULL_TREE);
-  else if ((TREE_CODE (value) == FUNCTION_DECL
-           && DECL_FUNCTION_MEMBER_P (value))
-          || (TREE_CODE (value) == OVERLOAD
-              && DECL_FUNCTION_MEMBER_P (OVL_CURRENT (value))))
-    {
-      tree decl;
-
-      if (TREE_CODE (value) == OVERLOAD)
-       value = OVL_CURRENT (value);
-
-      decl = maybe_dummy_object (DECL_CONTEXT (value), 0);
-      value = finish_class_member_access_expr (decl, name);
-    }
-  else if (really_overloaded_fn (value))
-    ;
-  else if (TREE_CODE (value) == OVERLOAD)
-    /* not really overloaded function */
-    mark_used (OVL_FUNCTION (value));
-  else if (TREE_CODE (value) == TREE_LIST)
-    {
-      /* Ambiguous reference to base members, possibly other cases?.  */
-      tree t = value;
-      while (t && TREE_CODE (t) == TREE_LIST)
-       {
-         mark_used (TREE_VALUE (t));
-         t = TREE_CHAIN (t);
-       }
-    }
-  else if (TREE_CODE (value) == NAMESPACE_DECL)
-    {
-      error ("use of namespace `%D' as expression", value);
-      return error_mark_node;
-    }
-  else if (DECL_CLASS_TEMPLATE_P (value))
-    {
-      error ("use of class template `%T' as expression", value);
-      return error_mark_node;
-    }
-  else
-    mark_used (value);
-
-  if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL
-      || TREE_CODE (value) == RESULT_DECL)
-    {
-      tree context = decl_function_context (value);
-      if (context != NULL_TREE && context != current_function_decl
-         && ! TREE_STATIC (value))
-       {
-         error ("use of %s from containing function",
-                     (TREE_CODE (value) == VAR_DECL
-                      ? "`auto' variable" : "parameter"));
-         cp_error_at ("  `%#D' declared here", value);
-         value = error_mark_node;
-       }
-    }
-
-  if (DECL_P (value) && DECL_NONLOCAL (value))
-    {
-      if (DECL_CLASS_SCOPE_P (value)
-         && DECL_CONTEXT (value) != current_class_type)
-       {
-         tree path;
-         path = currently_open_derived_class (DECL_CONTEXT (value));
-         enforce_access (path, value);
-       }
-    }
-  else if (TREE_CODE (value) == TREE_LIST 
-          && TREE_TYPE (value) == error_mark_node)
-    {
-      error ("\
-request for member `%D' is ambiguous in multiple inheritance lattice",
-               name);
-      print_candidates (value);
-      return error_mark_node;
-    }
-
-  if (! processing_template_decl)
-    value = convert_from_reference (value);
-  return value;
-}
-
-\f
 /* Return a this or result adjusting thunk to FUNCTION.  THIS_ADJUSTING
    indicates whether it is a this or result adjusting thunk.
    FIXED_OFFSET and VIRTUAL_OFFSET indicate how to do the adjustment
@@ -215,8 +105,10 @@ make_thunk (tree function, bool this_adjusting,
   tree thunk;
   
   my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 20021025);
-  /* We can have this thunks to covariant thunks, but not vice versa. */
+  /* We can have this thunks to covariant thunks, but not vice versa.  */
   my_friendly_assert (!DECL_THIS_THUNK_P (function), 20021127);
+  my_friendly_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting,
+                     20031123);
   
   /* Scale the VIRTUAL_OFFSET to be in terms of bytes.  */
   if (this_adjusting && virtual_offset)
@@ -230,26 +122,33 @@ make_thunk (tree function, bool this_adjusting,
   
   /* See if we already have the thunk in question.  For this_adjusting
      thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
-     will be a BINFO. */
+     will be a BINFO.  */
   for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
     if (DECL_THIS_THUNK_P (thunk) == this_adjusting
-       && THUNK_FIXED_OFFSET (thunk) == d
-       && (this_adjusting
-           ? (!THUNK_VIRTUAL_OFFSET (thunk) == !virtual_offset
-              && (!virtual_offset
-                  || tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk), 
-                                         virtual_offset)))
-           : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset))
+       && THUNK_FIXED_OFFSET (thunk) == d
+       && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk)
+       && (!virtual_offset
+           || (this_adjusting
+               ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
+                                     virtual_offset)
+               : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))
       return thunk;
   
   /* All thunks must be created before FUNCTION is actually emitted;
      the ABI requires that all thunks be emitted together with the
      function to which they transfer control.  */
   my_friendly_assert (!TREE_ASM_WRITTEN (function), 20021025);
+  /* Likewise, we can only be adding thunks to a function declared in
+     the class currently being laid out.  */
+  my_friendly_assert (TYPE_SIZE (DECL_CONTEXT (function))
+                     && TYPE_BEING_DEFINED (DECL_CONTEXT (function)),
+                     20031211);
 
   thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
   DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
   cxx_dup_lang_specific_decl (thunk);
+  DECL_THUNKS (thunk) = NULL_TREE;
+  
   DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
   TREE_READONLY (thunk) = TREE_READONLY (function);
   TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
@@ -260,6 +159,7 @@ make_thunk (tree function, bool this_adjusting,
   THUNK_TARGET (thunk) = function;
   THUNK_FIXED_OFFSET (thunk) = d;
   THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
+  THUNK_ALIAS (thunk) = NULL_TREE;
   
   /* The thunk itself is not a constructor or destructor, even if
      the thing it is thunking to is.  */
@@ -281,6 +181,7 @@ make_thunk (tree function, bool this_adjusting,
   DECL_DECLARED_INLINE_P (thunk) = 0;
   /* Nor has it been deferred.  */
   DECL_DEFERRED_FN (thunk) = 0;
+  
   /* Add it to the list of thunks associated with FUNCTION.  */
   TREE_CHAIN (thunk) = DECL_THUNKS (function);
   DECL_THUNKS (function) = thunk;
@@ -303,14 +204,35 @@ finish_thunk (tree thunk)
   function = THUNK_TARGET (thunk);
   name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk),
                       fixed_offset, virtual_offset);
+
+  /* We can end up with declarations of (logically) different
+     covariant thunks, that do identical adjustments.  The two thunks
+     will be adjusting between within different hierarchies, which
+     happen to have the same layout.  We must nullify one of them to
+     refer to the other.  */
+  if (DECL_RESULT_THUNK_P (thunk))
+    {
+      tree cov_probe;
+
+      for (cov_probe = DECL_THUNKS (function);
+          cov_probe; cov_probe = TREE_CHAIN (cov_probe))
+       if (DECL_NAME (cov_probe) == name)
+         {
+           my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
+           THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)
+                                  ? THUNK_ALIAS (cov_probe) : cov_probe);
+           break;
+         }
+    }
+  
   DECL_NAME (thunk) = name;
   SET_DECL_ASSEMBLER_NAME (thunk, name);
 }
 
 /* Adjust PTR by the constant FIXED_OFFSET, and by the vtable
    offset indicated by VIRTUAL_OFFSET, if that is
-   non-null. THIS_ADJUSTING is non-zero for a this adjusting thunk and
-   zero for a result adjusting thunk. */
+   non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and
+   zero for a result adjusting thunk.  */
 
 static tree
 thunk_adjust (tree ptr, bool this_adjusting,
@@ -351,6 +273,57 @@ thunk_adjust (tree ptr, bool this_adjusting,
   return ptr;
 }
 
+/* Garbage collector tables contains thunk_labelno even when places
+   inside ifdef block.  */
+static GTY (()) int thunk_labelno;
+#ifdef ASM_OUTPUT_DEF
+
+/* Create a static alias to function.  */
+
+static tree
+make_alias_for_thunk (tree function)
+{
+  tree alias;
+  char buf[256];
+
+  ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno);
+  thunk_labelno++;
+  alias = build_decl (FUNCTION_DECL, get_identifier (buf),
+                     TREE_TYPE (function));
+  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
+  cxx_dup_lang_specific_decl (alias);
+  DECL_CONTEXT (alias) = NULL;
+  TREE_READONLY (alias) = TREE_READONLY (function);
+  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
+  TREE_PUBLIC (alias) = 0;
+  DECL_INTERFACE_KNOWN (alias) = 1;
+  DECL_NOT_REALLY_EXTERN (alias) = 1;
+  DECL_THIS_STATIC (alias) = 1;
+  DECL_SAVED_FUNCTION_DATA (alias) = NULL;
+  DECL_DESTRUCTOR_P (alias) = 0;
+  DECL_CONSTRUCTOR_P (alias) = 0;
+  DECL_CLONED_FUNCTION (alias) = NULL_TREE;
+  DECL_EXTERNAL (alias) = 0;
+  DECL_ARTIFICIAL (alias) = 1;
+  DECL_NO_STATIC_CHAIN (alias) = 1;
+  DECL_PENDING_INLINE_P (alias) = 0;
+  DECL_INLINE (alias) = 0;
+  DECL_DECLARED_INLINE_P (alias) = 0;
+  DECL_DEFERRED_FN (alias) = 0;
+  DECL_USE_TEMPLATE (alias) = 0;
+  DECL_TEMPLATE_INSTANTIATED (alias) = 0;
+  DECL_TEMPLATE_INFO (alias) = NULL;
+  DECL_INITIAL (alias) = error_mark_node;
+  TREE_ADDRESSABLE (alias) = 1;
+  TREE_USED (alias) = 1;
+  SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
+  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
+  if (!flag_syntax_only)
+    assemble_alias (alias, DECL_ASSEMBLER_NAME (function));
+  return alias;
+}
+#endif
+
 /* Emit the definition of a C++ multiple inheritance or covariant
    return vtable thunk.  If EMIT_P is nonzero, the thunk is emitted
    immediately.  */
@@ -358,14 +331,18 @@ thunk_adjust (tree ptr, bool this_adjusting,
 void
 use_thunk (tree thunk_fndecl, bool emit_p)
 {
-  tree function;
+  tree a, t, function, alias;
   tree virtual_offset;
   HOST_WIDE_INT fixed_offset, virtual_value;
   bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);
 
-  /* We should have called finish_thunk to give it a name. */
+  /* We should have called finish_thunk to give it a name.  */
   my_friendly_assert (DECL_NAME (thunk_fndecl), 20021127);
 
+  /* We should never be using an alias, always refer to the
+     aliased thunk.  */
+  my_friendly_assert (!THUNK_ALIAS (thunk_fndecl), 20031023);
+
   if (TREE_ASM_WRITTEN (thunk_fndecl))
     return;
   
@@ -382,10 +359,16 @@ use_thunk (tree thunk_fndecl, bool emit_p)
      this translation unit.  */
   TREE_ADDRESSABLE (function) = 1;
   mark_used (function);
-  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1;
+  mark_referenced (DECL_ASSEMBLER_NAME (function));
   if (!emit_p)
     return;
 
+#ifdef ASM_OUTPUT_DEF
+  alias = make_alias_for_thunk (function);
+#else
+  alias = function;
+#endif
+
   fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl);
   virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl);
 
@@ -406,6 +389,9 @@ use_thunk (tree thunk_fndecl, bool emit_p)
   /* The linkage of the function may have changed.  FIXME in linkage
      rewrite.  */
   TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
+  DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
+  if (flag_weak && TREE_PUBLIC (thunk_fndecl))
+    comdat_linkage (thunk_fndecl);
 
   if (flag_syntax_only)
     {
@@ -415,26 +401,54 @@ use_thunk (tree thunk_fndecl, bool emit_p)
 
   push_to_top_level ();
 
+#ifdef ASM_OUTPUT_DEF
+  if (targetm.have_named_sections)
+    {
+      resolve_unique_section (function, 0, flag_function_sections);
+
+      if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function))
+       {
+         resolve_unique_section (thunk_fndecl, 0, flag_function_sections);
+
+         /* Output the thunk into the same section as function.  */
+         DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function);
+       }
+    }
+#endif
+
   /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
      create one.  */
   DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
-  BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = DECL_ARGUMENTS (thunk_fndecl);
+
+  /* Set up cloned argument trees for the thunk.  */
+  t = NULL_TREE;
+  for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
+    {
+      tree x = copy_node (a);
+      TREE_CHAIN (x) = t;
+      DECL_CONTEXT (x) = thunk_fndecl;
+      SET_DECL_RTL (x, NULL_RTX);
+      t = x;
+    }
+  a = nreverse (t);
+  DECL_ARGUMENTS (thunk_fndecl) = a;
+  BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = a;
   
   if (this_adjusting
       && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
-                                             virtual_value, function))
+                                             virtual_value, alias))
     {
       const char *fnname;
       current_function_decl = thunk_fndecl;
       DECL_RESULT (thunk_fndecl)
        = build_decl (RESULT_DECL, 0, integer_type_node);
       fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
-      init_function_start (thunk_fndecl, input_filename, input_line);
+      init_function_start (thunk_fndecl);
       current_function_is_thunk = 1;
       assemble_start_function (thunk_fndecl, fnname);
 
       targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
-                                      fixed_offset, virtual_value, function);
+                                      fixed_offset, virtual_value, alias);
 
       assemble_end_function (thunk_fndecl, fnname);
       current_function_decl = 0;
@@ -451,32 +465,17 @@ use_thunk (tree thunk_fndecl, bool emit_p)
         just makes a call to the real function.  Unfortunately, this
         doesn't work for varargs.  */
 
-      tree a, t;
-      int saved_check_access;
-
       if (varargs_function_p (function))
        error ("generic thunk code fails for method `%#D' which uses `...'",
               function);
 
-      /* Set up cloned argument trees for the thunk.  */
-      t = NULL_TREE;
-      for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
-       {
-         tree x = copy_node (a);
-         TREE_CHAIN (x) = t;
-         DECL_CONTEXT (x) = thunk_fndecl;
-         t = x;
-       }
-      a = nreverse (t);
-      DECL_ARGUMENTS (thunk_fndecl) = a;
       DECL_RESULT (thunk_fndecl) = NULL_TREE;
 
       start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
       /* We don't bother with a body block for thunks.  */
 
       /* There's no need to check accessibility inside the thunk body.  */
-      saved_check_access = scope_chain->check_access;
-      scope_chain->check_access = 0;
+      push_deferring_access_checks (dk_no_check);
 
       t = a;
       if (this_adjusting)
@@ -488,25 +487,29 @@ use_thunk (tree thunk_fndecl, bool emit_p)
       for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
        t = tree_cons (NULL_TREE, a, t);
       t = nreverse (t);
-      t = build_call (function, t);
-      if (!this_adjusting)
-       t = thunk_adjust (t, /*this_adjusting=*/0,
-                         fixed_offset, virtual_offset);
+      t = build_call (alias, t);
+      CALL_FROM_THUNK_P (t) = 1;
       
       if (VOID_TYPE_P (TREE_TYPE (t)))
        finish_expr_stmt (t);
       else
-       finish_return_stmt (t);
+       {
+         t = force_target_expr (TREE_TYPE (t), t);
+         if (!this_adjusting)
+           t = thunk_adjust (t, /*this_adjusting=*/0,
+                             fixed_offset, virtual_offset);
+         finish_return_stmt (t);
+       }
 
       /* Since we want to emit the thunk, we explicitly mark its name as
         referenced.  */
-      TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (thunk_fndecl)) = 1;
+      mark_referenced (DECL_ASSEMBLER_NAME (thunk_fndecl));
 
       /* But we don't want debugging information about it.  */
       DECL_IGNORED_P (thunk_fndecl) = 1;
 
       /* Re-enable access control.  */
-      scope_chain->check_access = saved_check_access;
+      pop_deferring_access_checks ();
 
       expand_body (finish_function (0));
     }
@@ -627,7 +630,7 @@ do_build_assign_ref (tree fndecl)
   tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
   tree compound_stmt;
 
-  compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
   parm = convert_from_reference (parm);
 
   if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)
@@ -645,7 +648,7 @@ do_build_assign_ref (tree fndecl)
       int cvquals = cp_type_quals (TREE_TYPE (parm));
       int i;
 
-      /* Assign to each of thedirect base classes.  */
+      /* Assign to each of the direct base classes.  */
       for (i = 0; i < CLASSTYPE_N_BASECLASSES (current_class_type); ++i)
        {
          tree binfo;
@@ -720,7 +723,7 @@ do_build_assign_ref (tree fndecl)
        }
     }
   finish_return_stmt (current_class_ref);
-  finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+  finish_compound_stmt (compound_stmt);
 }
 
 void
@@ -743,6 +746,10 @@ synthesize_method (tree fndecl)
       return;
     }
 
+  /* We may be in the middle of deferred access check.  Disable
+     it now.  */
+  push_deferring_access_checks (dk_no_deferred);
+
   if (! context)
     push_to_top_level ();
   else if (nested)
@@ -754,8 +761,7 @@ synthesize_method (tree fndecl)
      where the attempt to generate the function occurs, giving the
      user a hint as to why we are attempting to generate the
      function.  */
-  DECL_SOURCE_LINE (fndecl) = input_line;
-  DECL_SOURCE_FILE (fndecl) = input_filename;
+  DECL_SOURCE_LOCATION (fndecl) = input_location;
 
   interface_unknown = 1;
   start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);
@@ -781,18 +787,20 @@ synthesize_method (tree fndecl)
   if (need_body)
     {
       tree compound_stmt;
-      compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-      finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+      compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
+      finish_compound_stmt (compound_stmt);
     }
 
   finish_function_body (stmt);
-  expand_body (finish_function (0));
+  expand_or_defer_fn (finish_function (0));
 
   extract_interface_info ();
   if (! context)
     pop_from_top_level ();
   else if (nested)
     pop_function_context_from (context);
+
+  pop_deferring_access_checks ();
 }
 
 /* Use EXTRACTOR to locate the relevant function called for each base &
@@ -922,9 +930,7 @@ locate_copy (tree type, void *client_)
       parms = TREE_CHAIN (parms);
       if (!parms)
         continue;
-      src_type = TREE_VALUE (parms);
-      if (TREE_CODE (src_type) == REFERENCE_TYPE)
-        src_type = TREE_TYPE (src_type);
+      src_type = non_reference (TREE_VALUE (parms));
       if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
         continue;
       if (!sufficient_parms_p (TREE_CHAIN (parms)))
@@ -1051,3 +1057,5 @@ skip_artificial_parms_for (tree fn, tree list)
     list = TREE_CHAIN (list);
   return list;
 }
+
+#include "gt-cp-method.h"