@@ -3570,6 +3570,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
unsigned, unsigned *crc_ptr);
bool read_namespaces (unsigned);
+ void intercluster_seed (trees_out &sec, unsigned index, depset *dep);
unsigned write_cluster (elf_out *to, depset *depsets[], unsigned size,
depset::hash &, unsigned *counts, unsigned *crc_ptr);
bool read_cluster (unsigned snum);
@@ -8548,8 +8549,7 @@ trees_out::decl_node (tree decl, walk_kind ref)
gcc_checking_assert (index == ~import_entity_index (decl));
#if CHECKING_P
- if (importedness)
- gcc_assert (!import == (importedness < 0));
+ gcc_assert (!import || importedness >= 0);
#endif
i (tt_entity);
u (import);
@@ -14419,7 +14419,33 @@ enum ct_bind_flags
cbf_wrapped = 0x8, /* ... that is wrapped. */
};
-/* Write the cluster of depsets in SCC[0-SIZE). */
+/* DEP belongs to a different cluster, seed it to prevent
+ unfortunately timed duplicate import. */
+// FIXME: QOI For inter-cluster references we could just only pick
+// one entity from an earlier cluster. Even better track
+// dependencies between earlier clusters
+
+void
+module_state::intercluster_seed (trees_out &sec, unsigned index_hwm, depset *dep)
+{
+ if (dep->is_import ()
+ || dep->cluster < index_hwm)
+ {
+ tree ent = dep->get_entity ();
+ if (!TREE_VISITED (ent))
+ {
+ sec.tree_node (ent);
+ dump (dumper::CLUSTER)
+ && dump ("Seeded %s %N",
+ dep->is_import () ? "import" : "intercluster", ent);
+ }
+ }
+}
+
+/* Write the cluster of depsets in SCC[0-SIZE).
+ dep->section -> section number
+ dep->cluster -> entity number
+ */
unsigned
module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
@@ -14431,6 +14457,7 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
trees_out sec (to, this, table, table.section);
sec.begin ();
+ unsigned index_lwm = counts[MSC_entities];
/* Determine entity numbers, mark for writing. */
dump (dumper::CLUSTER) && dump ("Cluster members:") && (dump.indent (), true);
@@ -14484,10 +14511,10 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
}
dump (dumper::CLUSTER) && (dump.outdent (), true);
- /* Ensure every imported decl is referenced before we start
- streaming. This ensures that we never encounter the situation
- where this cluster instantiates some implicit member that
- importing some other decl causes to be instantiated. */
+ /* Ensure every out-of-cluster decl is referenced before we start
+ streaming. We must do both imports *and* earlier clusters,
+ because the latter could reach into the former and cause a
+ duplicate loop. */
sec.set_importing (+1);
for (unsigned ix = 0; ix != size; ix++)
{
@@ -14505,30 +14532,14 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
depset *bind = dep->deps[ix];
if (bind->get_entity_kind () == depset::EK_USING)
bind = bind->deps[1];
- if (bind->is_import ())
- {
- tree import = bind->get_entity ();
- if (!TREE_VISITED (import))
- {
- sec.tree_node (import);
- dump (dumper::CLUSTER)
- && dump ("Seeded import %N", import);
- }
- }
+
+ intercluster_seed (sec, index_lwm, bind);
}
/* Also check the namespace itself. */
dep = dep->deps[0];
}
- if (dep->is_import ())
- {
- tree import = dep->get_entity ();
- if (!TREE_VISITED (import))
- {
- sec.tree_node (import);
- dump (dumper::CLUSTER) && dump ("Seeded import %N", import);
- }
- }
+ intercluster_seed (sec, index_lwm, dep);
}
}
sec.tree_node (NULL_TREE);
@@ -17,8 +17,8 @@ int main ()
// { dg-final { scan-lang-dump-times {Reading 1 initializers} 2 module } }
-// { dg-final { scan-lang-dump {Read:-1's named merge key \(new\) var_decl:'::var'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(new\) var_decl:'::var'} module } }
// { dg-final { scan-lang-dump-times {Reading definition var_decl '::var@[^\n]*/hdr-init-1_a.H:1'} 2 module } }
-// { dg-final { scan-lang-dump {Read:-1's named merge key \(matched\) var_decl:'::var'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) var_decl:'::var'} module } }
@@ -19,6 +19,6 @@ int main ()
// { dg-final { scan-lang-dump-not {Instantiation:-[0-9]* function_decl:'::foo::X@foo:.::frob@.()<0x0>'} module } }
// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::toto'@'bar' section:} module } }
-// { dg-final { scan-lang-dump {>Loading entity foo\[1\] section:1} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[.\] section:1} module } }
// { dg-final { scan-lang-dump {Imported:-[0-9]* template_decl:'::foo@foo:.::template TPL@foo:.'@foo} module } }
// { dg-final { scan-lang-dump {Reading definition type_decl '::foo@foo:.::TPL@bar:.<0x0>'} module } }
@@ -10,7 +10,7 @@ int main ()
}
// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::quux'@'bar' section:} module } }
-// { dg-final { scan-lang-dump {>Loading entity foo\[2\] section:1} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[.\] section:1} module } }
// { dg-final { scan-lang-dump {Imported:-[0-9]* template_decl:'::foo@foo:.::template TPL@foo:.'@foo} module } }
// { dg-final { scan-lang-dump {Reading definition function_decl '::foo@foo:.::TPL@bar:.<0x1>::frob@bar:.<0x2>'} module } }
@@ -4,6 +4,6 @@
import "lambda-3_a.H";
// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
-// { dg-final { scan-lang-dump {Read -1\[0\] matched attached decl '::template ._anon_0<#unnamed#>'} module } }
-// { dg-final { scan-lang-dump {Read -1\[0\] matched attached decl '::._anon_2'} module } }
-// { dg-final { scan-lang-dump {Read -1\[0\] matched attached decl '::._anon_1'} module } }
+// { dg-final { scan-lang-dump {Read -[0-9]*\[0\] matched attached decl '::template ._anon_0<#unnamed#>'} module } }
+// { dg-final { scan-lang-dump {Read -[0-9]*\[0\] matched attached decl '::._anon_2'} module } }
+// { dg-final { scan-lang-dump {Read -[0-9]*\[0\] matched attached decl '::._anon_1'} module } }
@@ -19,4 +19,4 @@ int main ()
return 0;
}
-// { dg-final { scan-lang-dump {Read:-1's named merge key \(matched\) template_decl:'::template Foo'\n Deduping '::template Foo@[^\n]*/late-ret-3_a.H:.'\n} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::template Foo'\n Deduping '::template Foo@[^\n]*/late-ret-3_a.H:.'\n} module } }
new file mode 100644
@@ -0,0 +1,23 @@
+template<bool, typename, typename>
+struct conditional;
+
+template<typename> struct incrementable_traits;
+
+template<typename _Iter, typename _Tp>
+struct __iter_traits_impl;
+
+class __max_diff_type;
+
+template<typename _Iter>
+concept weakly_incrementable
+ = __is_same (__iter_traits_impl<_Iter, incrementable_traits<_Iter>>,
+ __max_diff_type);
+
+template<typename _Iterator>
+class reverse_iterator
+{
+public:
+ using iterator_concept
+ = typename conditional<weakly_incrementable<_Iterator>,
+ int, int>::type;
+};
new file mode 100644
@@ -0,0 +1,33 @@
+// { dg-additional-options {-std=c++2a -fmodule-header} }
+// { dg-module-cmi {}
+
+#include "pr99283-6.h"
+
+template<typename _IteratorL, typename _IteratorR>
+constexpr bool
+ operator<(const reverse_iterator<_IteratorL>& __x,
+ const reverse_iterator<_IteratorR>& __y);
+
+template<typename _Tp>
+ struct numeric_limits;
+
+class __max_size_type
+{
+public:
+ template<typename _Tp>
+ constexpr
+ __max_size_type(_Tp __i) noexcept
+ : _M_val(__i), _M_msb(__i < 0)
+ { }
+
+ using __rep = __UINT64_TYPE__;
+private:
+ __rep _M_val = 0;
+ unsigned _M_msb:1 = 0;
+};
+
+class __max_diff_type
+{
+private:
+ __max_size_type _M_rep = 0;
+};
new file mode 100644
@@ -0,0 +1,164 @@
+// { dg-additional-options {-std=c++2a -fmodule-header} }
+// { dg-module-cmi {}
+
+#include "pr99283-6.h"
+
+template<typename _Tp>
+void __addressof(_Tp& __r) ;
+
+template<typename _Tp, _Tp __v>
+struct integral_constant
+{
+ static constexpr _Tp value = __v;
+};
+
+template<typename _Tp, _Tp __v>
+constexpr _Tp integral_constant<_Tp, __v>::value;
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+template<typename _B1, typename _B2>
+struct __and_
+ : public conditional<_B1::value, _B2, _B1>::type
+{ };
+
+template<typename _From, typename _To>
+struct is_convertible
+ : public true_type
+{ };
+
+template<bool, typename _Tp = void>
+struct enable_if
+{ };
+
+template<typename _Tp>
+struct enable_if<true, _Tp>
+{ typedef _Tp type; };
+
+template<bool _Cond, typename _Tp = void>
+using __enable_if_t = typename enable_if<_Cond, _Tp>::type;
+
+template<typename A, typename B>
+using _Require = __enable_if_t<__and_<A, B>::value>;
+
+template<bool _Cond, typename _Iftrue, typename _Iffalse>
+struct conditional
+{ typedef _Iftrue type; };
+
+template<typename> struct iterator_traits;
+
+
+template<typename _IteratorL, typename _IteratorR>
+constexpr bool
+ operator!=(const reverse_iterator<_IteratorL>& __x,
+ const reverse_iterator<_IteratorR>& __y);
+
+typedef __INT64_TYPE__ int64_t;
+typedef int64_t intmax_t;
+
+template<intmax_t _Num>
+struct ratio
+{
+};
+
+namespace chrono
+{
+template<typename _Rep>
+struct duration;
+
+template<typename _ToDur, typename _Rep>
+constexpr _ToDur
+ duration_cast(const duration<_Rep>& __d)
+{
+ typedef typename _ToDur::rep __to_rep;
+ return _ToDur(static_cast<__to_rep>(static_cast<intmax_t>(__d.count())));
+}
+
+template<typename _Rep>
+struct duration
+{
+
+public:
+ using rep = _Rep;
+
+ constexpr duration() = default;
+
+ duration(const duration&) = default;
+
+ template<typename _Rep2, typename
+ = _Require<is_convertible<const _Rep2&, rep>,
+ true_type>>
+ constexpr explicit duration(const _Rep2& __rep)
+ : __r (__rep) {}
+
+ ~duration() = default;
+ duration& operator=(const duration&) = default;
+
+ rep count() const;
+
+private:
+ rep __r;
+};
+
+using seconds = duration<int64_t>;
+
+template<typename _Clock, typename _Dur>
+struct time_point
+{
+ typedef _Dur duration;
+
+ duration time_since_epoch() const;
+
+private:
+ duration __d;
+};
+
+struct system_clock
+{
+ typedef chrono::seconds duration;
+
+ typedef chrono::time_point<system_clock, duration> time_point;
+
+ static void
+ to_time_t(const time_point& __t) noexcept
+ {
+ duration_cast<chrono::seconds>
+ (__t.time_since_epoch()).count();
+ }
+};
+
+}
+
+template<typename>
+class allocator;
+
+template<typename _ForwardIterator>
+constexpr void
+ __destroy(_ForwardIterator __first, _ForwardIterator __last)
+{
+ for (; __first != __last; ++__first)
+ __addressof (*__first);
+}
+
+template<typename _Alloc>
+struct allocator_traits
+{
+private:
+ template<typename _Alloc2, typename _Tp>
+ static constexpr void
+ _S_destroy(_Alloc2&, _Tp* __p, ...)
+ noexcept
+ {
+ __destroy(__p);
+ }
+};
+
+template<typename _Tp>
+struct allocator_traits<allocator<_Tp>>
+{
+ using value_type = _Tp;
+ using pointer = _Tp*;
+};
+
+import "pr99283-6_a.H";
new file mode 100644
@@ -0,0 +1,10 @@
+// { dg-additional-options {-std=c++2a -fmodules-ts} }
+
+import "pr99283-6_b.H";
+
+template<typename _Alloc>
+struct __allocated_ptr
+{
+ using value_type = allocator_traits<_Alloc>;
+};
+
@@ -15,5 +15,5 @@ inline void widget (Cont parm)
ssize (parm);
}
-// { dg-final { scan-lang-dump {Read:-[0-9]*'s alias spec merge key \(new\) type_decl:'::make_signed_t'\n ... Read:-[0-9]*'s type spec merge key \(new\) type_decl:'::make_signed'\n Read:-1's named merge key \(matched\) template_decl:'::template ssize'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s alias spec merge key \(new\) type_decl:'::make_signed_t'\n ... Read:-[0-9]*'s type spec merge key \(new\) type_decl:'::make_signed'\n Read:-[0-9]*'s named merge key \(matched\) template_decl:'::template ssize'} module } }
@@ -7,5 +7,5 @@ void frob (Cont parm)
ssize (parm);
}
-// { dg-final { scan-lang-dump {Read:-1's named merge key \(new\) template_decl:'::template ssize'} module } }
-// { dg-final { scan-lang-dump {Read:-1's named merge key \(matched\) template_decl:'::template ssize'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(new\) template_decl:'::template ssize'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::template ssize'} module } }