diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-03-14 22:51:56 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-04-05 13:40:36 +0200 |
commit | 76a7e7e706ac4c01cead3c6514322aaad88f9a63 (patch) | |
tree | b373e3d40f0e988db5f8e5de72b5c91a7e3d0508 /gcc/d/decl.cc | |
parent | 3cb9e3aee98a206b786d7414ad28e67fbcceba5c (diff) | |
download | gcc-76a7e7e706ac4c01cead3c6514322aaad88f9a63.zip gcc-76a7e7e706ac4c01cead3c6514322aaad88f9a63.tar.gz gcc-76a7e7e706ac4c01cead3c6514322aaad88f9a63.tar.bz2 |
d: Use weak linkage for template symbols instead of gnu.linkonce (PR99914)
The default linkage of templates in the D language is now DECL_WEAK
instead of DECL_ONE_ONLY, if supported. This better matches the
expected override semantics of template symbols compiled to object code.
For example:
module rt.config;
template rt_flag()
{
pragma(mangle, "rt_flag") __gshared bool rt_flag = true;
}
module main;
extern(C) __gshared bool rt_flag = false;
The above currently does not succeed in linking due to there being
multiple definitions of `rt_flag' in different sections that aren't
considered mergeable.
The compiler flag enabling toggling of this has been given a clearer
named `-fweak-templates', which distinguishes itself from G++ `-fweak',
which is intended only for testing.
gcc/d/ChangeLog:
PR d/99914
* d-lang.cc (d_init): Disable flag_weak_templates if no support for
weak or one-only symbols.
* d-tree.h (VAR_OR_FUNCTION_DECL_CHECK): New macro.
(DECL_INSTANTIATED): New macro.
(d_comdat_linkage): Remove declaration.
(d_linkonce_linkage): Remove declaration.
(set_linkage_for_decl): New declaration.
* decl.cc (DeclVisitor::visit (StructDeclaration *)): Replace call to
d_linkonce_linkage with setting DECL_INSTANTIATED.
(DeclVisitor::visit (ClassDeclaration *)): Likewise.
(DeclVisitor::visit (EnumDeclaration *)): Likewise.
(DeclVisitor::visit (InterfaceDeclaration *)): Remove call to
d_linkonce_linkage.
(get_symbol_decl): Call set_linkage_for_decl instead of
d_linkonce_linkage.
(d_finish_decl): Call set_linkage_for_decl.
(d_comdat_linkage): Made function static. Only set DECL_COMDAT for
DECL_INSTANTIATED decls.
(d_linkonce_linkage): Remove function.
(d_weak_linkage): New function.
(set_linkage_for_decl): New function.
* gdc.texi (Runtime Options): Rename -fno-weak to -fno-weak-templates,
update documentation of option.
* lang.opt (fweak): Rename option to ...
(fweak-templates): ... this. Update help string.
* modules.cc (get_internal_fn): Add Prot parameter. Set generated
function flag.
(build_internal_fn): Update call to get_internal_fn.
(build_dso_cdtor_fn): Likewise.
(register_moduleinfo): Call d_finish_decl on dso_slot_node and
dso_initialized_node.
* typeinfo.cc (TypeInfoVisitor::internal_reference): Call
set_linkage_for_decl instead of d_comdat_linkage.
(TypeInfoDeclVisitor::visit (TypeInfoDeclaration *)): Remove calls to
d_linkonce_linkage and d_comdat_linkage.
(get_cpp_typeinfo_decl): Likewise.
gcc/testsuite/ChangeLog:
PR d/99914
* gdc.dg/pr99914.d: New test.
Diffstat (limited to 'gcc/d/decl.cc')
-rw-r--r-- | gcc/d/decl.cc | 92 |
1 files changed, 57 insertions, 35 deletions
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 0ec1934..a59f00d 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -387,10 +387,7 @@ public: /* Generate static initializer. */ d->sinit = aggregate_initializer_decl (d); DECL_INITIAL (d->sinit) = layout_struct_initializer (d); - - if (d->isInstantiated ()) - d_linkonce_linkage (d->sinit); - + DECL_INSTANTIATED (d->sinit) = (d->isInstantiated () != NULL); d_finish_decl (d->sinit); /* Put out the members. There might be static constructors in the members @@ -503,7 +500,7 @@ public: /* Generate static initializer. */ DECL_INITIAL (d->sinit) = layout_class_initializer (d); - d_linkonce_linkage (d->sinit); + DECL_INSTANTIATED (d->sinit) = (d->isInstantiated () != NULL); d_finish_decl (d->sinit); /* Put out the TypeInfo. */ @@ -511,7 +508,6 @@ public: create_typeinfo (d->type, NULL); DECL_INITIAL (d->csym) = layout_classinfo (d); - d_linkonce_linkage (d->csym); d_finish_decl (d->csym); /* Put out the vtbl[]. */ @@ -534,7 +530,6 @@ public: DECL_INITIAL (d->vtblsym) = build_constructor (TREE_TYPE (d->vtblsym), elms); - d_comdat_linkage (d->vtblsym); d_finish_decl (d->vtblsym); /* Add this decl to the current binding level. */ @@ -578,7 +573,6 @@ public: } DECL_INITIAL (d->csym) = layout_classinfo (d); - d_linkonce_linkage (d->csym); d_finish_decl (d->csym); /* Add this decl to the current binding level. */ @@ -617,10 +611,7 @@ public: /* Generate static initializer. */ d->sinit = enum_initializer_decl (d); DECL_INITIAL (d->sinit) = build_expr (tc->sym->defaultval, true); - - if (d->isInstantiated ()) - d_linkonce_linkage (d->sinit); - + DECL_INSTANTIATED (d->sinit) = (d->isInstantiated () != NULL); d_finish_decl (d->sinit); } @@ -1257,22 +1248,22 @@ get_symbol_decl (Declaration *decl) DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1; } + /* Mark compiler generated functions as artificial. */ + if (fd->generated) + DECL_ARTIFICIAL (decl->csym) = 1; + /* Vector array operations are always compiler generated. */ if (fd->isArrayOp) { - TREE_PUBLIC (decl->csym) = 1; DECL_ARTIFICIAL (decl->csym) = 1; DECL_DECLARED_INLINE_P (decl->csym) = 1; - d_comdat_linkage (decl->csym); } - /* And so are ensure and require contracts. */ + /* Ensure and require contracts are lexically nested in the function they + part of, but are always publicly callable. */ if (fd->ident == Identifier::idPool ("ensure") || fd->ident == Identifier::idPool ("require")) - { - DECL_ARTIFICIAL (decl->csym) = 1; - TREE_PUBLIC (decl->csym) = 1; - } + TREE_PUBLIC (decl->csym) = 1; if (decl->storage_class & STCfinal) DECL_FINAL_P (decl->csym) = 1; @@ -1336,8 +1327,8 @@ get_symbol_decl (Declaration *decl) /* The decl has not been defined -- yet. */ DECL_EXTERNAL (decl->csym) = 1; - if (decl->isInstantiated ()) - d_linkonce_linkage (decl->csym); + DECL_INSTANTIATED (decl->csym) = (decl->isInstantiated () != NULL); + set_linkage_for_decl (decl->csym); } /* Symbol is going in thread local storage. */ @@ -1545,6 +1536,7 @@ d_finish_decl (tree decl) set_decl_tls_model (decl, decl_default_tls_model (decl)); relayout_decl (decl); + set_linkage_for_decl (decl); if (flag_checking && DECL_INITIAL (decl)) { @@ -2327,12 +2319,15 @@ d_comdat_group (tree decl) /* Set DECL up to have the closest approximation of "initialized common" linkage available. */ -void +static void d_comdat_linkage (tree decl) { - if (flag_weak) + /* COMDAT definitions have to be public. */ + gcc_assert (TREE_PUBLIC (decl)); + + if (supports_one_only ()) make_decl_one_only (decl, d_comdat_group (decl)); - else if (TREE_CODE (decl) == FUNCTION_DECL + else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INSTANTIATED (decl)) || (VAR_P (decl) && DECL_ARTIFICIAL (decl))) /* We can just emit function and compiler-generated variables statically; having multiple copies is (for the most part) only a waste of space. */ @@ -2342,26 +2337,53 @@ d_comdat_linkage (tree decl) /* Fallback, cannot have multiple copies. */ DECL_COMMON (decl) = 1; - if (TREE_PUBLIC (decl)) + if (TREE_PUBLIC (decl) && DECL_INSTANTIATED (decl)) DECL_COMDAT (decl) = 1; } -/* Set DECL up to have the closest approximation of "linkonce" linkage. */ +/* Set DECL up to have the closest approximation of "weak" linkage. */ -void -d_linkonce_linkage (tree decl) +static void +d_weak_linkage (tree decl) { /* Weak definitions have to be public. */ + gcc_assert (TREE_PUBLIC (decl)); + + /* Allow comdat linkage to be forced with the flag `-fno-weak-templates'. */ + if (!flag_weak_templates || !TARGET_SUPPORTS_WEAK) + return d_comdat_linkage (decl); + + declare_weak (decl); +} + +/* DECL is a FUNCTION_DECL or a VAR_DECL with static storage. Set flags to + reflect the linkage that DECL will receive in the object file. */ + +void +set_linkage_for_decl (tree decl) +{ + gcc_assert (VAR_OR_FUNCTION_DECL_P (decl) && TREE_STATIC (decl)); + + /* Non-public decls keep their internal linkage. */ if (!TREE_PUBLIC (decl)) return; - /* Necessary to allow DECL_ONE_ONLY or DECL_WEAK functions to be inlined. */ - if (TREE_CODE (decl) == FUNCTION_DECL) - DECL_DECLARED_INLINE_P (decl) = 1; + /* Don't need to give private or protected symbols a special linkage. */ + if ((TREE_PRIVATE (decl) || TREE_PROTECTED (decl)) + && !DECL_INSTANTIATED (decl)) + return; + + /* Functions declared as `pragma(inline, true)' can appear in multiple + translation units. */ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)) + return d_comdat_linkage (decl); - /* No weak support, fallback to COMDAT linkage. */ - if (!flag_weak) - return d_comdat_linkage (decl); + /* Instantiated variables and functions need to be overridable by any other + symbol with the same name, so give them weak linkage. */ + if (DECL_INSTANTIATED (decl)) + return d_weak_linkage (decl); - make_decl_one_only (decl, d_comdat_group (decl)); + /* Compiler generated public symbols can appear in multiple contexts. */ + if (DECL_ARTIFICIAL (decl)) + return d_weak_linkage (decl); } |