aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/module.cc')
-rw-r--r--gcc/cp/module.cc136
1 files changed, 127 insertions, 9 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index beceafe..214fb91 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -3012,6 +3012,7 @@ public:
bool read_definition (tree decl);
private:
+ void check_abi_tags (tree existing, tree decl, tree &eattr, tree &dattr);
bool is_matching_decl (tree existing, tree decl, bool is_typedef);
static bool install_implicit_member (tree decl);
bool read_function_def (tree decl, tree maybe_template);
@@ -5541,6 +5542,50 @@ trees_in::start (unsigned code)
return t;
}
+/* The kinds of interface an importer could have for a decl. */
+
+enum class importer_interface {
+ unknown, /* The definition may or may not need to be emitted. */
+ always_import, /* The definition can always be found in another TU. */
+ always_emit, /* The definition must be emitted in the importer's TU. */
+};
+
+/* Returns what kind of interface an importer will have of DECL. */
+
+static importer_interface
+get_importer_interface (tree decl)
+{
+ /* Internal linkage entities must be emitted in each importer if
+ there is a definition available. */
+ if (!TREE_PUBLIC (decl))
+ return importer_interface::always_emit;
+
+ /* Entities that aren't vague linkage are either not definitions or
+ will be emitted in this TU, so importers can just refer to an
+ external definition. */
+ if (!vague_linkage_p (decl))
+ return importer_interface::always_import;
+
+ /* For explicit instantiations, importers can always rely on there
+ being a definition in another TU, unless this is a definition
+ in a header module: in which case the importer will always need
+ to emit it. */
+ if (DECL_LANG_SPECIFIC (decl)
+ && DECL_EXPLICIT_INSTANTIATION (decl))
+ return (header_module_p () && !DECL_EXTERNAL (decl)
+ ? importer_interface::always_emit
+ : importer_interface::always_import);
+
+ /* A gnu_inline function is never emitted in any TU. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_DECLARED_INLINE_P (decl)
+ && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)))
+ return importer_interface::always_import;
+
+ /* Everything else has vague linkage. */
+ return importer_interface::unknown;
+}
+
/* The structure streamers access the raw fields, because the
alternative, of using the accessor macros can require using
different accessors for the same underlying field, depending on the
@@ -5660,7 +5705,8 @@ trees_out::core_bools (tree t, bits_out& bits)
we need to import or export any vague-linkage entities on
stream-in. */
bool interface_known = t->decl_common.lang_flag_5;
- if (interface_known && vague_linkage_p (t))
+ if (interface_known
+ && get_importer_interface (t) == importer_interface::unknown)
interface_known = false;
WB (interface_known);
}
@@ -5694,8 +5740,8 @@ trees_out::core_bools (tree t, bits_out& bits)
is_external = true;
gcc_fallthrough ();
case FUNCTION_DECL:
- if (TREE_PUBLIC (t)
- && !vague_linkage_p (t))
+ if (get_importer_interface (t)
+ == importer_interface::always_import)
is_external = true;
break;
}
@@ -8787,8 +8833,11 @@ trees_in::decl_value ()
tree etype = TREE_TYPE (existing);
/* Handle separate declarations with different attributes. */
+ tree &dattr = TYPE_ATTRIBUTES (type);
tree &eattr = TYPE_ATTRIBUTES (etype);
- eattr = merge_attributes (eattr, TYPE_ATTRIBUTES (type));
+ check_abi_tags (existing, decl, eattr, dattr);
+ // TODO: handle other conflicting type attributes
+ eattr = merge_attributes (eattr, dattr);
/* When merging a partial specialisation, the existing decl may have
had its TYPE_CANONICAL adjusted. If so we should use structural
@@ -11966,6 +12015,51 @@ trees_in::binfo_mergeable (tree *type)
return u ();
}
+/* DECL is a just streamed declaration with attributes DATTR that should
+ have matching ABI tags as EXISTING's attributes EATTR. Check that the
+ ABI tags match, and report an error if not. */
+
+void
+trees_in::check_abi_tags (tree existing, tree decl, tree &eattr, tree &dattr)
+{
+ tree etags = lookup_attribute ("abi_tag", eattr);
+ tree dtags = lookup_attribute ("abi_tag", dattr);
+ if ((etags == nullptr) != (dtags == nullptr)
+ || (etags && !attribute_value_equal (etags, dtags)))
+ {
+ if (etags)
+ etags = TREE_VALUE (etags);
+ if (dtags)
+ dtags = TREE_VALUE (dtags);
+
+ /* We only error if mangling wouldn't consider the tags equivalent. */
+ if (!equal_abi_tags (etags, dtags))
+ {
+ auto_diagnostic_group d;
+ if (dtags)
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "mismatching abi tags for %qD with tags %qE",
+ decl, dtags);
+ else
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "mismatching abi tags for %qD with no tags", decl);
+ if (etags)
+ inform (DECL_SOURCE_LOCATION (existing),
+ "existing declaration here with tags %qE", etags);
+ else
+ inform (DECL_SOURCE_LOCATION (existing),
+ "existing declaration here with no tags");
+ }
+
+ /* Always use the existing abi_tags as the canonical set so that
+ later processing doesn't get confused. */
+ if (dtags)
+ dattr = remove_attribute ("abi_tag", dattr);
+ if (etags)
+ duplicate_one_attribute (&dattr, eattr, "abi_tag");
+ }
+}
+
/* DECL is a just streamed mergeable decl that should match EXISTING. Check
it does and issue an appropriate diagnostic if not. Merge any
bits from DECL to EXISTING. This is stricter matching than
@@ -12159,10 +12253,28 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
if (TREE_CODE (d_inner) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (d_inner))
- DECL_DECLARED_INLINE_P (e_inner) = true;
+ {
+ DECL_DECLARED_INLINE_P (e_inner) = true;
+ if (!DECL_SAVED_TREE (e_inner)
+ && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (d_inner))
+ && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (e_inner)))
+ {
+ DECL_INTERFACE_KNOWN (e_inner)
+ |= DECL_INTERFACE_KNOWN (d_inner);
+ DECL_DISREGARD_INLINE_LIMITS (e_inner)
+ |= DECL_DISREGARD_INLINE_LIMITS (d_inner);
+ // TODO: we will eventually want to merge all decl attributes
+ duplicate_one_attribute (&DECL_ATTRIBUTES (e_inner),
+ DECL_ATTRIBUTES (d_inner), "gnu_inline");
+ }
+ }
if (!DECL_EXTERNAL (d_inner))
DECL_EXTERNAL (e_inner) = false;
+ if (VAR_OR_FUNCTION_DECL_P (d_inner))
+ check_abi_tags (existing, decl,
+ DECL_ATTRIBUTES (e_inner), DECL_ATTRIBUTES (d_inner));
+
if (TREE_CODE (decl) == TEMPLATE_DECL)
{
/* Merge default template arguments. */
@@ -12626,6 +12738,8 @@ trees_in::read_var_def (tree decl, tree maybe_template)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
tentative_decl_linkage (decl);
if (DECL_IMPLICIT_INSTANTIATION (decl)
+ || (DECL_EXPLICIT_INSTANTIATION (decl)
+ && !DECL_EXTERNAL (decl))
|| (DECL_CLASS_SCOPE_P (decl)
&& !DECL_VTABLE_OR_VTT_P (decl)
&& !DECL_TEMPLATE_INFO (decl)))
@@ -20310,20 +20424,24 @@ get_originating_module_decl (tree decl)
return decl;
}
+/* If DECL is imported, return which module imported it, or 0 for the current
+ module. Except that if GLOBAL_M1, return -1 for decls attached to the
+ global module. */
+
int
-get_originating_module (tree decl, bool for_mangle)
+get_originating_module (tree decl, bool global_m1)
{
tree owner = get_originating_module_decl (decl);
tree not_tmpl = STRIP_TEMPLATE (owner);
if (!DECL_LANG_SPECIFIC (not_tmpl))
- return for_mangle ? -1 : 0;
+ return global_m1 ? -1 : 0;
- if (for_mangle && !DECL_MODULE_ATTACH_P (not_tmpl))
+ if (global_m1 && !DECL_MODULE_ATTACH_P (not_tmpl))
return -1;
int mod = !DECL_MODULE_IMPORT_P (not_tmpl) ? 0 : get_importing_module (owner);
- gcc_checking_assert (!for_mangle || !(*modules)[mod]->is_header ());
+ gcc_checking_assert (!global_m1 || !(*modules)[mod]->is_header ());
return mod;
}