aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/module.cc88
-rw-r--r--gcc/testsuite/g++.dg/modules/late-ret-4_a.H22
-rw-r--r--gcc/testsuite/g++.dg/modules/late-ret-4_b.C4
3 files changed, 89 insertions, 25 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 9323023..dde7e5f 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2336,6 +2336,8 @@ private:
entity. */
DB_IMPORTED_BIT, /* An imported entity. */
DB_UNREACHED_BIT, /* A yet-to-be reached entity. */
+ DB_MAYBE_RECURSIVE_BIT, /* An entity maybe in a recursive cluster. */
+ DB_ENTRY_BIT, /* The first reached recursive dep. */
DB_HIDDEN_BIT, /* A hidden binding. */
/* The following bits are not independent, but enumerating them is
awkward. */
@@ -2437,6 +2439,14 @@ public:
{
return get_flag_bit<DB_HIDDEN_BIT> ();
}
+ bool is_maybe_recursive () const
+ {
+ return get_flag_bit<DB_MAYBE_RECURSIVE_BIT> ();
+ }
+ bool is_entry () const
+ {
+ return get_flag_bit<DB_ENTRY_BIT> ();
+ }
bool is_type_spec () const
{
return get_flag_bit<DB_TYPE_SPEC_BIT> ();
@@ -2548,11 +2558,12 @@ public:
depset *current; /* Current depset being depended. */
unsigned section; /* When writing out, the section. */
bool reached_unreached; /* We reached an unreached entity. */
+ bool writing_merge_key; /* We're writing merge key information. */
public:
hash (size_t size, hash *c = NULL)
: parent (size), chain (c), current (NULL), section (0),
- reached_unreached (false)
+ reached_unreached (false), writing_merge_key (false)
{
worklist.create (size);
}
@@ -7934,21 +7945,24 @@ trees_out::decl_value (tree decl, depset *dep)
/* Stream the container, we want it correctly canonicalized before
we start emitting keys for this decl. */
tree container = decl_container (decl);
-
unsigned tpl_levels = 0;
- if (decl != inner)
- tpl_header (decl, &tpl_levels);
- if (TREE_CODE (inner) == FUNCTION_DECL)
- fn_parms_init (inner);
- /* Now write out the merging information, and then really
- install the tag values. */
- key_mergeable (tag, mk, decl, inner, container, dep);
+ {
+ auto wmk = make_temp_override (dep_hash->writing_merge_key, true);
+ if (decl != inner)
+ tpl_header (decl, &tpl_levels);
+ if (TREE_CODE (inner) == FUNCTION_DECL)
+ fn_parms_init (inner);
- if (streaming_p ())
- dump (dumper::MERGE)
- && dump ("Wrote:%d's %s merge key %C:%N", tag,
- merge_kind_name[mk], TREE_CODE (decl), decl);
+ /* Now write out the merging information, and then really
+ install the tag values. */
+ key_mergeable (tag, mk, decl, inner, container, dep);
+
+ if (streaming_p ())
+ dump (dumper::MERGE)
+ && dump ("Wrote:%d's %s merge key %C:%N", tag,
+ merge_kind_name[mk], TREE_CODE (decl), decl);
+ }
if (TREE_CODE (inner) == FUNCTION_DECL)
fn_parms_fini (inner);
@@ -13106,6 +13120,17 @@ depset::hash::add_dependency (depset *dep)
dep->deps.safe_push (current);
}
+ /* If two dependencies recursively depend on each other existing within
+ their own merge keys, we must ensure that the first dep we saw while
+ walking is written first in this cluster. See sort_cluster for more
+ details. */
+ if (writing_merge_key)
+ {
+ dep->set_flag_bit<DB_MAYBE_RECURSIVE_BIT> ();
+ if (!current->is_maybe_recursive ())
+ current->set_flag_bit<DB_ENTRY_BIT> ();
+ }
+
if (dep->is_unreached ())
{
/* The dependency is reachable now. */
@@ -14117,7 +14142,7 @@ sort_cluster (depset::hash *original, depset *scc[], unsigned size)
table.find_dependencies (nullptr);
- vec<depset *> order = table.connect ();
+ auto_vec<depset *> order = table.connect ();
gcc_checking_assert (order.length () == use_lwm);
/* Now rewrite entries [0,lwm), in the dependency order we
@@ -14134,26 +14159,39 @@ sort_cluster (depset::hash *original, depset *scc[], unsigned size)
from Foo's declaration, so we only need to treat Foo as mergable
(We'll do structural comparison of TPL<decltype (arg)>).
- Finding the single cluster entry dep is very tricky and
- expensive. Let's just not do that. It's harmless in this case
- anyway. */
- unsigned pos = 0;
+ We approximate finding the single cluster entry dep by checking for
+ entities recursively depending on a dep first seen when streaming
+ its own merge key; the first dep we see in such a cluster should be
+ the first one streamed. */
+ unsigned entry_pos = ~0u;
unsigned cluster = ~0u;
for (unsigned ix = 0; ix != order.length (); ix++)
{
gcc_checking_assert (order[ix]->is_special ());
+ bool tight = order[ix]->cluster == cluster;
depset *dep = order[ix]->deps[0];
- scc[pos++] = dep;
dump (dumper::MERGE)
- && dump ("Mergeable %u is %N%s", ix, dep->get_entity (),
- order[ix]->cluster == cluster ? " (tight)" : "");
+ && dump ("Mergeable %u is %N%s%s", ix, dep->get_entity (),
+ tight ? " (tight)" : "", dep->is_entry () ? " (entry)" : "");
+ scc[ix] = dep;
+ if (tight)
+ {
+ gcc_checking_assert (dep->is_maybe_recursive ());
+ if (dep->is_entry ())
+ {
+ /* There should only be one entry dep in a cluster. */
+ gcc_checking_assert (!scc[entry_pos]->is_entry ());
+ gcc_checking_assert (scc[entry_pos]->is_maybe_recursive ());
+ scc[ix] = scc[entry_pos];
+ scc[entry_pos] = dep;
+ }
+ }
+ else
+ entry_pos = ix;
cluster = order[ix]->cluster;
}
- gcc_checking_assert (pos == use_lwm);
-
- order.release ();
- dump (dumper::MERGE) && dump ("Ordered %u keys", pos);
+ dump (dumper::MERGE) && dump ("Ordered %u keys", order.length ());
dump.outdent ();
}
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-4_a.H b/gcc/testsuite/g++.dg/modules/late-ret-4_a.H
new file mode 100644
index 0000000..80c8214
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-4_a.H
@@ -0,0 +1,22 @@
+// PR c++/116317
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi {} }
+
+template <typename T> using element_t = int;
+
+template <typename B>
+struct reverse_adaptor {
+ void pairwise();
+
+ template <typename T>
+ auto first(T self) -> element_t<decltype(self)>;
+
+ // We can get the same issue with function parameters
+ template <typename T>
+ void second(T self, element_t<decltype(self)> second);
+};
+
+template <typename B>
+void reverse_adaptor<B>::pairwise() {
+ reverse_adaptor<int>{};
+}
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-4_b.C b/gcc/testsuite/g++.dg/modules/late-ret-4_b.C
new file mode 100644
index 0000000..f9a83ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-4_b.C
@@ -0,0 +1,4 @@
+// PR c++/116317
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+import "late-ret-4_a.H";