OSDN Git Service

PR c++/25811
[pf3gnuchains/gcc-fork.git] / gcc / cp / method.c
index 7e4e956..5ed98bc 100644 (file)
@@ -1,14 +1,15 @@
 /* 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, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
-   
+
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -17,9 +18,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 /* Handle method declarations.  */
@@ -36,6 +36,10 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "tm_p.h"
 #include "target.h"
+#include "tree-pass.h"
+#include "diagnostic.h"
+#include "cgraph.h"
+#include "gimple.h"
 
 /* Various flags to control the mangling process.  */
 
@@ -55,13 +59,9 @@ 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 *);
-static tree locate_dtor (tree, void *);
-static tree locate_ctor (tree, void *);
-static tree locate_copy (tree, void *);
 static tree make_alias_for_thunk (tree);
 
 /* Called once to initialize method.c.  */
@@ -87,22 +87,22 @@ make_thunk (tree function, bool this_adjusting,
 {
   HOST_WIDE_INT d;
   tree thunk;
-  
+
   gcc_assert (TREE_CODE (function) == FUNCTION_DECL);
   /* We can have this thunks to covariant thunks, but not vice versa.  */
   gcc_assert (!DECL_THIS_THUNK_P (function));
   gcc_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting);
-  
+
   /* Scale the VIRTUAL_OFFSET to be in terms of bytes.  */
   if (this_adjusting && virtual_offset)
-    virtual_offset 
+    virtual_offset
       = size_binop (MULT_EXPR,
-                   virtual_offset,
-                   convert (ssizetype,
-                            TYPE_SIZE_UNIT (vtable_entry_type)));
-  
+                   virtual_offset,
+                   convert (ssizetype,
+                            TYPE_SIZE_UNIT (vtable_entry_type)));
+
   d = tree_low_cst (fixed_offset, 0);
-  
+
   /* 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.  */
@@ -116,7 +116,7 @@ make_thunk (tree function, bool this_adjusting,
                                      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.  */
@@ -126,23 +126,22 @@ 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;
-  
+
   DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
   TREE_READONLY (thunk) = TREE_READONLY (function);
   TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
   TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
-  if (flag_weak)
-    comdat_linkage (thunk);
   SET_DECL_THUNK_P (thunk, 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.  */
   DECL_INTERFACE_KNOWN (thunk) = 1;
@@ -152,16 +151,13 @@ 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_INLINE (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;
+
   /* Add it to the list of thunks associated with FUNCTION.  */
   TREE_CHAIN (thunk) = DECL_THUNKS (function);
   DECL_THUNKS (function) = thunk;
@@ -204,99 +200,73 @@ finish_thunk (tree thunk)
            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 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 (PLUS_EXPR, TREE_TYPE (ptr), ptr,
-                      ssize_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 = build2 (PLUS_EXPR, TREE_TYPE (vtable), vtable, virtual_offset);
-      /* Get the offset itself.  */
-      vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable);
-      /* Adjust the `this' pointer.  */
-      ptr = fold_build2 (PLUS_EXPR, TREE_TYPE (ptr), ptr, vtable);
-    }
-  
-  if (!this_adjusting)
-    /* Adjust the pointer by the constant.  */
-    ptr = fold_build2 (PLUS_EXPR, TREE_TYPE (ptr), ptr,
-                      ssize_int (fixed_offset));
-
-  return ptr;
-}
-
 static GTY (()) int thunk_labelno;
 
-/* Create a static alias to function.  */
+/* Create a static alias to target.  */
 
-static tree
-make_alias_for_thunk (tree function)
+tree
+make_alias_for (tree target, tree newid)
 {
-  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);
+  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_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;
+  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));
   TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
+  return alias;
+}
+
+static tree
+make_alias_for_thunk (tree function)
+{
+  tree alias;
+  char buf[256];
+
+  ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno);
+  thunk_labelno++;
+
+  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;
 }
 
@@ -321,7 +291,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
 
   if (TREE_ASM_WRITTEN (thunk_fndecl))
     return;
-  
+
   function = THUNK_TARGET (thunk_fndecl);
   if (DECL_RESULT (thunk_fndecl))
     /* We already turned this thunk into an ordinary function.
@@ -331,7 +301,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
   if (DECL_THUNK_P (function))
     /* The target is itself a thunk, process it now.  */
     use_thunk (function, emit_p);
-  
+
   /* Thunks are always addressable; they only appear in vtables.  */
   TREE_ADDRESSABLE (thunk_fndecl) = 1;
 
@@ -359,7 +329,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
     }
   else
     virtual_value = 0;
-  
+
   /* And, if we need to emit the thunk, it's used.  */
   mark_used (thunk_fndecl);
   /* This thunk is actually defined.  */
@@ -368,10 +338,10 @@ use_thunk (tree thunk_fndecl, bool emit_p)
      rewrite.  */
   TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
   DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
-  DECL_VISIBILITY_SPECIFIED (thunk_fndecl) 
+  DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
     = DECL_VISIBILITY_SPECIFIED (function);
-  if (flag_weak && TREE_PUBLIC (thunk_fndecl))
-    comdat_linkage (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)
     {
@@ -395,10 +365,6 @@ use_thunk (tree thunk_fndecl, bool emit_p)
        }
     }
 
-  /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
-     create one.  */
-  DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
-
   /* Set up cloned argument trees for the thunk.  */
   t = NULL_TREE;
   for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
@@ -407,34 +373,19 @@ use_thunk (tree thunk_fndecl, bool emit_p)
       TREE_CHAIN (x) = t;
       DECL_CONTEXT (x) = thunk_fndecl;
       SET_DECL_RTL (x, NULL_RTX);
+      DECL_HAS_VALUE_EXPR_P (x) = 0;
       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, 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);
-      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, alias);
-
-      assemble_end_function (thunk_fndecl, fnname);
-      current_function_decl = 0;
-      cfun = 0;
-      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))
     {
       /* If this is a covariant thunk, or we don't have the necessary
         code for efficient thunks, generate a thunk function that
@@ -444,67 +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.  */
-      t = tree_cons (NULL_TREE, t, NULL_TREE);
-      for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
-       t = tree_cons (NULL_TREE, a, t);
-      t = nreverse (t);
-      t = build_call (alias, t);
-      CALL_FROM_THUNK_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));
-           }
-         t = force_target_expr (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 ();
-
-      expand_body (finish_function (0));
     }
 
   pop_from_top_level ();
@@ -512,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);
 
@@ -537,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
@@ -547,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++)
        {
-         member_init_list 
+         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);
        }
 
@@ -559,19 +452,19 @@ do_build_copy_constructor (tree fndecl)
           BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
        {
          if (BINFO_VIRTUAL_P (base_binfo))
-           continue; 
+           continue;
 
-         member_init_list 
+         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;
 
@@ -598,13 +491,16 @@ do_build_copy_constructor (tree fndecl)
          if (TREE_CODE (expr_type) != REFERENCE_TYPE)
            {
              int quals = cvquals;
-             
+
              if (DECL_MUTABLE_P (field))
                quals &= ~TYPE_QUAL_CONST;
+             quals |= 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);
@@ -643,23 +539,26 @@ do_build_assign_ref (tree fndecl)
           BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
        {
          tree converted_parm;
+         VEC(tree,gc) *parmvec;
 
          /* We must convert PARM directly to the base class
             explicitly since the base class may be ambiguous.  */
          converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
          /* Call the base class assignment operator.  */
-         finish_expr_stmt 
-           (build_special_member_call (current_class_ref, 
+         parmvec = make_tree_vector_single (converted_parm);
+         finish_expr_stmt
+           (build_special_member_call (current_class_ref,
                                        ansi_assopname (NOP_EXPR),
-                                       build_tree_list (NULL_TREE, 
-                                                        converted_parm),
+                                       &parmvec,
                                        base_binfo,
-                                       LOOKUP_NORMAL | LOOKUP_NONVIRTUAL));
+                                       LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
+                                        tf_warning_or_error));
+         release_tree_vector (parmvec);
        }
 
       /* Assign to each of the non-static data members.  */
-      for (fields = TYPE_FIELDS (current_class_type); 
-          fields; 
+      for (fields = TYPE_FIELDS (current_class_type);
+          fields;
           fields = TREE_CHAIN (fields))
        {
          tree comp = current_class_ref;
@@ -672,17 +571,17 @@ do_build_assign_ref (tree fndecl)
            continue;
 
          expr_type = TREE_TYPE (field);
-         
+
          if (CP_TYPE_CONST_P (expr_type))
            {
-              error ("non-static const member %q#D, can't use default "
-                     "assignment operator", field);
+             error ("non-static const member %q#D, can't use default "
+                    "assignment operator", field);
              continue;
            }
          else if (TREE_CODE (expr_type) == REFERENCE_TYPE)
            {
              error ("non-static reference member %q#D, can't use "
-                     "default assignment operator", field);
+                    "default assignment operator", field);
              continue;
            }
 
@@ -699,17 +598,18 @@ do_build_assign_ref (tree fndecl)
            continue;
 
          comp = build3 (COMPONENT_REF, expr_type, comp, field, NULL_TREE);
-         
+
          /* Compute the type of init->field  */
          quals = cvquals;
          if (DECL_MUTABLE_P (field))
            quals &= ~TYPE_QUAL_CONST;
          expr_type = cp_build_qualified_type (expr_type, quals);
-         
+
          init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE);
 
          if (DECL_NAME (field))
-           init = build_modify_expr (comp, NOP_EXPR, init);
+           init = cp_build_modify_expr (comp, NOP_EXPR, init, 
+                                        tf_warning_or_error);
          else
            init = build2 (MODIFY_EXPR, TREE_TYPE (comp), comp, init);
          finish_expr_stmt (init);
@@ -719,6 +619,8 @@ do_build_assign_ref (tree fndecl)
   finish_compound_stmt (compound_stmt);
 }
 
+/* Synthesize FNDECL, a non-static member function.   */
+
 void
 synthesize_method (tree fndecl)
 {
@@ -727,17 +629,19 @@ synthesize_method (tree fndecl)
   bool need_body = true;
   tree stmt;
   location_t save_input_location = input_location;
+  int error_count = errorcount;
+  int warning_count = warningcount;
+
+  /* Reset the source location, we might have been previously
+     deferred, and thus have saved where we were first needed.  */
+  DECL_SOURCE_LOCATION (fndecl)
+    = DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (fndecl)));
 
   /* If we've been asked to synthesize a clone, just synthesize the
      cloned function instead.  Doing so will automatically fill in the
      body for the clone.  */
   if (DECL_CLONED_FUNCTION_P (fndecl))
-    {
-      DECL_SOURCE_LOCATION (DECL_CLONED_FUNCTION (fndecl)) =
-       DECL_SOURCE_LOCATION (fndecl);
-      synthesize_method (DECL_CLONED_FUNCTION (fndecl));
-      return;
-    }
+    fndecl = DECL_CLONED_FUNCTION (fndecl);
 
   /* We may be in the middle of deferred access check.  Disable
      it now.  */
@@ -746,7 +650,7 @@ synthesize_method (tree fndecl)
   if (! context)
     push_to_top_level ();
   else if (nested)
-    push_function_context_to (context);
+    push_function_context ();
 
   input_location = DECL_SOURCE_LOCATION (fndecl);
 
@@ -763,7 +667,7 @@ synthesize_method (tree fndecl)
       tree arg_chain = FUNCTION_FIRST_USER_PARMTYPE (fndecl);
       if (arg_chain != void_list_node)
        do_build_copy_constructor (fndecl);
-      else if (TYPE_NEEDS_CONSTRUCTING (current_class_type))
+      else
        finish_mem_initializers (NULL_TREE);
     }
 
@@ -784,9 +688,13 @@ synthesize_method (tree fndecl)
   if (! context)
     pop_from_top_level ();
   else if (nested)
-    pop_function_context_from (context);
+    pop_function_context ();
 
   pop_deferring_access_checks ();
+
+  if (error_count != errorcount || warning_count != warningcount)
+    inform (input_location, "synthesized method %qD first required here ",
+           fndecl);
 }
 
 /* Use EXTRACTOR to locate the relevant function called for each base &
@@ -797,7 +705,7 @@ synthesize_method (tree fndecl)
 
 static tree
 synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
-                           void *client)
+                          void *client)
 {
   tree raises = empty_except_spec;
   tree fields = TYPE_FIELDS (type);
@@ -809,38 +717,38 @@ synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
     {
       tree fn = (*extractor) (BINFO_TYPE (base_binfo), client);
       if (fn)
-        {
-          tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-          
-          raises = merge_exception_specifiers (raises, fn_raises);
-        }
+       {
+         tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+
+         raises = merge_exception_specifiers (raises, fn_raises);
+       }
     }
   for (; fields; fields = TREE_CHAIN (fields))
     {
       tree type = TREE_TYPE (fields);
       tree fn;
-      
+
       if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
-        continue;
+       continue;
       while (TREE_CODE (type) == ARRAY_TYPE)
-       type = TREE_TYPE (type);
-      if (TREE_CODE (type) != RECORD_TYPE)
-        continue;
-      
+       type = TREE_TYPE (type);
+      if (!CLASS_TYPE_P (type))
+       continue;
+
       fn = (*extractor) (type, client);
       if (fn)
-        {
-          tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-          
-          raises = merge_exception_specifiers (raises, fn_raises);
-        }
+       {
+         tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+
+         raises = merge_exception_specifiers (raises, fn_raises);
+       }
     }
   return raises;
 }
 
 /* Locate the dtor of TYPE.  */
 
-static tree
+tree
 locate_dtor (tree type, void *client ATTRIBUTE_UNUSED)
 {
   return CLASSTYPE_DESTRUCTORS (type);
@@ -848,11 +756,11 @@ locate_dtor (tree type, void *client ATTRIBUTE_UNUSED)
 
 /* Locate the default ctor of TYPE.  */
 
-static tree
+tree
 locate_ctor (tree type, void *client ATTRIBUTE_UNUSED)
 {
   tree fns;
-  
+
   if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
     return NULL_TREE;
 
@@ -865,11 +773,13 @@ locate_ctor (tree type, void *client ATTRIBUTE_UNUSED)
     {
       tree fn = OVL_CURRENT (fns);
       tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
-      
-      if (sufficient_parms_p (TREE_CHAIN (parms)))
-        return fn;
+
+      parms = skip_artificial_parms_for (fn, parms);
+
+      if (sufficient_parms_p (parms))
+       return fn;
     }
-  return NULL_TREE;
+  gcc_unreachable ();
 }
 
 struct copy_data
@@ -882,14 +792,14 @@ struct copy_data
    points to a COPY_DATA holding the name (NULL for the ctor)
    and desired qualifiers of the source operand.  */
 
-static tree
+tree
 locate_copy (tree type, void *client_)
 {
   struct copy_data *client = (struct copy_data *)client_;
   tree fns;
   tree best = NULL_TREE;
   bool excess_p = false;
-  
+
   if (client->name)
     {
       int ix;
@@ -904,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
@@ -915,27 +827,31 @@ locate_copy (tree type, void *client_)
       tree src_type;
       int excess;
       int quals;
-      
-      parms = TREE_CHAIN (parms);
+
+      parms = skip_artificial_parms_for (fn, parms);
       if (!parms)
-        continue;
+       continue;
       src_type = non_reference (TREE_VALUE (parms));
+
+      if (src_type == error_mark_node)
+        return NULL_TREE;
+
       if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
-        continue;
+       continue;
       if (!sufficient_parms_p (TREE_CHAIN (parms)))
-        continue;
+       continue;
       quals = cp_type_quals (src_type);
       if (client->quals & ~quals)
-        continue;
+       continue;
       excess = quals & ~client->quals;
       if (!best || (excess_p && !excess))
-        {
-          best = fn;
-          excess_p = excess;
-        }
+       {
+         best = fn;
+         excess_p = excess;
+       }
       else
-        /* Ambiguous */
-        return NULL_TREE;
+       /* Ambiguous */
+       return NULL_TREE;
     }
   return best;
 }
@@ -946,7 +862,7 @@ locate_copy (tree type, void *client_)
    reference argument or a non-const reference.  Returns the
    FUNCTION_DECL for the implicitly declared function.  */
 
-tree
+static tree
 implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
 {
   tree fn;
@@ -955,7 +871,21 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   tree fn_type;
   tree raises = empty_except_spec;
   tree rhs_parm_type = NULL_TREE;
+  tree this_parm;
   tree name;
+  HOST_WIDE_INT saved_processing_template_decl;
+
+  /* Because we create declarations for implicitly declared functions
+     lazily, we may be creating the declaration for a member of TYPE
+     while in some completely different context.  However, TYPE will
+     never be a dependent class (because we never want to do lookups
+     for implicitly defined functions in a dependent class).
+     Furthermore, we must set PROCESSING_TEMPLATE_DECL to zero here
+     because we only create clones for constructors and destructors
+     when not in a template.  */
+  gcc_assert (!dependent_type_p (type));
+  saved_processing_template_decl = processing_template_decl;
+  processing_template_decl = 0;
 
   type = TYPE_MAIN_VARIANT (type);
 
@@ -986,28 +916,31 @@ 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;
-      
+
       data.name = NULL;
       data.quals = 0;
       if (kind == sfk_assignment_operator)
-        {
+       {
          return_type = build_reference_type (type);
-          name = ansi_assopname (NOP_EXPR);
-          data.name = name;
-        }
+         name = ansi_assopname (NOP_EXPR);
+         data.name = name;
+       }
       else
        name = constructor_name (type);
 
       if (const_p)
-        {
-          data.quals = TYPE_QUAL_CONST;
+       {
+         data.quals = TYPE_QUAL_CONST;
          rhs_parm_type = 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;
@@ -1022,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;
@@ -1031,8 +965,15 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
       DECL_ASSIGNMENT_OPERATOR_P (fn) = 1;
       SET_OVERLOADED_OPERATOR_CODE (fn, NOP_EXPR);
     }
-  /* Create the argument list.  The call to "grokclassfn" will add the
-     "this" parameter and any other implicit parameters.  */
+  
+  /* If pointers to member functions use the least significant bit to
+     indicate whether a function is virtual, ensure a pointer
+     to this function will have that bit clear.  */
+  if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
+      && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
+    DECL_ALIGN (fn) = 2 * BITS_PER_UNIT;
+
+  /* Create the explicit arguments.  */
   if (rhs_parm_type)
     {
       /* Note that this parameter is *not* marked DECL_ARTIFICIAL; we
@@ -1041,22 +982,112 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
       DECL_ARGUMENTS (fn) = cp_build_parm_decl (NULL_TREE, rhs_parm_type);
       TREE_READONLY (DECL_ARGUMENTS (fn)) = 1;
     }
+  /* Add the "this" parameter.  */
+  this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED);
+  TREE_CHAIN (this_parm) = DECL_ARGUMENTS (fn);
+  DECL_ARGUMENTS (fn) = this_parm;
 
-  grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL,
-              TYPE_UNQUALIFIED);
-  grok_special_member_properties (fn);
+  grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL);
   set_linkage_according_to_type (type, fn);
   rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
   DECL_IN_AGGR_P (fn) = 1;
   DECL_ARTIFICIAL (fn) = 1;
+  DECL_DEFAULTED_FN (fn) = 1;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
-  DECL_INLINE (fn) = 1;
   gcc_assert (!TREE_USED (fn));
 
+  /* Restore PROCESSING_TEMPLATE_DECL.  */
+  processing_template_decl = saved_processing_template_decl;
+
   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.  */
@@ -1082,9 +1113,9 @@ lazily_declare_fn (special_function_kind sfk, tree type)
   if (sfk == sfk_destructor)
     check_for_override (fn, type);
   /* Add it to CLASSTYPE_METHOD_VEC.  */
-  add_method (type, fn);
+  add_method (type, fn, NULL_TREE);
   /* Add it to TYPE_METHODS.  */
-  if (sfk == sfk_destructor 
+  if (sfk == sfk_destructor
       && DECL_VIRTUAL_P (fn)
       && abi_version_at_least (2))
     /* The ABI requires that a virtual destructor go at the end of the
@@ -1094,9 +1125,9 @@ 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))
-       warning ("vtable layout for class %qT may not be ABI-compliant"
+        in an incorrect location in the vtable.  */
+      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",
                 type);
@@ -1113,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.  */
@@ -1126,7 +1159,7 @@ lazily_declare_fn (special_function_kind sfk, tree type)
    as there are artificial parms in FN.  */
 
 tree
-skip_artificial_parms_for (tree fn, tree list)
+skip_artificial_parms_for (const_tree fn, tree list)
 {
   if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
     list = TREE_CHAIN (list);
@@ -1140,4 +1173,25 @@ skip_artificial_parms_for (tree fn, tree list)
   return list;
 }
 
+/* Given a FUNCTION_DECL FN and a chain LIST, return the number of
+   artificial parms in FN.  */
+
+int
+num_artificial_parms_for (const_tree fn)
+{
+  int count = 0;
+
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+    count++;
+  else
+    return 0;
+
+  if (DECL_HAS_IN_CHARGE_PARM_P (fn))
+    count++;
+  if (DECL_HAS_VTT_PARM_P (fn))
+    count++;
+  return count;
+}
+
+
 #include "gt-cp-method.h"