aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/cp/method.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/cp/method.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/cp/method.c1206
1 files changed, 0 insertions, 1206 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/cp/method.c b/gcc-4.2.1-5666.3/gcc/cp/method.c
deleted file mode 100644
index 67fb84c0f..000000000
--- a/gcc-4.2.1-5666.3/gcc/cp/method.c
+++ /dev/null
@@ -1,1206 +0,0 @@
-/* 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.
- 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)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-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, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
-
-
-/* Handle method declarations. */
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
-#include "cp-tree.h"
-#include "rtl.h"
-#include "expr.h"
-#include "output.h"
-#include "flags.h"
-#include "toplev.h"
-#include "tm_p.h"
-#include "target.h"
-#include "tree-pass.h"
-#include "diagnostic.h"
-
-/* Various flags to control the mangling process. */
-
-enum mangling_flags
-{
- /* No flags. */
- mf_none = 0,
- /* The thing we are presently mangling is part of a template type,
- rather than a fully instantiated type. Therefore, we may see
- complex expressions where we would normally expect to see a
- simple integer constant. */
- mf_maybe_uninstantiated = 1,
- /* When mangling a numeric value, use the form `_XX_' (instead of
- just `XX') if the value has more than one digit. */
- mf_use_underscores_around_value = 2
-};
-
-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. */
-
-void
-init_method (void)
-{
- init_mangle ();
-}
-
-/* Return a this or result adjusting thunk to FUNCTION. THIS_ADJUSTING
- indicates whether it is a this or result adjusting thunk.
- FIXED_OFFSET and VIRTUAL_OFFSET indicate how to do the adjustment
- (see thunk_adjust). VIRTUAL_OFFSET can be NULL, but FIXED_OFFSET
- never is. VIRTUAL_OFFSET is the /index/ into the vtable for this
- adjusting thunks, we scale it to a byte offset. For covariant
- thunks VIRTUAL_OFFSET is the virtual binfo. You must post process
- the returned thunk with finish_thunk. */
-
-tree
-make_thunk (tree function, bool this_adjusting,
- tree fixed_offset, tree virtual_offset)
-{
- 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
- = size_binop (MULT_EXPR,
- 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. */
- for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
- if (DECL_THIS_THUNK_P (thunk) == this_adjusting
- && THUNK_FIXED_OFFSET (thunk) == d
- && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk)
- && (!virtual_offset
- || (this_adjusting
- ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
- virtual_offset)
- : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))
- return thunk;
-
- /* All thunks must be created before FUNCTION is actually emitted;
- the ABI requires that all thunks be emitted together with the
- function to which they transfer control. */
- gcc_assert (!TREE_ASM_WRITTEN (function));
- /* Likewise, we can only be adding thunks to a function declared in
- the class currently being laid out. */
- gcc_assert (TYPE_SIZE (DECL_CONTEXT (function))
- && TYPE_BEING_DEFINED (DECL_CONTEXT (function)));
-
- thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
- DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
- cxx_dup_lang_specific_decl (thunk);
- DECL_THUNKS (thunk) = NULL_TREE;
-
- DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
- TREE_READONLY (thunk) = TREE_READONLY (function);
- TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
- TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
- 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;
- DECL_NOT_REALLY_EXTERN (thunk) = 1;
- DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
- DECL_DESTRUCTOR_P (thunk) = 0;
- 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;
-
- return thunk;
-}
-
-/* Finish THUNK, a thunk decl. */
-
-void
-finish_thunk (tree thunk)
-{
- tree function, name;
- tree fixed_offset = ssize_int (THUNK_FIXED_OFFSET (thunk));
- tree virtual_offset = THUNK_VIRTUAL_OFFSET (thunk);
-
- gcc_assert (!DECL_NAME (thunk) && DECL_THUNK_P (thunk));
- if (virtual_offset && DECL_RESULT_THUNK_P (thunk))
- virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
- function = THUNK_TARGET (thunk);
- name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk),
- fixed_offset, virtual_offset);
-
- /* We can end up with declarations of (logically) different
- covariant thunks, that do identical adjustments. The two thunks
- will be adjusting between within different hierarchies, which
- happen to have the same layout. We must nullify one of them to
- refer to the other. */
- if (DECL_RESULT_THUNK_P (thunk))
- {
- tree cov_probe;
-
- for (cov_probe = DECL_THUNKS (function);
- cov_probe; cov_probe = TREE_CHAIN (cov_probe))
- if (DECL_NAME (cov_probe) == name)
- {
- gcc_assert (!DECL_THUNKS (thunk));
- THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)
- ? THUNK_ALIAS (cov_probe) : cov_probe);
- break;
- }
- }
-
- DECL_NAME (thunk) = name;
- SET_DECL_ASSEMBLER_NAME (thunk, name);
-}
-
-/* Adjust PTR by the constant FIXED_OFFSET, and by the vtable
- offset indicated by VIRTUAL_OFFSET, if that is
- non-null. THIS_ADJUSTING is 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. */
-
-tree
-make_alias_for (tree function, tree newid)
-{
- tree alias = build_decl (FUNCTION_DECL, newid, TREE_TYPE (function));
- DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
- cxx_dup_lang_specific_decl (alias);
- DECL_CONTEXT (alias) = NULL;
- TREE_READONLY (alias) = TREE_READONLY (function);
- TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
- TREE_PUBLIC (alias) = 0;
- DECL_INTERFACE_KNOWN (alias) = 1;
- DECL_NOT_REALLY_EXTERN (alias) = 1;
- DECL_THIS_STATIC (alias) = 1;
- DECL_SAVED_FUNCTION_DATA (alias) = NULL;
- DECL_DESTRUCTOR_P (alias) = 0;
- DECL_CONSTRUCTOR_P (alias) = 0;
- DECL_CLONED_FUNCTION (alias) = NULL_TREE;
- DECL_EXTERNAL (alias) = 0;
- DECL_ARTIFICIAL (alias) = 1;
- DECL_NO_STATIC_CHAIN (alias) = 1;
- DECL_PENDING_INLINE_P (alias) = 0;
- DECL_INLINE (alias) = 0;
- DECL_DECLARED_INLINE_P (alias) = 0;
- DECL_DEFERRED_FN (alias) = 0;
- DECL_USE_TEMPLATE (alias) = 0;
- DECL_TEMPLATE_INSTANTIATED (alias) = 0;
- DECL_TEMPLATE_INFO (alias) = NULL;
- DECL_INITIAL (alias) = error_mark_node;
- TREE_ADDRESSABLE (alias) = 1;
- TREE_USED (alias) = 1;
- SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
- TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
- 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));
-
- return alias;
-}
-
-/* Emit the definition of a C++ multiple inheritance or covariant
- return vtable thunk. If EMIT_P is nonzero, the thunk is emitted
- immediately. */
-
-void
-use_thunk (tree thunk_fndecl, bool emit_p)
-{
- tree a, t, function, alias;
- tree virtual_offset;
- HOST_WIDE_INT fixed_offset, virtual_value;
- bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);
-
- /* We should have called finish_thunk to give it a name. */
- gcc_assert (DECL_NAME (thunk_fndecl));
-
- /* We should never be using an alias, always refer to the
- aliased thunk. */
- gcc_assert (!THUNK_ALIAS (thunk_fndecl));
-
- 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.
- There's no need to process this thunk again. */
- return;
-
- 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;
-
- /* Figure out what function is being thunked to. It's referenced in
- this translation unit. */
- TREE_ADDRESSABLE (function) = 1;
- mark_used (function);
- if (!emit_p)
- return;
-
- if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function))
- alias = make_alias_for_thunk (function);
- else
- alias = function;
-
- fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl);
- virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl);
-
- if (virtual_offset)
- {
- if (!this_adjusting)
- virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
- virtual_value = tree_low_cst (virtual_offset, /*pos=*/0);
- gcc_assert (virtual_value);
- }
- else
- virtual_value = 0;
-
- /* And, if we need to emit the thunk, it's used. */
- mark_used (thunk_fndecl);
- /* This thunk is actually defined. */
- DECL_EXTERNAL (thunk_fndecl) = 0;
- /* The linkage of the function may have changed. FIXME in linkage
- rewrite. */
- TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
- DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
- DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
- = DECL_VISIBILITY_SPECIFIED (function);
- if (DECL_ONE_ONLY (function))
- make_decl_one_only (thunk_fndecl);
-
- if (flag_syntax_only)
- {
- TREE_ASM_WRITTEN (thunk_fndecl) = 1;
- return;
- }
-
- push_to_top_level ();
-
- if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
- && targetm.have_named_sections)
- {
- resolve_unique_section (function, 0, flag_function_sections);
-
- if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function))
- {
- resolve_unique_section (thunk_fndecl, 0, flag_function_sections);
-
- /* Output the thunk into the same section as function. */
- DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function);
- }
- }
-
-/* APPLE LOCAL begin mainline 2006-12-02 5128086 */ \
- /* Set up cloned argument trees for the thunk. */
- t = NULL_TREE;
- for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
- {
- tree x = copy_node (a);
- TREE_CHAIN (x) = t;
- DECL_CONTEXT (x) = thunk_fndecl;
- SET_DECL_RTL (x, NULL_RTX);
- DECL_HAS_VALUE_EXPR_P (x) = 0;
- t = x;
- }
- 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 = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
- /* 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;
-/* APPLE LOCAL end mainline 2006-12-02 5128086 */ \
- 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);
- init_insn_lengths ();
- current_function_decl = 0;
- cfun = 0;
- TREE_ASM_WRITTEN (thunk_fndecl) = 1;
- }
- else
- {
- /* 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
- doesn't work for varargs. */
-
- 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));
- }
- if (IS_AGGR_TYPE (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);
- tree_lowering_passes (thunk_fndecl);
- expand_body (thunk_fndecl);
- }
-
- pop_from_top_level ();
-}
-
-/* Code for synthesizing methods which have default semantics defined. */
-
-/* Generate code for default X(X&) constructor. */
-
-static void
-do_build_copy_constructor (tree fndecl)
-{
- tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
-
- parm = convert_from_reference (parm);
-
- if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)
- && is_empty_class (current_class_type))
- /* Don't copy the padding byte; it might not have been allocated
- if *this is a base subobject. */;
- else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type))
- {
- tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm);
- finish_expr_stmt (t);
- }
- else
- {
- tree fields = TYPE_FIELDS (current_class_type);
- tree member_init_list = NULL_TREE;
- int cvquals = cp_type_quals (TREE_TYPE (parm));
- int i;
- tree binfo, base_binfo;
- VEC(tree,gc) *vbases;
-
- /* Initialize all the base-classes with the parameter converted
- to their type so that we get their copy constructor and not
- another constructor that takes current_class_type. We must
- deal with the binfo's directly as a direct base might be
- inaccessible due to ambiguity. */
- for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
- VEC_iterate (tree, vbases, i, binfo); i++)
- {
- member_init_list
- = tree_cons (binfo,
- build_tree_list (NULL_TREE,
- build_base_path (PLUS_EXPR, parm,
- binfo, 1)),
- member_init_list);
- }
-
- for (binfo = TYPE_BINFO (current_class_type), i = 0;
- BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
- {
- if (BINFO_VIRTUAL_P (base_binfo))
- continue;
-
- member_init_list
- = tree_cons (base_binfo,
- build_tree_list (NULL_TREE,
- build_base_path (PLUS_EXPR, parm,
- base_binfo, 1)),
- member_init_list);
- }
-
- for (; fields; fields = TREE_CHAIN (fields))
- {
- tree init = parm;
- tree field = fields;
- tree expr_type;
-
- if (TREE_CODE (field) != FIELD_DECL)
- continue;
-
- expr_type = TREE_TYPE (field);
- if (DECL_NAME (field))
- {
- if (VFIELD_NAME_P (DECL_NAME (field)))
- continue;
- }
- else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type))
- /* Just use the field; anonymous types can't have
- nontrivial copy ctors or assignment ops. */;
- else
- continue;
-
- /* Compute the type of "init->field". If the copy-constructor
- parameter is, for example, "const S&", and the type of
- the field is "T", then the type will usually be "const
- T". (There are no cv-qualified variants of reference
- types.) */
- 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);
-
- member_init_list = tree_cons (field, init, member_init_list);
- }
- finish_mem_initializers (member_init_list);
- }
-}
-
-static void
-do_build_assign_ref (tree fndecl)
-{
- tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
- tree compound_stmt;
-
- compound_stmt = begin_compound_stmt (0);
- parm = convert_from_reference (parm);
-
- if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)
- && is_empty_class (current_class_type))
- /* Don't copy the padding byte; it might not have been allocated
- if *this is a base subobject. */;
- else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type))
- {
- tree t = build2 (MODIFY_EXPR, void_type_node, current_class_ref, parm);
- finish_expr_stmt (t);
- }
- else
- {
- tree fields;
- int cvquals = cp_type_quals (TREE_TYPE (parm));
- int i;
- tree binfo, base_binfo;
-
- /* Assign to each of the direct base classes. */
- for (binfo = TYPE_BINFO (current_class_type), i = 0;
- BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
- {
- tree converted_parm;
-
- /* 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,
- ansi_assopname (NOP_EXPR),
- 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;
- fields = TREE_CHAIN (fields))
- {
- tree comp = current_class_ref;
- tree init = parm;
- tree field = fields;
- tree expr_type;
- int quals;
-
- if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
- 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);
- continue;
- }
- else if (TREE_CODE (expr_type) == REFERENCE_TYPE)
- {
- error ("non-static reference member %q#D, can't use "
- "default assignment operator", field);
- continue;
- }
-
- if (DECL_NAME (field))
- {
- if (VFIELD_NAME_P (DECL_NAME (field)))
- continue;
- }
- else if (ANON_AGGR_TYPE_P (expr_type)
- && TYPE_FIELDS (expr_type) != NULL_TREE)
- /* Just use the field; anonymous types can't have
- nontrivial copy ctors or assignment ops. */;
- else
- 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);
- else
- init = build2 (MODIFY_EXPR, TREE_TYPE (comp), comp, init);
- finish_expr_stmt (init);
- }
- }
- finish_return_stmt (current_class_ref);
- finish_compound_stmt (compound_stmt);
-}
-
-/* Synthesize FNDECL, a non-static member function. */
-
-void
-synthesize_method (tree fndecl)
-{
- bool nested = (current_function_decl != NULL_TREE);
- tree context = decl_function_context (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))
- fndecl = DECL_CLONED_FUNCTION (fndecl);
-
- /* We may be in the middle of deferred access check. Disable
- it now. */
- push_deferring_access_checks (dk_no_deferred);
-
- if (! context)
- push_to_top_level ();
- else if (nested)
- push_function_context_to (context);
-
- input_location = DECL_SOURCE_LOCATION (fndecl);
-
- start_preparsed_function (fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);
- stmt = begin_function_body ();
-
- if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR)
- {
- do_build_assign_ref (fndecl);
- need_body = false;
- }
- else if (DECL_CONSTRUCTOR_P (fndecl))
- {
- tree arg_chain = FUNCTION_FIRST_USER_PARMTYPE (fndecl);
- if (arg_chain != void_list_node)
- do_build_copy_constructor (fndecl);
- else
- finish_mem_initializers (NULL_TREE);
- }
-
- /* If we haven't yet generated the body of the function, just
- generate an empty compound statement. */
- if (need_body)
- {
- tree compound_stmt;
- compound_stmt = begin_compound_stmt (BCS_FN_BODY);
- finish_compound_stmt (compound_stmt);
- }
-
- finish_function_body (stmt);
- expand_or_defer_fn (finish_function (0));
-
- input_location = save_input_location;
-
- if (! context)
- pop_from_top_level ();
- else if (nested)
- pop_function_context_from (context);
-
- pop_deferring_access_checks ();
-
- if (error_count != errorcount || warning_count != warningcount)
- inform ("%Hsynthesized method %qD first required here ",
- &input_location, fndecl);
-}
-
-/* Use EXTRACTOR to locate the relevant function called for each base &
- class field of TYPE. CLIENT allows additional information to be passed
- to EXTRACTOR. Generates the union of all exceptions generated by those
- functions. Note that we haven't updated TYPE_FIELDS and such of any
- variants yet, so we need to look at the main one. */
-
-static tree
-synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
- void *client)
-{
- tree raises = empty_except_spec;
- tree fields = TYPE_FIELDS (type);
- tree binfo, base_binfo;
- int i;
-
- for (binfo = TYPE_BINFO (type), i = 0;
- BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
- {
- 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);
- }
- }
- for (; fields; fields = TREE_CHAIN (fields))
- {
- tree type = TREE_TYPE (fields);
- tree fn;
-
- if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
- continue;
- while (TREE_CODE (type) == ARRAY_TYPE)
- 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);
- }
- }
- return raises;
-}
-
-/* Locate the dtor of TYPE. */
-
-static tree
-locate_dtor (tree type, void *client ATTRIBUTE_UNUSED)
-{
- return CLASSTYPE_DESTRUCTORS (type);
-}
-
-/* Locate the default ctor of TYPE. */
-
-static tree
-locate_ctor (tree type, void *client ATTRIBUTE_UNUSED)
-{
- tree fns;
-
- if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
- return NULL_TREE;
-
- /* Call lookup_fnfields_1 to create the constructor declarations, if
- necessary. */
- if (CLASSTYPE_LAZY_DEFAULT_CTOR (type))
- return lazily_declare_fn (sfk_constructor, type);
-
- for (fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns))
- {
- tree fn = OVL_CURRENT (fns);
- tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
-
- parms = skip_artificial_parms_for (fn, parms);
-
- if (sufficient_parms_p (parms))
- return fn;
- }
- gcc_unreachable ();
-}
-
-struct copy_data
-{
- tree name;
- int quals;
-};
-
-/* Locate the copy ctor or copy assignment of TYPE. CLIENT_
- points to a COPY_DATA holding the name (NULL for the ctor)
- and desired qualifiers of the source operand. */
-
-static 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;
- ix = lookup_fnfields_1 (type, client->name);
- if (ix < 0)
- return NULL_TREE;
- fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix);
- }
- else if (TYPE_HAS_INIT_REF (type))
- {
- /* If construction of the copy constructor was postponed, create
- it now. */
- if (CLASSTYPE_LAZY_COPY_CTOR (type))
- lazily_declare_fn (sfk_copy_constructor, type);
- fns = CLASSTYPE_CONSTRUCTORS (type);
- }
- else
- return NULL_TREE;
- for (; fns; fns = OVL_NEXT (fns))
- {
- tree fn = OVL_CURRENT (fns);
- tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
- tree src_type;
- int excess;
- int quals;
-
- parms = skip_artificial_parms_for (fn, parms);
- if (!parms)
- 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;
- if (!sufficient_parms_p (TREE_CHAIN (parms)))
- continue;
- quals = cp_type_quals (src_type);
- if (client->quals & ~quals)
- continue;
- excess = quals & ~client->quals;
- if (!best || (excess_p && !excess))
- {
- best = fn;
- excess_p = excess;
- }
- else
- /* Ambiguous */
- return NULL_TREE;
- }
- return best;
-}
-
-/* Implicitly declare the special function indicated by KIND, as a
- member of TYPE. For copy constructors and assignment operators,
- CONST_P indicates whether these functions should take a const
- reference argument or a non-const reference. Returns the
- FUNCTION_DECL for the implicitly declared function. */
-
-static tree
-implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
-{
- tree fn;
- tree parameter_types = void_list_node;
- tree return_type;
- 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);
-
- if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (type))
- {
- if (kind == sfk_destructor)
- /* See comment in check_special_function_return_type. */
- return_type = build_pointer_type (void_type_node);
- else
- return_type = build_pointer_type (type);
- }
- else
- return_type = void_type_node;
-
- switch (kind)
- {
- case sfk_destructor:
- /* Destructor. */
- name = constructor_name (type);
- raises = synthesize_exception_spec (type, &locate_dtor, 0);
- break;
-
- case sfk_constructor:
- /* Default constructor. */
- name = constructor_name (type);
- raises = synthesize_exception_spec (type, &locate_ctor, 0);
- break;
-
- case sfk_copy_constructor:
- 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;
- }
- else
- name = constructor_name (type);
-
- if (const_p)
- {
- 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);
- parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
- raises = synthesize_exception_spec (type, &locate_copy, &data);
- break;
- }
- default:
- gcc_unreachable ();
- }
-
- /* Create the function. */
- fn_type = build_method_type_directly (type, return_type, parameter_types);
- if (raises)
- 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)
- DECL_CONSTRUCTOR_P (fn) = 1;
- else if (kind == sfk_destructor)
- DECL_DESTRUCTOR_P (fn) = 1;
- else
- {
- DECL_ASSIGNMENT_OPERATOR_P (fn) = 1;
- SET_OVERLOADED_OPERATOR_CODE (fn, NOP_EXPR);
- }
- /* Create the explicit arguments. */
- if (rhs_parm_type)
- {
- /* Note that this parameter is *not* marked DECL_ARTIFICIAL; we
- want its type to be included in the mangled function
- name. */
- 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;
-
- /* APPLE LOCAL begin mainline aligned functions 5933878 */
- /* 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
- && TREE_CODE (fn_type) == METHOD_TYPE
- && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT)
- DECL_ALIGN (fn) = 2 * BITS_PER_UNIT;
- /* APPLE LOCAL end mainline aligned functions 5933878 */
-
- 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_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;
-}
-
-/* Add an implicit declaration to TYPE for the kind of function
- indicated by SFK. Return the FUNCTION_DECL for the new implicit
- declaration. */
-
-tree
-lazily_declare_fn (special_function_kind sfk, tree type)
-{
- tree fn;
- bool const_p;
-
- /* Figure out whether or not the argument has a const reference
- type. */
- if (sfk == sfk_copy_constructor)
- const_p = TYPE_HAS_CONST_INIT_REF (type);
- else if (sfk == sfk_assignment_operator)
- const_p = TYPE_HAS_CONST_ASSIGN_REF (type);
- else
- /* In this case, CONST_P will be ignored. */
- const_p = false;
- /* Declare the function. */
- fn = implicitly_declare_fn (sfk, type, const_p);
- /* A destructor may be virtual. */
- if (sfk == sfk_destructor)
- check_for_override (fn, type);
- /* Add it to CLASSTYPE_METHOD_VEC. */
- add_method (type, fn, NULL_TREE);
- /* Add it to TYPE_METHODS. */
- 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
- vtable. */
- TYPE_METHODS (type) = chainon (TYPE_METHODS (type), fn);
- else
- {
- /* 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 (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);
- TREE_CHAIN (fn) = TYPE_METHODS (type);
- TYPE_METHODS (type) = fn;
- }
- maybe_add_class_template_decl_list (type, fn, /*friend_p=*/0);
- if (sfk == sfk_assignment_operator)
- CLASSTYPE_LAZY_ASSIGNMENT_OP (type) = 0;
- else
- {
- /* Remember that the function has been created. */
- if (sfk == sfk_constructor)
- CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
- else if (sfk == sfk_copy_constructor)
- CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
- else if (sfk == sfk_destructor)
- CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
- /* Create appropriate clones. */
- clone_function_decl (fn, /*update_method_vec=*/true);
- }
-
- return fn;
-}
-
-/* Given a FUNCTION_DECL FN and a chain LIST, skip as many elements of LIST
- as there are artificial parms in FN. */
-
-tree
-skip_artificial_parms_for (tree fn, tree list)
-{
- if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
- list = TREE_CHAIN (list);
- else
- return list;
-
- if (DECL_HAS_IN_CHARGE_PARM_P (fn))
- list = TREE_CHAIN (list);
- if (DECL_HAS_VTT_PARM_P (fn))
- list = TREE_CHAIN (list);
- return list;
-}
-
-#include "gt-cp-method.h"