OSDN Git Service

PR c++/41468
[pf3gnuchains/gcc-fork.git] / gcc / cp / method.c
index 410503d..43b84dd 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 *);
@@ -126,7 +126,8 @@ make_thunk (tree function, bool this_adjusting,
   gcc_assert (TYPE_SIZE (DECL_CONTEXT (function))
              && TYPE_BEING_DEFINED (DECL_CONTEXT (function)));
 
-  thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
+  thunk = build_decl (DECL_SOURCE_LOCATION (function),
+                     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;
@@ -150,14 +151,9 @@ make_thunk (tree function, bool this_adjusting,
   DECL_CONSTRUCTOR_P (thunk) = 0;
   DECL_EXTERNAL (thunk) = 1;
   DECL_ARTIFICIAL (thunk) = 1;
-  /* Even if this thunk is a member of a local class, we don't
-     need a static chain.  */
-  DECL_NO_STATIC_CHAIN (thunk) = 1;
   /* The THUNK is not a pending inline, even if the FUNCTION is.  */
   DECL_PENDING_INLINE_P (thunk) = 0;
   DECL_DECLARED_INLINE_P (thunk) = 0;
-  /* Nor has it been deferred.  */
-  DECL_DEFERRED_FN (thunk) = 0;
   /* Nor is it a template instantiation.  */
   DECL_USE_TEMPLATE (thunk) = 0;
   DECL_TEMPLATE_INFO (thunk) = NULL;
@@ -209,83 +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 (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 (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 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
-                        fold_convert (sizetype, vtable));
-    }
-
-  if (!this_adjusting)
-    /* Adjust the pointer by the constant.  */
-    ptr = fold_build2 (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 (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;
-  DECL_CLONED_FUNCTION (alias) = NULL_TREE;
+  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_NO_STATIC_CHAIN (alias) = 1;
-  DECL_PENDING_INLINE_P (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;
+  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));
@@ -305,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;
 }
@@ -380,8 +340,8 @@ use_thunk (tree thunk_fndecl, bool emit_p)
   DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
   DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
     = DECL_VISIBILITY_SPECIFIED (function);
-  if (DECL_ONE_ONLY (function))
-    make_decl_one_only (thunk_fndecl);
+  if (DECL_ONE_ONLY (function) || DECL_WEAK (function))
+    make_decl_one_only (thunk_fndecl, cxx_comdat_group (thunk_fndecl));
 
   if (flag_syntax_only)
     {
@@ -418,40 +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))
-    {
-      const char *fnname;
-      tree fn_block;
-      
-      current_function_decl = thunk_fndecl;
-      DECL_RESULT (thunk_fndecl)
-       = build_decl (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 ();
-      current_function_decl = 0;
-      set_cfun (NULL);
-      TREE_ASM_WRITTEN (thunk_fndecl) = 1;
-    }
-  else
+  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))
     {
-      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 ();
@@ -530,12 +402,13 @@ use_thunk (tree thunk_fndecl, bool emit_p)
 \f
 /* Code for synthesizing methods which have default semantics defined.  */
 
-/* Generate code for default X(X&) constructor.  */
+/* Generate code for default X(X&) or X(X&&) constructor.  */
 
 static void
 do_build_copy_constructor (tree fndecl)
 {
   tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
+  bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
 
   parm = convert_from_reference (parm);
 
@@ -555,6 +428,7 @@ do_build_copy_constructor (tree fndecl)
       int cvquals = cp_type_quals (TREE_TYPE (parm));
       int i;
       tree binfo, base_binfo;
+      tree init;
       VEC(tree,gc) *vbases;
 
       /* Initialize all the base-classes with the parameter converted
@@ -565,11 +439,12 @@ do_build_copy_constructor (tree fndecl)
       for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
           VEC_iterate (tree, vbases, i, binfo); i++)
        {
+         init = build_base_path (PLUS_EXPR, parm, binfo, 1);
+         if (move_p)
+           init = move (init);
          member_init_list
            = tree_cons (binfo,
-                        build_tree_list (NULL_TREE,
-                                         build_base_path (PLUS_EXPR, parm,
-                                                          binfo, 1)),
+                        build_tree_list (NULL_TREE, init),
                         member_init_list);
        }
 
@@ -579,17 +454,17 @@ do_build_copy_constructor (tree fndecl)
          if (BINFO_VIRTUAL_P (base_binfo))
            continue;
 
+         init = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
+         if (move_p)
+           init = move (init);
          member_init_list
            = tree_cons (base_binfo,
-                        build_tree_list (NULL_TREE,
-                                         build_base_path (PLUS_EXPR, parm,
-                                                          base_binfo, 1)),
+                        build_tree_list (NULL_TREE, init),
                         member_init_list);
        }
 
       for (; fields; fields = TREE_CHAIN (fields))
        {
-         tree init = parm;
          tree field = fields;
          tree expr_type;
 
@@ -619,10 +494,13 @@ do_build_copy_constructor (tree fndecl)
 
              if (DECL_MUTABLE_P (field))
                quals &= ~TYPE_QUAL_CONST;
+             quals |= cp_type_quals (expr_type);
              expr_type = cp_build_qualified_type (expr_type, quals);
            }
 
-         init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE);
+         init = build3 (COMPONENT_REF, expr_type, parm, field, NULL_TREE);
+         if (move_p && TREE_CODE (expr_type) != REFERENCE_TYPE)
+           init = move (init);
          init = build_tree_list (NULL_TREE, init);
 
          member_init_list = tree_cons (field, init, member_init_list);
@@ -936,6 +814,8 @@ locate_copy (tree type, void *client_)
         it now.  */
       if (CLASSTYPE_LAZY_COPY_CTOR (type))
        lazily_declare_fn (sfk_copy_constructor, type);
+      if (CLASSTYPE_LAZY_MOVE_CTOR (type))
+       lazily_declare_fn (sfk_move_constructor, type);
       fns = CLASSTYPE_CONSTRUCTORS (type);
     }
   else
@@ -1036,6 +916,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
 
     case sfk_copy_constructor:
     case sfk_assignment_operator:
+    case sfk_move_constructor:
     {
       struct copy_data data;
 
@@ -1053,11 +934,13 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
       if (const_p)
        {
          data.quals = TYPE_QUAL_CONST;
-         rhs_parm_type = build_qualified_type (type, TYPE_QUAL_CONST);
+         rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
        }
       else
        rhs_parm_type = type;
-      rhs_parm_type = build_reference_type (rhs_parm_type);
+      rhs_parm_type
+       = cp_build_reference_type (rhs_parm_type,
+                                  kind == sfk_move_constructor);
       parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
       raises = synthesize_exception_spec (type, &locate_copy, &data);
       break;
@@ -1072,7 +955,8 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
     fn_type = build_exception_variant (fn_type, raises);
   fn = build_lang_decl (FUNCTION_DECL, name, fn_type);
   DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
-  if (kind == sfk_constructor || kind == sfk_copy_constructor)
+  if (kind == sfk_constructor || kind == sfk_copy_constructor
+      || kind == sfk_move_constructor)
     DECL_CONSTRUCTOR_P (fn) = 1;
   else if (kind == sfk_destructor)
     DECL_DESTRUCTOR_P (fn) = 1;
@@ -1119,6 +1003,91 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   return fn;
 }
 
+/* Gives any errors about defaulted functions which need to be deferred
+   until the containing class is complete.  */
+
+void
+defaulted_late_check (tree fn)
+{
+  /* Complain about invalid signature for defaulted fn.  */
+  tree ctx = DECL_CONTEXT (fn);
+  special_function_kind kind = special_function_p (fn);
+  bool fn_const_p = (copy_fn_p (fn) == 2);
+  tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p);
+
+  if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)),
+                   TREE_TYPE (TREE_TYPE (implicit_fn)))
+      || !compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)),
+                    TYPE_ARG_TYPES (TREE_TYPE (implicit_fn))))
+    {
+      error ("defaulted declaration %q+D", fn);
+      error_at (DECL_SOURCE_LOCATION (fn),
+               "does not match expected signature %qD", implicit_fn);
+    }
+}
+
+/* Returns true iff FN can be explicitly defaulted, and gives any
+   errors if defaulting FN is ill-formed.  */
+
+bool
+defaultable_fn_check (tree fn)
+{
+  special_function_kind kind = sfk_none;
+
+  if (DECL_CONSTRUCTOR_P (fn))
+    {
+      if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node)
+       kind = sfk_constructor;
+      else if (copy_fn_p (fn) > 0
+              && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn))
+                  == void_list_node))
+       kind = sfk_copy_constructor;
+      else if (move_fn_p (fn))
+       kind = sfk_move_constructor;
+    }
+  else if (DECL_DESTRUCTOR_P (fn))
+    kind = sfk_destructor;
+  else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
+          && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
+          && copy_fn_p (fn))
+    kind = sfk_assignment_operator;
+
+  if (kind == sfk_none)
+    {
+      error ("%qD cannot be defaulted", fn);
+      return false;
+    }
+  else
+    {
+      tree t = FUNCTION_FIRST_USER_PARMTYPE (fn);
+      for (; t && t != void_list_node; t = TREE_CHAIN (t))
+       if (TREE_PURPOSE (t))
+         {
+           error ("defaulted function %q+D with default argument", fn);
+           break;
+         }
+      if (TYPE_BEING_DEFINED (DECL_CONTEXT (fn)))
+       {
+         if (DECL_NONCONVERTING_P (fn))
+           error ("%qD declared explicit cannot be defaulted in the class "
+                  "body", fn);
+         if (current_access_specifier != access_public_node)
+           error ("%qD declared with non-public access cannot be defaulted "
+                  "in the class body", 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);
+
+      return true;
+    }
+}
+
 /* Add an implicit declaration to TYPE for the kind of function
    indicated by SFK.  Return the FUNCTION_DECL for the new implicit
    declaration.  */
@@ -1157,7 +1126,7 @@ lazily_declare_fn (special_function_kind sfk, tree type)
       /* G++ 3.2 put the implicit destructor at the *beginning* of the
         TYPE_METHODS list, which cause the destructor to be emitted
         in an incorrect location in the vtable.  */
-      if (warn_abi && DECL_VIRTUAL_P (fn))
+      if (warn_abi && sfk == sfk_destructor && DECL_VIRTUAL_P (fn))
        warning (OPT_Wabi, "vtable layout for class %qT may not be ABI-compliant"
                 "and may change in a future version of GCC due to "
                 "implicit virtual destructor",
@@ -1175,6 +1144,8 @@ lazily_declare_fn (special_function_kind sfk, tree type)
        CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
       else if (sfk == sfk_copy_constructor)
        CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
+      else if (sfk == sfk_move_constructor)
+       CLASSTYPE_LAZY_MOVE_CTOR (type) = 0;
       else if (sfk == sfk_destructor)
        CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
       /* Create appropriate clones.  */