Bootstrapped and regtested (so far just modules.exp) on x86_64-pc-linux-gnu, OK for trunk if full regtest passes?
-- >8 -- Currently name lookup generally seems to assume that all entities declared within a named module (partition) are attached to said module, which is not true for GM entities (e.g. via extern "C++"), and causes issues with deduplication. This patch fixes the issue by ensuring that module attachment of a declaration is consistently used to handling merging. Handling this exposes some issues with deduplicating temploid friends; to resolve this we always create the BINDING_SLOT_PARTITION slot so that we have somewhere to place attached names (from any module). PR c++/114950 gcc/cp/ChangeLog: * module.cc (trees_out::decl_value): Stream bit indicating imported temploid friends early. (trees_in::decl_value): Use this bit with key_mergeable. (trees_in::key_mergeable): Allow merging attached declarations if they're imported temploid friends. (module_state::read_cluster): Check for GM entities that may require merging even when importing from partitions. * name-lookup.cc (enum binding_slots): Adjust comment. (get_fixed_binding_slot): Always create partition slot. (name_lookup::search_namespace_only): Support binding vectors with both partition and GM entities to dedup. (walk_module_binding): Likewise. (name_lookup::adl_namespace_fns): Likewise. (set_module_binding): Likewise. (check_module_override): Use attachment of the decl when checking overrides rather than named_module_p. (lookup_imported_hidden_friend): Use partition slot for finding mergeable template bindings. * name-lookup.h (set_module_binding): Split mod_glob_flag parameter into separate global_p and partition_p params. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-13_e.C: Adjust error message. * g++.dg/modules/ambig-2_a.C: New test. * g++.dg/modules/ambig-2_b.C: New test. * g++.dg/modules/part-9_a.C: New test. * g++.dg/modules/part-9_b.C: New test. * g++.dg/modules/part-9_c.C: New test. * g++.dg/modules/tpl-friend-15.h: New test. * g++.dg/modules/tpl-friend-15_a.C: New test. * g++.dg/modules/tpl-friend-15_b.C: New test. * g++.dg/modules/tpl-friend-15_c.C: New test. Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> --- gcc/cp/module.cc | 55 ++++++++++------ gcc/cp/name-lookup.cc | 65 ++++++++++--------- gcc/cp/name-lookup.h | 2 +- gcc/testsuite/g++.dg/modules/ambig-2_a.C | 7 ++ gcc/testsuite/g++.dg/modules/ambig-2_b.C | 10 +++ gcc/testsuite/g++.dg/modules/part-9_a.C | 10 +++ gcc/testsuite/g++.dg/modules/part-9_b.C | 10 +++ gcc/testsuite/g++.dg/modules/part-9_c.C | 8 +++ .../g++.dg/modules/tpl-friend-13_e.C | 4 +- gcc/testsuite/g++.dg/modules/tpl-friend-15.h | 11 ++++ .../g++.dg/modules/tpl-friend-15_a.C | 8 +++ .../g++.dg/modules/tpl-friend-15_b.C | 8 +++ .../g++.dg/modules/tpl-friend-15_c.C | 7 ++ 13 files changed, 150 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/ambig-2_a.C create mode 100644 gcc/testsuite/g++.dg/modules/ambig-2_b.C create mode 100644 gcc/testsuite/g++.dg/modules/part-9_a.C create mode 100644 gcc/testsuite/g++.dg/modules/part-9_b.C create mode 100644 gcc/testsuite/g++.dg/modules/part-9_c.C create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-15.h create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-15_a.C create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-15_b.C create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-15_c.C diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index d1607a06757..e6b569ebca5 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2955,7 +2955,8 @@ private: public: tree decl_container (); tree key_mergeable (int tag, merge_kind, tree decl, tree inner, tree type, - tree container, bool is_attached); + tree container, bool is_attached, + bool is_imported_temploid_friend); unsigned binfo_mergeable (tree *); private: @@ -7803,6 +7804,7 @@ trees_out::decl_value (tree decl, depset *dep) || !TYPE_PTRMEMFUNC_P (TREE_TYPE (decl))); merge_kind mk = get_merge_kind (decl, dep); + bool is_imported_temploid_friend = imported_temploid_friends->get (decl); if (CHECKING_P) { @@ -7838,13 +7840,11 @@ trees_out::decl_value (tree decl, depset *dep) && DECL_MODULE_ATTACH_P (not_tmpl)) is_attached = true; - /* But don't consider imported temploid friends as attached, - since importers will need to merge this decl even if it was - attached to a different module. */ - if (imported_temploid_friends->get (decl)) - is_attached = false; - bits.b (is_attached); + + /* Also tell the importer whether this is an imported temploid + friend, which has implications for merging. */ + bits.b (is_imported_temploid_friend); } bits.b (dep && dep->has_defn ()); } @@ -8021,13 +8021,12 @@ trees_out::decl_value (tree decl, depset *dep) } } - if (TREE_CODE (inner) == FUNCTION_DECL - || TREE_CODE (inner) == TYPE_DECL) + if (is_imported_temploid_friend) { /* Write imported temploid friends so that importers can reconstruct this information on stream-in. */ tree* slot = imported_temploid_friends->get (decl); - tree_node (slot ? *slot : NULL_TREE); + tree_node (*slot); } bool is_typedef = false; @@ -8106,6 +8105,7 @@ trees_in::decl_value () { int tag = 0; bool is_attached = false; + bool is_imported_temploid_friend = false; bool has_defn = false; unsigned mk_u = u (); if (mk_u >= MK_hwm || !merge_kind_name[mk_u]) @@ -8126,7 +8126,10 @@ trees_in::decl_value () { bits_in bits = stream_bits (); if (!(mk & MK_template_mask) && !state->is_header ()) - is_attached = bits.b (); + { + is_attached = bits.b (); + is_imported_temploid_friend = bits.b (); + } has_defn = bits.b (); } @@ -8231,7 +8234,7 @@ trees_in::decl_value () parm_tag = fn_parms_init (inner); tree existing = key_mergeable (tag, mk, decl, inner, type, container, - is_attached); + is_attached, is_imported_temploid_friend); tree existing_inner = existing; if (existing) { @@ -8336,8 +8339,7 @@ trees_in::decl_value () } } - if (TREE_CODE (inner) == FUNCTION_DECL - || TREE_CODE (inner) == TYPE_DECL) + if (is_imported_temploid_friend) if (tree owner = tree_node ()) if (is_new) imported_temploid_friends->put (decl, owner); @@ -11174,7 +11176,8 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key) tree trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, - tree type, tree container, bool is_attached) + tree type, tree container, bool is_attached, + bool is_imported_temploid_friend) { const char *kind = "new"; tree existing = NULL_TREE; @@ -11316,6 +11319,7 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, case NAMESPACE_DECL: if (is_attached + && !is_imported_temploid_friend && !(state->is_module () || state->is_partition ())) kind = "unique"; else @@ -11347,7 +11351,9 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, break; case TYPE_DECL: - if (is_attached && !(state->is_module () || state->is_partition ()) + if (is_attached + && !is_imported_temploid_friend + && !(state->is_module () || state->is_partition ()) /* Implicit member functions can come from anywhere. */ && !(DECL_ARTIFICIAL (decl) @@ -15291,6 +15297,7 @@ module_state::read_cluster (unsigned snum) tree visible = NULL_TREE; tree type = NULL_TREE; bool dedup = false; + bool global_p = false; /* We rely on the bindings being in the reverse order of the resulting overload set. */ @@ -15308,6 +15315,16 @@ module_state::read_cluster (unsigned snum) if (sec.get_overrun ()) break; + if (!global_p) + { + /* Check if the decl could require GM merging. */ + tree orig = get_originating_module_decl (decl); + tree inner = STRIP_TEMPLATE (orig); + if (!DECL_LANG_SPECIFIC (inner) + || !DECL_MODULE_ATTACH_P (inner)) + global_p = true; + } + if (decls && TREE_CODE (decl) == TYPE_DECL) { /* Stat hack. */ @@ -15394,10 +15411,8 @@ module_state::read_cluster (unsigned snum) break; /* Bail. */ dump () && dump ("Binding of %P", ns, name); - if (!set_module_binding (ns, name, mod, - is_header () ? -1 - : is_module () || is_partition () ? 1 - : 0, + if (!set_module_binding (ns, name, mod, global_p, + is_module () || is_partition (), decls, type, visible)) sec.set_overrun (); } diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 8823ab71c60..872f1af0b2e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -51,8 +51,8 @@ enum binding_slots { BINDING_SLOT_CURRENT, /* Slot for current TU. */ BINDING_SLOT_GLOBAL, /* Slot for merged global module. */ - BINDING_SLOT_PARTITION, /* Slot for merged partition entities - (optional). */ + BINDING_SLOT_PARTITION, /* Slot for merged partition entities or + imported friends. */ /* Number of always-allocated slots. */ BINDING_SLOTS_FIXED = BINDING_SLOT_GLOBAL + 1 @@ -248,9 +248,10 @@ get_fixed_binding_slot (tree *slot, tree name, unsigned ix, int create) if (!create) return NULL; - /* The partition slot is only needed when we're a named - module. */ - bool partition_slot = named_module_p (); + /* The partition slot is always needed, in case we have imported + temploid friends with attachment different from the module we + imported them from. */ + bool partition_slot = true; unsigned want = ((BINDING_SLOTS_FIXED + partition_slot + (create < 0) + BINDING_VECTOR_SLOTS_PER_CLUSTER - 1) / BINDING_VECTOR_SLOTS_PER_CLUSTER); @@ -937,7 +938,6 @@ name_lookup::search_namespace_only (tree scope) stat_hack, then everything was exported. */ tree type = NULL_TREE; - /* If STAT_HACK_P is false, everything is visible, and there's no duplication possibilities. */ if (STAT_HACK_P (bind)) @@ -947,9 +947,9 @@ name_lookup::search_namespace_only (tree scope) /* Do we need to engage deduplication? */ int dup = 0; if (MODULE_BINDING_GLOBAL_P (bind)) - dup = 1; - else if (MODULE_BINDING_PARTITION_P (bind)) - dup = 2; + dup |= 1; + if (MODULE_BINDING_PARTITION_P (bind)) + dup |= 2; if (unsigned hit = dup_detect & dup) { if ((hit & 1 && BINDING_VECTOR_GLOBAL_DUPS_P (val)) @@ -1275,9 +1275,9 @@ name_lookup::adl_namespace_fns (tree scope, bitmap imports) /* Do we need to engage deduplication? */ int dup = 0; if (MODULE_BINDING_GLOBAL_P (bind)) - dup = 1; - else if (MODULE_BINDING_PARTITION_P (bind)) - dup = 2; + dup |= 1; + if (MODULE_BINDING_PARTITION_P (bind)) + dup |= 2; if (unsigned hit = dup_detect & dup) if ((hit & 1 && BINDING_VECTOR_GLOBAL_DUPS_P (val)) || (hit & 2 @@ -3758,6 +3758,9 @@ check_module_override (tree decl, tree mvec, bool hiding, binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (mvec); unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (mvec); + tree nontmpl = STRIP_TEMPLATE (decl); + bool attached = DECL_LANG_SPECIFIC (nontmpl) && DECL_MODULE_ATTACH_P (nontmpl); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) { cluster++; @@ -3819,7 +3822,7 @@ check_module_override (tree decl, tree mvec, bool hiding, { /* Look in the appropriate mergeable decl slot. */ tree mergeable = NULL_TREE; - if (named_module_p ()) + if (attached) mergeable = BINDING_VECTOR_CLUSTER (mvec, BINDING_SLOT_PARTITION / BINDING_VECTOR_SLOTS_PER_CLUSTER) .slots[BINDING_SLOT_PARTITION % BINDING_VECTOR_SLOTS_PER_CLUSTER]; @@ -3839,15 +3842,13 @@ check_module_override (tree decl, tree mvec, bool hiding, matched: if (match != error_mark_node) { - if (named_module_p ()) + if (attached) BINDING_VECTOR_PARTITION_DUPS_P (mvec) = true; else BINDING_VECTOR_GLOBAL_DUPS_P (mvec) = true; } return match; - - } /* Record DECL as belonging to the current lexical scope. Check for @@ -4300,7 +4301,9 @@ walk_module_binding (tree binding, bitmap partitions, cluster++; } - bool maybe_dups = BINDING_VECTOR_PARTITION_DUPS_P (binding); + /* There could be duplicate module or GMF entries. */ + bool maybe_dups = (BINDING_VECTOR_PARTITION_DUPS_P (binding) + || BINDING_VECTOR_GLOBAL_DUPS_P (binding)); for (; ix--; cluster++) for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) @@ -4394,14 +4397,14 @@ import_module_binding (tree ns, tree name, unsigned mod, unsigned snum) } /* An import of MODULE is binding NS::NAME. There should be no - existing binding for >= MODULE. MOD_GLOB indicates whether MODULE - is a header_unit (-1) or part of the current module (+1). VALUE - and TYPE are the value and type bindings. VISIBLE are the value - bindings being exported. */ + existing binding for >= MODULE. GLOBAL_P indicates whether the + bindings include global module entities. PARTITION_P is true if + it is part of the current module. VALUE and TYPE are the value + and type bindings. VISIBLE are the value bindings being exported. */ bool -set_module_binding (tree ns, tree name, unsigned mod, int mod_glob, - tree value, tree type, tree visible) +set_module_binding (tree ns, tree name, unsigned mod, bool global_p, + bool partition_p, tree value, tree type, tree visible) { if (!value) /* Bogus BMIs could give rise to nothing to bind. */ @@ -4419,19 +4422,19 @@ set_module_binding (tree ns, tree name, unsigned mod, int mod_glob, return false; tree bind = value; - if (type || visible != bind || mod_glob) + if (type || visible != bind || partition_p || global_p) { bind = stat_hack (bind, type); STAT_VISIBLE (bind) = visible; - if ((mod_glob > 0 && TREE_PUBLIC (ns)) + if ((partition_p && TREE_PUBLIC (ns)) || (type && DECL_MODULE_EXPORT_P (type))) STAT_TYPE_VISIBLE_P (bind) = true; } - /* Note if this is this-module or global binding. */ - if (mod_glob > 0) + /* Note if this is this-module and/or global binding. */ + if (partition_p) MODULE_BINDING_PARTITION_P (bind) = true; - else if (mod_glob < 0) + if (global_p) MODULE_BINDING_GLOBAL_P (bind) = true; *mslot = bind; @@ -4540,10 +4543,8 @@ lookup_imported_hidden_friend (tree friend_tmpl) || !DECL_MODULE_IMPORT_P (inner)) return NULL_TREE; - /* Imported temploid friends are not considered as attached to this - module for merging purposes. */ - tree bind = get_mergeable_namespace_binding (current_namespace, - DECL_NAME (inner), false); + tree bind = get_mergeable_namespace_binding + (current_namespace, DECL_NAME (inner), DECL_MODULE_ATTACH_P (inner)); if (!bind) return NULL_TREE; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 5cf6ae6374a..7c4193444dd 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -484,7 +484,7 @@ extern tree lookup_class_binding (tree ctx, tree name); extern bool import_module_binding (tree ctx, tree name, unsigned mod, unsigned snum); extern bool set_module_binding (tree ctx, tree name, unsigned mod, - int mod_glob_flag, + bool global_p, bool partition_p, tree value, tree type, tree visible); extern void add_module_namespace_decl (tree ns, tree decl); diff --git a/gcc/testsuite/g++.dg/modules/ambig-2_a.C b/gcc/testsuite/g++.dg/modules/ambig-2_a.C new file mode 100644 index 00000000000..d5dcc93584a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/ambig-2_a.C @@ -0,0 +1,7 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi A } + +export module A; + +extern "C++" int foo (); +extern "C++" char bar (); diff --git a/gcc/testsuite/g++.dg/modules/ambig-2_b.C b/gcc/testsuite/g++.dg/modules/ambig-2_b.C new file mode 100644 index 00000000000..b94416aabbf --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/ambig-2_b.C @@ -0,0 +1,10 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi !B } + +export module B; +import A; + +extern "C++" int foo (); +extern "C++" int bar (); // { dg-error "ambiguating new declaration" } + +// { dg-prune-output "not writing module" } diff --git a/gcc/testsuite/g++.dg/modules/part-9_a.C b/gcc/testsuite/g++.dg/modules/part-9_a.C new file mode 100644 index 00000000000..dc033d301ee --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/part-9_a.C @@ -0,0 +1,10 @@ +// PR c++/114950 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M:a } + +module M:a; + +struct A {}; +extern "C++" struct B {}; +void f(int) {} +extern "C++" void f(double) {} diff --git a/gcc/testsuite/g++.dg/modules/part-9_b.C b/gcc/testsuite/g++.dg/modules/part-9_b.C new file mode 100644 index 00000000000..7339da22d97 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/part-9_b.C @@ -0,0 +1,10 @@ +// PR c++/114950 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M:b } + +module M:b; + +struct A {}; +extern "C++" struct B {}; +void f(int) {} +extern "C++" void f(double) {} diff --git a/gcc/testsuite/g++.dg/modules/part-9_c.C b/gcc/testsuite/g++.dg/modules/part-9_c.C new file mode 100644 index 00000000000..26ac6777b7a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/part-9_c.C @@ -0,0 +1,8 @@ +// PR c++/114950 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M } +// Handle merging definitions of extern "C++" decls across partitions + +export module M; +import :a; +import :b; diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-13_e.C b/gcc/testsuite/g++.dg/modules/tpl-friend-13_e.C index afbd0a39c23..b32fd98b756 100644 --- a/gcc/testsuite/g++.dg/modules/tpl-friend-13_e.C +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-13_e.C @@ -1,8 +1,8 @@ // { dg-additional-options "-fmodules-ts" } // 'import X' does not correctly notice that S has already been declared. -struct S {}; // { dg-message "previously declared" "" { xfail *-*-* } } -template <typename> struct T {}; // { dg-message "previously declared" } +struct S {}; // { dg-message "previous declaration" "" { xfail *-*-* } } +template <typename> struct T {}; // { dg-message "previous declaration" } void f() {} // { dg-message "previously declared" } template <typename T> void g() {} // { dg-message "previously declared" } diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-15.h b/gcc/testsuite/g++.dg/modules/tpl-friend-15.h new file mode 100644 index 00000000000..e4d3fff4445 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-15.h @@ -0,0 +1,11 @@ +// PR c++/114950 + +template <typename T> +struct A { + friend void x(); +}; +template <typename T> +struct B { + virtual void f() { A<T> r; } +}; +template struct B<int>; diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-15_a.C b/gcc/testsuite/g++.dg/modules/tpl-friend-15_a.C new file mode 100644 index 00000000000..04c800875f4 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-15_a.C @@ -0,0 +1,8 @@ +// PR c++/114950 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M:a } + +module M:a; +extern "C++" { + #include "tpl-friend-15.h" +} diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-15_b.C b/gcc/testsuite/g++.dg/modules/tpl-friend-15_b.C new file mode 100644 index 00000000000..781882f97bc --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-15_b.C @@ -0,0 +1,8 @@ +// PR c++/114950 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M:b } + +module M:b; +extern "C++" { + #include "tpl-friend-15.h" +} diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-15_c.C b/gcc/testsuite/g++.dg/modules/tpl-friend-15_c.C new file mode 100644 index 00000000000..ced7e87d993 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-15_c.C @@ -0,0 +1,7 @@ +// PR c++/114950 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M } + +export module M; +import :a; +import :b; -- 2.43.2