#include "input.h"
#include "integrate.h"
#include "toplev.h"
-#include "varray.h"
#include "params.h"
#include "hashtab.h"
#include "target.h"
stmts = DECL_SAVED_TREE (fn);
walk_tree (&stmts, copy_tree_body_r, &id, NULL);
+
+ /* Also remap the initializer of any static variables so that they (in
+ particular, any label addresses) correspond to the base variant rather
+ than the abstract one. */
+ if (DECL_NAME (clone) == base_dtor_identifier
+ || DECL_NAME (clone) == base_ctor_identifier)
+ {
+ tree decls = DECL_STRUCT_FUNCTION (fn)->local_decls;
+ for (; decls; decls = TREE_CHAIN (decls))
+ {
+ tree decl = TREE_VALUE (decls);
+ walk_tree (&DECL_INITIAL (decl), copy_tree_body_r, &id, NULL);
+ }
+ }
+
append_to_statement_list_force (stmts, &DECL_SAVED_TREE (clone));
}
bool first = true;
bool in_charge_parm_used;
int idx;
+ bool need_alias = false;
/* We only clone constructors and destructors. */
if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
else
gcc_unreachable ();
+ /* Remember if we can't have multiple clones for some reason. We need to
+ check this before we remap local static initializers in clone_body. */
+ if (!tree_versionable_function_p (fn))
+ need_alias = true;
+
/* We know that any clones immediately follow FN in the TYPE_METHODS
list. */
push_to_top_level ();
&& (SUPPORTS_ONE_ONLY || !DECL_WEAK (fns[0]))
&& (!DECL_ONE_ONLY (fns[0])
|| (HAVE_COMDAT_GROUP
- && DECL_WEAK (fns[0])
- /* Don't optimize synthetized virtual dtors, because then
- the deleting and other dtors are emitted when needed
- and so it is not certain we would emit both
- deleting and complete/base dtors in the comdat group. */
- && (fns[2] == NULL || !DECL_ARTIFICIAL (fn))))
+ && DECL_WEAK (fns[0])))
&& cgraph_same_body_alias (clone, fns[0]))
{
alias = true;
/* No need to populate body. */ ;
else
{
+ /* If we can't have multiple copies of FN (say, because there's a
+ static local initialized with the address of a label), we need
+ to use an alias for the complete variant. */
+ if (idx == 1 && need_alias)
+ {
+ if (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_set)
+ sorry (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_reason, fn);
+ else
+ sorry ("making multiple clones of %qD", fn);
+ }
+
/* Remap the parameters. */
decl_map = pointer_map_create ();
for (parmno = 0,
{
DECL_COMDAT_GROUP (fns[1]) = comdat_group;
if (fns[2])
- /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
- virtual, it goes into the same comdat group as well. */
- DECL_COMDAT_GROUP (fns[2]) = comdat_group;
+ {
+ struct cgraph_node *base_dtor_node, *deleting_dtor_node;
+ /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
+ virtual, it goes into the same comdat group as well. */
+ DECL_COMDAT_GROUP (fns[2]) = comdat_group;
+ base_dtor_node = cgraph_node (fns[0]);
+ deleting_dtor_node = cgraph_node (fns[2]);
+ gcc_assert (base_dtor_node->same_comdat_group == NULL);
+ gcc_assert (deleting_dtor_node->same_comdat_group == NULL);
+ base_dtor_node->same_comdat_group = deleting_dtor_node;
+ deleting_dtor_node->same_comdat_group = base_dtor_node;
+ }
}
/* We don't need to process the original function any further. */