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:
|| !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)
{
&& 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 ());
}
}
}
- 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;
{
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])
{
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 ();
}
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)
{
}
}
- 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);
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;
case NAMESPACE_DECL:
if (is_attached
+ && !is_imported_temploid_friend
&& !(state->is_module () || state->is_partition ()))
kind = "unique";
else
break;
case TYPE_DECL:
+ gcc_checking_assert (!is_imported_temploid_friend);
if (is_attached && !(state->is_module () || state->is_partition ())
/* Implicit member functions can come from
anywhere. */
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. */
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. */
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 ();
}
{
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
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);
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))
/* 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))
/* 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
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++;
{
/* 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];
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
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++)
}
/* 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. */
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;
|| !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;
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);
--- /dev/null
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi A }
+
+export module A;
+
+extern "C++" int foo ();
+extern "C++" char bar ();
--- /dev/null
+// { 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" }
--- /dev/null
+// 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) {}
--- /dev/null
+// 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) {}
--- /dev/null
+// 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;
// { 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" }
--- /dev/null
+// 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>;
--- /dev/null
+// PR c++/114950
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M:a }
+
+module M:a;
+extern "C++" {
+ #include "tpl-friend-15.h"
+}
--- /dev/null
+// PR c++/114950
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M:b }
+
+module M:b;
+extern "C++" {
+ #include "tpl-friend-15.h"
+}
--- /dev/null
+// PR c++/114950
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+export module M;
+import :a;
+import :b;