1/* Perform optimizations on tree structure.
2 Copyright (C) 1998-2024 Free Software Foundation, Inc.
3 Written by Mark Michell (mark@codesourcery.com).
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "target.h"
25#include "cp-tree.h"
26#include "stringpool.h"
27#include "cgraph.h"
28#include "debug.h"
29#include "tree-inline.h"
30#include "tree-iterator.h"
31#include "attribs.h"
32
33/* Prototypes. */
34
35static void update_cloned_parm (tree, tree, bool);
36
37/* CLONED_PARM is a copy of CLONE, generated for a cloned constructor
38 or destructor. Update it to ensure that the source-position for
39 the cloned parameter matches that for the original, and that the
40 debugging generation code will be able to find the original PARM. */
41
42static void
43update_cloned_parm (tree parm, tree cloned_parm, bool first)
44{
45 DECL_ABSTRACT_ORIGIN (cloned_parm) = parm;
46
47 /* We may have taken its address. */
48 TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm);
49
50 DECL_BY_REFERENCE (cloned_parm) = DECL_BY_REFERENCE (parm);
51
52 /* The definition might have different constness. */
53 TREE_READONLY (cloned_parm) = TREE_READONLY (parm);
54
55 TREE_USED (cloned_parm) = !first || TREE_USED (parm);
56
57 /* The name may have changed from the declaration. */
58 DECL_NAME (cloned_parm) = DECL_NAME (parm);
59 DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm);
60 TREE_TYPE (cloned_parm) = TREE_TYPE (parm);
61
62 DECL_NOT_GIMPLE_REG_P (cloned_parm) = DECL_NOT_GIMPLE_REG_P (parm);
63}
64
65/* Like copy_decl_no_change, but handle DECL_OMP_PRIVATIZED_MEMBER
66 properly. */
67
68static tree
69cxx_copy_decl (tree decl, copy_body_data *id)
70{
71 tree copy = copy_decl_no_change (decl, id);
72 if (VAR_P (decl)
73 && DECL_HAS_VALUE_EXPR_P (decl)
74 && DECL_ARTIFICIAL (decl)
75 && DECL_LANG_SPECIFIC (decl)
76 && DECL_OMP_PRIVATIZED_MEMBER (decl))
77 {
78 tree expr = DECL_VALUE_EXPR (copy);
79 walk_tree (&expr, copy_tree_body_r, id, NULL);
80 SET_DECL_VALUE_EXPR (copy, expr);
81 }
82 return copy;
83}
84
85/* FN is a function in High GIMPLE form that has a complete body and no
86 CFG. CLONE is a function whose body is to be set to a copy of FN,
87 mapping argument declarations according to the ARG_MAP splay_tree. */
88
89static void
90clone_body (tree clone, tree fn, void *arg_map)
91{
92 copy_body_data id;
93 tree stmts;
94
95 /* Clone the body, as if we were making an inline call. But, remap
96 the parameters in the callee to the parameters of caller. */
97 memset (s: &id, c: 0, n: sizeof (id));
98 id.src_fn = fn;
99 id.dst_fn = clone;
100 id.src_cfun = DECL_STRUCT_FUNCTION (fn);
101 id.decl_map = static_cast<hash_map<tree, tree> *> (arg_map);
102
103 id.copy_decl = cxx_copy_decl;
104 id.transform_call_graph_edges = CB_CGE_DUPLICATE;
105 id.transform_new_cfg = true;
106 id.transform_return_to_modify = false;
107
108 /* We're not inside any EH region. */
109 id.eh_lp_nr = 0;
110
111 stmts = DECL_SAVED_TREE (fn);
112 walk_tree (&stmts, copy_tree_body_r, &id, NULL);
113
114 /* Also remap the initializer of any static variables so that they (in
115 particular, any label addresses) correspond to the base variant rather
116 than the abstract one. */
117 if (DECL_NAME (clone) == base_dtor_identifier
118 || DECL_NAME (clone) == base_ctor_identifier)
119 {
120 unsigned ix;
121 tree decl;
122
123 FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (fn), ix, decl)
124 walk_tree (&DECL_INITIAL (decl), copy_tree_body_r, &id, NULL);
125 }
126
127 append_to_statement_list_force (stmts, &DECL_SAVED_TREE (clone));
128}
129
130/* DELETE_DTOR is a delete destructor whose body will be built.
131 COMPLETE_DTOR is the corresponding complete destructor. */
132
133static void
134build_delete_destructor_body (tree delete_dtor, tree complete_dtor)
135{
136 tree parm = DECL_ARGUMENTS (delete_dtor);
137 tree virtual_size = cxx_sizeof (current_class_type);
138
139 /* Call the delete function. */
140 tree call_delete = build_op_delete_call (DELETE_EXPR, current_class_ptr,
141 virtual_size,
142 /*global_p=*/false,
143 /*placement=*/NULL_TREE,
144 /*alloc_fn=*/NULL_TREE,
145 tf_warning_or_error);
146
147 tree op = get_callee_fndecl (call_delete);
148 if (op && DECL_P (op) && destroying_delete_p (op))
149 {
150 /* The destroying delete will handle calling complete_dtor. */
151 add_stmt (call_delete);
152 }
153 else
154 {
155 /* Call the corresponding complete destructor. */
156 gcc_assert (complete_dtor);
157 tree call_dtor = build_cxx_call (complete_dtor, 1, &parm,
158 tf_warning_or_error);
159
160 /* Operator delete must be called, whether or not the dtor throws. */
161 add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node,
162 call_dtor, call_delete));
163 }
164
165 /* Return the address of the object.
166 ??? How is it useful to return an invalid address? */
167 maybe_return_this ();
168}
169
170/* Return name of comdat group for complete and base ctor (or dtor)
171 that have the same body. If dtor is virtual, deleting dtor goes
172 into this comdat group as well. */
173
174static tree
175cdtor_comdat_group (tree complete, tree base)
176{
177 tree complete_name = DECL_ASSEMBLER_NAME (complete);
178 tree base_name = DECL_ASSEMBLER_NAME (base);
179 char *grp_name;
180 const char *p, *q;
181 bool diff_seen = false;
182 size_t idx;
183 gcc_assert (IDENTIFIER_LENGTH (complete_name)
184 == IDENTIFIER_LENGTH (base_name));
185 grp_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (complete_name) + 1);
186 p = IDENTIFIER_POINTER (complete_name);
187 q = IDENTIFIER_POINTER (base_name);
188 for (idx = 0; idx < IDENTIFIER_LENGTH (complete_name); idx++)
189 if (p[idx] == q[idx])
190 grp_name[idx] = p[idx];
191 else
192 {
193 gcc_assert (!diff_seen
194 && idx > 0
195 && (p[idx - 1] == 'C' || p[idx - 1] == 'D'
196 || p[idx - 1] == 'I')
197 && p[idx] == '1'
198 && q[idx] == '2');
199 grp_name[idx] = '5';
200 diff_seen = true;
201 }
202 grp_name[idx] = '\0';
203 gcc_assert (diff_seen);
204 return get_identifier (grp_name);
205}
206
207/* Returns true iff we can make the base and complete [cd]tor aliases of
208 the same symbol rather than separate functions. */
209
210static bool
211can_alias_cdtor (tree fn)
212{
213 /* If aliases aren't supported by the assembler, fail. */
214 if (!TARGET_SUPPORTS_ALIASES)
215 return false;
216
217 /* We can't use an alias if there are virtual bases. */
218 if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)))
219 return false;
220 gcc_assert (DECL_MAYBE_IN_CHARGE_CDTOR_P (fn));
221 /* Don't use aliases for weak/linkonce definitions unless we can put both
222 symbols in the same COMDAT group. */
223 return (DECL_INTERFACE_KNOWN (fn)
224 && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fn))
225 && (!DECL_ONE_ONLY (fn)
226 || (HAVE_COMDAT_GROUP && DECL_WEAK (fn))));
227}
228
229/* FN is a [cd]tor, fns is a pointer to an array of length 3. Fill fns
230 with pointers to the base, complete, and deleting variants. */
231
232static void
233populate_clone_array (tree fn, tree *fns)
234{
235 tree clone;
236
237 fns[0] = NULL_TREE;
238 fns[1] = NULL_TREE;
239 fns[2] = NULL_TREE;
240
241 FOR_EACH_CLONE (clone, fn)
242 if (DECL_NAME (clone) == complete_dtor_identifier
243 || DECL_NAME (clone) == complete_ctor_identifier)
244 fns[1] = clone;
245 else if (DECL_NAME (clone) == base_dtor_identifier
246 || DECL_NAME (clone) == base_ctor_identifier)
247 fns[0] = clone;
248 else if (DECL_NAME (clone) == deleting_dtor_identifier)
249 fns[2] = clone;
250 else
251 gcc_unreachable ();
252}
253
254/* FN is a constructor or destructor, and there are FUNCTION_DECLs
255 cloned from it nearby. Instead of cloning this body, leave it
256 alone and create tiny one-call bodies for the cloned
257 FUNCTION_DECLs. These clones are sibcall candidates, and their
258 resulting code will be very thunk-esque. */
259
260static bool
261maybe_thunk_body (tree fn, bool force)
262{
263 tree bind, block, call, clone, clone_result, fn_parm, fn_parm_typelist;
264 tree last_arg, modify, *args;
265 int parmno, vtt_parmno, max_parms;
266 tree fns[3];
267
268 if (!force && !flag_declone_ctor_dtor)
269 return 0;
270
271 /* If function accepts variable arguments, give up. */
272 last_arg = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fn)));
273 if (last_arg != void_list_node)
274 return 0;
275
276 /* If we got this far, we've decided to turn the clones into thunks. */
277
278 /* We're going to generate code for fn, so it is no longer "abstract."
279 Also make the unified ctor/dtor private to either the translation unit
280 (for non-vague linkage ctors) or the COMDAT group (otherwise). */
281
282 populate_clone_array (fn, fns);
283
284 /* Can happen during error recovery (c++/71464). */
285 if (!fns[0] || !fns[1])
286 return 0;
287
288 /* Don't use thunks if the base clone omits inherited parameters. */
289 if (ctor_omit_inherited_parms (fns[0]))
290 return 0;
291
292 DECL_ABSTRACT_P (fn) = false;
293 if (!DECL_WEAK (fn))
294 {
295 TREE_PUBLIC (fn) = false;
296 DECL_EXTERNAL (fn) = false;
297 DECL_INTERFACE_KNOWN (fn) = true;
298 }
299 else if (HAVE_COMDAT_GROUP)
300 {
301 /* At eof, defer creation of mangling aliases temporarily. */
302 bool save_defer_mangling_aliases = defer_mangling_aliases;
303 defer_mangling_aliases = true;
304 tree comdat_group = cdtor_comdat_group (complete: fns[1], base: fns[0]);
305 defer_mangling_aliases = save_defer_mangling_aliases;
306 cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group);
307 cgraph_node::get_create (fns[1])->add_to_same_comdat_group
308 (old_node: cgraph_node::get_create (fns[0]));
309 symtab_node::get (decl: fn)->add_to_same_comdat_group
310 (old_node: symtab_node::get (decl: fns[0]));
311 if (fns[2])
312 /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
313 virtual, it goes into the same comdat group as well. */
314 cgraph_node::get_create (fns[2])->add_to_same_comdat_group
315 (old_node: symtab_node::get (decl: fns[0]));
316 /* Emit them now that the thunks are same comdat group aliases. */
317 if (!save_defer_mangling_aliases)
318 generate_mangling_aliases ();
319 TREE_PUBLIC (fn) = false;
320 DECL_EXTERNAL (fn) = false;
321 DECL_INTERFACE_KNOWN (fn) = true;
322 /* function_and_variable_visibility doesn't want !PUBLIC decls to
323 have these flags set. */
324 DECL_WEAK (fn) = false;
325 DECL_COMDAT (fn) = false;
326 }
327
328 /* Find the vtt_parm, if present. */
329 for (vtt_parmno = -1, parmno = 0, fn_parm = DECL_ARGUMENTS (fn);
330 fn_parm;
331 ++parmno, fn_parm = TREE_CHAIN (fn_parm))
332 {
333 if (DECL_ARTIFICIAL (fn_parm)
334 && DECL_NAME (fn_parm) == vtt_parm_identifier)
335 {
336 /* Compensate for removed in_charge parameter. */
337 vtt_parmno = parmno;
338 break;
339 }
340 }
341
342 /* Allocate an argument buffer for build_cxx_call().
343 Make sure it is large enough for any of the clones. */
344 max_parms = 0;
345 FOR_EACH_CLONE (clone, fn)
346 {
347 int length = list_length (DECL_ARGUMENTS (fn));
348 if (length > max_parms)
349 max_parms = length;
350 }
351 args = XALLOCAVEC (tree, max_parms);
352
353 /* We know that any clones immediately follow FN in TYPE_FIELDS. */
354 FOR_EACH_CLONE (clone, fn)
355 {
356 tree clone_parm;
357
358 /* If we've already generated a body for this clone, avoid
359 duplicating it. (Is it possible for a clone-list to grow after we
360 first see it?) */
361 if (DECL_SAVED_TREE (clone) || TREE_ASM_WRITTEN (clone))
362 continue;
363
364 /* Start processing the function. */
365 start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
366
367 if (clone == fns[2])
368 {
369 for (clone_parm = DECL_ARGUMENTS (clone); clone_parm;
370 clone_parm = TREE_CHAIN (clone_parm))
371 DECL_ABSTRACT_ORIGIN (clone_parm) = NULL_TREE;
372 /* Build the delete destructor by calling complete destructor and
373 delete function. */
374 build_delete_destructor_body (delete_dtor: clone, complete_dtor: fns[1]);
375 }
376 else
377 {
378 /* Walk parameter lists together, creating parameter list for
379 call to original function. */
380 for (parmno = 0,
381 fn_parm = DECL_ARGUMENTS (fn),
382 fn_parm_typelist = TYPE_ARG_TYPES (TREE_TYPE (fn)),
383 clone_parm = DECL_ARGUMENTS (clone);
384 fn_parm;
385 ++parmno,
386 fn_parm = TREE_CHAIN (fn_parm))
387 {
388 if (parmno == vtt_parmno && ! DECL_HAS_VTT_PARM_P (clone))
389 {
390 gcc_assert (fn_parm_typelist);
391 /* Clobber argument with formal parameter type. */
392 args[parmno]
393 = convert (TREE_VALUE (fn_parm_typelist),
394 null_pointer_node);
395 }
396 else if (parmno == 1 && DECL_HAS_IN_CHARGE_PARM_P (fn))
397 {
398 tree in_charge
399 = copy_node (in_charge_arg_for_name (DECL_NAME (clone)));
400 args[parmno] = in_charge;
401 }
402 /* Map other parameters to their equivalents in the cloned
403 function. */
404 else
405 {
406 gcc_assert (clone_parm);
407 DECL_ABSTRACT_ORIGIN (clone_parm) = NULL;
408 args[parmno] = clone_parm;
409 /* Clear TREE_ADDRESSABLE on thunk arguments. */
410 TREE_ADDRESSABLE (clone_parm) = 0;
411 clone_parm = TREE_CHAIN (clone_parm);
412 }
413 if (fn_parm_typelist)
414 fn_parm_typelist = TREE_CHAIN (fn_parm_typelist);
415 }
416
417 /* We built this list backwards; fix now. */
418 mark_used (fn);
419 call = build_cxx_call (fn, parmno, args, tf_warning_or_error);
420 /* Arguments passed to the thunk by invisible reference should
421 be transmitted to the callee unchanged. Do not create a
422 temporary and invoke the copy constructor. The thunking
423 transformation must not introduce any constructor calls. */
424 CALL_FROM_THUNK_P (call) = 1;
425 block = make_node (BLOCK);
426 if (targetm.cxx.cdtor_returns_this ())
427 {
428 clone_result = DECL_RESULT (clone);
429 modify = build2 (MODIFY_EXPR, TREE_TYPE (clone_result),
430 clone_result, call);
431 modify = build1 (RETURN_EXPR, void_type_node, modify);
432 add_stmt (modify);
433 }
434 else
435 {
436 add_stmt (call);
437 }
438 bind = c_build_bind_expr (DECL_SOURCE_LOCATION (clone),
439 block, cur_stmt_list);
440 DECL_SAVED_TREE (clone) = push_stmt_list ();
441 add_stmt (bind);
442 }
443
444 DECL_ABSTRACT_ORIGIN (clone) = NULL;
445 expand_or_defer_fn (finish_function (/*inline_p=*/false));
446 }
447 return 1;
448}
449
450/* Copy most attributes from ATTRS, omitting attributes that can really only
451 apply to a single decl. */
452
453tree
454clone_attrs (tree attrs)
455{
456 tree new_attrs = NULL_TREE;
457 tree *p = &new_attrs;
458
459 for (tree a = attrs; a; a = TREE_CHAIN (a))
460 {
461 tree aname = get_attribute_name (a);
462 if (is_attribute_namespace_p (attr_ns: "", attr: a)
463 && (is_attribute_p (attr_name: "alias", ident: aname)
464 || is_attribute_p (attr_name: "ifunc", ident: aname)))
465 continue;
466 *p = copy_node (a);
467 p = &TREE_CHAIN (*p);
468 }
469 *p = NULL_TREE;
470 return new_attrs;
471}
472
473/* FN is a function that has a complete body. Clone the body as
474 necessary. Returns nonzero if there's no longer any need to
475 process the main body. */
476
477bool
478maybe_clone_body (tree fn)
479{
480 tree comdat_group = NULL_TREE;
481 tree clone;
482 tree fns[3];
483 bool first = true;
484 int idx;
485 bool need_alias = false;
486
487 /* We only clone constructors and destructors. */
488 if (!DECL_MAYBE_IN_CHARGE_CDTOR_P (fn))
489 return 0;
490
491 populate_clone_array (fn, fns);
492
493 /* Remember if we can't have multiple clones for some reason. We need to
494 check this before we remap local static initializers in clone_body. */
495 if (!tree_versionable_function_p (fn))
496 need_alias = true;
497
498 /* We know that any clones immediately follow FN in the TYPE_FIELDS
499 list. */
500 push_to_top_level ();
501 for (idx = 0; idx < 3; idx++)
502 {
503 tree parm;
504 tree clone_parm;
505
506 clone = fns[idx];
507 if (!clone)
508 continue;
509
510 /* Update CLONE's source position information to match FN's. */
511 DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
512 DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
513 DECL_DECLARED_CONSTEXPR_P (clone) = DECL_DECLARED_CONSTEXPR_P (fn);
514 DECL_COMDAT (clone) = DECL_COMDAT (fn);
515 DECL_WEAK (clone) = DECL_WEAK (fn);
516
517 /* We don't copy the comdat group from fn to clone because the assembler
518 name of fn was corrupted by write_mangled_name by adding *INTERNAL*
519 to it. By doing so, it also corrupted the comdat group. */
520 if (DECL_ONE_ONLY (fn))
521 cgraph_node::get_create (clone)->set_comdat_group (cxx_comdat_group (clone));
522 DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
523 DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
524 DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
525 DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
526 TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
527 DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn);
528 DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn);
529 DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn);
530 DECL_ATTRIBUTES (clone) = clone_attrs (DECL_ATTRIBUTES (fn));
531 DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn);
532 set_decl_section_name (clone, fn);
533
534 /* Adjust the parameter names and locations. */
535 parm = DECL_ARGUMENTS (fn);
536 clone_parm = DECL_ARGUMENTS (clone);
537 /* Update the `this' parameter, which is always first. */
538 update_cloned_parm (parm, cloned_parm: clone_parm, first);
539 parm = DECL_CHAIN (parm);
540 clone_parm = DECL_CHAIN (clone_parm);
541 if (DECL_HAS_IN_CHARGE_PARM_P (fn))
542 parm = DECL_CHAIN (parm);
543 if (DECL_HAS_VTT_PARM_P (fn))
544 parm = DECL_CHAIN (parm);
545 if (DECL_HAS_VTT_PARM_P (clone))
546 clone_parm = DECL_CHAIN (clone_parm);
547 for (; parm && clone_parm;
548 parm = DECL_CHAIN (parm), clone_parm = DECL_CHAIN (clone_parm))
549 /* Update this parameter. */
550 update_cloned_parm (parm, cloned_parm: clone_parm, first);
551 }
552
553 bool can_alias = can_alias_cdtor (fn);
554
555 /* If we decide to turn clones into thunks, they will branch to fn.
556 Must have original function available to call. */
557 if (!can_alias && maybe_thunk_body (fn, force: need_alias))
558 {
559 pop_from_top_level ();
560 /* We still need to emit the original function. */
561 return 0;
562 }
563
564 /* Emit the DWARF1 abstract instance. */
565 (*debug_hooks->deferred_inline_function) (fn);
566
567 /* We know that any clones immediately follow FN in the TYPE_FIELDS. */
568 for (idx = 0; idx < 3; idx++)
569 {
570 tree parm;
571 tree clone_parm;
572 int parmno;
573 hash_map<tree, tree> *decl_map;
574 bool alias = false;
575
576 clone = fns[idx];
577 if (!clone)
578 continue;
579
580 /* Start processing the function. */
581 start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
582
583 /* Tell cgraph if both ctors or both dtors are known to have
584 the same body. */
585 if (can_alias
586 && fns[0]
587 && idx == 1
588 && cgraph_node::get_create (fns[0])->create_same_body_alias
589 (alias: clone, decl: fns[0]))
590 {
591 alias = true;
592 if (DECL_ONE_ONLY (fns[0]))
593 {
594 /* For comdat base and complete cdtors put them
595 into the same, *[CD]5* comdat group instead of
596 *[CD][12]*. */
597 comdat_group = cdtor_comdat_group (complete: fns[1], base: fns[0]);
598 cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group);
599 if (symtab_node::get (decl: clone)->same_comdat_group)
600 symtab_node::get (decl: clone)->remove_from_same_comdat_group ();
601 symtab_node::get (decl: clone)->add_to_same_comdat_group
602 (old_node: symtab_node::get (decl: fns[0]));
603 }
604 }
605
606 /* Build the delete destructor by calling complete destructor
607 and delete function. */
608 if (idx == 2)
609 {
610 build_delete_destructor_body (delete_dtor: clone, complete_dtor: fns[1]);
611 /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
612 virtual, it goes into the same comdat group as well. */
613 if (comdat_group)
614 cgraph_node::get_create (clone)->add_to_same_comdat_group
615 (old_node: symtab_node::get (decl: fns[0]));
616 }
617 else if (alias)
618 /* No need to populate body. */ ;
619 else
620 {
621 /* If we can't have multiple copies of FN (say, because there's a
622 static local initialized with the address of a label), we need
623 to use an alias for the complete variant. */
624 if (idx == 1 && need_alias)
625 {
626 if (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_set)
627 sorry (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_reason, fn);
628 else
629 sorry ("making multiple clones of %qD", fn);
630 }
631
632 /* Remap the parameters. */
633 decl_map = new hash_map<tree, tree>;
634 for (parmno = 0,
635 parm = DECL_ARGUMENTS (fn),
636 clone_parm = DECL_ARGUMENTS (clone);
637 parm;
638 ++parmno,
639 parm = DECL_CHAIN (parm))
640 {
641 /* Map the in-charge parameter to an appropriate constant. */
642 if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
643 {
644 tree in_charge;
645 in_charge = in_charge_arg_for_name (DECL_NAME (clone));
646 decl_map->put (k: parm, v: in_charge);
647 }
648 else if (DECL_ARTIFICIAL (parm)
649 && DECL_NAME (parm) == vtt_parm_identifier)
650 {
651 /* For a subobject constructor or destructor, the next
652 argument is the VTT parameter. Remap the VTT_PARM
653 from the CLONE to this parameter. */
654 if (DECL_HAS_VTT_PARM_P (clone))
655 {
656 DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
657 decl_map->put (k: parm, v: clone_parm);
658 clone_parm = DECL_CHAIN (clone_parm);
659 }
660 /* Otherwise, map the VTT parameter to `NULL'. */
661 else
662 {
663 tree t
664 = fold_convert (TREE_TYPE (parm), null_pointer_node);
665 decl_map->put (k: parm, v: t);
666 }
667 }
668 /* Map other parameters to their equivalents in the cloned
669 function. */
670 else
671 {
672 tree replacement;
673 if (clone_parm)
674 {
675 replacement = clone_parm;
676 clone_parm = DECL_CHAIN (clone_parm);
677 }
678 else
679 {
680 /* Inheriting ctors can omit parameters from the base
681 clone. Replace them with null lvalues. */
682 tree reftype = build_reference_type (TREE_TYPE (parm));
683 replacement = fold_convert (reftype, null_pointer_node);
684 replacement = convert_from_reference (replacement);
685 }
686 decl_map->put (k: parm, v: replacement);
687 }
688 }
689
690 if (targetm.cxx.cdtor_returns_this ())
691 {
692 parm = DECL_RESULT (fn);
693 clone_parm = DECL_RESULT (clone);
694 decl_map->put (k: parm, v: clone_parm);
695 }
696
697 /* Clone the body. */
698 clone_body (clone, fn, arg_map: decl_map);
699
700 /* Clean up. */
701 delete decl_map;
702 }
703
704 /* The clone can throw iff the original function can throw. */
705 cp_function_chain->can_throw = !TREE_NOTHROW (fn);
706
707 /* Now, expand this function into RTL, if appropriate. */
708 finish_function (/*inline_p=*/false);
709 BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
710 if (alias)
711 {
712 if (expand_or_defer_fn_1 (clone))
713 emit_associated_thunks (clone);
714 /* We didn't generate a body, so remove the empty one. */
715 DECL_SAVED_TREE (clone) = NULL_TREE;
716 }
717 else
718 expand_or_defer_fn (clone);
719 first = false;
720 }
721 pop_from_top_level ();
722
723 /* We don't need to process the original function any further. */
724 return 1;
725}
726

source code of gcc/cp/optimize.cc