[gcc/devel/c++-modules] More explicit merge kind discriminators
Nathan Sidwell
nathan@gcc.gnu.org
Tue Mar 3 22:42:00 GMT 2020
https://gcc.gnu.org/g:329b9d79faf4ab674704a18cd0e57b10200d64df
commit 329b9d79faf4ab674704a18cd0e57b10200d64df
Author: Nathan Sidwell <nathan@acm.org>
Date: Tue Mar 3 14:42:21 2020 -0800
More explicit merge kind discriminators
gcc/cp/
* module.cc (enum merge_kind): Add more discriminators.
(merge_kind_name): Adjust.
(trees_{in,out}::key_mergeable): Partition via new discriminators.
(trees_in::decl_value): Remove bad formatting.
(trees_out::get_merge_kind): Select new discriminators.
(mergeable_namespace_entity, mergeable_class_member): Fold into
reimplemented key_mergeable.
gcc/testsuite/
* g++.dg/modules/merge-[56]_b.C: Adjust scans.
Diff:
---
ChangeLog.modules | 11 +
gcc/cp/module.cc | 661 +++++++++++++++----------------
gcc/testsuite/g++.dg/modules/merge-5_b.C | 2 +-
gcc/testsuite/g++.dg/modules/merge-6_b.C | 2 +-
4 files changed, 337 insertions(+), 339 deletions(-)
diff --git a/ChangeLog.modules b/ChangeLog.modules
index 8339ee0..c7d619a 100644
--- a/ChangeLog.modules
+++ b/ChangeLog.modules
@@ -1,6 +1,17 @@
2020-03-03 Nathan Sidwell <nathan@acm.org>
gcc/cp/
+ * module.cc (enum merge_kind): Add more discriminators.
+ (merge_kind_name): Adjust.
+ (trees_{in,out}::key_mergeable): Partition via new discriminators.
+ (trees_in::decl_value): Remove bad formatting.
+ (trees_out::get_merge_kind): Select new discriminators.
+ (mergeable_namespace_entity, mergeable_class_member): Fold into
+ reimplemented key_mergeable.
+ gcc/testsuite/
+ * g++.dg/modules/merge-[56]_b.C: Adjust scans.
+
+ gcc/cp/
* module.cc (struct merge_key): Remove index as tree hack ...
(merge_key::{read,write}): ... here.
(trees_{in,out}::key_mergeable): Adjust.
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index ff2190b..e4bf20d 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2740,7 +2740,7 @@ enum tree_tag {
tt_parm, /* Function paramter or result. */
tt_enum_value, /* An enum value. */
tt_enum_decl, /* An enum decl. */
- tt_data_member, /* Data member or enum value. */
+ tt_data_member, /* Data member/using-decl. */
tt_binfo, /* A BINFO. */
tt_vtable, /* A vtable. */
@@ -2759,15 +2759,22 @@ enum walk_kind {
WK_value, /* By-value walk. */
};
+// class - as-base
+// class - vtable index of the vtable
+// class - field/using/anon-member-type/anon-bitfield/bitfield-representative
+// class - field-for-base
+//
enum merge_kind
{
- MK_unique, /* Known unique. */
- MK_via_ctx = 0x1, /* Found by CTX, NAME. But as unique as ctx. */
- MK_named = 0x2, /* Found by CTX, NAME + maybe_arg types. */
+ MK_unique, /* Known unique. */
+ MK_named, /* Found by CTX, NAME + maybe_arg types etc. */
+ MK_field, /* Found by CTX and index on TYPE_FIELDS */
+ MK_vtable, /* Found by CTX and index on TYPE_VTABLES */
+ MK_as_base, /* Found by CTX. */
- MK_indirect_mask = 0x4,
- MK_local_friend = MK_indirect_mask |0x1, /* Found by CTX, index. */
- MK_enum = MK_indirect_mask | 0x3, /* Found by CTX, & 1stMemberNAME. */
+ MK_indirect_lwm = 0x6,
+ MK_local_friend = MK_indirect_lwm, /* Found by CTX, index. */
+ MK_enum, /* Found by CTX, & 1stMemberNAME. */
/* Template specialization kinds below. These are all found via
primary template and specialization args. */
@@ -2790,8 +2797,8 @@ enum merge_kind
an invalid merge_kind number. */
static char const *const merge_kind_name[MK_hwm] =
{
- "unique", "via-ctx", "named", NULL, /* 0...3 */
- NULL, "local friend", NULL, "enum", /* 4...7 */
+ "unique", "named", "field", "vtable", /* 0...3 */
+ "asbase", NULL, "local friend", "enum", /* 4...7 */
"type spec", "type tmpl spec", NULL, "type partial spec", /* 8...11 */
"decl spec", "decl tmpl spec", "both spec", "both tmpl spec" /* 12...15 */
};
@@ -3017,8 +3024,8 @@ public:
public:
merge_kind get_merge_kind (tree decl, depset *maybe_dep);
tree decl_container (tree decl);
- void key_mergeable (int tag, merge_kind, tree decl, tree container,
- depset *maybe_dep);
+ void key_mergeable (int tag, merge_kind, tree decl, tree inner,
+ tree container, depset *maybe_dep);
void binfo_mergeable (tree binfo);
private:
@@ -7366,7 +7373,7 @@ trees_out::decl_value (tree decl, depset *dep)
/* Now write out the merging information, and then really
install the tag values. */
- key_mergeable (tag, mk, decl, container, dep);
+ key_mergeable (tag, mk, decl, inner, container, dep);
if (streaming_p ())
dump (dumper::MERGE)
@@ -7561,48 +7568,45 @@ trees_in::decl_value ()
/* Read the container, to ensure it's already been streamed in. */
tree container = decl_container ();
unsigned tpl_levels = 0;
- if (true)
- {
- /* Figure out if this decl is already known about. */
- int parm_tag = 0;
- if (decl != inner)
- if (!tpl_header (decl, &tpl_levels))
- goto bail;
- if (TREE_CODE (inner) == FUNCTION_DECL)
- parm_tag = fn_parms_init (inner);
+ /* Figure out if this decl is already known about. */
+ int parm_tag = 0;
- tree existing = key_mergeable (tag, mk, decl, inner, type,
- container, is_mod);
- if (existing)
- {
- if (existing == error_mark_node)
- goto bail;
+ if (decl != inner)
+ if (!tpl_header (decl, &tpl_levels))
+ goto bail;
+ if (TREE_CODE (inner) == FUNCTION_DECL)
+ parm_tag = fn_parms_init (inner);
- /* Install the existing decl into the back ref array. */
- register_duplicate (decl, existing);
- back_refs[~tag] = existing;
- if (inner_tag != 0)
- {
- existing = DECL_TEMPLATE_RESULT (existing);
- back_refs[~inner_tag] = existing;
- }
+ tree existing = key_mergeable (tag, mk, decl, inner, type, container, is_mod);
+ if (existing)
+ {
+ if (existing == error_mark_node)
+ goto bail;
- if (type_tag != 0)
- {
- tree existing_type = TREE_TYPE (existing);
- back_refs[~type_tag] = existing_type;
- if (stub_tag != 0)
- back_refs[~stub_tag] = TYPE_STUB_DECL (existing_type);
- }
+ /* Install the existing decl into the back ref array. */
+ register_duplicate (decl, existing);
+ back_refs[~tag] = existing;
+ if (inner_tag != 0)
+ {
+ existing = DECL_TEMPLATE_RESULT (existing);
+ back_refs[~inner_tag] = existing;
}
- if (parm_tag)
- // FIXME: Is this comment 100% accurate?
- /* EXISTING is the template result (or NULL). */
- fn_parms_fini (parm_tag, inner, existing, has_defn);
+ if (type_tag != 0)
+ {
+ tree existing_type = TREE_TYPE (existing);
+ back_refs[~type_tag] = existing_type;
+ if (stub_tag != 0)
+ back_refs[~stub_tag] = TYPE_STUB_DECL (existing_type);
+ }
}
+ if (parm_tag)
+ // FIXME: Is this comment 100% accurate?
+ /* EXISTING is the template result (or NULL). */
+ fn_parms_fini (parm_tag, inner, existing, has_defn);
+
if (!tree_node_vals (decl))
goto bail;
@@ -7634,7 +7638,7 @@ trees_in::decl_value ()
DECL_ORIGINAL_TYPE (inner) = NULL_TREE;
}
- tree existing = back_refs[~tag];
+ existing = back_refs[~tag];
unsigned entity_index = u ();
if (!entity_index)
;
@@ -9597,27 +9601,55 @@ trees_out::get_merge_kind (tree decl, depset *dep)
return MK_unique;
gcc_checking_assert (TYPE_P (ctx));
- if (TREE_CODE (decl) == FIELD_DECL
- && !DECL_NAME (decl)
- && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
- && !DECL_BIT_FIELD_REPRESENTATIVE (decl))
+ if (TREE_CODE (decl) == USING_DECL)
+ return MK_field;
+
+ if (TREE_CODE (decl) == FIELD_DECL)
{
- /* The underlying storage unit for a bitfield. We do not
- need to dedup these, because it's only reachable through
- the bitfields it represents. And those are deduped. */
- // FIXME: Is that assertion correct -- do we ever fish it
- // out and put it in an expr?
- gcc_checking_assert ((TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
- ? TREE_CODE (TREE_TYPE (TREE_TYPE (decl)))
- : TREE_CODE (TREE_TYPE (decl))) == INTEGER_TYPE);
- return MK_unique;
+ if (DECL_NAME (decl))
+ {
+ /* Anonymous FIELD_DECLs have a NULL name. */
+ gcc_checking_assert (!IDENTIFIER_ANON_P (DECL_NAME (decl)));
+ return MK_named;
+ }
+
+ if (!DECL_NAME (decl)
+ && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
+ && !DECL_BIT_FIELD_REPRESENTATIVE (decl))
+ {
+ /* The underlying storage unit for a bitfield. We do not
+ need to dedup it, because it's only reachable through
+ the bitfields it represents. And those are deduped. */
+ // FIXME: Is that assertion correct -- do we ever fish it
+ // out and put it in an expr?
+ gcc_checking_assert ((TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+ ? TREE_CODE (TREE_TYPE (TREE_TYPE (decl)))
+ : TREE_CODE (TREE_TYPE (decl)))
+ == INTEGER_TYPE);
+ return MK_unique;
+ }
+ return MK_field;
}
- return MK_via_ctx;
+ if (TREE_CODE (decl) == CONST_DECL)
+ return MK_named;
+
+ if (TREE_CODE (decl) == VAR_DECL
+ && DECL_VTABLE_OR_VTT_P (decl))
+ return MK_vtable;
+
+ if (DECL_THUNK_P (decl))
+ /* Thunks are unique-enough, because they're only referenced
+ from the vtable. And that's either new (so we want the
+ thunks), or it's a duplicate (so it will be dropped). */
+ return MK_unique;
+
+ gcc_unreachable ();
}
gcc_checking_assert (TREE_CODE (decl) != FIELD_DECL
- && TREE_CODE (decl) != USING_DECL);
+ && TREE_CODE (decl) != USING_DECL
+ && TREE_CODE (decl) != CONST_DECL);
gcc_checking_assert (decl == dep->get_entity ());
@@ -9643,6 +9675,10 @@ trees_out::get_merge_kind (tree decl, depset *dep)
case RECORD_TYPE:
case UNION_TYPE:
+ if (DECL_NAME (decl) == as_base_identifier)
+ mk = MK_as_base;
+ else if (IDENTIFIER_ANON_P (DECL_NAME (decl)))
+ mk = MK_field;
break;
case NAMESPACE_DECL:
@@ -9793,7 +9829,7 @@ trees_in::decl_container ()
written. The container has already been streamed. */
void
-trees_out::key_mergeable (int tag, merge_kind mk, tree decl,
+trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
tree container, depset *dep)
{
if (streaming_p ())
@@ -9804,10 +9840,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl,
merge_key key;
- tree inner = decl;
- if (TREE_CODE (decl) == TEMPLATE_DECL)
- /* A template needs its template parms for identification. */
- inner = DECL_TEMPLATE_RESULT (decl);
+ key.ctx_or_tmpl = container;
/* Now write the locating information. */
if (mk & MK_template_mask)
@@ -9859,129 +9892,121 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl,
gcc_assert (existing == decl);
}
}
- else if (mk & MK_indirect_mask)
+ else
{
- tree name = decl;
- unsigned index = 0;
-
- if (mk == MK_enum)
+ key.name_or_spec = DECL_NAME (decl);
+ switch (mk)
{
- /* Anonymous enums are located by their first identifier. */
- gcc_checking_assert (UNSCOPED_ENUM_P (TREE_TYPE (decl)));
- if (tree values = TYPE_VALUES (TREE_TYPE (decl)))
- name = DECL_NAME (TREE_VALUE (values));
- }
- else if (mk == MK_local_friend)
- {
- /* Find by index on the class */
- unsigned ix = 0;
- for (tree decls = CLASSTYPE_DECL_LIST (TREE_CHAIN (decl));
- decls; decls = TREE_CHAIN (decls))
- if (!TREE_PURPOSE (decls))
- {
- tree frnd = friend_from_decl_list (TREE_VALUE (decls));
- if (frnd == decl)
- break;
- ix++;
- }
- index = ix;
- }
- else
- gcc_unreachable ();
-
- key.ctx_and_name (container, name);
- key.index = index;
- }
- else if (mk != MK_unique)
- {
- /* Regular decls are located by their context, name, and
- additional disambiguating data. */
- tree name = DECL_NAME (decl);
- if (!name && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
- {
- /* A field for an anonymous member type, or direct base, use
- the type as the name. */
- gcc_checking_assert (TREE_CODE (decl) == FIELD_DECL);
- name = TYPE_NAME (TREE_TYPE (decl));
- }
- else if (!name || IDENTIFIER_ANON_P (name)
- || TREE_CODE (inner) == USING_DECL)
- {
- /* An anonymous member type, or anonymous bitfield or a
- using_decl. Find its position in the (filtered)
- TYPE_FIELDS list and use that as an INTEGER_CST. */
- // FIXME: Perhaps (unmergable) anonymous namespace-scope
- // types get here too? We should have set those to
- // MK_unique earlier.
- // FIXME: What about anonymous bitfields (of dependent type?)
- // in templates?
- gcc_checking_assert (TYPE_P (CP_DECL_CONTEXT (decl))
- && (TREE_CODE (decl) != TEMPLATE_DECL
- || !DECL_MEMBER_TEMPLATE_P (decl)));
- if (TREE_CODE (inner) != USING_DECL)
- gcc_checking_assert (name ? TREE_CODE (inner) == TYPE_DECL
- : (TREE_CODE (inner) == FIELD_DECL
- && DECL_BIT_FIELD_REPRESENTATIVE (inner)));
- unsigned ix = 0;
- enum tree_code code = TREE_CODE (inner);
- for (tree field = TYPE_FIELDS (CP_DECL_CONTEXT (decl));
- field; field = DECL_CHAIN (field))
- if (code == TREE_CODE (STRIP_TEMPLATE (field))
- && (code == USING_DECL
- || !DECL_NAME (field)
- || IDENTIFIER_ANON_P (DECL_NAME (field))))
- {
- if (field == inner)
- {
- // FIXME: use index
- name = build_int_cst (unsigned_type_node, ix);
- break;
- }
- ix++;
- }
- /* Make sure we found it. */
- gcc_checking_assert (TREE_CODE (name) == INTEGER_CST);
- }
- else if (IDENTIFIER_CONV_OP_P (name))
- name = conv_op_identifier;
-
- // FIXME: We should just be given the non-template?
- key.ctx_and_name (container, name);
+ default:
+ gcc_unreachable ();
- if (TREE_CODE (inner) == FUNCTION_DECL)
- {
- /* Functions are distinguished by parameter types. */
- tree fn_type = TREE_TYPE (inner);
+ case MK_unique:
+ break;
- key.arg_types (fn_type);
+ case MK_named:
+ if (IDENTIFIER_CONV_OP_P (key.name_or_spec))
+ key.name_or_spec = conv_op_identifier;
- if (decl != inner)
+ if (TREE_CODE (inner) == FUNCTION_DECL)
{
- tree reqs = get_constraints (inner);
+ /* Functions are distinguished by parameter types. */
+ tree fn_type = TREE_TYPE (inner);
- if (reqs)
+ key.arg_types (fn_type);
+
+ if (decl != inner)
{
- if (cxx_dialect < cxx2a)
- reqs = CI_ASSOCIATED_CONSTRAINTS (reqs);
- else
+ tree reqs = get_constraints (inner);
+
+ if (reqs)
{
- reqs = CI_DECLARATOR_REQS (reqs);
- if (reqs)
- reqs = maybe_substitute_reqs_for (reqs, inner);
+ if (cxx_dialect < cxx2a)
+ reqs = CI_ASSOCIATED_CONSTRAINTS (reqs);
+ else
+ {
+ reqs = CI_DECLARATOR_REQS (reqs);
+ if (reqs)
+ reqs = maybe_substitute_reqs_for (reqs, inner);
+ }
}
+ key.constraints = reqs;
}
- key.constraints = reqs;
+
+ if (decl != inner || key.name_or_spec == conv_op_identifier)
+ /* And a function template, or conversion operator needs
+ the return type. */
+ // FIXME: What if the return type is a voldemort? We
+ // should be using the declared return type.
+ key.ret = TREE_TYPE (fn_type);
}
+ break;
- if (decl != inner || name == conv_op_identifier)
- /* And a function template, or conversion operator needs
- the return type. */
- // FIXME: What if the return type is a voldemort? We
- // should be using the declared return type.
- key.ret = TREE_TYPE (fn_type);
+ case MK_field:
+ // FIXME: Much like tt_data_member -- commonize?
+ {
+ unsigned ix = 0;
+
+ for (tree field = TYPE_FIELDS (TREE_TYPE (container));
+ ; field = DECL_CHAIN (field))
+ {
+ tree finner = STRIP_TEMPLATE (field);
+ if (TREE_CODE (finner) == TREE_CODE (inner))
+ {
+ if (finner == inner)
+ break;
+ ix++;
+ }
+ }
+ key.index = ix;
+ }
+ break;
+
+ case MK_vtable:
+ // FIXME: Much like tt_vtable -- commonize?
+ {
+ tree vtable = CLASSTYPE_VTABLES (TREE_TYPE (container));
+ for (unsigned ix = 0; ; vtable = DECL_CHAIN (vtable), ix++)
+ if (vtable == decl)
+ {
+ key.index = ix;
+ break;
+ }
+ }
+ break;
+
+ case MK_as_base:
+ gcc_checking_assert
+ (decl == TYPE_NAME (CLASSTYPE_AS_BASE (TREE_TYPE (container))));
+ break;
+
+ case MK_local_friend:
+ {
+ /* Find by index on the class's DECL_LIST */
+ unsigned ix = 0;
+ for (tree decls = CLASSTYPE_DECL_LIST (TREE_CHAIN (decl));
+ decls; decls = TREE_CHAIN (decls))
+ if (!TREE_PURPOSE (decls))
+ {
+ tree frnd = friend_from_decl_list (TREE_VALUE (decls));
+ if (frnd == decl)
+ break;
+ ix++;
+ }
+ key.index = ix;
+ key.name_or_spec = NULL_TREE;
+ }
+ break;
+
+ case MK_enum:
+ /* Anonymous enums are located by their first identifier. */
+ gcc_checking_assert (UNSCOPED_ENUM_P (TREE_TYPE (decl)));
+ if (tree values = TYPE_VALUES (TREE_TYPE (decl)))
+ key.name_or_spec = DECL_NAME (TREE_VALUE (values));
+ break;
}
}
+ // FIXME: Open code and elide some pieces
key.write (*this, mk, container);
}
@@ -10092,119 +10117,6 @@ check_mergeable_decl (merge_match kind, tree decl, tree ovl,
return NULL_TREE;
}
-/* DECL is a yet-to-be-loaded mergeable entity in namespace CTX slot
- NAME. PARTITION is true if it is from a module partition
- (otherwise it is a global module entity), RET and ARGS are its
- distinguishing features (some of which may be NULL). Look for an
- existing mergeable that matches and return that if found.
- Otherwise add this DECL into the mergeable list. */
-// FIXME: move anonymous enum key scheme elsewhere or pass in flag
-// that that's happening
-tree
-mergeable_namespace_entity (merge_kind, tree decl,
- merge_key const &key, bool partition)
-{
- tree *gslot = mergeable_namespace_entities (key.ctx_or_tmpl, key.name_or_spec,
- !partition);
-
- if (tree match = check_mergeable_decl
- (DECL_NAME (decl) ? MM_namespace_scope : MM_anon_enum,
- decl, *gslot, key))
- return match;
-
- if (DECL_NAME (decl))
- add_mergeable_namespace_entity (gslot, decl);
-
- return NULL_TREE;
-}
-
-tree
-mergeable_class_member (merge_kind, tree decl, merge_key const &key)
-{
- tree found = NULL_TREE;
- tree klass = TREE_TYPE (key.ctx_or_tmpl);
- tree name = key.name_or_spec;
-
- // FIXME: Stop keying off TREE_CODE (name), use mk
- switch (TREE_CODE (name))
- {
- default:
- /* The CMI is faulty, but don't explode here. */
- break;
-
- case INTEGER_CST:
- /* An anonymous member type, or unnamed bitfield, or using_decl */
- {
- unsigned ix = TREE_INT_CST_LOW (key.name_or_spec);
- enum tree_code code = TREE_CODE (STRIP_TEMPLATE (decl));
- for (tree field = TYPE_FIELDS (klass); field; field = DECL_CHAIN (field))
- if (code == TREE_CODE (STRIP_TEMPLATE (field))
- && (code == USING_DECL
- || !DECL_NAME (field)
- || IDENTIFIER_ANON_P (DECL_NAME (field))))
- if (!ix--)
- {
- found = field;
- break;
- }
- }
- break;
-
- case TYPE_DECL:
- /* An anonymous or base field for an anonymous member type. */
- for (tree field = TYPE_FIELDS (klass); field; field = DECL_CHAIN (field))
- if (TREE_CODE (field) == FIELD_DECL
- && TREE_TYPE (field) == TREE_TYPE (name))
- {
- found = field;
- break;
- }
- break;
-
- case IDENTIFIER_NODE:
- {
- gcc_checking_assert (IDENTIFIER_CONV_OP_P (name)
- == (name == conv_op_identifier));
-
- if (name == as_base_identifier)
- {
- // FIXME: Perhaps just push this into the member vector?
- found = CLASSTYPE_AS_BASE (klass);
- if (!found || found == klass)
- found = NULL_TREE;
- else
- found = TYPE_NAME (found);
- }
- else
- found = mergeable_class_entities (klass, name);
- }
- break;
- }
-
- if (found)
- {
- tree inner = decl;
- if (TREE_CODE (inner) == TEMPLATE_DECL
- && !DECL_MEMBER_TEMPLATE_P (inner))
- inner = DECL_TEMPLATE_RESULT (inner);
-
- if (TREE_CODE (name) == IDENTIFIER_NODE)
- found = check_mergeable_decl
- (MM_class_scope, inner, found, key);
-
- if (found && inner != decl)
- {
- tree ti;
- if (DECL_IMPLICIT_TYPEDEF_P (found))
- ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found));
- else
- ti = DECL_TEMPLATE_INFO (found);
- found = TI_TEMPLATE (ti);
- }
- }
- return found;
-}
-
/* DECL, INNER & TYPE are a skeleton set of nodes for a decl. Only
the bools have been filled in. Read its merging key and merge it.
Returns the existing decl if there is one. */
@@ -10227,7 +10139,7 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
}
else
{
- if (!(mk & MK_indirect_mask))
+ if (mk < MK_indirect_lwm)
DECL_NAME (decl) = key.name_or_spec;
DECL_CONTEXT (decl) = FROB_CONTEXT (key.ctx_or_tmpl);
}
@@ -10255,10 +10167,8 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
insert = type;
}
- existing = match_mergeable_specialization (is_decl,
- key.ctx_or_tmpl,
- key.name_or_spec,
- insert);
+ existing = match_mergeable_specialization (is_decl, key.ctx_or_tmpl,
+ key.name_or_spec, insert);
if (!existing)
{
@@ -10309,65 +10219,142 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
else if (mk == MK_unique)
kind = "unique";
else
- {
- switch (TREE_CODE (key.ctx_or_tmpl))
- {
- default:
- gcc_unreachable ();
+ switch (TREE_CODE (key.ctx_or_tmpl))
+ {
+ default:
+ gcc_unreachable ();
- case NAMESPACE_DECL:
- if (is_mod && !(state->is_module () || state->is_partition ()))
- kind = "unique";
- else
- existing = mergeable_namespace_entity (mk, decl, key, is_mod);
- break;
+ case NAMESPACE_DECL:
+ if (is_mod && !(state->is_module () || state->is_partition ()))
+ kind = "unique";
+ else
+ {
+ gcc_checking_assert (mk == MK_named || mk == MK_enum);
+ tree *gslot = mergeable_namespace_entities
+ (key.ctx_or_tmpl, key.name_or_spec, !is_mod);
- case FUNCTION_DECL:
- // FIXME: What about a voldemort? how do we find what it
- // duplicates? Do we have to number vmorts relative to
- // their containing function? But how would that work
- // when matching an in-TU declaration?
+ existing = check_mergeable_decl
+ (mk == MK_named ? MM_namespace_scope : MM_anon_enum,
+ decl, *gslot, key);
+
+ if (!existing && mk == MK_named)
+ add_mergeable_namespace_entity (gslot, decl);
+ }
+ break;
+
+ case FUNCTION_DECL:
+ // FIXME: What about a voldemort? how do we find what it
+ // duplicates? Do we have to number vmorts relative to
+ // their containing function? But how would that work
+ // when matching an in-TU declaration?
+ kind = "unique";
+ break;
+
+ case TYPE_DECL:
+ if (is_mod && !(state->is_module () || state->is_partition ())
+ /* Implicit member functions can come from
+ anywhere. */
+ && !(DECL_ARTIFICIAL (decl)
+ && TREE_CODE (decl) == FUNCTION_DECL
+ && !DECL_THUNK_P (decl)))
kind = "unique";
- break;
+ else
+ {
+ tree ctx = TREE_TYPE (key.ctx_or_tmpl);
+
+ /* For some reason templated enumeral types are not marked
+ as COMPLETE_TYPE_P, even though they have members.
+ This may well be a bug elsewhere. */
+ if (TREE_CODE (ctx) == ENUMERAL_TYPE)
+ existing = find_enum_member (ctx, key.name_or_spec);
+ else if (COMPLETE_TYPE_P (ctx))
+ {
+ switch (mk)
+ {
+ default:
+ gcc_unreachable ();
- case TYPE_DECL:
- if (is_mod && !(state->is_module () || state->is_partition ())
- /* Implicit member functions can come from
- anywhere. */
- && !(DECL_ARTIFICIAL (decl)
- && TREE_CODE (decl) == FUNCTION_DECL
- && !DECL_THUNK_P (decl)))
- kind = "unique";
- else
- {
- /* We do not appear to set TYPE_SIZE for templated
- enums. So, they always appear incomplete.
- Perhaps we should? */
- tree ctx = TREE_TYPE (key.ctx_or_tmpl);
- if (TREE_CODE (ctx) == ENUMERAL_TYPE)
- existing = find_enum_member (ctx, key.name_or_spec);
- else if (COMPLETE_TYPE_P (ctx))
- {
- if (mk == MK_local_friend)
+ case MK_named:
+ existing = mergeable_class_entities (ctx, key.name_or_spec);
+ if (existing)
+ {
+ tree inner = decl;
+ if (TREE_CODE (inner) == TEMPLATE_DECL
+ && !DECL_MEMBER_TEMPLATE_P (inner))
+ inner = DECL_TEMPLATE_RESULT (inner);
+
+ existing = check_mergeable_decl
+ (MM_class_scope, inner, existing, key);
+ }
+ break;
+
+ case MK_field:
+ {
+ unsigned ix = key.index;
+ for (tree field = TYPE_FIELDS (ctx);
+ field; field = DECL_CHAIN (field))
+ {
+ tree finner = STRIP_TEMPLATE (field);
+ if (TREE_CODE (finner) == TREE_CODE (inner))
+ if (!ix--)
+ {
+ existing = field;
+ break;
+ }
+ }
+ }
+ break;
+
+ case MK_vtable:
+ {
+ unsigned ix = key.index;
+ for (tree vtable = CLASSTYPE_VTABLES (ctx);
+ vtable; vtable = DECL_CHAIN (vtable))
+ if (!ix--)
+ {
+ existing = vtable;
+ break;
+ }
+ }
+ break;
+
+ case MK_as_base:
+ {
+ tree as_base = CLASSTYPE_AS_BASE (ctx);
+ if (as_base && as_base != ctx)
+ existing = TYPE_NAME (as_base);
+ }
+ break;
+
+ case MK_local_friend:
{
unsigned ix = key.index;
for (tree decls = CLASSTYPE_DECL_LIST (ctx);
decls; decls = TREE_CHAIN (decls))
- if (!TREE_PURPOSE (decls)
- && !ix--)
+ if (!TREE_PURPOSE (decls) && !ix--)
{
existing
= friend_from_decl_list (TREE_VALUE (decls));
break;
}
}
- else
- existing = mergeable_class_member (mk, decl, key);
- }
- }
- break;
- }
- }
+ break;
+ }
+
+ if (existing && mk < MK_indirect_lwm
+ && TREE_CODE (decl) == TEMPLATE_DECL
+ && !DECL_MEMBER_TEMPLATE_P (decl))
+ {
+ tree ti;
+ if (DECL_IMPLICIT_TYPEDEF_P (existing))
+ ti = TYPE_TEMPLATE_INFO (TREE_TYPE (existing));
+ else
+ ti = DECL_TEMPLATE_INFO (existing);
+ existing = TI_TEMPLATE (ti);
+ }
+ }
+ }
+ }
dump (dumper::MERGE)
&& dump ("Read:%d's %s merge key (%s) %C:%N", tag, merge_kind_name[mk],
diff --git a/gcc/testsuite/g++.dg/modules/merge-5_b.C b/gcc/testsuite/g++.dg/modules/merge-5_b.C
index 0da68de..58c2a34 100644
--- a/gcc/testsuite/g++.dg/modules/merge-5_b.C
+++ b/gcc/testsuite/g++.dg/modules/merge-5_b.C
@@ -3,6 +3,6 @@
#include "merge-5.h"
import "merge-5_a.H";
-// { dg-final { scan-lang-dump {Read:-[0-9]*'s via-ctx merge key \(matched\) const_decl:'::template __traitor<T>::template X<T>::__value'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) const_decl:'::template __traitor<T>::template X<T>::__value'} module } }
// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
// { dg-final { scan-lang-dump-not {merge key \(unique\)} module } }
diff --git a/gcc/testsuite/g++.dg/modules/merge-6_b.C b/gcc/testsuite/g++.dg/modules/merge-6_b.C
index bc8476d..7ef814e 100644
--- a/gcc/testsuite/g++.dg/modules/merge-6_b.C
+++ b/gcc/testsuite/g++.dg/modules/merge-6_b.C
@@ -3,6 +3,6 @@
#include "merge-6.h"
import "merge-6_a.H";
-// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::template __traitor<T>::template 0x0'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s field merge key \(matched\) template_decl:'::template __traitor<T>::template ._anon_.'} module } }
// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
// { dg-final { scan-lang-dump-not {merge key \(unique\)} module } }
More information about the Gcc-cvs
mailing list