OSDN Git Service

PR c++/34111
[pf3gnuchains/gcc-fork.git] / gcc / cp / method.c
index ac85bf4..3ef73fb 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
+   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.  */
@@ -61,9 +61,6 @@ 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.  */
@@ -89,22 +86,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.  */
@@ -118,7 +115,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.  */
@@ -132,19 +129,17 @@ make_thunk (tree function, bool this_adjusting,
   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;
@@ -163,7 +158,10 @@ make_thunk (tree function, bool this_adjusting,
   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;
@@ -206,7 +204,7 @@ finish_thunk (tree thunk)
            break;
          }
     }
-  
+
   DECL_NAME (thunk) = name;
   SET_DECL_ASSEMBLER_NAME (thunk, name);
 }
@@ -222,8 +220,8 @@ thunk_adjust (tree ptr, bool this_adjusting,
 {
   if (this_adjusting)
     /* Adjust the pointer by the constant.  */
-    ptr = fold_build2 (PLUS_EXPR, TREE_TYPE (ptr), ptr,
-                      ssize_int (fixed_offset));
+    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.  */
@@ -234,23 +232,25 @@ thunk_adjust (tree ptr, bool this_adjusting,
       ptr = save_expr (ptr);
       /* The vptr is always at offset zero in the object.  */
       vtable = build1 (NOP_EXPR,
-                      build_pointer_type (build_pointer_type 
+                      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);
+      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 (PLUS_EXPR, TREE_TYPE (ptr), ptr, vtable);
+      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 (PLUS_EXPR, TREE_TYPE (ptr), ptr,
-                      ssize_int (fixed_offset));
+    ptr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
+                      size_int (fixed_offset));
 
   return ptr;
 }
@@ -332,7 +332,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.
@@ -342,7 +342,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;
 
@@ -370,7 +370,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.  */
@@ -379,10 +379,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))
+    make_decl_one_only (thunk_fndecl);
 
   if (flag_syntax_only)
     {
@@ -406,10 +406,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))
@@ -418,21 +414,28 @@ 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;
+      tree fn_block;
+      
       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);
+      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);
       current_function_is_thunk = 1;
       assemble_start_function (thunk_fndecl, fnname);
@@ -441,12 +444,15 @@ use_thunk (tree thunk_fndecl, bool emit_p)
                                       fixed_offset, virtual_value, alias);
 
       assemble_end_function (thunk_fndecl, fnname);
+      init_insn_lengths ();
       current_function_decl = 0;
-      cfun = 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
@@ -468,15 +474,15 @@ use_thunk (tree thunk_fndecl, bool emit_p)
       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);
+      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
@@ -494,14 +500,15 @@ use_thunk (tree thunk_fndecl, bool emit_p)
                  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);
+         if (IS_AGGR_TYPE (TREE_TYPE (t)))
+           t = build_cplus_new (TREE_TYPE (t), t);
          finish_return_stmt (t);
        }
 
@@ -517,7 +524,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
 
       thunk_fndecl = finish_function (0);
       tree_lowering_passes (thunk_fndecl);
-      expand_body (thunk_fndecl);
+      tree_rest_of_compilation (thunk_fndecl);
     }
 
   pop_from_top_level ();
@@ -560,7 +567,7 @@ 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 
+         member_init_list
            = tree_cons (binfo,
                         build_tree_list (NULL_TREE,
                                          build_base_path (PLUS_EXPR, parm,
@@ -572,9 +579,9 @@ 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 
+         member_init_list
            = tree_cons (base_binfo,
                         build_tree_list (NULL_TREE,
                                          build_base_path (PLUS_EXPR, parm,
@@ -611,12 +618,12 @@ 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;
              expr_type = cp_build_qualified_type (expr_type, quals);
            }
-         
+
          init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE);
          init = build_tree_list (NULL_TREE, init);
 
@@ -661,18 +668,18 @@ do_build_assign_ref (tree fndecl)
             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, 
+         finish_expr_stmt
+           (build_special_member_call (current_class_ref,
                                        ansi_assopname (NOP_EXPR),
-                                       build_tree_list (NULL_TREE, 
+                                       build_tree_list (NULL_TREE,
                                                         converted_parm),
                                        base_binfo,
                                        LOOKUP_NORMAL | LOOKUP_NONVIRTUAL));
        }
 
       /* 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;
@@ -685,17 +692,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;
            }
 
@@ -712,13 +719,13 @@ 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))
@@ -749,7 +756,7 @@ synthesize_method (tree fndecl)
      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.  */
@@ -780,7 +787,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);
     }
 
@@ -806,8 +813,8 @@ synthesize_method (tree fndecl)
   pop_deferring_access_checks ();
 
   if (error_count != errorcount || warning_count != warningcount)
-    warning (0, "%Hsynthesized method %qD first required here ",
-            &input_location, fndecl);
+    inform ("%Hsynthesized method %qD first required here ",
+           &input_location, fndecl);
 }
 
 /* Use EXTRACTOR to locate the relevant function called for each base &
@@ -818,7 +825,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);
@@ -830,38 +837,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);
@@ -869,11 +876,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;
 
@@ -886,11 +893,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
@@ -903,14 +912,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;
@@ -936,27 +945,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;
 }
@@ -967,7 +980,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;
@@ -976,10 +989,11 @@ 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 implictly declared functions
+  /* 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
@@ -1022,23 +1036,23 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
     case sfk_assignment_operator:
     {
       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);
@@ -1065,8 +1079,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
@@ -1075,10 +1096,12 @@ 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;
@@ -1119,9 +1142,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
@@ -1131,9 +1154,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.  */ 
+        in an incorrect location in the vtable.  */
       if (warn_abi && DECL_VIRTUAL_P (fn))
-       warning (0, "vtable layout for class %qT may not be ABI-compliant"
+       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);
@@ -1163,7 +1186,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);
@@ -1177,4 +1200,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"