aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/decl.cc
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2021-03-14 22:51:56 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2021-04-05 13:40:36 +0200
commit76a7e7e706ac4c01cead3c6514322aaad88f9a63 (patch)
treeb373e3d40f0e988db5f8e5de72b5c91a7e3d0508 /gcc/d/decl.cc
parent3cb9e3aee98a206b786d7414ad28e67fbcceba5c (diff)
downloadgcc-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.cc92
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);
}