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
update_cloned_parm(tree parm,tree cloned_parm,bool first)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
cxx_copy_decl(tree decl,copy_body_data * id)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
clone_body(tree clone,tree fn,void * arg_map)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
build_delete_destructor_body(tree delete_dtor,tree complete_dtor)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
cdtor_comdat_group(tree complete,tree base)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
can_alias_cdtor(tree fn)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
populate_clone_array(tree fn,tree * fns)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
maybe_thunk_body(tree fn,bool force)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
maybe_clone_body(tree fn)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