123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- /* Perform optimizations on tree structure.
- Copyright (C) 1998-2015 Free Software Foundation, Inc.
- Written by Mark Michell (mark@codesourcery.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 3, 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 COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "stringpool.h"
- #include "cp-tree.h"
- #include "input.h"
- #include "params.h"
- #include "hashtab.h"
- #include "target.h"
- #include "debug.h"
- #include "tree-inline.h"
- #include "flags.h"
- #include "langhooks.h"
- #include "diagnostic-core.h"
- #include "dumpfile.h"
- #include "tree-iterator.h"
- #include "hash-map.h"
- #include "is-a.h"
- #include "plugin-api.h"
- #include "hard-reg-set.h"
- #include "function.h"
- #include "ipa-ref.h"
- #include "cgraph.h"
- /* Prototypes. */
- static void update_cloned_parm (tree, tree, bool);
- /* CLONED_PARM is a copy of CLONE, generated for a cloned constructor
- or destructor. Update it to ensure that the source-position for
- the cloned parameter matches that for the original, and that the
- debugging generation code will be able to find the original PARM. */
- static void
- update_cloned_parm (tree parm, tree cloned_parm, bool first)
- {
- DECL_ABSTRACT_ORIGIN (cloned_parm) = parm;
- /* We may have taken its address. */
- TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm);
- /* The definition might have different constness. */
- TREE_READONLY (cloned_parm) = TREE_READONLY (parm);
- TREE_USED (cloned_parm) = !first || TREE_USED (parm);
- /* The name may have changed from the declaration. */
- DECL_NAME (cloned_parm) = DECL_NAME (parm);
- DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm);
- TREE_TYPE (cloned_parm) = TREE_TYPE (parm);
- DECL_GIMPLE_REG_P (cloned_parm) = DECL_GIMPLE_REG_P (parm);
- }
- /* FN is a function in High GIMPLE form that has a complete body and no
- CFG. CLONE is a function whose body is to be set to a copy of FN,
- mapping argument declarations according to the ARG_MAP splay_tree. */
- static void
- clone_body (tree clone, tree fn, void *arg_map)
- {
- copy_body_data id;
- tree stmts;
- /* Clone the body, as if we were making an inline call. But, remap
- the parameters in the callee to the parameters of caller. */
- memset (&id, 0, sizeof (id));
- id.src_fn = fn;
- id.dst_fn = clone;
- id.src_cfun = DECL_STRUCT_FUNCTION (fn);
- id.decl_map = static_cast<hash_map<tree, tree> *> (arg_map);
- id.copy_decl = copy_decl_no_change;
- id.transform_call_graph_edges = CB_CGE_DUPLICATE;
- id.transform_new_cfg = true;
- id.transform_return_to_modify = false;
- id.transform_lang_insert_block = NULL;
- /* We're not inside any EH region. */
- id.eh_lp_nr = 0;
- stmts = DECL_SAVED_TREE (fn);
- walk_tree (&stmts, copy_tree_body_r, &id, NULL);
- /* Also remap the initializer of any static variables so that they (in
- particular, any label addresses) correspond to the base variant rather
- than the abstract one. */
- if (DECL_NAME (clone) == base_dtor_identifier
- || DECL_NAME (clone) == base_ctor_identifier)
- {
- unsigned ix;
- tree decl;
- FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (fn), ix, decl)
- walk_tree (&DECL_INITIAL (decl), copy_tree_body_r, &id, NULL);
- }
- append_to_statement_list_force (stmts, &DECL_SAVED_TREE (clone));
- }
- /* DELETE_DTOR is a delete destructor whose body will be built.
- COMPLETE_DTOR is the corresponding complete destructor. */
- static void
- build_delete_destructor_body (tree delete_dtor, tree complete_dtor)
- {
- tree call_dtor, call_delete;
- tree parm = DECL_ARGUMENTS (delete_dtor);
- tree virtual_size = cxx_sizeof (current_class_type);
- /* Call the corresponding complete destructor. */
- gcc_assert (complete_dtor);
- call_dtor = build_cxx_call (complete_dtor, 1, &parm,
- tf_warning_or_error);
- add_stmt (call_dtor);
- add_stmt (build_stmt (0, LABEL_EXPR, cdtor_label));
- /* Call the delete function. */
- call_delete = build_op_delete_call (DELETE_EXPR, current_class_ptr,
- virtual_size,
- /*global_p=*/false,
- /*placement=*/NULL_TREE,
- /*alloc_fn=*/NULL_TREE,
- tf_warning_or_error);
- add_stmt (call_delete);
- /* Return the address of the object. */
- if (targetm.cxx.cdtor_returns_this ())
- {
- tree val = DECL_ARGUMENTS (delete_dtor);
- val = build2 (MODIFY_EXPR, TREE_TYPE (val),
- DECL_RESULT (delete_dtor), val);
- add_stmt (build_stmt (0, RETURN_EXPR, val));
- }
- }
- /* Return name of comdat group for complete and base ctor (or dtor)
- that have the same body. If dtor is virtual, deleting dtor goes
- into this comdat group as well. */
- static tree
- cdtor_comdat_group (tree complete, tree base)
- {
- tree complete_name = DECL_ASSEMBLER_NAME (complete);
- tree base_name = DECL_ASSEMBLER_NAME (base);
- char *grp_name;
- const char *p, *q;
- bool diff_seen = false;
- size_t idx;
- gcc_assert (IDENTIFIER_LENGTH (complete_name)
- == IDENTIFIER_LENGTH (base_name));
- grp_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (complete_name) + 1);
- p = IDENTIFIER_POINTER (complete_name);
- q = IDENTIFIER_POINTER (base_name);
- for (idx = 0; idx < IDENTIFIER_LENGTH (complete_name); idx++)
- if (p[idx] == q[idx])
- grp_name[idx] = p[idx];
- else
- {
- gcc_assert (!diff_seen
- && idx > 0
- && (p[idx - 1] == 'C' || p[idx - 1] == 'D')
- && p[idx] == '1'
- && q[idx] == '2');
- grp_name[idx] = '5';
- diff_seen = true;
- }
- grp_name[idx] = '\0';
- gcc_assert (diff_seen);
- return get_identifier (grp_name);
- }
- /* Returns true iff we can make the base and complete [cd]tor aliases of
- the same symbol rather than separate functions. */
- static bool
- can_alias_cdtor (tree fn)
- {
- #ifndef ASM_OUTPUT_DEF
- /* If aliases aren't supported by the assembler, fail. */
- return false;
- #endif
- /* We can't use an alias if there are virtual bases. */
- if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)))
- return false;
- /* ??? Why not use aliases with -frepo? */
- if (flag_use_repository)
- return false;
- gcc_assert (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
- || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn));
- /* Don't use aliases for weak/linkonce definitions unless we can put both
- symbols in the same COMDAT group. */
- return (DECL_INTERFACE_KNOWN (fn)
- && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fn))
- && (!DECL_ONE_ONLY (fn)
- || (HAVE_COMDAT_GROUP && DECL_WEAK (fn))));
- }
- /* FN is a [cd]tor, fns is a pointer to an array of length 3. Fill fns
- with pointers to the base, complete, and deleting variants. */
- static void
- populate_clone_array (tree fn, tree *fns)
- {
- tree clone;
- fns[0] = NULL_TREE;
- fns[1] = NULL_TREE;
- fns[2] = NULL_TREE;
- /* Look for the complete destructor which may be used to build the
- delete destructor. */
- FOR_EACH_CLONE (clone, fn)
- if (DECL_NAME (clone) == complete_dtor_identifier
- || DECL_NAME (clone) == complete_ctor_identifier)
- fns[1] = clone;
- else if (DECL_NAME (clone) == base_dtor_identifier
- || DECL_NAME (clone) == base_ctor_identifier)
- fns[0] = clone;
- else if (DECL_NAME (clone) == deleting_dtor_identifier)
- fns[2] = clone;
- else
- gcc_unreachable ();
- }
- /* FN is a constructor or destructor, and there are FUNCTION_DECLs
- cloned from it nearby. Instead of cloning this body, leave it
- alone and create tiny one-call bodies for the cloned
- FUNCTION_DECLs. These clones are sibcall candidates, and their
- resulting code will be very thunk-esque. */
- static bool
- maybe_thunk_body (tree fn, bool force)
- {
- tree bind, block, call, clone, clone_result, fn_parm, fn_parm_typelist;
- tree last_arg, modify, *args;
- int parmno, vtt_parmno, max_parms;
- tree fns[3];
- if (!force && !flag_declone_ctor_dtor)
- return 0;
- /* If function accepts variable arguments, give up. */
- last_arg = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fn)));
- if (last_arg != void_list_node)
- return 0;
- /* If we got this far, we've decided to turn the clones into thunks. */
- /* We're going to generate code for fn, so it is no longer "abstract."
- Also make the unified ctor/dtor private to either the translation unit
- (for non-vague linkage ctors) or the COMDAT group (otherwise). */
- populate_clone_array (fn, fns);
- DECL_ABSTRACT_P (fn) = false;
- if (!DECL_WEAK (fn))
- {
- TREE_PUBLIC (fn) = false;
- DECL_EXTERNAL (fn) = false;
- DECL_INTERFACE_KNOWN (fn) = true;
- }
- else if (HAVE_COMDAT_GROUP)
- {
- tree comdat_group = cdtor_comdat_group (fns[1], fns[0]);
- cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group);
- cgraph_node::get_create (fns[1])->add_to_same_comdat_group
- (cgraph_node::get_create (fns[0]));
- symtab_node::get (fn)->add_to_same_comdat_group
- (symtab_node::get (fns[0]));
- if (fns[2])
- /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
- virtual, it goes into the same comdat group as well. */
- cgraph_node::get_create (fns[2])->add_to_same_comdat_group
- (symtab_node::get (fns[0]));
- TREE_PUBLIC (fn) = false;
- DECL_EXTERNAL (fn) = false;
- DECL_INTERFACE_KNOWN (fn) = true;
- /* function_and_variable_visibility doesn't want !PUBLIC decls to
- have these flags set. */
- DECL_WEAK (fn) = false;
- DECL_COMDAT (fn) = false;
- }
- /* Find the vtt_parm, if present. */
- for (vtt_parmno = -1, parmno = 0, fn_parm = DECL_ARGUMENTS (fn);
- fn_parm;
- ++parmno, fn_parm = TREE_CHAIN (fn_parm))
- {
- if (DECL_ARTIFICIAL (fn_parm)
- && DECL_NAME (fn_parm) == vtt_parm_identifier)
- {
- /* Compensate for removed in_charge parameter. */
- vtt_parmno = parmno;
- break;
- }
- }
- /* Allocate an argument buffer for build_cxx_call().
- Make sure it is large enough for any of the clones. */
- max_parms = 0;
- FOR_EACH_CLONE (clone, fn)
- {
- int length = list_length (DECL_ARGUMENTS (fn));
- if (length > max_parms)
- max_parms = length;
- }
- args = (tree *) alloca (max_parms * sizeof (tree));
- /* We know that any clones immediately follow FN in TYPE_METHODS. */
- FOR_EACH_CLONE (clone, fn)
- {
- tree clone_parm;
- /* If we've already generated a body for this clone, avoid
- duplicating it. (Is it possible for a clone-list to grow after we
- first see it?) */
- if (DECL_SAVED_TREE (clone) || TREE_ASM_WRITTEN (clone))
- continue;
- /* Start processing the function. */
- start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
- if (clone == fns[2])
- {
- for (clone_parm = DECL_ARGUMENTS (clone); clone_parm;
- clone_parm = TREE_CHAIN (clone_parm))
- DECL_ABSTRACT_ORIGIN (clone_parm) = NULL_TREE;
- /* Build the delete destructor by calling complete destructor and
- delete function. */
- build_delete_destructor_body (clone, fns[1]);
- }
- else
- {
- /* Walk parameter lists together, creating parameter list for
- call to original function. */
- for (parmno = 0,
- fn_parm = DECL_ARGUMENTS (fn),
- fn_parm_typelist = TYPE_ARG_TYPES (TREE_TYPE (fn)),
- clone_parm = DECL_ARGUMENTS (clone);
- fn_parm;
- ++parmno,
- fn_parm = TREE_CHAIN (fn_parm))
- {
- if (parmno == vtt_parmno && ! DECL_HAS_VTT_PARM_P (clone))
- {
- gcc_assert (fn_parm_typelist);
- /* Clobber argument with formal parameter type. */
- args[parmno]
- = convert (TREE_VALUE (fn_parm_typelist),
- null_pointer_node);
- }
- else if (parmno == 1 && DECL_HAS_IN_CHARGE_PARM_P (fn))
- {
- tree in_charge
- = copy_node (in_charge_arg_for_name (DECL_NAME (clone)));
- args[parmno] = in_charge;
- }
- /* Map other parameters to their equivalents in the cloned
- function. */
- else
- {
- gcc_assert (clone_parm);
- DECL_ABSTRACT_ORIGIN (clone_parm) = NULL;
- args[parmno] = clone_parm;
- clone_parm = TREE_CHAIN (clone_parm);
- }
- if (fn_parm_typelist)
- fn_parm_typelist = TREE_CHAIN (fn_parm_typelist);
- }
- /* We built this list backwards; fix now. */
- mark_used (fn);
- call = build_cxx_call (fn, parmno, args, tf_warning_or_error);
- /* Arguments passed to the thunk by invisible reference should
- be transmitted to the callee unchanged. Do not create a
- temporary and invoke the copy constructor. The thunking
- transformation must not introduce any constructor calls. */
- CALL_FROM_THUNK_P (call) = 1;
- block = make_node (BLOCK);
- if (targetm.cxx.cdtor_returns_this ())
- {
- clone_result = DECL_RESULT (clone);
- modify = build2 (MODIFY_EXPR, TREE_TYPE (clone_result),
- clone_result, call);
- modify = build1 (RETURN_EXPR, void_type_node, modify);
- add_stmt (modify);
- }
- else
- {
- add_stmt (call);
- }
- bind = c_build_bind_expr (DECL_SOURCE_LOCATION (clone),
- block, cur_stmt_list);
- DECL_SAVED_TREE (clone) = push_stmt_list ();
- add_stmt (bind);
- }
- DECL_ABSTRACT_ORIGIN (clone) = NULL;
- expand_or_defer_fn (finish_function (0));
- }
- return 1;
- }
- /* FN is a function that has a complete body. Clone the body as
- necessary. Returns nonzero if there's no longer any need to
- process the main body. */
- bool
- maybe_clone_body (tree fn)
- {
- tree comdat_group = NULL_TREE;
- tree clone;
- tree fns[3];
- bool first = true;
- int idx;
- bool need_alias = false;
- /* We only clone constructors and destructors. */
- if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
- && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
- return 0;
- populate_clone_array (fn, fns);
- /* Remember if we can't have multiple clones for some reason. We need to
- check this before we remap local static initializers in clone_body. */
- if (!tree_versionable_function_p (fn))
- need_alias = true;
- /* We know that any clones immediately follow FN in the TYPE_METHODS
- list. */
- push_to_top_level ();
- for (idx = 0; idx < 3; idx++)
- {
- tree parm;
- tree clone_parm;
- clone = fns[idx];
- if (!clone)
- continue;
- /* Update CLONE's source position information to match FN's. */
- DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
- DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
- DECL_DECLARED_CONSTEXPR_P (clone) = DECL_DECLARED_CONSTEXPR_P (fn);
- DECL_COMDAT (clone) = DECL_COMDAT (fn);
- DECL_WEAK (clone) = DECL_WEAK (fn);
- /* We don't copy the comdat group from fn to clone because the assembler
- name of fn was corrupted by write_mangled_name by adding *INTERNAL*
- to it. By doing so, it also corrupted the comdat group. */
- if (DECL_ONE_ONLY (fn))
- cgraph_node::get_create (clone)->set_comdat_group (cxx_comdat_group (clone));
- DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
- DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
- DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
- DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
- TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
- DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn);
- DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn);
- DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn);
- DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn));
- DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn);
- set_decl_section_name (clone, DECL_SECTION_NAME (fn));
- /* Adjust the parameter names and locations. */
- parm = DECL_ARGUMENTS (fn);
- clone_parm = DECL_ARGUMENTS (clone);
- /* Update the `this' parameter, which is always first. */
- update_cloned_parm (parm, clone_parm, first);
- parm = DECL_CHAIN (parm);
- clone_parm = DECL_CHAIN (clone_parm);
- if (DECL_HAS_IN_CHARGE_PARM_P (fn))
- parm = DECL_CHAIN (parm);
- if (DECL_HAS_VTT_PARM_P (fn))
- parm = DECL_CHAIN (parm);
- if (DECL_HAS_VTT_PARM_P (clone))
- clone_parm = DECL_CHAIN (clone_parm);
- for (; parm;
- parm = DECL_CHAIN (parm), clone_parm = DECL_CHAIN (clone_parm))
- /* Update this parameter. */
- update_cloned_parm (parm, clone_parm, first);
- }
- bool can_alias = can_alias_cdtor (fn);
- /* If we decide to turn clones into thunks, they will branch to fn.
- Must have original function available to call. */
- if (!can_alias && maybe_thunk_body (fn, need_alias))
- {
- pop_from_top_level ();
- /* We still need to emit the original function. */
- return 0;
- }
- /* Emit the DWARF1 abstract instance. */
- (*debug_hooks->deferred_inline_function) (fn);
- /* We know that any clones immediately follow FN in the TYPE_METHODS list. */
- for (idx = 0; idx < 3; idx++)
- {
- tree parm;
- tree clone_parm;
- int parmno;
- hash_map<tree, tree> *decl_map;
- bool alias = false;
- clone = fns[idx];
- if (!clone)
- continue;
- /* Start processing the function. */
- start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
- /* Tell cgraph if both ctors or both dtors are known to have
- the same body. */
- if (can_alias
- && fns[0]
- && idx == 1
- && cgraph_node::get_create (fns[0])->create_same_body_alias
- (clone, fns[0]))
- {
- alias = true;
- if (DECL_ONE_ONLY (fns[0]))
- {
- /* For comdat base and complete cdtors put them
- into the same, *[CD]5* comdat group instead of
- *[CD][12]*. */
- comdat_group = cdtor_comdat_group (fns[1], fns[0]);
- cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group);
- if (symtab_node::get (clone)->same_comdat_group)
- symtab_node::get (clone)->remove_from_same_comdat_group ();
- symtab_node::get (clone)->add_to_same_comdat_group
- (symtab_node::get (fns[0]));
- }
- }
- /* Build the delete destructor by calling complete destructor
- and delete function. */
- if (idx == 2)
- {
- build_delete_destructor_body (clone, fns[1]);
- /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
- virtual, it goes into the same comdat group as well. */
- if (comdat_group)
- cgraph_node::get_create (clone)->add_to_same_comdat_group
- (symtab_node::get (fns[0]));
- }
- else if (alias)
- /* No need to populate body. */ ;
- else
- {
- /* If we can't have multiple copies of FN (say, because there's a
- static local initialized with the address of a label), we need
- to use an alias for the complete variant. */
- if (idx == 1 && need_alias)
- {
- if (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_set)
- sorry (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_reason, fn);
- else
- sorry ("making multiple clones of %qD", fn);
- }
- /* Remap the parameters. */
- decl_map = new hash_map<tree, tree>;
- for (parmno = 0,
- parm = DECL_ARGUMENTS (fn),
- clone_parm = DECL_ARGUMENTS (clone);
- parm;
- ++parmno,
- parm = DECL_CHAIN (parm))
- {
- /* Map the in-charge parameter to an appropriate constant. */
- if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
- {
- tree in_charge;
- in_charge = in_charge_arg_for_name (DECL_NAME (clone));
- decl_map->put (parm, in_charge);
- }
- else if (DECL_ARTIFICIAL (parm)
- && DECL_NAME (parm) == vtt_parm_identifier)
- {
- /* For a subobject constructor or destructor, the next
- argument is the VTT parameter. Remap the VTT_PARM
- from the CLONE to this parameter. */
- if (DECL_HAS_VTT_PARM_P (clone))
- {
- DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
- decl_map->put (parm, clone_parm);
- clone_parm = DECL_CHAIN (clone_parm);
- }
- /* Otherwise, map the VTT parameter to `NULL'. */
- else
- {
- tree t
- = fold_convert (TREE_TYPE (parm), null_pointer_node);
- decl_map->put (parm, t);
- }
- }
- /* Map other parameters to their equivalents in the cloned
- function. */
- else
- {
- decl_map->put (parm, clone_parm);
- clone_parm = DECL_CHAIN (clone_parm);
- }
- }
- if (targetm.cxx.cdtor_returns_this ())
- {
- parm = DECL_RESULT (fn);
- clone_parm = DECL_RESULT (clone);
- decl_map->put (parm, clone_parm);
- }
- /* Clone the body. */
- clone_body (clone, fn, decl_map);
- /* Clean up. */
- delete decl_map;
- }
- /* The clone can throw iff the original function can throw. */
- cp_function_chain->can_throw = !TREE_NOTHROW (fn);
- /* Now, expand this function into RTL, if appropriate. */
- finish_function (0);
- BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
- if (alias)
- {
- if (expand_or_defer_fn_1 (clone))
- emit_associated_thunks (clone);
- }
- else
- expand_or_defer_fn (clone);
- first = false;
- }
- pop_from_top_level ();
- /* We don't need to process the original function any further. */
- return 1;
- }
|