OSDN Git Service

PR c++/25811
[pf3gnuchains/gcc-fork.git] / gcc / cp / method.c
index 47f9e42..5ed98bc 100644 (file)
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "diagnostic.h"
 #include "cgraph.h"
+#include "gimple.h"
 
 /* Various flags to control the mangling process.  */
 
@@ -58,7 +59,6 @@ enum mangling_flags
 
 typedef enum mangling_flags mangling_flags;
 
-static tree thunk_adjust (tree, bool, HOST_WIDE_INT, tree);
 static void do_build_assign_ref (tree);
 static void do_build_copy_constructor (tree);
 static tree synthesize_exception_spec (tree, tree (*) (tree, void *), void *);
@@ -205,85 +205,43 @@ finish_thunk (tree thunk)
   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 nonzero for a this adjusting thunk and
-   zero for a result adjusting thunk.  */
-
-static tree
-thunk_adjust (tree ptr, bool this_adjusting,
-             HOST_WIDE_INT fixed_offset, tree virtual_offset)
-{
-  if (this_adjusting)
-    /* Adjust the pointer by the constant.  */
-    ptr = fold_build2_loc (input_location,
-                      POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
-                      size_int (fixed_offset));
-
-  /* If there's a virtual offset, look up that value in the vtable and
-     adjust the pointer again.  */
-  if (virtual_offset)
-    {
-      tree vtable;
-
-      ptr = save_expr (ptr);
-      /* The vptr is always at offset zero in the object.  */
-      vtable = build1 (NOP_EXPR,
-                      build_pointer_type (build_pointer_type
-                                          (vtable_entry_type)),
-                      ptr);
-      /* Form the vtable address.  */
-      vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable);
-      /* Find the entry with the vcall offset.  */
-      vtable = fold_build2_loc (input_location,
-                           POINTER_PLUS_EXPR, TREE_TYPE (vtable), vtable,
-                           fold_convert (sizetype, virtual_offset));
-      /* Get the offset itself.  */
-      vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable);
-      /* Adjust the `this' pointer.  */
-      ptr = fold_build2_loc (input_location,
-                        POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
-                        fold_convert (sizetype, vtable));
-    }
-
-  if (!this_adjusting)
-    /* Adjust the pointer by the constant.  */
-    ptr = fold_build2_loc (input_location,
-                      POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
-                      size_int (fixed_offset));
-
-  return ptr;
-}
-
 static GTY (()) int thunk_labelno;
 
-/* Create a static alias to function.  */
+/* Create a static alias to target.  */
 
 tree
-make_alias_for (tree function, tree newid)
+make_alias_for (tree target, tree newid)
 {
-  tree alias = build_decl (DECL_SOURCE_LOCATION (function),
-                          FUNCTION_DECL, newid, TREE_TYPE (function));
-  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
+  tree alias = build_decl (DECL_SOURCE_LOCATION (target),
+                          TREE_CODE (target), newid, TREE_TYPE (target));
+  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (target);
   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_READONLY (alias) = TREE_READONLY (target);
+  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (target);
   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;
+  if (DECL_LANG_SPECIFIC (alias))
+    {
+      DECL_NOT_REALLY_EXTERN (alias) = 1;
+      DECL_USE_TEMPLATE (alias) = 0;
+      DECL_TEMPLATE_INFO (alias) = NULL;
+    }
   DECL_EXTERNAL (alias) = 0;
   DECL_ARTIFICIAL (alias) = 1;
-  DECL_PENDING_INLINE_P (alias) = 0;
-  DECL_DECLARED_INLINE_P (alias) = 0;
-  DECL_USE_TEMPLATE (alias) = 0;
   DECL_TEMPLATE_INSTANTIATED (alias) = 0;
-  DECL_TEMPLATE_INFO (alias) = NULL;
-  DECL_INITIAL (alias) = error_mark_node;
+  if (TREE_CODE (alias) == FUNCTION_DECL)
+    {
+      DECL_SAVED_FUNCTION_DATA (alias) = NULL;
+      DECL_DESTRUCTOR_P (alias) = 0;
+      DECL_CONSTRUCTOR_P (alias) = 0;
+      DECL_PENDING_INLINE_P (alias) = 0;
+      DECL_DECLARED_INLINE_P (alias) = 0;
+      DECL_INITIAL (alias) = error_mark_node;
+      DECL_ARGUMENTS (alias) = copy_list (DECL_ARGUMENTS (target));
+    }
+  else
+    TREE_STATIC (alias) = 1;
   TREE_ADDRESSABLE (alias) = 1;
   TREE_USED (alias) = 1;
   SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
@@ -303,7 +261,11 @@ make_alias_for_thunk (tree function)
   alias = make_alias_for (function, get_identifier (buf));
 
   if (!flag_syntax_only)
-    assemble_alias (alias, DECL_ASSEMBLER_NAME (function));
+    {
+      bool ok = cgraph_same_body_alias (alias, function);
+      DECL_ASSEMBLER_NAME (function);
+      gcc_assert (ok);
+    }
 
   return alias;
 }
@@ -416,42 +378,15 @@ use_thunk (tree thunk_fndecl, bool emit_p)
     }
   a = nreverse (t);
   DECL_ARGUMENTS (thunk_fndecl) = a;
-
-  if (this_adjusting
-      && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
-                                             virtual_value, alias))
+  TREE_ASM_WRITTEN (thunk_fndecl) = 1;
+  cgraph_add_thunk (thunk_fndecl, function,
+                   this_adjusting, fixed_offset, virtual_value,
+                   virtual_offset, alias);
+
+  if (!this_adjusting
+      || !targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
+                                              virtual_value, alias))
     {
-      const char *fnname;
-      tree fn_block;
-      
-      current_function_decl = thunk_fndecl;
-      DECL_RESULT (thunk_fndecl)
-       = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
-                     RESULT_DECL, 0, integer_type_node);
-      fnname = IDENTIFIER_POINTER (DECL_NAME (thunk_fndecl));
-      /* The back end expects DECL_INITIAL to contain a BLOCK, so we
-        create one.  */
-      fn_block = make_node (BLOCK);
-      BLOCK_VARS (fn_block) = a;
-      DECL_INITIAL (thunk_fndecl) = fn_block;
-      init_function_start (thunk_fndecl);
-      cfun->is_thunk = 1;
-      assemble_start_function (thunk_fndecl, fnname);
-
-      targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
-                                      fixed_offset, virtual_value, alias);
-
-      assemble_end_function (thunk_fndecl, fnname);
-      init_insn_lengths ();
-      free_after_compilation (cfun);
-      current_function_decl = 0;
-      set_cfun (NULL);
-      TREE_ASM_WRITTEN (thunk_fndecl) = 1;
-    }
-  else
-    {
-      int i;
-      tree *argarray = (tree *) alloca (list_length (a) * sizeof (tree));
       /* If this is a covariant thunk, or we don't have the necessary
         code for efficient thunks, generate a thunk function that
         just makes a call to the real function.  Unfortunately, this
@@ -460,69 +395,6 @@ use_thunk (tree thunk_fndecl, bool emit_p)
       if (varargs_function_p (function))
        error ("generic thunk code fails for method %q#D which uses %<...%>",
               function);
-
-      DECL_RESULT (thunk_fndecl) = NULL_TREE;
-
-      start_preparsed_function (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.  */
-      push_deferring_access_checks (dk_no_check);
-
-      t = a;
-      if (this_adjusting)
-       t = thunk_adjust (t, /*this_adjusting=*/1,
-                         fixed_offset, virtual_offset);
-
-      /* Build up the call to the real function.  */
-      argarray[0] = t;
-      for (i = 1, a = TREE_CHAIN (a); a; a = TREE_CHAIN (a), i++)
-       argarray[i] = a;
-      t = build_call_a (alias, i, argarray);
-      CALL_FROM_THUNK_P (t) = 1;
-      CALL_CANNOT_INLINE_P (t) = 1;
-
-      if (VOID_TYPE_P (TREE_TYPE (t)))
-       finish_expr_stmt (t);
-      else
-       {
-         if (!this_adjusting)
-           {
-             tree cond = NULL_TREE;
-
-             if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
-               {
-                 /* If the return type is a pointer, we need to
-                    protect against NULL.  We know there will be an
-                    adjustment, because that's why we're emitting a
-                    thunk.  */
-                 t = save_expr (t);
-                 cond = cp_convert (boolean_type_node, t);
-               }
-
-             t = thunk_adjust (t, /*this_adjusting=*/0,
-                               fixed_offset, virtual_offset);
-             if (cond)
-               t = build3 (COND_EXPR, TREE_TYPE (t), cond, t,
-                           cp_convert (TREE_TYPE (t), integer_zero_node));
-           }
-         if (MAYBE_CLASS_TYPE_P (TREE_TYPE (t)))
-           t = build_cplus_new (TREE_TYPE (t), t);
-         finish_return_stmt (t);
-       }
-
-      /* Since we want to emit the thunk, we explicitly mark its name as
-        referenced.  */
-      mark_decl_referenced (thunk_fndecl);
-
-      /* But we don't want debugging information about it.  */
-      DECL_IGNORED_P (thunk_fndecl) = 1;
-
-      /* Re-enable access control.  */
-      pop_deferring_access_checks ();
-
-      thunk_fndecl = finish_function (0);
-      cgraph_add_new_function (thunk_fndecl, false);
     }
 
   pop_from_top_level ();
@@ -1205,6 +1077,9 @@ defaultable_fn_check (tree fn)
          if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
            error ("function %q+D defaulted on its first declaration "
                   "must not have an exception-specification", fn);
+         if (DECL_VIRTUAL_P (fn))
+           error ("%qD declared virtual cannot be defaulted in the class "
+                  "body", fn);
        }
       else if (!processing_template_decl)
        defaulted_late_check (fn);