138fd1498Szrj /* Perform optimizations on tree structure. 238fd1498Szrj Copyright (C) 1998-2018 Free Software Foundation, Inc. 338fd1498Szrj Written by Mark Michell (mark@codesourcery.com). 438fd1498Szrj 538fd1498Szrj This file is part of GCC. 638fd1498Szrj 738fd1498Szrj GCC is free software; you can redistribute it and/or modify it 838fd1498Szrj under the terms of the GNU General Public License as published by 938fd1498Szrj the Free Software Foundation; either version 3, or (at your option) 1038fd1498Szrj any later version. 1138fd1498Szrj 1238fd1498Szrj GCC is distributed in the hope that it will be useful, but 1338fd1498Szrj WITHOUT ANY WARRANTY; without even the implied warranty of 1438fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1538fd1498Szrj General Public License for more details. 1638fd1498Szrj 1738fd1498Szrj You should have received a copy of the GNU General Public License 1838fd1498Szrj along with GCC; see the file COPYING3. If not see 1938fd1498Szrj <http://www.gnu.org/licenses/>. */ 2038fd1498Szrj 2138fd1498Szrj #include "config.h" 2238fd1498Szrj #include "system.h" 2338fd1498Szrj #include "coretypes.h" 2438fd1498Szrj #include "target.h" 2538fd1498Szrj #include "cp-tree.h" 2638fd1498Szrj #include "stringpool.h" 2738fd1498Szrj #include "cgraph.h" 2838fd1498Szrj #include "debug.h" 2938fd1498Szrj #include "tree-inline.h" 3038fd1498Szrj #include "tree-iterator.h" 3138fd1498Szrj 3238fd1498Szrj /* Prototypes. */ 3338fd1498Szrj 3438fd1498Szrj static void update_cloned_parm (tree, tree, bool); 3538fd1498Szrj 3638fd1498Szrj /* CLONED_PARM is a copy of CLONE, generated for a cloned constructor 3738fd1498Szrj or destructor. Update it to ensure that the source-position for 3838fd1498Szrj the cloned parameter matches that for the original, and that the 3938fd1498Szrj debugging generation code will be able to find the original PARM. */ 4038fd1498Szrj 4138fd1498Szrj static void 4238fd1498Szrj update_cloned_parm (tree parm, tree cloned_parm, bool first) 4338fd1498Szrj { 4438fd1498Szrj DECL_ABSTRACT_ORIGIN (cloned_parm) = parm; 4538fd1498Szrj 4638fd1498Szrj /* We may have taken its address. */ 4738fd1498Szrj TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm); 4838fd1498Szrj 49*58e805e6Szrj DECL_BY_REFERENCE (cloned_parm) = DECL_BY_REFERENCE (parm); 50*58e805e6Szrj 5138fd1498Szrj /* The definition might have different constness. */ 5238fd1498Szrj TREE_READONLY (cloned_parm) = TREE_READONLY (parm); 5338fd1498Szrj 5438fd1498Szrj TREE_USED (cloned_parm) = !first || TREE_USED (parm); 5538fd1498Szrj 5638fd1498Szrj /* The name may have changed from the declaration. */ 5738fd1498Szrj DECL_NAME (cloned_parm) = DECL_NAME (parm); 5838fd1498Szrj DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm); 5938fd1498Szrj TREE_TYPE (cloned_parm) = TREE_TYPE (parm); 6038fd1498Szrj 6138fd1498Szrj DECL_GIMPLE_REG_P (cloned_parm) = DECL_GIMPLE_REG_P (parm); 6238fd1498Szrj } 6338fd1498Szrj 64*58e805e6Szrj /* Like copy_decl_no_change, but handle DECL_OMP_PRIVATIZED_MEMBER 65*58e805e6Szrj properly. */ 66*58e805e6Szrj 67*58e805e6Szrj static tree 68*58e805e6Szrj cxx_copy_decl (tree decl, copy_body_data *id) 69*58e805e6Szrj { 70*58e805e6Szrj tree copy = copy_decl_no_change (decl, id); 71*58e805e6Szrj if (VAR_P (decl) 72*58e805e6Szrj && DECL_HAS_VALUE_EXPR_P (decl) 73*58e805e6Szrj && DECL_ARTIFICIAL (decl) 74*58e805e6Szrj && DECL_LANG_SPECIFIC (decl) 75*58e805e6Szrj && DECL_OMP_PRIVATIZED_MEMBER (decl)) 76*58e805e6Szrj { 77*58e805e6Szrj tree expr = DECL_VALUE_EXPR (copy); 78*58e805e6Szrj walk_tree (&expr, copy_tree_body_r, id, NULL); 79*58e805e6Szrj SET_DECL_VALUE_EXPR (copy, expr); 80*58e805e6Szrj } 81*58e805e6Szrj return copy; 82*58e805e6Szrj } 8338fd1498Szrj 8438fd1498Szrj /* FN is a function in High GIMPLE form that has a complete body and no 8538fd1498Szrj CFG. CLONE is a function whose body is to be set to a copy of FN, 8638fd1498Szrj mapping argument declarations according to the ARG_MAP splay_tree. */ 8738fd1498Szrj 8838fd1498Szrj static void 8938fd1498Szrj clone_body (tree clone, tree fn, void *arg_map) 9038fd1498Szrj { 9138fd1498Szrj copy_body_data id; 9238fd1498Szrj tree stmts; 9338fd1498Szrj 9438fd1498Szrj /* Clone the body, as if we were making an inline call. But, remap 9538fd1498Szrj the parameters in the callee to the parameters of caller. */ 9638fd1498Szrj memset (&id, 0, sizeof (id)); 9738fd1498Szrj id.src_fn = fn; 9838fd1498Szrj id.dst_fn = clone; 9938fd1498Szrj id.src_cfun = DECL_STRUCT_FUNCTION (fn); 10038fd1498Szrj id.decl_map = static_cast<hash_map<tree, tree> *> (arg_map); 10138fd1498Szrj 102*58e805e6Szrj id.copy_decl = cxx_copy_decl; 10338fd1498Szrj id.transform_call_graph_edges = CB_CGE_DUPLICATE; 10438fd1498Szrj id.transform_new_cfg = true; 10538fd1498Szrj id.transform_return_to_modify = false; 10638fd1498Szrj id.transform_lang_insert_block = NULL; 10738fd1498Szrj 10838fd1498Szrj /* We're not inside any EH region. */ 10938fd1498Szrj id.eh_lp_nr = 0; 11038fd1498Szrj 11138fd1498Szrj stmts = DECL_SAVED_TREE (fn); 11238fd1498Szrj walk_tree (&stmts, copy_tree_body_r, &id, NULL); 11338fd1498Szrj 11438fd1498Szrj /* Also remap the initializer of any static variables so that they (in 11538fd1498Szrj particular, any label addresses) correspond to the base variant rather 11638fd1498Szrj than the abstract one. */ 11738fd1498Szrj if (DECL_NAME (clone) == base_dtor_identifier 11838fd1498Szrj || DECL_NAME (clone) == base_ctor_identifier) 11938fd1498Szrj { 12038fd1498Szrj unsigned ix; 12138fd1498Szrj tree decl; 12238fd1498Szrj 12338fd1498Szrj FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (fn), ix, decl) 12438fd1498Szrj walk_tree (&DECL_INITIAL (decl), copy_tree_body_r, &id, NULL); 12538fd1498Szrj } 12638fd1498Szrj 12738fd1498Szrj append_to_statement_list_force (stmts, &DECL_SAVED_TREE (clone)); 12838fd1498Szrj } 12938fd1498Szrj 13038fd1498Szrj /* DELETE_DTOR is a delete destructor whose body will be built. 13138fd1498Szrj COMPLETE_DTOR is the corresponding complete destructor. */ 13238fd1498Szrj 13338fd1498Szrj static void 13438fd1498Szrj build_delete_destructor_body (tree delete_dtor, tree complete_dtor) 13538fd1498Szrj { 13638fd1498Szrj tree parm = DECL_ARGUMENTS (delete_dtor); 13738fd1498Szrj tree virtual_size = cxx_sizeof (current_class_type); 13838fd1498Szrj 13938fd1498Szrj /* Call the corresponding complete destructor. */ 14038fd1498Szrj gcc_assert (complete_dtor); 14138fd1498Szrj tree call_dtor = build_cxx_call (complete_dtor, 1, &parm, 14238fd1498Szrj tf_warning_or_error); 14338fd1498Szrj 14438fd1498Szrj /* Call the delete function. */ 14538fd1498Szrj tree call_delete = build_op_delete_call (DELETE_EXPR, current_class_ptr, 14638fd1498Szrj virtual_size, 14738fd1498Szrj /*global_p=*/false, 14838fd1498Szrj /*placement=*/NULL_TREE, 14938fd1498Szrj /*alloc_fn=*/NULL_TREE, 15038fd1498Szrj tf_warning_or_error); 15138fd1498Szrj 15238fd1498Szrj /* Operator delete must be called, whether or not the dtor throws. */ 15338fd1498Szrj add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, call_dtor, call_delete)); 15438fd1498Szrj 15538fd1498Szrj /* Return the address of the object. */ 15638fd1498Szrj if (targetm.cxx.cdtor_returns_this ()) 15738fd1498Szrj { 15838fd1498Szrj tree val = DECL_ARGUMENTS (delete_dtor); 15938fd1498Szrj val = build2 (MODIFY_EXPR, TREE_TYPE (val), 16038fd1498Szrj DECL_RESULT (delete_dtor), val); 16138fd1498Szrj add_stmt (build_stmt (0, RETURN_EXPR, val)); 16238fd1498Szrj } 16338fd1498Szrj } 16438fd1498Szrj 16538fd1498Szrj /* Return name of comdat group for complete and base ctor (or dtor) 16638fd1498Szrj that have the same body. If dtor is virtual, deleting dtor goes 16738fd1498Szrj into this comdat group as well. */ 16838fd1498Szrj 16938fd1498Szrj static tree 17038fd1498Szrj cdtor_comdat_group (tree complete, tree base) 17138fd1498Szrj { 17238fd1498Szrj tree complete_name = DECL_ASSEMBLER_NAME (complete); 17338fd1498Szrj tree base_name = DECL_ASSEMBLER_NAME (base); 17438fd1498Szrj char *grp_name; 17538fd1498Szrj const char *p, *q; 17638fd1498Szrj bool diff_seen = false; 17738fd1498Szrj size_t idx; 17838fd1498Szrj gcc_assert (IDENTIFIER_LENGTH (complete_name) 17938fd1498Szrj == IDENTIFIER_LENGTH (base_name)); 18038fd1498Szrj grp_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (complete_name) + 1); 18138fd1498Szrj p = IDENTIFIER_POINTER (complete_name); 18238fd1498Szrj q = IDENTIFIER_POINTER (base_name); 18338fd1498Szrj for (idx = 0; idx < IDENTIFIER_LENGTH (complete_name); idx++) 18438fd1498Szrj if (p[idx] == q[idx]) 18538fd1498Szrj grp_name[idx] = p[idx]; 18638fd1498Szrj else 18738fd1498Szrj { 18838fd1498Szrj gcc_assert (!diff_seen 18938fd1498Szrj && idx > 0 19038fd1498Szrj && (p[idx - 1] == 'C' || p[idx - 1] == 'D' 19138fd1498Szrj || p[idx - 1] == 'I') 19238fd1498Szrj && p[idx] == '1' 19338fd1498Szrj && q[idx] == '2'); 19438fd1498Szrj grp_name[idx] = '5'; 19538fd1498Szrj diff_seen = true; 19638fd1498Szrj } 19738fd1498Szrj grp_name[idx] = '\0'; 19838fd1498Szrj gcc_assert (diff_seen); 19938fd1498Szrj return get_identifier (grp_name); 20038fd1498Szrj } 20138fd1498Szrj 20238fd1498Szrj /* Returns true iff we can make the base and complete [cd]tor aliases of 20338fd1498Szrj the same symbol rather than separate functions. */ 20438fd1498Szrj 20538fd1498Szrj static bool 20638fd1498Szrj can_alias_cdtor (tree fn) 20738fd1498Szrj { 20838fd1498Szrj /* If aliases aren't supported by the assembler, fail. */ 20938fd1498Szrj if (!TARGET_SUPPORTS_ALIASES) 21038fd1498Szrj return false; 21138fd1498Szrj 21238fd1498Szrj /* We can't use an alias if there are virtual bases. */ 21338fd1498Szrj if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn))) 21438fd1498Szrj return false; 21538fd1498Szrj /* ??? Why not use aliases with -frepo? */ 21638fd1498Szrj if (flag_use_repository) 21738fd1498Szrj return false; 21838fd1498Szrj gcc_assert (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) 21938fd1498Szrj || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)); 22038fd1498Szrj /* Don't use aliases for weak/linkonce definitions unless we can put both 22138fd1498Szrj symbols in the same COMDAT group. */ 22238fd1498Szrj return (DECL_INTERFACE_KNOWN (fn) 22338fd1498Szrj && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fn)) 22438fd1498Szrj && (!DECL_ONE_ONLY (fn) 22538fd1498Szrj || (HAVE_COMDAT_GROUP && DECL_WEAK (fn)))); 22638fd1498Szrj } 22738fd1498Szrj 22838fd1498Szrj /* FN is a [cd]tor, fns is a pointer to an array of length 3. Fill fns 22938fd1498Szrj with pointers to the base, complete, and deleting variants. */ 23038fd1498Szrj 23138fd1498Szrj static void 23238fd1498Szrj populate_clone_array (tree fn, tree *fns) 23338fd1498Szrj { 23438fd1498Szrj tree clone; 23538fd1498Szrj 23638fd1498Szrj fns[0] = NULL_TREE; 23738fd1498Szrj fns[1] = NULL_TREE; 23838fd1498Szrj fns[2] = NULL_TREE; 23938fd1498Szrj 24038fd1498Szrj /* Look for the complete destructor which may be used to build the 24138fd1498Szrj delete destructor. */ 24238fd1498Szrj FOR_EACH_CLONE (clone, fn) 24338fd1498Szrj if (DECL_NAME (clone) == complete_dtor_identifier 24438fd1498Szrj || DECL_NAME (clone) == complete_ctor_identifier) 24538fd1498Szrj fns[1] = clone; 24638fd1498Szrj else if (DECL_NAME (clone) == base_dtor_identifier 24738fd1498Szrj || DECL_NAME (clone) == base_ctor_identifier) 24838fd1498Szrj fns[0] = clone; 24938fd1498Szrj else if (DECL_NAME (clone) == deleting_dtor_identifier) 25038fd1498Szrj fns[2] = clone; 25138fd1498Szrj else 25238fd1498Szrj gcc_unreachable (); 25338fd1498Szrj } 25438fd1498Szrj 25538fd1498Szrj /* FN is a constructor or destructor, and there are FUNCTION_DECLs 25638fd1498Szrj cloned from it nearby. Instead of cloning this body, leave it 25738fd1498Szrj alone and create tiny one-call bodies for the cloned 25838fd1498Szrj FUNCTION_DECLs. These clones are sibcall candidates, and their 25938fd1498Szrj resulting code will be very thunk-esque. */ 26038fd1498Szrj 26138fd1498Szrj static bool 26238fd1498Szrj maybe_thunk_body (tree fn, bool force) 26338fd1498Szrj { 26438fd1498Szrj tree bind, block, call, clone, clone_result, fn_parm, fn_parm_typelist; 26538fd1498Szrj tree last_arg, modify, *args; 26638fd1498Szrj int parmno, vtt_parmno, max_parms; 26738fd1498Szrj tree fns[3]; 26838fd1498Szrj 26938fd1498Szrj if (!force && !flag_declone_ctor_dtor) 27038fd1498Szrj return 0; 27138fd1498Szrj 27238fd1498Szrj /* If function accepts variable arguments, give up. */ 27338fd1498Szrj last_arg = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fn))); 27438fd1498Szrj if (last_arg != void_list_node) 27538fd1498Szrj return 0; 27638fd1498Szrj 27738fd1498Szrj /* If we got this far, we've decided to turn the clones into thunks. */ 27838fd1498Szrj 27938fd1498Szrj /* We're going to generate code for fn, so it is no longer "abstract." 28038fd1498Szrj Also make the unified ctor/dtor private to either the translation unit 28138fd1498Szrj (for non-vague linkage ctors) or the COMDAT group (otherwise). */ 28238fd1498Szrj 28338fd1498Szrj populate_clone_array (fn, fns); 28438fd1498Szrj 28538fd1498Szrj /* Can happen during error recovery (c++/71464). */ 28638fd1498Szrj if (!fns[0] || !fns[1]) 28738fd1498Szrj return 0; 28838fd1498Szrj 28938fd1498Szrj /* Don't use thunks if the base clone omits inherited parameters. */ 29038fd1498Szrj if (ctor_omit_inherited_parms (fns[0])) 29138fd1498Szrj return 0; 29238fd1498Szrj 29338fd1498Szrj DECL_ABSTRACT_P (fn) = false; 29438fd1498Szrj if (!DECL_WEAK (fn)) 29538fd1498Szrj { 29638fd1498Szrj TREE_PUBLIC (fn) = false; 29738fd1498Szrj DECL_EXTERNAL (fn) = false; 29838fd1498Szrj DECL_INTERFACE_KNOWN (fn) = true; 29938fd1498Szrj } 30038fd1498Szrj else if (HAVE_COMDAT_GROUP) 30138fd1498Szrj { 30238fd1498Szrj /* At eof, defer creation of mangling aliases temporarily. */ 30338fd1498Szrj bool save_defer_mangling_aliases = defer_mangling_aliases; 30438fd1498Szrj defer_mangling_aliases = true; 30538fd1498Szrj tree comdat_group = cdtor_comdat_group (fns[1], fns[0]); 30638fd1498Szrj defer_mangling_aliases = save_defer_mangling_aliases; 30738fd1498Szrj cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group); 30838fd1498Szrj cgraph_node::get_create (fns[1])->add_to_same_comdat_group 30938fd1498Szrj (cgraph_node::get_create (fns[0])); 31038fd1498Szrj symtab_node::get (fn)->add_to_same_comdat_group 31138fd1498Szrj (symtab_node::get (fns[0])); 31238fd1498Szrj if (fns[2]) 31338fd1498Szrj /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is 31438fd1498Szrj virtual, it goes into the same comdat group as well. */ 31538fd1498Szrj cgraph_node::get_create (fns[2])->add_to_same_comdat_group 31638fd1498Szrj (symtab_node::get (fns[0])); 31738fd1498Szrj /* Emit them now that the thunks are same comdat group aliases. */ 31838fd1498Szrj if (!save_defer_mangling_aliases) 31938fd1498Szrj generate_mangling_aliases (); 32038fd1498Szrj TREE_PUBLIC (fn) = false; 32138fd1498Szrj DECL_EXTERNAL (fn) = false; 32238fd1498Szrj DECL_INTERFACE_KNOWN (fn) = true; 32338fd1498Szrj /* function_and_variable_visibility doesn't want !PUBLIC decls to 32438fd1498Szrj have these flags set. */ 32538fd1498Szrj DECL_WEAK (fn) = false; 32638fd1498Szrj DECL_COMDAT (fn) = false; 32738fd1498Szrj } 32838fd1498Szrj 32938fd1498Szrj /* Find the vtt_parm, if present. */ 33038fd1498Szrj for (vtt_parmno = -1, parmno = 0, fn_parm = DECL_ARGUMENTS (fn); 33138fd1498Szrj fn_parm; 33238fd1498Szrj ++parmno, fn_parm = TREE_CHAIN (fn_parm)) 33338fd1498Szrj { 33438fd1498Szrj if (DECL_ARTIFICIAL (fn_parm) 33538fd1498Szrj && DECL_NAME (fn_parm) == vtt_parm_identifier) 33638fd1498Szrj { 33738fd1498Szrj /* Compensate for removed in_charge parameter. */ 33838fd1498Szrj vtt_parmno = parmno; 33938fd1498Szrj break; 34038fd1498Szrj } 34138fd1498Szrj } 34238fd1498Szrj 34338fd1498Szrj /* Allocate an argument buffer for build_cxx_call(). 34438fd1498Szrj Make sure it is large enough for any of the clones. */ 34538fd1498Szrj max_parms = 0; 34638fd1498Szrj FOR_EACH_CLONE (clone, fn) 34738fd1498Szrj { 34838fd1498Szrj int length = list_length (DECL_ARGUMENTS (fn)); 34938fd1498Szrj if (length > max_parms) 35038fd1498Szrj max_parms = length; 35138fd1498Szrj } 35238fd1498Szrj args = XALLOCAVEC (tree, max_parms); 35338fd1498Szrj 35438fd1498Szrj /* We know that any clones immediately follow FN in TYPE_FIELDS. */ 35538fd1498Szrj FOR_EACH_CLONE (clone, fn) 35638fd1498Szrj { 35738fd1498Szrj tree clone_parm; 35838fd1498Szrj 35938fd1498Szrj /* If we've already generated a body for this clone, avoid 36038fd1498Szrj duplicating it. (Is it possible for a clone-list to grow after we 36138fd1498Szrj first see it?) */ 36238fd1498Szrj if (DECL_SAVED_TREE (clone) || TREE_ASM_WRITTEN (clone)) 36338fd1498Szrj continue; 36438fd1498Szrj 36538fd1498Szrj /* Start processing the function. */ 36638fd1498Szrj start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED); 36738fd1498Szrj 36838fd1498Szrj if (clone == fns[2]) 36938fd1498Szrj { 37038fd1498Szrj for (clone_parm = DECL_ARGUMENTS (clone); clone_parm; 37138fd1498Szrj clone_parm = TREE_CHAIN (clone_parm)) 37238fd1498Szrj DECL_ABSTRACT_ORIGIN (clone_parm) = NULL_TREE; 37338fd1498Szrj /* Build the delete destructor by calling complete destructor and 37438fd1498Szrj delete function. */ 37538fd1498Szrj build_delete_destructor_body (clone, fns[1]); 37638fd1498Szrj } 37738fd1498Szrj else 37838fd1498Szrj { 37938fd1498Szrj /* Walk parameter lists together, creating parameter list for 38038fd1498Szrj call to original function. */ 38138fd1498Szrj for (parmno = 0, 38238fd1498Szrj fn_parm = DECL_ARGUMENTS (fn), 38338fd1498Szrj fn_parm_typelist = TYPE_ARG_TYPES (TREE_TYPE (fn)), 38438fd1498Szrj clone_parm = DECL_ARGUMENTS (clone); 38538fd1498Szrj fn_parm; 38638fd1498Szrj ++parmno, 38738fd1498Szrj fn_parm = TREE_CHAIN (fn_parm)) 38838fd1498Szrj { 38938fd1498Szrj if (parmno == vtt_parmno && ! DECL_HAS_VTT_PARM_P (clone)) 39038fd1498Szrj { 39138fd1498Szrj gcc_assert (fn_parm_typelist); 39238fd1498Szrj /* Clobber argument with formal parameter type. */ 39338fd1498Szrj args[parmno] 39438fd1498Szrj = convert (TREE_VALUE (fn_parm_typelist), 39538fd1498Szrj null_pointer_node); 39638fd1498Szrj } 39738fd1498Szrj else if (parmno == 1 && DECL_HAS_IN_CHARGE_PARM_P (fn)) 39838fd1498Szrj { 39938fd1498Szrj tree in_charge 40038fd1498Szrj = copy_node (in_charge_arg_for_name (DECL_NAME (clone))); 40138fd1498Szrj args[parmno] = in_charge; 40238fd1498Szrj } 40338fd1498Szrj /* Map other parameters to their equivalents in the cloned 40438fd1498Szrj function. */ 40538fd1498Szrj else 40638fd1498Szrj { 40738fd1498Szrj gcc_assert (clone_parm); 40838fd1498Szrj DECL_ABSTRACT_ORIGIN (clone_parm) = NULL; 40938fd1498Szrj args[parmno] = clone_parm; 410*58e805e6Szrj /* Clear TREE_ADDRESSABLE on thunk arguments. */ 411*58e805e6Szrj TREE_ADDRESSABLE (clone_parm) = 0; 41238fd1498Szrj clone_parm = TREE_CHAIN (clone_parm); 41338fd1498Szrj } 41438fd1498Szrj if (fn_parm_typelist) 41538fd1498Szrj fn_parm_typelist = TREE_CHAIN (fn_parm_typelist); 41638fd1498Szrj } 41738fd1498Szrj 41838fd1498Szrj /* We built this list backwards; fix now. */ 41938fd1498Szrj mark_used (fn); 42038fd1498Szrj call = build_cxx_call (fn, parmno, args, tf_warning_or_error); 42138fd1498Szrj /* Arguments passed to the thunk by invisible reference should 42238fd1498Szrj be transmitted to the callee unchanged. Do not create a 42338fd1498Szrj temporary and invoke the copy constructor. The thunking 42438fd1498Szrj transformation must not introduce any constructor calls. */ 42538fd1498Szrj CALL_FROM_THUNK_P (call) = 1; 42638fd1498Szrj block = make_node (BLOCK); 42738fd1498Szrj if (targetm.cxx.cdtor_returns_this ()) 42838fd1498Szrj { 42938fd1498Szrj clone_result = DECL_RESULT (clone); 43038fd1498Szrj modify = build2 (MODIFY_EXPR, TREE_TYPE (clone_result), 43138fd1498Szrj clone_result, call); 43238fd1498Szrj modify = build1 (RETURN_EXPR, void_type_node, modify); 43338fd1498Szrj add_stmt (modify); 43438fd1498Szrj } 43538fd1498Szrj else 43638fd1498Szrj { 43738fd1498Szrj add_stmt (call); 43838fd1498Szrj } 43938fd1498Szrj bind = c_build_bind_expr (DECL_SOURCE_LOCATION (clone), 44038fd1498Szrj block, cur_stmt_list); 44138fd1498Szrj DECL_SAVED_TREE (clone) = push_stmt_list (); 44238fd1498Szrj add_stmt (bind); 44338fd1498Szrj } 44438fd1498Szrj 44538fd1498Szrj DECL_ABSTRACT_ORIGIN (clone) = NULL; 44638fd1498Szrj expand_or_defer_fn (finish_function (/*inline_p=*/false)); 44738fd1498Szrj } 44838fd1498Szrj return 1; 44938fd1498Szrj } 45038fd1498Szrj 45138fd1498Szrj /* FN is a function that has a complete body. Clone the body as 45238fd1498Szrj necessary. Returns nonzero if there's no longer any need to 45338fd1498Szrj process the main body. */ 45438fd1498Szrj 45538fd1498Szrj bool 45638fd1498Szrj maybe_clone_body (tree fn) 45738fd1498Szrj { 45838fd1498Szrj tree comdat_group = NULL_TREE; 45938fd1498Szrj tree clone; 46038fd1498Szrj tree fns[3]; 46138fd1498Szrj bool first = true; 46238fd1498Szrj int idx; 46338fd1498Szrj bool need_alias = false; 46438fd1498Szrj 46538fd1498Szrj /* We only clone constructors and destructors. */ 46638fd1498Szrj if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) 46738fd1498Szrj && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)) 46838fd1498Szrj return 0; 46938fd1498Szrj 47038fd1498Szrj populate_clone_array (fn, fns); 47138fd1498Szrj 47238fd1498Szrj /* Remember if we can't have multiple clones for some reason. We need to 47338fd1498Szrj check this before we remap local static initializers in clone_body. */ 47438fd1498Szrj if (!tree_versionable_function_p (fn)) 47538fd1498Szrj need_alias = true; 47638fd1498Szrj 47738fd1498Szrj /* We know that any clones immediately follow FN in the TYPE_FIELDS 47838fd1498Szrj list. */ 47938fd1498Szrj push_to_top_level (); 48038fd1498Szrj for (idx = 0; idx < 3; idx++) 48138fd1498Szrj { 48238fd1498Szrj tree parm; 48338fd1498Szrj tree clone_parm; 48438fd1498Szrj 48538fd1498Szrj clone = fns[idx]; 48638fd1498Szrj if (!clone) 48738fd1498Szrj continue; 48838fd1498Szrj 48938fd1498Szrj /* Update CLONE's source position information to match FN's. */ 49038fd1498Szrj DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn); 49138fd1498Szrj DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn); 49238fd1498Szrj DECL_DECLARED_CONSTEXPR_P (clone) = DECL_DECLARED_CONSTEXPR_P (fn); 49338fd1498Szrj DECL_COMDAT (clone) = DECL_COMDAT (fn); 49438fd1498Szrj DECL_WEAK (clone) = DECL_WEAK (fn); 49538fd1498Szrj 49638fd1498Szrj /* We don't copy the comdat group from fn to clone because the assembler 49738fd1498Szrj name of fn was corrupted by write_mangled_name by adding *INTERNAL* 49838fd1498Szrj to it. By doing so, it also corrupted the comdat group. */ 49938fd1498Szrj if (DECL_ONE_ONLY (fn)) 50038fd1498Szrj cgraph_node::get_create (clone)->set_comdat_group (cxx_comdat_group (clone)); 50138fd1498Szrj DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn); 50238fd1498Szrj DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn); 50338fd1498Szrj DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn); 50438fd1498Szrj DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn); 50538fd1498Szrj TREE_PUBLIC (clone) = TREE_PUBLIC (fn); 50638fd1498Szrj DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn); 50738fd1498Szrj DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn); 50838fd1498Szrj DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn); 50938fd1498Szrj DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn)); 51038fd1498Szrj DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn); 51138fd1498Szrj set_decl_section_name (clone, DECL_SECTION_NAME (fn)); 51238fd1498Szrj 51338fd1498Szrj /* Adjust the parameter names and locations. */ 51438fd1498Szrj parm = DECL_ARGUMENTS (fn); 51538fd1498Szrj clone_parm = DECL_ARGUMENTS (clone); 51638fd1498Szrj /* Update the `this' parameter, which is always first. */ 51738fd1498Szrj update_cloned_parm (parm, clone_parm, first); 51838fd1498Szrj parm = DECL_CHAIN (parm); 51938fd1498Szrj clone_parm = DECL_CHAIN (clone_parm); 52038fd1498Szrj if (DECL_HAS_IN_CHARGE_PARM_P (fn)) 52138fd1498Szrj parm = DECL_CHAIN (parm); 52238fd1498Szrj if (DECL_HAS_VTT_PARM_P (fn)) 52338fd1498Szrj parm = DECL_CHAIN (parm); 52438fd1498Szrj if (DECL_HAS_VTT_PARM_P (clone)) 52538fd1498Szrj clone_parm = DECL_CHAIN (clone_parm); 52638fd1498Szrj for (; parm && clone_parm; 52738fd1498Szrj parm = DECL_CHAIN (parm), clone_parm = DECL_CHAIN (clone_parm)) 52838fd1498Szrj /* Update this parameter. */ 52938fd1498Szrj update_cloned_parm (parm, clone_parm, first); 53038fd1498Szrj } 53138fd1498Szrj 53238fd1498Szrj bool can_alias = can_alias_cdtor (fn); 53338fd1498Szrj 53438fd1498Szrj /* If we decide to turn clones into thunks, they will branch to fn. 53538fd1498Szrj Must have original function available to call. */ 53638fd1498Szrj if (!can_alias && maybe_thunk_body (fn, need_alias)) 53738fd1498Szrj { 53838fd1498Szrj pop_from_top_level (); 53938fd1498Szrj /* We still need to emit the original function. */ 54038fd1498Szrj return 0; 54138fd1498Szrj } 54238fd1498Szrj 54338fd1498Szrj /* Emit the DWARF1 abstract instance. */ 54438fd1498Szrj (*debug_hooks->deferred_inline_function) (fn); 54538fd1498Szrj 54638fd1498Szrj /* We know that any clones immediately follow FN in the TYPE_FIELDS. */ 54738fd1498Szrj for (idx = 0; idx < 3; idx++) 54838fd1498Szrj { 54938fd1498Szrj tree parm; 55038fd1498Szrj tree clone_parm; 55138fd1498Szrj int parmno; 55238fd1498Szrj hash_map<tree, tree> *decl_map; 55338fd1498Szrj bool alias = false; 55438fd1498Szrj 55538fd1498Szrj clone = fns[idx]; 55638fd1498Szrj if (!clone) 55738fd1498Szrj continue; 55838fd1498Szrj 55938fd1498Szrj /* Start processing the function. */ 56038fd1498Szrj start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED); 56138fd1498Szrj 56238fd1498Szrj /* Tell cgraph if both ctors or both dtors are known to have 56338fd1498Szrj the same body. */ 56438fd1498Szrj if (can_alias 56538fd1498Szrj && fns[0] 56638fd1498Szrj && idx == 1 56738fd1498Szrj && cgraph_node::get_create (fns[0])->create_same_body_alias 56838fd1498Szrj (clone, fns[0])) 56938fd1498Szrj { 57038fd1498Szrj alias = true; 57138fd1498Szrj if (DECL_ONE_ONLY (fns[0])) 57238fd1498Szrj { 57338fd1498Szrj /* For comdat base and complete cdtors put them 57438fd1498Szrj into the same, *[CD]5* comdat group instead of 57538fd1498Szrj *[CD][12]*. */ 57638fd1498Szrj comdat_group = cdtor_comdat_group (fns[1], fns[0]); 57738fd1498Szrj cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group); 57838fd1498Szrj if (symtab_node::get (clone)->same_comdat_group) 57938fd1498Szrj symtab_node::get (clone)->remove_from_same_comdat_group (); 58038fd1498Szrj symtab_node::get (clone)->add_to_same_comdat_group 58138fd1498Szrj (symtab_node::get (fns[0])); 58238fd1498Szrj } 58338fd1498Szrj } 58438fd1498Szrj 58538fd1498Szrj /* Build the delete destructor by calling complete destructor 58638fd1498Szrj and delete function. */ 58738fd1498Szrj if (idx == 2) 58838fd1498Szrj { 58938fd1498Szrj build_delete_destructor_body (clone, fns[1]); 59038fd1498Szrj /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is 59138fd1498Szrj virtual, it goes into the same comdat group as well. */ 59238fd1498Szrj if (comdat_group) 59338fd1498Szrj cgraph_node::get_create (clone)->add_to_same_comdat_group 59438fd1498Szrj (symtab_node::get (fns[0])); 59538fd1498Szrj } 59638fd1498Szrj else if (alias) 59738fd1498Szrj /* No need to populate body. */ ; 59838fd1498Szrj else 59938fd1498Szrj { 60038fd1498Szrj /* If we can't have multiple copies of FN (say, because there's a 60138fd1498Szrj static local initialized with the address of a label), we need 60238fd1498Szrj to use an alias for the complete variant. */ 60338fd1498Szrj if (idx == 1 && need_alias) 60438fd1498Szrj { 60538fd1498Szrj if (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_set) 60638fd1498Szrj sorry (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_reason, fn); 60738fd1498Szrj else 60838fd1498Szrj sorry ("making multiple clones of %qD", fn); 60938fd1498Szrj } 61038fd1498Szrj 61138fd1498Szrj /* Remap the parameters. */ 61238fd1498Szrj decl_map = new hash_map<tree, tree>; 61338fd1498Szrj for (parmno = 0, 61438fd1498Szrj parm = DECL_ARGUMENTS (fn), 61538fd1498Szrj clone_parm = DECL_ARGUMENTS (clone); 61638fd1498Szrj parm; 61738fd1498Szrj ++parmno, 61838fd1498Szrj parm = DECL_CHAIN (parm)) 61938fd1498Szrj { 62038fd1498Szrj /* Map the in-charge parameter to an appropriate constant. */ 62138fd1498Szrj if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1) 62238fd1498Szrj { 62338fd1498Szrj tree in_charge; 62438fd1498Szrj in_charge = in_charge_arg_for_name (DECL_NAME (clone)); 62538fd1498Szrj decl_map->put (parm, in_charge); 62638fd1498Szrj } 62738fd1498Szrj else if (DECL_ARTIFICIAL (parm) 62838fd1498Szrj && DECL_NAME (parm) == vtt_parm_identifier) 62938fd1498Szrj { 63038fd1498Szrj /* For a subobject constructor or destructor, the next 63138fd1498Szrj argument is the VTT parameter. Remap the VTT_PARM 63238fd1498Szrj from the CLONE to this parameter. */ 63338fd1498Szrj if (DECL_HAS_VTT_PARM_P (clone)) 63438fd1498Szrj { 63538fd1498Szrj DECL_ABSTRACT_ORIGIN (clone_parm) = parm; 63638fd1498Szrj decl_map->put (parm, clone_parm); 63738fd1498Szrj clone_parm = DECL_CHAIN (clone_parm); 63838fd1498Szrj } 63938fd1498Szrj /* Otherwise, map the VTT parameter to `NULL'. */ 64038fd1498Szrj else 64138fd1498Szrj { 64238fd1498Szrj tree t 64338fd1498Szrj = fold_convert (TREE_TYPE (parm), null_pointer_node); 64438fd1498Szrj decl_map->put (parm, t); 64538fd1498Szrj } 64638fd1498Szrj } 64738fd1498Szrj /* Map other parameters to their equivalents in the cloned 64838fd1498Szrj function. */ 64938fd1498Szrj else 65038fd1498Szrj { 65138fd1498Szrj tree replacement; 65238fd1498Szrj if (clone_parm) 65338fd1498Szrj { 65438fd1498Szrj replacement = clone_parm; 65538fd1498Szrj clone_parm = DECL_CHAIN (clone_parm); 65638fd1498Szrj } 65738fd1498Szrj else 65838fd1498Szrj { 65938fd1498Szrj /* Inheriting ctors can omit parameters from the base 66038fd1498Szrj clone. Replace them with null lvalues. */ 66138fd1498Szrj tree reftype = build_reference_type (TREE_TYPE (parm)); 66238fd1498Szrj replacement = fold_convert (reftype, null_pointer_node); 66338fd1498Szrj replacement = convert_from_reference (replacement); 66438fd1498Szrj } 66538fd1498Szrj decl_map->put (parm, replacement); 66638fd1498Szrj } 66738fd1498Szrj } 66838fd1498Szrj 66938fd1498Szrj if (targetm.cxx.cdtor_returns_this ()) 67038fd1498Szrj { 67138fd1498Szrj parm = DECL_RESULT (fn); 67238fd1498Szrj clone_parm = DECL_RESULT (clone); 67338fd1498Szrj decl_map->put (parm, clone_parm); 67438fd1498Szrj } 67538fd1498Szrj 67638fd1498Szrj /* Clone the body. */ 67738fd1498Szrj clone_body (clone, fn, decl_map); 67838fd1498Szrj 67938fd1498Szrj /* Clean up. */ 68038fd1498Szrj delete decl_map; 68138fd1498Szrj } 68238fd1498Szrj 68338fd1498Szrj /* The clone can throw iff the original function can throw. */ 68438fd1498Szrj cp_function_chain->can_throw = !TREE_NOTHROW (fn); 68538fd1498Szrj 68638fd1498Szrj /* Now, expand this function into RTL, if appropriate. */ 68738fd1498Szrj finish_function (/*inline_p=*/false); 68838fd1498Szrj BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn); 68938fd1498Szrj if (alias) 69038fd1498Szrj { 69138fd1498Szrj if (expand_or_defer_fn_1 (clone)) 69238fd1498Szrj emit_associated_thunks (clone); 69338fd1498Szrj /* We didn't generate a body, so remove the empty one. */ 69438fd1498Szrj DECL_SAVED_TREE (clone) = NULL_TREE; 69538fd1498Szrj } 69638fd1498Szrj else 69738fd1498Szrj expand_or_defer_fn (clone); 69838fd1498Szrj first = false; 69938fd1498Szrj } 70038fd1498Szrj pop_from_top_level (); 70138fd1498Szrj 70238fd1498Szrj /* We don't need to process the original function any further. */ 70338fd1498Szrj return 1; 70438fd1498Szrj } 705