1 | /* Perform optimizations on tree structure. |
2 | Copyright (C) 1998-2024 Free Software Foundation, Inc. |
3 | Written by Mark Michell (mark@codesourcery.com). |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it |
8 | under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 3, or (at your option) |
10 | any later version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along 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 | |
35 | static 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 | |
42 | static void |
43 | update_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 | |
68 | static tree |
69 | cxx_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 | |
89 | static void |
90 | clone_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 | |
133 | static void |
134 | build_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 | |
174 | static tree |
175 | cdtor_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 | |
210 | static bool |
211 | can_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 | |
232 | static void |
233 | populate_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 | |
260 | static bool |
261 | maybe_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 | |
453 | tree |
454 | clone_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 | |
477 | bool |
478 | maybe_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 | |