diff --git a/gcc/testsuite/g++.dg/modules/access-1_a.C b/gcc/testsuite/g++.dg/modules/access-1_a.C
new file mode 100644
index 00000000000..241701728a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/access-1_a.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Foo;
+// { dg-module-cmi Foo }
+
+export class Base
+{
+public:
+ int m;
+};
diff --git a/gcc/testsuite/g++.dg/modules/access-1_b.C b/gcc/testsuite/g++.dg/modules/access-1_b.C
new file mode 100644
index 00000000000..454dea5332f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/access-1_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Bar;
+// { dg-module-cmi Bar }
+
+import Foo;
+
+export class Derived : public Base
+{
+private:
+ using Base::m;
+};
diff --git a/gcc/testsuite/g++.dg/modules/access-1_c.C b/gcc/testsuite/g++.dg/modules/access-1_c.C
new file mode 100644
index 00000000000..27b84c2ce1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/access-1_c.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+import Bar;
+import Foo;
+
+void foo (Derived *d)
+{
+ d->m = 1; // { dg-error "inaccessible within this context" }
+ static_cast (d)->m = 1; //ok
+}
diff --git a/gcc/testsuite/g++.dg/modules/adhoc-1_a.C b/gcc/testsuite/g++.dg/modules/adhoc-1_a.C
new file mode 100644
index 00000000000..50067acbf13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adhoc-1_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi bob }
+
+export module bob;
+export int massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea (int);
+ export void massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea (float);
diff --git a/gcc/testsuite/g++.dg/modules/adhoc-1_b.C b/gcc/testsuite/g++.dg/modules/adhoc-1_b.C
new file mode 100644
index 00000000000..59907a01d20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adhoc-1_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts -fdiagnostics-show-caret" }
+
+import bob;
+void foo ()
+{
+ massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea ();
+}
+
+// { dg-regexp "\n\[^\n]*adhoc-1_b.C:6:74: error: no matching function for call to 'massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea\\(\\)'\n massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea \\(\\);\n \\^$" }
+// { dg-regexp "\nIn module bob, imported at \[^\n]*adhoc-1_b.C:3:\n\[^\n]*adhoc-1_a.C:5:12: note: candidate: 'int massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea@bob\\(int\\)'\n export int massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea \\(int\\);\n \\^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~$" }
+// { dg-regexp "\nIn module bob, imported at \[^\n]*adhoc-1_b.C:3:\n\[^\n]*adhoc-1_a.C:6:188: note: candidate: 'void massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea@bob\\(float\\)'\n\[ \t]*export void massivelongnamethatcausesadhoclocationsokeepaddingcharsyourgettheidea \\(float\\);\n\[ \t]*\\^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~?$" }
+// For some reason dg-regexp inserts a blank line
+// { dg-allow-blank-lines-in-output 1 }
diff --git a/gcc/testsuite/g++.dg/modules/adl-1_a.C b/gcc/testsuite/g++.dg/modules/adl-1_a.C
new file mode 100644
index 00000000000..d4a53cb9cb2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-1_a.C
@@ -0,0 +1,13 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodules-ts }
+export module worker;
+// { dg-module-cmi worker }
+
+namespace details {
+
+export int fn (int x)
+{
+ return x;
+}
+
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-1_b.C b/gcc/testsuite/g++.dg/modules/adl-1_b.C
new file mode 100644
index 00000000000..6cf123e41fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-1_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+export module inter;
+// { dg-module-cmi inter }
+
+import worker;
+
+namespace hidden {
+export int fn (int x)
+{
+ return -x;
+}
+}
+
+export template
+int TPL (T &t)
+{
+ return fn (t);
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-1_c.C b/gcc/testsuite/g++.dg/modules/adl-1_c.C
new file mode 100644
index 00000000000..8be02e74937
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-1_c.C
@@ -0,0 +1,57 @@
+// { dg-additional-options -fmodules-ts }
+
+import inter;
+
+namespace details
+{
+
+struct X
+{
+
+ int m;
+ X (int m) : m(m)
+ {
+ }
+
+ operator int () const
+ {
+ return m;
+ }
+};
+
+}
+
+namespace hidden
+{
+
+struct Y
+{
+
+ int m;
+ Y (int m) : m(m)
+ {
+ }
+
+ operator int () const
+ {
+ return m;
+ }
+};
+
+}
+
+int main ()
+{
+ details::X x(2);
+ hidden::Y y(2);
+
+ // details::fn@worker is visible from TPL@inter
+ if (TPL (x) != 2) // instantiate TPL(T&)
+ return 1;
+
+ // hidden::fn@inter is visible from TPL@inter
+ if (TPL (y) != -2) // instantiate TPL(T&)
+ return 2;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-2_a.C b/gcc/testsuite/g++.dg/modules/adl-2_a.C
new file mode 100644
index 00000000000..d8f481cad97
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-2_a.C
@@ -0,0 +1,10 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export template
+int TPL (T const &t)
+{
+ return frob (t);
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-2_b.C b/gcc/testsuite/g++.dg/modules/adl-2_b.C
new file mode 100644
index 00000000000..60e794343ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-2_b.C
@@ -0,0 +1,21 @@
+// { dg-additional-options -fmodules-ts }
+
+export module hidden;
+// { dg-module-cmi hidden }
+
+export struct X
+{
+ int m;
+
+ X(int m) :m(m) {}
+
+ operator int () const
+ {
+ return m;
+ }
+};
+
+export int frob (int x)
+{
+ return x;
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-2_c.C b/gcc/testsuite/g++.dg/modules/adl-2_c.C
new file mode 100644
index 00000000000..9c75b6d14a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-2_c.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+import hidden;
+
+int main ()
+{
+ X x (2);
+
+ if (frob (x) != 2)
+ return 1;
+
+ if (TPL (x) != 2)
+ return 2;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-3_a.C b/gcc/testsuite/g++.dg/modules/adl-3_a.C
new file mode 100644
index 00000000000..a2639789438
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-3_a.C
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodules-ts }
+export module worker;
+// { dg-module-cmi worker }
+
+namespace details {
+
+int fn (int x)
+{
+ return x;
+}
+
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-3_b.C b/gcc/testsuite/g++.dg/modules/adl-3_b.C
new file mode 100644
index 00000000000..1f3011fdbb9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-3_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+export module inter;
+// { dg-module-cmi inter }
+
+export template
+int TPL (T &t)
+{
+ return fn (t);
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-3_c.C b/gcc/testsuite/g++.dg/modules/adl-3_c.C
new file mode 100644
index 00000000000..c4dc0adc00c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-3_c.C
@@ -0,0 +1,36 @@
+// { dg-additional-options -fmodules-ts }
+
+import inter;
+import worker;
+
+namespace details
+{
+struct X
+{
+
+ int m;
+ X (int m) : m(m)
+ {
+ }
+
+ operator int () const
+ {
+ return m;
+ }
+};
+
+}
+
+int main ()
+{
+ details::X x(2);
+
+ if (fn (x) != 2) // { dg-error "not declared in" }
+ return 1;
+
+ // { dg-regexp "\n\[^\n]*adl-3_b.C:8:13: error: 'fn' was not declared in this scope$" }
+ if (TPL (x) != 2) // { dg-message "required from here" }
+ return 2;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-4_a.C b/gcc/testsuite/g++.dg/modules/adl-4_a.C
new file mode 100644
index 00000000000..5d956c057e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-4_a.C
@@ -0,0 +1,15 @@
+// { dg-additional-options -fmodules-ts }
+export module inter;
+// { dg-module-cmi inter }
+
+namespace hidden {
+// not found via ADL
+int fn (int x);
+
+}
+
+export template
+int TPL (T &t)
+{
+ return fn (t);
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-4_b.C b/gcc/testsuite/g++.dg/modules/adl-4_b.C
new file mode 100644
index 00000000000..aa1396f7ce2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-4_b.C
@@ -0,0 +1,36 @@
+// { dg-additional-options -fmodules-ts }
+
+import inter;
+
+namespace hidden
+{
+
+struct Y
+{
+
+ int m;
+ Y (int m) : m(m)
+ {
+ }
+
+ operator int () const
+ {
+ return m;
+ }
+};
+
+}
+
+int main ()
+{
+ hidden::Y y(2);
+
+ // unexported hidden::fn@inter is not visible from TPL@inter
+ if (TPL (y) != -2)
+ return 2;
+
+ return 0;
+}
+
+// ADL fails
+// { dg-regexp {[^\n]*/adl-4_a.C:14:[0-9]*: error: 'fn' was not declared in this scope\n} }
diff --git a/gcc/testsuite/g++.dg/modules/adl-5_a.c b/gcc/testsuite/g++.dg/modules/adl-5_a.c
new file mode 100644
index 00000000000..5b8692211d4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-5_a.c
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export template
+int TPL (T const &t)
+{
+ return frob (t);
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-5_b.C b/gcc/testsuite/g++.dg/modules/adl-5_b.C
new file mode 100644
index 00000000000..3c64cd4a75e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-5_b.C
@@ -0,0 +1,22 @@
+// { dg-additional-options -fmodules-ts }
+
+export module hidden;
+// { dg-module-cmi hidden }
+
+export struct X
+{
+ int m;
+
+ X(int m) :m(m) {}
+
+ operator int () const
+ {
+ return m;
+ }
+};
+
+// Not found via any ADL outside of module hidden
+int frob (int x)
+{
+ return x;
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-5_c.C b/gcc/testsuite/g++.dg/modules/adl-5_c.C
new file mode 100644
index 00000000000..e047aec4b1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-5_c.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+
+module hidden;
+import foo;
+
+int frob ()
+{
+ X x (2);
+
+ if (frob (x) != 2)
+ return 1;
+
+ if (TPL (x) != 2)
+ return 2;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/adl-5_d.C b/gcc/testsuite/g++.dg/modules/adl-5_d.C
new file mode 100644
index 00000000000..9c75b6d14a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/adl-5_d.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+import hidden;
+
+int main ()
+{
+ X x (2);
+
+ if (frob (x) != 2)
+ return 1;
+
+ if (TPL (x) != 2)
+ return 2;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/alias-1_a.H b/gcc/testsuite/g++.dg/modules/alias-1_a.H
new file mode 100644
index 00000000000..8c5683608ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/alias-1_a.H
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodule-header -isystem [srcdir]" }
+// { dg-module-cmi {} }
+
+#ifndef ALIAS_1_A
+#define ALIAS_1_A
+
+int frob ();
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/alias-1_b.C b/gcc/testsuite/g++.dg/modules/alias-1_b.C
new file mode 100644
index 00000000000..b3d7c2df353
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/alias-1_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module -isystem [srcdir]" }
+
+// Alias at the header file. We have one CMI file
+import "alias-1_a.H";
+import ;
+
+int main ()
+{
+ frob ();
+}
+
+// { dg-final { scan-lang-dump-times {CMI is } 1 module } }
diff --git a/gcc/testsuite/g++.dg/modules/alias-1_c.C b/gcc/testsuite/g++.dg/modules/alias-1_c.C
new file mode 100644
index 00000000000..6f9f1aa06c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/alias-1_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -isystem [srcdir]" }
+// { dg-module-cmi bob }
+
+export module bob;
+import "alias-1_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/alias-1_d.C b/gcc/testsuite/g++.dg/modules/alias-1_d.C
new file mode 100644
index 00000000000..9b481e5b185
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/alias-1_d.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -isystem [srcdir]" }
+// { dg-module-cmi kevin }
+
+export module kevin;
+import ;
diff --git a/gcc/testsuite/g++.dg/modules/alias-1_e.C b/gcc/testsuite/g++.dg/modules/alias-1_e.C
new file mode 100644
index 00000000000..862ae32882f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/alias-1_e.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -isystem [srcdir]" }
+
+import bob;
+import kevin;
diff --git a/gcc/testsuite/g++.dg/modules/alias-1_f.C b/gcc/testsuite/g++.dg/modules/alias-1_f.C
new file mode 100644
index 00000000000..4c694d1a903
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/alias-1_f.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module -isystem [srcdir]" }
+
+import kevin;
+import bob;
diff --git a/gcc/testsuite/g++.dg/modules/alias-2_a.H b/gcc/testsuite/g++.dg/modules/alias-2_a.H
new file mode 100644
index 00000000000..1befe85cf49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/alias-2_a.H
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodule-header -isystem [srcdir]/sys" }
+// { dg-module-cmi {} }
+// { dg-module-headers test sys/alias-2_a.H }
+#ifndef ALIAS_2_A
+#define ALIAS_2_A
+
+int frob ();
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/alias-2_b.C b/gcc/testsuite/g++.dg/modules/alias-2_b.C
new file mode 100644
index 00000000000..00eff590e3b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/alias-2_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module -isystem [srcdir]/sys" }
+
+// These find different headers
+import "alias-2_a.H";
+import ;
+
+int main ()
+{
+ frob ();
+ frob (1);
+}
+
+// { dg-final { scan-lang-dump-times {CMI is} 2 module } }
diff --git a/gcc/testsuite/g++.dg/modules/align-type-1_a.C b/gcc/testsuite/g++.dg/modules/align-type-1_a.C
new file mode 100644
index 00000000000..71240341469
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/align-type-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export using aint = __attribute__ ((aligned(16))) int;
+
+
diff --git a/gcc/testsuite/g++.dg/modules/align-type-1_b.C b/gcc/testsuite/g++.dg/modules/align-type-1_b.C
new file mode 100644
index 00000000000..8372e6f3e1b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/align-type-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+struct B
+{
+ aint m;
+};
+
+static_assert (alignof (B) == 16);
diff --git a/gcc/testsuite/g++.dg/modules/ambig-1_a.C b/gcc/testsuite/g++.dg/modules/ambig-1_a.C
new file mode 100644
index 00000000000..fbb3db2ac47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/ambig-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+export module One;
+// { dg-module-cmi One }
+
+export int foo ();
+export char bax ();
+export int quux (float);
+
+
diff --git a/gcc/testsuite/g++.dg/modules/ambig-1_b.C b/gcc/testsuite/g++.dg/modules/ambig-1_b.C
new file mode 100644
index 00000000000..c1de9192323
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/ambig-1_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+import One;
+
+int foo (); // { dg-error "conflicts with import" }
+int bax (); // { dg-error "ambiguating new declaration" }
+int quux (int);
diff --git a/gcc/testsuite/g++.dg/modules/anon-1_a.C b/gcc/testsuite/g++.dg/modules/anon-1_a.C
new file mode 100644
index 00000000000..e56b85ce720
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/anon-1_a.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+
+export module anon;
+// { dg-module-cmi anon }
+
+export struct foo
+{
+ enum {bob};
+ union
+ {
+ int i;
+ float f;
+ };
+};
diff --git a/gcc/testsuite/g++.dg/modules/anon-1_b.C b/gcc/testsuite/g++.dg/modules/anon-1_b.C
new file mode 100644
index 00000000000..66d25053049
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/anon-1_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+
+export module namer;
+// { dg-module-cmi namer }
+
+import anon;
+
+export inline int &get_int (foo &obj)
+{
+ return obj.i;
+}
+
+export inline float &get_float (foo &obj)
+{
+ return obj.f;
+}
+
+
diff --git a/gcc/testsuite/g++.dg/modules/anon-1_c.C b/gcc/testsuite/g++.dg/modules/anon-1_c.C
new file mode 100644
index 00000000000..cbe89e15ed9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/anon-1_c.C
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodules-ts }
+
+import namer;
+import anon;
+
+int main ()
+{
+ foo obj;
+ int *ip = &get_int (obj);
+ float *fp = &get_float (obj);
+
+ return !((void *)ip == (void *)fp);
+}
diff --git a/gcc/testsuite/g++.dg/modules/anon-2.h b/gcc/testsuite/g++.dg/modules/anon-2.h
new file mode 100644
index 00000000000..81c793c7ffc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/anon-2.h
@@ -0,0 +1,6 @@
+
+
+struct __pthread_cond_s
+{
+ union {};
+};
diff --git a/gcc/testsuite/g++.dg/modules/anon-2_a.H b/gcc/testsuite/g++.dg/modules/anon-2_a.H
new file mode 100644
index 00000000000..6861c194fce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/anon-2_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "anon-2.h"
diff --git a/gcc/testsuite/g++.dg/modules/anon-2_b.C b/gcc/testsuite/g++.dg/modules/anon-2_b.C
new file mode 100644
index 00000000000..24bb61b5f14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/anon-2_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+#include "anon-2.h"
+import "anon-2_a.H";
+
diff --git a/gcc/testsuite/g++.dg/modules/atom-decl-0_a.C b/gcc/testsuite/g++.dg/modules/atom-decl-0_a.C
new file mode 100644
index 00000000000..d226f32cea1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-decl-0_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module thing;
+// { dg-module-cmi "thing" }
+
+export int baz ();
diff --git a/gcc/testsuite/g++.dg/modules/atom-decl-0_b.C b/gcc/testsuite/g++.dg/modules/atom-decl-0_b.C
new file mode 100644
index 00000000000..8ca006d64ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-decl-0_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+import thing;
+
+void bink ()
+{
+ baz ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/atom-decl-0_c.C b/gcc/testsuite/g++.dg/modules/atom-decl-0_c.C
new file mode 100644
index 00000000000..96e74956e90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-decl-0_c.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+export module pop;
+// { dg-module-cmi "pop" }
+export import thing;
+
+void bink ();
+
+void bonk ()
+{
+ baz ();
+ bink ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/atom-decl-2.C b/gcc/testsuite/g++.dg/modules/atom-decl-2.C
new file mode 100644
index 00000000000..b463dc8e214
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-decl-2.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+export module thing;
+int i;
+import baz; // { dg-error "must be contiguous" }
+
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/atom-decl-3.C b/gcc/testsuite/g++.dg/modules/atom-decl-3.C
new file mode 100644
index 00000000000..6eb6e6bd93f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-decl-3.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+int i;
+import bazza;
+// { dg-error "failed to read" "" { target *-*-* } 0 }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/modules/atom-pragma-1.C b/gcc/testsuite/g++.dg/modules/atom-pragma-1.C
new file mode 100644
index 00000000000..133382e8886
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-pragma-1.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+export module foo;
+// { dg-module-cmi foo }
+
+#pragma bob
+int i;
diff --git a/gcc/testsuite/g++.dg/modules/atom-pragma-3.C b/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
new file mode 100644
index 00000000000..b95b2c8ad75
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+
+export module foo;
+// { dg-module-cmi !foo }
+;
+
+#pragma pack(2)
+import baz; // { dg-error "must be contiguous" }
+
+int i;
+
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-1.C b/gcc/testsuite/g++.dg/modules/atom-preamble-1.C
new file mode 100644
index 00000000000..1161d41b561
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-1.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+#define EXPORT export // { dg-error "only occur after a module" }
+EXPORT module bob; // { dg-error "does not name a type" }
+// { dg-message "not recognized as" "" { target *-*-* } .-1 }
+
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C
new file mode 100644
index 00000000000..02fbd84afff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+#define malcolm kevin
+export module malcolm;
+// { dg-module-cmi kevin }
+
+export class X;
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_b.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_b.C
new file mode 100644
index 00000000000..a97d9758fd2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+#if 1
+export module bob;
+// { dg-module-cmi bob }
+#endif
+
+import kevin;
+
+X *f;
+
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_c.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_c.C
new file mode 100644
index 00000000000..d3804c2b0bc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_c.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+#pragma bob
+
+import kevin;
+
+X *f;
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C
new file mode 100644
index 00000000000..0c3b290499a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+import kevin;
+
+#if 1
+#if 1
+import kevin;
+#endif
+#elif 1
+int i;
+#endif
+
+int j; // end here
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_e.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_e.C
new file mode 100644
index 00000000000..074f8ebadb4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_e.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+import kevin;
+
+#if 0
+#if 1
+import kevin;
+#endif
+#elif 1
+import kevin;
+#endif
+
+int i; // end here
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C
new file mode 100644
index 00000000000..28e54b808b2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+export module stuart;
+// { dg-module-cmi !stuart }
+
+# 6 "atom-preamble-2_f.C" 1
+import kevin; // { dg-error "not be from header" }
+# 8 "" 2
+
+import kevin; // ok
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-3.C b/gcc/testsuite/g++.dg/modules/atom-preamble-3.C
new file mode 100644
index 00000000000..74dba7d23a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-3.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+#define import import
+import malcolm; // { dg-error "object-like macro" }
+// { dg-error "failed to read" "" { target *-*-* } 0 }
+
+// { dg-prune-output "compilation terminated" }
+// { dg-prune-output "fatal error:" }
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-4.C b/gcc/testsuite/g++.dg/modules/atom-preamble-4.C
new file mode 100644
index 00000000000..21a8d57da65
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-4.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+#define NAME(X) X;
+
+export module NAME(bob)
+
diff --git a/gcc/testsuite/g++.dg/modules/auto-1.h b/gcc/testsuite/g++.dg/modules/auto-1.h
new file mode 100644
index 00000000000..f8ae751df32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-1.h
@@ -0,0 +1,19 @@
+
+template auto frob (T t)
+{
+ return t;
+}
+
+struct Bob
+{
+ operator auto ()
+ {
+ return 0;
+ }
+};
+
+inline auto foo ()
+{
+ return frob (1) + int (Bob ());
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/auto-1_a.H b/gcc/testsuite/g++.dg/modules/auto-1_a.H
new file mode 100644
index 00000000000..4d3bc77dbb1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "auto-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/auto-1_b.C b/gcc/testsuite/g++.dg/modules/auto-1_b.C
new file mode 100644
index 00000000000..96350662fed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "auto-1.h"
+import "auto-1_a.H";
+
+int bar ()
+{
+ return foo () + frob (0u);
+}
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git a/gcc/testsuite/g++.dg/modules/auto-2.h b/gcc/testsuite/g++.dg/modules/auto-2.h
new file mode 100644
index 00000000000..4759ab8bbc1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-2.h
@@ -0,0 +1,13 @@
+
+template
+struct _RangeAdaptor
+{
+ constexpr _RangeAdaptor(const _Callable &) { }
+};
+
+template
+_RangeAdaptor(_Callable) -> _RangeAdaptor<_Callable>;
+
+template
+inline constexpr _RangeAdaptor elements = [] (auto&& __r) {};
+
diff --git a/gcc/testsuite/g++.dg/modules/auto-2_a.H b/gcc/testsuite/g++.dg/modules/auto-2_a.H
new file mode 100644
index 00000000000..46bd74697a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-2_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -fconcepts" }
+// { dg-module-cmi {} }
+
+#include "auto-2.h"
diff --git a/gcc/testsuite/g++.dg/modules/auto-2_b.C b/gcc/testsuite/g++.dg/modules/auto-2_b.C
new file mode 100644
index 00000000000..5ed882f7416
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-2_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts -fconcepts -fdump-lang-module-alias -fno-module-lazy" }
+
+#include "auto-2.h"
+import "auto-2_a.H";
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git a/gcc/testsuite/g++.dg/modules/bad-mapper-1.C b/gcc/testsuite/g++.dg/modules/bad-mapper-1.C
new file mode 100644
index 00000000000..7ed75b824b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bad-mapper-1.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=|this-will-not-work" }
+import unique1.bob;
+// { dg-error "-:failed exec.*mapper.* .*this-will-not-work" "" { target *-*-* } 0 }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "failed to read" }
+// { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/modules/bad-mapper-2.C b/gcc/testsuite/g++.dg/modules/bad-mapper-2.C
new file mode 100644
index 00000000000..f35d16bace3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bad-mapper-2.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=not-a-host:3838" }
+import unique2.bob;
+// { dg-error "failed .* mapper 'not-a-host" "" { target *-*-* } 0 }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "failed to read" }
+// { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/modules/bad-mapper-3.C b/gcc/testsuite/g++.dg/modules/bad-mapper-3.C
new file mode 100644
index 00000000000..9dab332ccb2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bad-mapper-3.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=localhost:172477262" }
+import unique3.bob;
+// { dg-error {failed connecting mapper 'localhost:172477262'} "" { target *-*-* } 0 }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "failed to read" }
+// { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/modules/ben-1.map b/gcc/testsuite/g++.dg/modules/ben-1.map
new file mode 100644
index 00000000000..182183ad089
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/ben-1.map
@@ -0,0 +1,3 @@
+$root .
+module:import partitions/module:import.mod
+module module.mod
diff --git a/gcc/testsuite/g++.dg/modules/ben-1_a.C b/gcc/testsuite/g++.dg/modules/ben-1_a.C
new file mode 100644
index 00000000000..7e9b5661026
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/ben-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=[srcdir]/ben-1.map" }
+// { dg-additional-files ben-1.map }
+
+export module module:import;
+// { dg-module-cmi =partitions/module:import.mod }
+
+export int b() {
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/ben-1_b.C b/gcc/testsuite/g++.dg/modules/ben-1_b.C
new file mode 100644
index 00000000000..e16fa2fc857
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/ben-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=[srcdir]/ben-1.map" }
+// { dg-additional-files ben-1.map }
+
+export module module;
+// { dg-module-cmi =module.mod }
+export import :import;
+
+export int c ()
+{
+ return b ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/bfield-1_a.C b/gcc/testsuite/g++.dg/modules/bfield-1_a.C
new file mode 100644
index 00000000000..15b8cb6c54a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bfield-1_a.C
@@ -0,0 +1,15 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export struct timex
+{
+ int a;
+ int :32;
+ int :32;
+ int :32;
+ int :32;
+ int :32;
+ int :32;
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/bfield-1_b.C b/gcc/testsuite/g++.dg/modules/bfield-1_b.C
new file mode 100644
index 00000000000..6c8dae6e29e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bfield-1_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodules-ts }
+import foo;
+
+timex v = {1};
diff --git a/gcc/testsuite/g++.dg/modules/bfield-2_a.C b/gcc/testsuite/g++.dg/modules/bfield-2_a.C
new file mode 100644
index 00000000000..5329e62da3d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bfield-2_a.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export struct ting
+{
+ int a;
+ int b : 3;
+ int c : 5;
+};
diff --git a/gcc/testsuite/g++.dg/modules/bfield-2_b.C b/gcc/testsuite/g++.dg/modules/bfield-2_b.C
new file mode 100644
index 00000000000..737173697c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bfield-2_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodules-ts }
+import foo;
+
+ting v = {1, 2, 3};
diff --git a/gcc/testsuite/g++.dg/modules/bool-1.h b/gcc/testsuite/g++.dg/modules/bool-1.h
new file mode 100644
index 00000000000..80f0ec161cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bool-1.h
@@ -0,0 +1,8 @@
+typedef signed char __v16qs __attribute__ ((__vector_size__ (16)));
+
+
+inline auto
+_mm_cmplt_epi8 (__v16qs __A, __v16qs __B)
+{
+ return __A < __B;
+}
diff --git a/gcc/testsuite/g++.dg/modules/bool-1_a.H b/gcc/testsuite/g++.dg/modules/bool-1_a.H
new file mode 100644
index 00000000000..3b4232c1d08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bool-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options {-fmodule-header -Wno-psabi} }
+// { dg-module-cmi {} }
+
+#include "bool-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/bool-1_b.H b/gcc/testsuite/g++.dg/modules/bool-1_b.H
new file mode 100644
index 00000000000..d22e1d93286
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bool-1_b.H
@@ -0,0 +1,5 @@
+// { dg-additional-options {-fmodule-header -fno-module-lazy -Wno-psabi} }
+// { dg-module-cmi {} }
+
+#include "bool-1.h"
+import "bool-1_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/bool-1_c.C b/gcc/testsuite/g++.dg/modules/bool-1_c.C
new file mode 100644
index 00000000000..01b08775191
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bool-1_c.C
@@ -0,0 +1,8 @@
+// { dg-additional-options {-fmodules-ts -Wno-psabi} }
+
+import "bool-1_b.H";
+
+void frob (signed char __attribute__ ((__vector_size__ (16))) arg)
+{
+ _mm_cmplt_epi8 (arg, arg);
+}
diff --git a/gcc/testsuite/g++.dg/modules/bug-1_a.C b/gcc/testsuite/g++.dg/modules/bug-1_a.C
new file mode 100644
index 00000000000..b828b7b8bc6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bug-1_a.C
@@ -0,0 +1,9 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module One;
+// { dg-module-cmi "One" }
+
+export int Frob (int a)
+{
+ return -a;
+}
diff --git a/gcc/testsuite/g++.dg/modules/bug-1_b.C b/gcc/testsuite/g++.dg/modules/bug-1_b.C
new file mode 100644
index 00000000000..7b5baeb9276
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/bug-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+import One;
+
+int main ()
+{
+ if (Frob (2) != -2)
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/builtin-1_a.C b/gcc/testsuite/g++.dg/modules/builtin-1_a.C
new file mode 100644
index 00000000000..6d0731a727d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-1_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-alias-uid" }
+export module builtin;
+// { dg-module-cmi builtin }
+
+export inline void ary_del (int *ptr)
+{
+ delete[] ptr;
+}
+
+export inline void scalar_del (int *ptr)
+{
+ delete ptr;
+}
+
+// { dg-final { scan-lang-dump {Wrote GMF:-[0-9]* function_decl:'::operator delete'@builtin} module } }
+// { dg-final { scan-lang-dump {Wrote GMF:-[0-9]* function_decl:'::operator delete \[\]'@builtin} module } }
+
+// { dg-final { scan-lang-dump {Writing named:-[0-9]* function_decl:'::operator delete'\n *Wrote[^\n]*\n *Writing:-[0-9]*'s named merge key \(decl\) function_decl:'::operator delete'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/builtin-1_b.C b/gcc/testsuite/g++.dg/modules/builtin-1_b.C
new file mode 100644
index 00000000000..e9f73485661
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-1_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" }
+import builtin;
+
+int main ()
+{
+ ary_del (nullptr);
+ scalar_del (nullptr);
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) function_decl:'::operator delete \[\]'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) function_decl:'::operator delete'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/builtin-2.C b/gcc/testsuite/g++.dg/modules/builtin-2.C
new file mode 100644
index 00000000000..f9de98fda9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-2.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+
+extern "C"
+{
+ extern int printf (const char *__restrict __format, ...);
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/builtin-3_b.C b/gcc/testsuite/g++.dg/modules/builtin-3_b.C
new file mode 100644
index 00000000000..93489bddba4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-3_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" }
+import builtins;
+
+int main ()
+{
+ length ("");
+ count (1, "", "", nullptr);
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) function_decl:'::__builtin_strlen'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) type_decl:'::__builtin_va_list'} module { target { x86_64-*-linux* } } } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(new\) type_decl:'::va_list'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(new\) type_decl:'::__gnuc_va_list'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/builtin-4_a.H b/gcc/testsuite/g++.dg/modules/builtin-4_a.H
new file mode 100644
index 00000000000..f7bc6aff639
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-4_a.H
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+void* operator new(__SIZE_TYPE__);
+void* operator new[](__SIZE_TYPE__);
+
+void operator delete (void*) noexcept;
+void operator delete[](void*) noexcept;
+
diff --git a/gcc/testsuite/g++.dg/modules/builtin-4_b.C b/gcc/testsuite/g++.dg/modules/builtin-4_b.C
new file mode 100644
index 00000000000..1d780e6a80f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-4_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+import "builtin-4_a.H";
+
+int main ()
+{
+ operator delete (operator new (10));
+ operator delete[] (operator new[] (10));
+}
+
+// { dg-final { scan-lang-dump {named merge key \(matched\) function_decl:'::operator new'} module } }
+// { dg-final { scan-lang-dump {named merge key \(matched\) function_decl:'::operator delete'} module } }
+// { dg-final { scan-lang-dump {named merge key \(matched\) function_decl:'::operator new \[\]'} module } }
+// { dg-final { scan-lang-dump {named merge key \(matched\) function_decl:'::operator delete \[\]'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/builtin-5_a.H b/gcc/testsuite/g++.dg/modules/builtin-5_a.H
new file mode 100644
index 00000000000..735d32388d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-5_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+extern "C" int printf (char const *, ...);
diff --git a/gcc/testsuite/g++.dg/modules/builtin-5_b.C b/gcc/testsuite/g++.dg/modules/builtin-5_b.C
new file mode 100644
index 00000000000..bfaa64f9b55
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-5_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" }
+
+import "builtin-5_a.H";
+
+void foo ()
+{
+ printf ("bob\n");
+}
+
+extern "C" int printf (char const *, int);
+
+// { dg-regexp {[^\n]*builtin-5_b.C:10:[0-9]*: error: conflicting declaration of C function 'int printf\(const char\*, int\)'\nIn module [^\n]*builtin-5_a.H, imported at [^\n]*builtin-5_b.C:3:\n[^\n]*builtin-5_a.H:3:[0-9]*: note: previous declaration 'int printf\(const char\*, ...\)'} }
+
+// { dg-final { scan-lang-dump {Read:-1's named merge key \(matched\) function_decl:'::printf'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/builtin-6_a.H b/gcc/testsuite/g++.dg/modules/builtin-6_a.H
new file mode 100644
index 00000000000..b3263bc9ba7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-6_a.H
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+extern "C" {
+
+static double sin (double)
+{
+ // extra small angle approximation :)
+ return 0.0;
+}
+
+}
diff --git a/gcc/testsuite/g++.dg/modules/builtin-6_b.C b/gcc/testsuite/g++.dg/modules/builtin-6_b.C
new file mode 100644
index 00000000000..80f8dc64a20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-6_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+
+import "builtin-6_a.H";
+
+int main ()
+{
+ return sin (0.0);
+}
diff --git a/gcc/testsuite/g++.dg/modules/builtin-7_a.H b/gcc/testsuite/g++.dg/modules/builtin-7_a.H
new file mode 100644
index 00000000000..a98a7b71092
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-7_a.H
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module_cmi {} }
+
+extern "C"
+{
+extern double nan(const char *);
+inline long double nanl(const char * __x) { return nan(__x); }
+}
diff --git a/gcc/testsuite/g++.dg/modules/builtin-7_b.C b/gcc/testsuite/g++.dg/modules/builtin-7_b.C
new file mode 100644
index 00000000000..28514571ce6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/builtin-7_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import "builtin-7_a.H";
+
+void f ()
+{
+ nanl ("");
+}
diff --git a/gcc/testsuite/g++.dg/modules/by-name-1.C b/gcc/testsuite/g++.dg/modules/by-name-1.C
new file mode 100644
index 00000000000..44eb4478d13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/by-name-1.C
@@ -0,0 +1,15 @@
+// check internals by name unless SCC
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+
+export module frob;
+// { dg-module-cmi frob }
+
+class X
+{
+ int i;
+};
+
+export X *f ();
+
+// { dg-final { scan-lang-dump {Wrote purview:-[0-9]* type_decl:'::X'} "module" } }
+// { dg-final { scan-lang-dump {Indirect:-[0-9]* decl's type record_type:'::X'} "module" } }
diff --git a/gcc/testsuite/g++.dg/modules/cexpr-1_a.C b/gcc/testsuite/g++.dg/modules/cexpr-1_a.C
new file mode 100644
index 00000000000..b9c4b1692f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cexpr-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Const;
+// { dg-module-cmi "Const" }
+
+export constexpr int SQ (int b)
+{
+ return b * b;
+}
diff --git a/gcc/testsuite/g++.dg/modules/cexpr-1_b.C b/gcc/testsuite/g++.dg/modules/cexpr-1_b.C
new file mode 100644
index 00000000000..30566110e02
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cexpr-1_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts" }
+import Const;
+
+static_assert (SQ(88) == 88 * 88, "waaa!");
diff --git a/gcc/testsuite/g++.dg/modules/cexpr-2_a.C b/gcc/testsuite/g++.dg/modules/cexpr-2_a.C
new file mode 100644
index 00000000000..632a4e3a485
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cexpr-2_a.C
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fmodules-ts" }
+export module sqrt;
+// { dg-module-cmi "sqrt" }
+
+export constexpr unsigned sqrt (unsigned X, unsigned x = 1)
+{
+ // Newton-Raphson, not binary restoring
+ // x <= x - f(x)/f'(x)
+ // f(x) = x^2 - X
+ // f'(x) = 2x
+ // x <= x - (x^2 - X) / 2x
+ // x <= x - x/2 + X/2x
+ // x <= x/2 + X/2x
+ // x <= 1/2(x + X/x)
+ unsigned nx = (x + X/x) / 2;
+ if (nx != x)
+ nx = sqrt (X, nx);
+ return nx;
+}
diff --git a/gcc/testsuite/g++.dg/modules/cexpr-2_b.C b/gcc/testsuite/g++.dg/modules/cexpr-2_b.C
new file mode 100644
index 00000000000..6a589aeb235
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cexpr-2_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts" }
+import sqrt;
+
+static_assert (sqrt(81) == 9, "waaa!");
diff --git a/gcc/testsuite/g++.dg/modules/circ-1_a.C b/gcc/testsuite/g++.dg/modules/circ-1_a.C
new file mode 100644
index 00000000000..fa56c78b703
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/circ-1_a.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Bob;
+// { dg-module-cmi Bob }
+
+export int bob ();
diff --git a/gcc/testsuite/g++.dg/modules/circ-1_b.C b/gcc/testsuite/g++.dg/modules/circ-1_b.C
new file mode 100644
index 00000000000..9174c1553ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/circ-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Kevin;
+// { dg-module-cmi Kevin }
+
+import Bob;
+
+export int kevin ();
diff --git a/gcc/testsuite/g++.dg/modules/circ-1_c.C b/gcc/testsuite/g++.dg/modules/circ-1_c.C
new file mode 100644
index 00000000000..cea17d7a2e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/circ-1_c.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Bob; // { dg-message "declared here" }
+// No need to dg-module-cmi
+
+import Kevin;
+// { dg-error "failed to read" "" { target *-*-* } 0 }
+// { dg-error "cannot import module" "" { target *-*-* } 0 }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/modules/circ-1_d.C b/gcc/testsuite/g++.dg/modules/circ-1_d.C
new file mode 100644
index 00000000000..b6f6b7ddd32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/circ-1_d.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+module;
+import Kevin;
+
+export module Bob; // { dg-error "module already imported" }
+// { dg-message "imported here" "Kevin.nms:" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/modules/class-1_a.C b/gcc/testsuite/g++.dg/modules/class-1_a.C
new file mode 100644
index 00000000000..6463719cae2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-1_a.C
@@ -0,0 +1,15 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module One;
+// { dg-module-cmi "One" }
+
+namespace Bob
+{
+ struct X;
+ export struct Y {
+ unsigned a;
+ unsigned b;
+ };
+}
+
+export void copy (Bob::Y *, const Bob::Y *);
diff --git a/gcc/testsuite/g++.dg/modules/class-1_b.C b/gcc/testsuite/g++.dg/modules/class-1_b.C
new file mode 100644
index 00000000000..5eac51da073
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-1_b.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts" }
+module One;
+
+struct Bob::X
+{
+ int i;
+};
+
+
+int x = sizeof (Bob::X);
+
+void copy (Bob::Y *dst, Bob::Y const *src)
+{
+ dst->a = src->a;
+ dst->b = src->b;
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-1_c.C b/gcc/testsuite/g++.dg/modules/class-1_c.C
new file mode 100644
index 00000000000..8e23c4f2db6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-1_c.C
@@ -0,0 +1,35 @@
+// { dg-additional-options "-fmodules-ts" }
+import One;
+
+int y = sizeof (Bob::Y);
+
+unsigned Foo (Bob::Y *ptr)
+{
+ return ptr->a + ptr->b;
+}
+
+int main ()
+{
+ if (y != 2 * sizeof (int))
+ return 1;
+
+ unsigned pun[4];
+ pun[0] = 0xdeadbeef;
+ pun[1] = 0xfeedface;
+ pun[2] = 0x8badf00d;
+ pun[3] = 0xcafed00d;
+
+ copy ((Bob::Y *)pun, (Bob::Y *)&pun[2]);
+
+ if (pun[0] != 0x8badf00d)
+ return 2;
+ if (pun[1] != 0xcafed00d)
+ return 3;
+ if (pun[2] != 0x8badf00d)
+ return 4;
+
+ if (Foo ((Bob::Y *)&pun[1]) != 0xcafed00d + 0x8badf00d)
+ return 5;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-2_a.C b/gcc/testsuite/g++.dg/modules/class-2_a.C
new file mode 100644
index 00000000000..04f11cd8c8f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-2_a.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts" }
+// This sequence is for errors
+
+export module One;
+// { dg-module-cmi "One" }
+
+namespace Bob
+{
+ struct X;
+ export struct Y {
+ unsigned a;
+ unsigned b;
+ };
+}
+
+export void copy (Bob::Y *, const Bob::Y *);
diff --git a/gcc/testsuite/g++.dg/modules/class-2_b.C b/gcc/testsuite/g++.dg/modules/class-2_b.C
new file mode 100644
index 00000000000..0f8edb87095
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-2_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts" }
+import One;
+
+int z = sizeof (Bob::X); // { dg-error "not a member of .Bob." }
diff --git a/gcc/testsuite/g++.dg/modules/class-3_a.C b/gcc/testsuite/g++.dg/modules/class-3_a.C
new file mode 100644
index 00000000000..c775f7b589c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-3_a.C
@@ -0,0 +1,15 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module One;
+// { dg-module-cmi "One" }
+
+export struct X
+{
+ X (int, int);
+ X (int a_)
+ : a(a_), b (a_ << 16)
+ {
+ }
+ int a;
+ int b;
+};
diff --git a/gcc/testsuite/g++.dg/modules/class-3_b.C b/gcc/testsuite/g++.dg/modules/class-3_b.C
new file mode 100644
index 00000000000..0e07e888753
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-3_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+export module Two;
+
+export import One;
+
+export inline void Frob (X &q)
+{
+ q.b = q.a;
+}
+
+// { dg-final { scan-lang-dump {Wrote import:-1 type_decl:'::X@One:.'} module } }
+// { dg-final { scan-lang-dump {Indirect:-2 decl's type record_type:'::X@One:.'} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* type_decl:'::X@One:.'@One} module } }
+// { dg-final { scan-lang-dump {Indirect:-[0-9]* decl's type record_type:'::X@One:.'} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* type_decl:'::X@One:.'@One} module } }
+// { dg-final { scan-lang-dump {Indirect:-[0-9]* decl's type record_type:'::X@One:.'} module } }
+// { dg-final { scan-lang-dump {Wrote member:-[0-9]* field_decl:'::X@One:.::a'} module } }
+// { dg-final { scan-lang-dump {Wrote member:-[0-9]* field_decl:'::X@One:.::b'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/class-3_c.C b/gcc/testsuite/g++.dg/modules/class-3_c.C
new file mode 100644
index 00000000000..6b82d1e7ffb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-3_c.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+module One;
+
+X::X (int a_, int b_)
+ : a (a_), b (b_)
+{
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-3_d.C b/gcc/testsuite/g++.dg/modules/class-3_d.C
new file mode 100644
index 00000000000..0710941d5ed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-3_d.C
@@ -0,0 +1,25 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+import Two;
+
+int main ()
+{
+ X x (0xdead, 0xbeef);
+
+ if (x.a != 0xdead || x.b != 0xbeef)
+ return 1;
+
+ Frob (x);
+ if (x.b != 0xdead)
+ return 2;
+
+ X y (0xcafe);
+ if (y.a != 0xcafe || y.b != 0xcafe << 16)
+ return 3;
+
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Imported:-1 type_decl:'::X@One:.'@One} module } }
+// { dg-final { scan-lang-dump {Indirect:-2 decl's type record_type:'::X@One:.'} module } }
+// { dg-final { scan-lang-dump {Read member:-[0-9]* field_decl:'::X@One:.::a'} module } }
+// { dg-final { scan-lang-dump {Read member:-[0-9]* field_decl:'::X@One:.::b'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/class-4_a.C b/gcc/testsuite/g++.dg/modules/class-4_a.C
new file mode 100644
index 00000000000..a9810ab3360
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-4_a.C
@@ -0,0 +1,25 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module One;
+// { dg-module-cmi "One" }
+
+export struct base
+{
+ int b;
+
+ base (int b_)
+ : b (b_)
+ {
+ }
+
+};
+
+export struct derived : base
+{
+ int d;
+
+ derived (int b_, int d_)
+ : base (b_), d (d_)
+ {
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/class-4_b.C b/gcc/testsuite/g++.dg/modules/class-4_b.C
new file mode 100644
index 00000000000..1cd39984052
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-4_b.C
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules-ts" }
+import One;
+
+int main ()
+{
+ base b (0xfeed);
+ if (!(b.b == 0xfeed))
+ return 1;
+
+ derived d (0xcafe, 0xbeef);
+ if (!(d.b == 0xcafe && d.d == 0xbeef))
+ return 2;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-5_a.C b/gcc/testsuite/g++.dg/modules/class-5_a.C
new file mode 100644
index 00000000000..417cb6b115c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-5_a.C
@@ -0,0 +1,16 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module One;
+// { dg-module-cmi "One" }
+
+export struct base
+{
+ int b;
+
+ base (int b_)
+ : b (b_)
+ {
+ }
+
+ virtual int getter () const;
+};
diff --git a/gcc/testsuite/g++.dg/modules/class-5_b.C b/gcc/testsuite/g++.dg/modules/class-5_b.C
new file mode 100644
index 00000000000..89db01c3be7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-5_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+module One;
+
+int base::getter () const
+{
+ return b;
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-5_c.C b/gcc/testsuite/g++.dg/modules/class-5_c.C
new file mode 100644
index 00000000000..ee3250d7bed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-5_c.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts" }
+import One;
+
+int vcall (base *ptr)
+{
+ return ptr->getter ();
+}
+
+int main ()
+{
+ base b (0xfeed);
+
+ if (!(vcall (&b) == 0xfeed))
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-6_a.C b/gcc/testsuite/g++.dg/modules/class-6_a.C
new file mode 100644
index 00000000000..9c117c944b8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-6_a.C
@@ -0,0 +1,30 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module One;
+// { dg-module-cmi "One" }
+
+export struct base
+{
+ int b;
+
+ base (int b_)
+ : b (b_)
+ {
+ }
+
+ virtual int getter () const;
+};
+
+export struct pad
+{
+ int pad;
+ virtual ~pad ();
+};
+
+export struct derived : pad, virtual base
+{
+ derived (int v)
+ :base (v)
+ {
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/class-6_b.C b/gcc/testsuite/g++.dg/modules/class-6_b.C
new file mode 100644
index 00000000000..1a49ced4b1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-6_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts" }
+module One;
+
+pad::~pad ()
+{
+}
+
+int base::getter () const
+{
+ return b;
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-6_c.C b/gcc/testsuite/g++.dg/modules/class-6_c.C
new file mode 100644
index 00000000000..4d3abf92697
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-6_c.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts" }
+import One;
+
+int vcall (derived *ptr)
+{
+ return ptr->getter ();
+}
+
+int main ()
+{
+ derived b (0xfeed);
+
+ if (!(vcall (&b) == 0xfeed))
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-7_a.C b/gcc/testsuite/g++.dg/modules/class-7_a.C
new file mode 100644
index 00000000000..20fd54bb8d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-7_a.C
@@ -0,0 +1,19 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module One;
+// { dg-module-cmi "One" }
+
+export struct base
+{
+ long long b;
+
+ base (int b_)
+ :b (b_)
+ {
+ }
+
+ base ()
+ :b(99)
+ {
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/class-7_b.C b/gcc/testsuite/g++.dg/modules/class-7_b.C
new file mode 100644
index 00000000000..3ed936f0a49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-7_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Two;
+// { dg-module-cmi "Two" }
+import One;
+
+export struct middle : virtual base
+{
+ long long m;
+
+ middle (int b_, int m_)
+ : base (b_), m (m_)
+ {
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/class-7_c.C b/gcc/testsuite/g++.dg/modules/class-7_c.C
new file mode 100644
index 00000000000..d1f2f56cb93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-7_c.C
@@ -0,0 +1,39 @@
+// { dg-additional-options "-fmodules-ts" }
+import One;
+import Two;
+
+struct derived : middle
+{
+ long long d;
+
+ derived (int b_, int m_, int d_)
+ : middle (b_, m_), d (d_)
+ {
+ }
+};
+
+int check (derived *d)
+{
+ if ((char *)&d->b != (char *)&d->d + sizeof (long long))
+ return 3;
+ if ((char *)&d->d != (char *)&d->m + sizeof (long long))
+ return 4;
+ return 0;
+}
+
+
+int main ()
+{
+ middle m (1, 2);
+
+
+ if (m.b != 1 || m.m != 2)
+ return 1;
+
+ derived d (1, 2, 3);
+
+ if (d.b != 99 || d.m != 2 || d.d != 3)
+ return 2;
+
+ return check (&d);
+}
diff --git a/gcc/testsuite/g++.dg/modules/class-8_a.C b/gcc/testsuite/g++.dg/modules/class-8_a.C
new file mode 100644
index 00000000000..53caa5c780d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-8_a.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+class A;
+
+class B
+{
+};
diff --git a/gcc/testsuite/g++.dg/modules/class-8_b.C b/gcc/testsuite/g++.dg/modules/class-8_b.C
new file mode 100644
index 00000000000..0bb01ac6a33
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-8_b.C
@@ -0,0 +1,23 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module} }
+module foo;
+
+// completes class A from interface
+class A
+{
+};
+
+void bill ()
+{
+ A a;
+}
+
+// redeclaration of class B{} from interface
+class B;
+
+void bob ()
+{
+ B b;
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::A'@'foo' section:} module } }
+// { dg-final { scan-lang-dump {Lazily binding '::B'@'foo' section:} module } }
diff --git a/gcc/testsuite/g++.dg/modules/clone-1_a.C b/gcc/testsuite/g++.dg/modules/clone-1_a.C
new file mode 100644
index 00000000000..43c4bbd8d31
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/clone-1_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template
+struct basic_string
+{
+ template basic_string();
+};
+
+inline basic_string
+to_string ()
+{
+ basic_string __str;
+
+ return __str;
+}
diff --git a/gcc/testsuite/g++.dg/modules/clone-1_b.C b/gcc/testsuite/g++.dg/modules/clone-1_b.C
new file mode 100644
index 00000000000..a013b9bdf28
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/clone-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+void frob ()
+{
+ to_string ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/concept-1_a.C b/gcc/testsuite/g++.dg/modules/concept-1_a.C
new file mode 100644
index 00000000000..1b4d83108cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-1_a.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fconcepts" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export template
+requires (!!sizeof (bool (T{})))
+T f1 (T x)
+{ return x; }
+
diff --git a/gcc/testsuite/g++.dg/modules/concept-1_b.C b/gcc/testsuite/g++.dg/modules/concept-1_b.C
new file mode 100644
index 00000000000..d6542e6dc73
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-1_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts -fconcepts" }
+
+import foo;
+
+struct X {};
+
+void foo (int i, X &x)
+{
+ f1 (i); // ok
+ f1 (x); // { dg-error "no match" }
+}
+
+// { dg-regexp {[^\n]*concept-1_a.C:7:[0-9]*: error: invalid cast[^\n]*\n} }
diff --git a/gcc/testsuite/g++.dg/modules/concept-2_a.C b/gcc/testsuite/g++.dg/modules/concept-2_a.C
new file mode 100644
index 00000000000..b1d477def38
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-2_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts -fconcepts" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export template
+requires (sizeof (T) == 1)
+ char f1 (T x) { return 0; }
+
+export template
+requires (sizeof (T) != 1)
+ int f1 (T x) { return 0; }
+
+void foo (int i, char c)
+{
+ static_assert (sizeof (f1 (i)) == sizeof (int));
+ static_assert (sizeof (f1 (c)) == sizeof (char));
+}
diff --git a/gcc/testsuite/g++.dg/modules/concept-2_b.C b/gcc/testsuite/g++.dg/modules/concept-2_b.C
new file mode 100644
index 00000000000..af0ab3ad88e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-2_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -fconcepts" }
+
+import foo;
+
+void foo (int i, char c)
+{
+ static_assert (sizeof (f1 (i)) == sizeof (int));
+ static_assert (sizeof (f1 (c)) == sizeof (char));
+}
diff --git a/gcc/testsuite/g++.dg/modules/concept-3_a.C b/gcc/testsuite/g++.dg/modules/concept-3_a.C
new file mode 100644
index 00000000000..36fc0861428
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-3_a.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts -std=c++2a" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+namespace foo
+{
+export template
+concept Addable = requires(_Tp& __t)
+ {
+ __t + __t;
+ };
+}
diff --git a/gcc/testsuite/g++.dg/modules/concept-3_b.C b/gcc/testsuite/g++.dg/modules/concept-3_b.C
new file mode 100644
index 00000000000..46bfe039956
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-3_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -std=c++2a" }
+
+import foo;
+
+template T Add (T a, T b)
+{
+ return a + b;
+}
+
+void frob ()
+{
+ Add (1, 2);
+ Add ((int *)0, (int *)0); // { dg-error "no match" }
+}
diff --git a/gcc/testsuite/g++.dg/modules/concept-4.H b/gcc/testsuite/g++.dg/modules/concept-4.H
new file mode 100644
index 00000000000..66d12017a7c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-4.H
@@ -0,0 +1,18 @@
+// { dg-additional-options "-std=c++2a -fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+inline constexpr bool disable = false;
+
+template
+concept sized = true;
+
+template
+class TPL
+{
+};
+
+template
+requires (!sized)
+inline constexpr bool disable>
+= true;
diff --git a/gcc/testsuite/g++.dg/modules/concept-5.h b/gcc/testsuite/g++.dg/modules/concept-5.h
new file mode 100644
index 00000000000..1b049f5f1be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-5.h
@@ -0,0 +1,7 @@
+template
+requires (sizeof (T) == 1)
+constexpr int f1 (T x) { return 1; }
+
+template
+requires (sizeof (T) != 1)
+constexpr int f1 (T x) { return 0; }
diff --git a/gcc/testsuite/g++.dg/modules/concept-5_a.H b/gcc/testsuite/g++.dg/modules/concept-5_a.H
new file mode 100644
index 00000000000..f38febea861
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-5_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -fconcepts" }
+// { dg-module-cmi {} }
+
+#include "concept-5.h"
diff --git a/gcc/testsuite/g++.dg/modules/concept-5_b.C b/gcc/testsuite/g++.dg/modules/concept-5_b.C
new file mode 100644
index 00000000000..6a196d8088d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-5_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fconcepts -fdump-lang-module-alias" }
+
+#include "concept-5.h"
+import "concept-5_a.H";
+
+static_assert (f1 ('a') == 1);
+static_assert (f1 (0xa) == 0);
+
+// { dg-final { scan-lang-dump-times {named merge key \(matched\) template_decl:'::template f1'} 2 module } }
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git a/gcc/testsuite/g++.dg/modules/concept-6.h b/gcc/testsuite/g++.dg/modules/concept-6.h
new file mode 100644
index 00000000000..0e98c98727a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-6.h
@@ -0,0 +1,19 @@
+
+template
+struct Base
+{
+ Base (const _Callable &)
+ requires true
+ {}
+};
+
+template
+struct Derived : Base<_Callable>
+{
+ using Base<_Callable>::Base;
+};
+
+template
+Derived (_Callable) -> Derived<_Callable>;
+
+inline Derived all = [] (auto&& __r) {};
diff --git a/gcc/testsuite/g++.dg/modules/concept-6_a.H b/gcc/testsuite/g++.dg/modules/concept-6_a.H
new file mode 100644
index 00000000000..e677531c5f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-6_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -fconcepts" }
+// { dg-module-cmi {} }
+
+#include "concept-6.h"
diff --git a/gcc/testsuite/g++.dg/modules/concept-6_b.C b/gcc/testsuite/g++.dg/modules/concept-6_b.C
new file mode 100644
index 00000000000..4c2058d8993
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/concept-6_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fconcepts -fdump-lang-module-alias -fno-module-lazy" }
+
+#include "concept-6.h"
+import "concept-6_a.H";
+
+// { dg-final { scan-lang-dump-times {named merge key \(matched\) function_decl:'::Derived<::._anon_0>::__ct '} 6 module } }
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git a/gcc/testsuite/g++.dg/modules/constrained-partial-1_a.C b/gcc/testsuite/g++.dg/modules/constrained-partial-1_a.C
new file mode 100644
index 00000000000..5a5482efc45
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/constrained-partial-1_a.C
@@ -0,0 +1,38 @@
+// { dg-additional-options "-fmodules-ts -std=c++20" }
+
+export module M;
+// { dg-module-cmi M }
+
+export template
+struct traits
+{
+ static constexpr int variant = 0;
+};
+
+// #2
+template
+requires requires { typename T2::element_type; }
+struct traits
+{
+ using type = typename T2::element_type;
+ static constexpr int variant = 2;
+};
+
+
+// #1
+template
+struct traits
+{
+ using type = T1;
+ static constexpr int variant = 1;
+};
+
+
+// #3
+template
+requires requires { typename T3::value_type; }
+struct traits
+{
+ using type = typename T3::value_type;
+ static constexpr int variant = 3;
+};
diff --git a/gcc/testsuite/g++.dg/modules/constrained-partial-1_b.C b/gcc/testsuite/g++.dg/modules/constrained-partial-1_b.C
new file mode 100644
index 00000000000..bbbbab54c0e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/constrained-partial-1_b.C
@@ -0,0 +1,31 @@
+// { dg-additional-options "-fmodules-ts -std=c++20" }
+
+import M;
+
+struct Variant0
+{
+};
+
+
+struct Variant2
+{
+ using element_type = double;
+};
+
+struct Variant3
+{
+ using value_type = float;
+};
+
+void f()
+{
+ using v0 = traits;
+ using v1 = traits;
+ using v2 = traits;
+ using v3 = traits;
+
+ static_assert (v0::variant == 0);
+ static_assert (v1::variant == 1);
+ static_assert (v2::variant == 2);
+ static_assert (v3::variant == 3);
+}
diff --git a/gcc/testsuite/g++.dg/modules/convop-1_a.C b/gcc/testsuite/g++.dg/modules/convop-1_a.C
new file mode 100644
index 00000000000..d0edec85c28
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/convop-1_a.C
@@ -0,0 +1,12 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module frob;
+// { dg-module-cmi "frob" }
+
+export struct A
+{
+ operator int ()
+ {
+ return 0;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/convop-1_b.C b/gcc/testsuite/g++.dg/modules/convop-1_b.C
new file mode 100644
index 00000000000..65350eee208
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/convop-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts" }
+import frob;
+
+int main ()
+{
+ A a;
+
+ if (static_cast (a))
+ return 1;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/cpp-1.C b/gcc/testsuite/g++.dg/modules/cpp-1.C
new file mode 100644
index 00000000000..2ad9637c8fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-1.C
@@ -0,0 +1,14 @@
+// { dg-do preprocess }
+
+module bob;
+#if 1
+export import stuart;
+#else
+import kevin;
+#endif
+import gru;
+#define EXPORT
+EXPORT import mabel;
+int i;
+
+// { dg-final { scan-file cpp-1.i "cpp-1.C\"\n\n\nmodule bob;\n\nexport import stuart;\n\n\n\nimport gru;\n\n import mabel;\n" } }
diff --git a/gcc/testsuite/g++.dg/modules/cpp-2_a.H b/gcc/testsuite/g++.dg/modules/cpp-2_a.H
new file mode 100644
index 00000000000..391843fb654
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-2_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+#define STRING_H
+#define NOPE
diff --git a/gcc/testsuite/g++.dg/modules/cpp-2_b.H b/gcc/testsuite/g++.dg/modules/cpp-2_b.H
new file mode 100644
index 00000000000..34c138d407f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-2_b.H
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#define STDIO_H
+#define think THIS IS STDIO
+#define CLOSE ]]
diff --git a/gcc/testsuite/g++.dg/modules/cpp-2_c.C b/gcc/testsuite/g++.dg/modules/cpp-2_c.C
new file mode 100644
index 00000000000..c6e02b7800a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-2_c.C
@@ -0,0 +1,17 @@
+// { dg-do preprocess }
+// { dg-additional-options "-fmodules-ts" }
+
+module bob;
+#pragma GCC unused
+import "./cpp-2_b.H" [[ CLOSE ]];
+import "cpp-2_a.H" [[ CLOSE;
+int i;
+#ifndef NOPE
+import nope;
+#endif
+think
+
+// { dg-final { scan-file cpp-2_c.i {cpp-2_c.C"\n\n\n\nmodule bob;\n#pragma GCC unused\nimport "[^\n]*\./cpp-2_b.H" \[\[ CLOSE ]];\nimport "[^\n]*cpp-2_a.H" \[\[ ]];\n} } }
+// { dg-final { scan-file cpp-2_c.i "int i;" } }
+// { dg-final { scan-file-not cpp-2_c.i "import *nope;" } }
+// { dg-final { scan-file cpp-2_c.i "THIS IS STDIO\n" } }
diff --git a/gcc/testsuite/g++.dg/modules/cpp-3.C b/gcc/testsuite/g++.dg/modules/cpp-3.C
new file mode 100644
index 00000000000..3aa0c6ec5f6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-3.C
@@ -0,0 +1,9 @@
+// { dg-do preprocess }
+
+#define NAME(X) X;
+
+export module NAME(bob)
+
+int i;
+// { dg-final { scan-file cpp-3.i "\nexport module bob;\n" } }
+// { dg-final { scan-file cpp-3.i "\nint i;\n" } }
diff --git a/gcc/testsuite/g++.dg/modules/cpp-4.C b/gcc/testsuite/g++.dg/modules/cpp-4.C
new file mode 100644
index 00000000000..6c194312311
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-4.C
@@ -0,0 +1,10 @@
+// { dg-do preprocess }
+
+#if 1
+#include "cpp-4.h"
+#endif
+
+// { dg-final { scan-file cpp-4.i "/cpp-4.h\\\" 1" } }
+// { dg-final { scan-file cpp-4.i "/cpp-4.C\\\" 2" } }
+// { dg-final { scan-file cpp-4.i "import x;\n" } }
+// { dg-final { scan-file cpp-4.i "int" } }
diff --git a/gcc/testsuite/g++.dg/modules/cpp-4.h b/gcc/testsuite/g++.dg/modules/cpp-4.h
new file mode 100644
index 00000000000..aec9547ed46
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-4.h
@@ -0,0 +1,4 @@
+#if 1
+import x;
+int i; // end here in middle of #if (ok)
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/cpp-5_a.H b/gcc/testsuite/g++.dg/modules/cpp-5_a.H
new file mode 100644
index 00000000000..3941ee817c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-5_a.H
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#ifndef AA
+#define AA
+
+#define Q 0
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/cpp-5_b.C b/gcc/testsuite/g++.dg/modules/cpp-5_b.C
new file mode 100644
index 00000000000..504e792b9b2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-5_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+// missing semicolon
+import "cpp-5_a.H" // { dg-error "expected" }
+
+int main ()
+{
+}
diff --git a/gcc/testsuite/g++.dg/modules/cpp-5_c.C b/gcc/testsuite/g++.dg/modules/cpp-5_c.C
new file mode 100644
index 00000000000..e0a78a516ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-5_c.C
@@ -0,0 +1,10 @@
+// { dg-do preprocess }
+// { dg-additional-options "-fmodules-ts" }
+#define Q 0
+#undef Q
+
+import "cpp-5_a.H";
+
+Q
+
+// { dg-final { scan-file cpp-5_c.i {\nimport "[^\n]*cpp-5_a.H";\n\n0\n} } }
diff --git a/gcc/testsuite/g++.dg/modules/cpp-6_a.H b/gcc/testsuite/g++.dg/modules/cpp-6_a.H
new file mode 100644
index 00000000000..0bb1f41629f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-6_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+#define bibity cpp-6_b.H
diff --git a/gcc/testsuite/g++.dg/modules/cpp-6_b.H b/gcc/testsuite/g++.dg/modules/cpp-6_b.H
new file mode 100644
index 00000000000..2d5bcccffb0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-6_b.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#define bobity cpp-6_b
diff --git a/gcc/testsuite/g++.dg/modules/cpp-6_c.C b/gcc/testsuite/g++.dg/modules/cpp-6_c.C
new file mode 100644
index 00000000000..f9b1e2d68b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cpp-6_c.C
@@ -0,0 +1,18 @@
+// { dg-do preprocess }
+// { dg-additional-options "-fmodules-ts -isystem [srcdir]" }
+
+#define empty
+#define nop(X) X
+
+ONE bibity bobity
+import ;
+TWO bibity bobity
+import empty nop();
+THREE bibity bobity
+import empty ;
+FOUR bibity bobity
+
+// { dg-final { scan-file cpp-6_c.i {ONE bibity bobity\n} } }
+// { dg-final { scan-file cpp-6_c.i {TWO cpp-6_b.H bobity\n} } }
+// { dg-final { scan-file cpp-6_c.i {THREE cpp-6_b.H cpp-6_b\n} } }
+// { dg-final { scan-file cpp-6_c.i {FOUR cpp-6_b.H cpp-6_b\n} } }
diff --git a/gcc/testsuite/g++.dg/modules/debug-1_a.C b/gcc/testsuite/g++.dg/modules/debug-1_a.C
new file mode 100644
index 00000000000..b0f1763bb98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/debug-1_a.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts -g" }
+
+export module frob;
+// { dg-module-cmi frob }
+
+export struct thingy
+{
+ virtual void X ()
+ {
+ thingy w;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/debug-1_b.C b/gcc/testsuite/g++.dg/modules/debug-1_b.C
new file mode 100644
index 00000000000..7fca87b6aeb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/debug-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -g" }
+
+import frob;
+
+struct thongy : thingy
+{
+ void X ()
+ {
+ thongy w;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/decomp-1_a.C b/gcc/testsuite/g++.dg/modules/decomp-1_a.C
new file mode 100644
index 00000000000..07506c9956f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/decomp-1_a.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -std=c++2a" }
+export module foo;
+// { dg-module-cmi foo }
+
+struct tuple { int a, b, c;};
+
+tuple maker ();
+
+export inline int bob ()
+{
+ auto [a, b, c] = maker ();
+
+ return a + b + c;
+}
diff --git a/gcc/testsuite/g++.dg/modules/decomp-1_b.C b/gcc/testsuite/g++.dg/modules/decomp-1_b.C
new file mode 100644
index 00000000000..709c333fd58
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/decomp-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -std=c++2a" }
+import foo;
+
+void x ()
+{
+ bob ();
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/deferred-1.h b/gcc/testsuite/g++.dg/modules/deferred-1.h
new file mode 100644
index 00000000000..dc0fd782a80
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/deferred-1.h
@@ -0,0 +1,12 @@
+template
+struct _Iterator
+{
+private:
+ static void mover (const _Iterator &arg = {}) noexcept (noexcept (arg));
+
+public:
+ _Iterator() = default;
+
+ friend void move (const _Iterator &arg2) noexcept (noexcept (mover (arg2)))
+ {}
+};
diff --git a/gcc/testsuite/g++.dg/modules/deferred-1_a.H b/gcc/testsuite/g++.dg/modules/deferred-1_a.H
new file mode 100644
index 00000000000..88e6fab6a3a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/deferred-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "deferred-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/deferred-1_b.C b/gcc/testsuite/g++.dg/modules/deferred-1_b.C
new file mode 100644
index 00000000000..5f75aec0a24
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/deferred-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "deferred-1.h"
+import "deferred-1_a.H";
+
+// { 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/dep-1_a.C b/gcc/testsuite/g++.dg/modules/dep-1_a.C
new file mode 100644
index 00000000000..766f4368ee6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dep-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -MD" }
+
+export module m:part;
+// { dg-module-cmi m:part }
+
+// All The Backslashes!
+// { dg-final { scan-file dep-1_a.d {\nm\\:part\.c\+\+m: gcm.cache/m-part\.gcm} } }
+// { dg-final { scan-file dep-1_a.d {\ngcm.cache/m-part\.gcm:| dep-1_a\.o} } }
+// { dg-final { scan-file dep-1_a.d {\n\.PHONY: m\\:part\.c\+\+m} } }
diff --git a/gcc/testsuite/g++.dg/modules/dep-1_b.C b/gcc/testsuite/g++.dg/modules/dep-1_b.C
new file mode 100644
index 00000000000..138832f709e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dep-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -MD" }
+export module m;
+// { dg-module-cmi m }
+
+export import :part;
+// { dg-final { scan-file dep-1_b.d {\ndep-1_b\.s gcm.cache/m\.gcm: m\\:part\.c\+\+m} } }
+// { dg-final { scan-file dep-1_b.d {\nm\.c\+\+m: gcm.cache/m\.gcm} } }
+// { dg-final { scan-file dep-1_b.d {\n\.PHONY: m\.c\+\+m} } }
+// { dg-final { scan-file dep-1_b.d {\ngcm.cache/m\.gcm:| dep-1_b.o} } }
+// { dg-final { scan-file dep-1_b.d {\nCXX_IMPORTS \+= m\\:part\.c\+\+m} } }
diff --git a/gcc/testsuite/g++.dg/modules/dep-2.C b/gcc/testsuite/g++.dg/modules/dep-2.C
new file mode 100644
index 00000000000..5e112c62350
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dep-2.C
@@ -0,0 +1,12 @@
+// { dg-do preprocess }
+// { dg-additional-options "-fmodules-ts -MD" }
+
+module m:part;
+// { dg-module-cmi !m:part }
+
+// All The Backslashes!
+// { dg-final { scan-file dep-2.d {\nm\\:part\.c\+\+m: gcm.cache/m-part\.gcm} } }
+// { dg-final { scan-file dep-2.d {\ngcm.cache/m\\:part\.gcm:| dep-2\.o} } }
+// { dg-final { scan-file dep-2.d {\n\.PHONY: m\\:part\.c\+\+m} } }
+
+// { dg-final { scan-file dep-2.i {\nmodule m:part;\n} } }
diff --git a/gcc/testsuite/g++.dg/modules/dep-3.C b/gcc/testsuite/g++.dg/modules/dep-3.C
new file mode 100644
index 00000000000..f0f883e86e3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dep-3.C
@@ -0,0 +1,9 @@
+// { dg-do preprocess }
+// { dg-additional-options "-fmodules-ts -MD -Mno-modules" }
+
+module m:part;
+// { dg-module-cmi !m:part }
+
+// All The Backslashes!
+// { dg-final { scan-file-not dep-3.d {part\.gcm} } }
+// { dg-final { scan-file-not dep-3.d {part\.c\+\+m} } }
diff --git a/gcc/testsuite/g++.dg/modules/dir-only-1.C b/gcc/testsuite/g++.dg/modules/dir-only-1.C
new file mode 100644
index 00000000000..d035b5f3def
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dir-only-1.C
@@ -0,0 +1,16 @@
+// { dg-do preprocess }
+// { dg-additional-options -fdirectives-only }
+
+#define major NO NOT ME
+
+#ifdef major
+# undef major
+#else
+# error major not initially defined
+#endif
+
+#ifdef major
+# error major still defined
+#endif
+
+// { dg-final { scan-file dir-only-1.i "#undef major\n" } }
diff --git a/gcc/testsuite/g++.dg/modules/dir-only-2_a.H b/gcc/testsuite/g++.dg/modules/dir-only-2_a.H
new file mode 100644
index 00000000000..3ed0de5d7b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dir-only-2_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#define X 1
diff --git a/gcc/testsuite/g++.dg/modules/dir-only-2_b.C b/gcc/testsuite/g++.dg/modules/dir-only-2_b.C
new file mode 100644
index 00000000000..0691f76ae36
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dir-only-2_b.C
@@ -0,0 +1,28 @@
+// { dg-do preprocess }
+// { dg-additional-options "-fmodules-ts -fdirectives-only -isystem [srcdir]" }
+// a comment
+module; // line
+frob
+export
+import foo; // line
+import 7;
+
+im\
+port \
+sing;
+// comment
+import "dir-only-2_a.H";
+import ;
+X
+#if !X
+#error "no X!"
+#endif
+export module bob;
+
+export import q;
+
+// { dg-final { scan-file dir-only-2_b.i {// a comment\nmodule ;\nfrob} } }
+// { dg-final { scan-file dir-only-2_b.i {frob\nexport\nimport foo;\nimport 7;} } }
+// { dg-final { scan-file dir-only-2_b.i {import "[^\n]*/dir-only-2_a.H";\nimport "[^\n]*/dir-only-2_a.H";\nX} } }
+// { dg-final { scan-file dir-only-2_b.i {export module bob;\n\nexport import q;} } }
+// { dg-final { scan-file dir-only-2_b.i {import sing;\n\n\n// comment} } }
diff --git a/gcc/testsuite/g++.dg/modules/dir-only-3.C b/gcc/testsuite/g++.dg/modules/dir-only-3.C
new file mode 100644
index 00000000000..6e3af8da45d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dir-only-3.C
@@ -0,0 +1,18 @@
+# 0 "dir-only-3.C"
+# 1 ""
+# 1 ""
+# 31 ""
+# 1 "/usr/include/stdc-predef.h" 1 3 4
+
+# 32 "" 2
+# 1 "dir-only-3.C"
+// { dg-additional-options {-fmodules-ts -fpreprocessed -fdirectives-only} }
+// { dg-module-cmi foo }
+module;
+#define foo baz
+export module foo;
+
+class import {};
+
+import
+x;
diff --git a/gcc/testsuite/g++.dg/modules/dir-only-4.C b/gcc/testsuite/g++.dg/modules/dir-only-4.C
new file mode 100644
index 00000000000..80d6461e81f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dir-only-4.C
@@ -0,0 +1,10 @@
+// { dg-additional-options {-fmodules-ts -fpreprocessed -fdirectives-only} }
+// { dg-module-cmi !foo }
+module;
+#define foo baz
+export module foo;
+
+class import {};
+
+import x; // { dg-error "post-module-declaration" }
+ // { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/dir-recovery.C b/gcc/testsuite/g++.dg/modules/dir-recovery.C
new file mode 100644
index 00000000000..90794b96882
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/dir-recovery.C
@@ -0,0 +1,9 @@
+// { dg-additional-options {-fmodules-ts -fpreprocessed} }
+module;
+
+; export module Hello; // { dg-error "global module fragment" }
+// { dg-error "after a module interface" "" { target *-*-* } .-1 }
+// { dg-error "not name a type" "" { target *-*-* } .-2 }
+// { dg-message "not recognized as a module control-line" "" { target *-*-* } .-3 }
+
+void SayHello ();
diff --git a/gcc/testsuite/g++.dg/modules/enum-1_a.C b/gcc/testsuite/g++.dg/modules/enum-1_a.C
new file mode 100644
index 00000000000..53e2ac88f20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-1_a.C
@@ -0,0 +1,30 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+export module enUm;
+// { dg-module-cmi "enUm" }
+
+export enum Bill
+{
+ Zero,
+ One,
+ Three = 3
+};
+
+export enum class Ben
+{
+ Zero,
+ Two = 2,
+ Three
+};
+
+export inline Ben func1 ()
+{
+ return Ben::Three;
+}
+
+export inline Ben func2 ()
+{
+ return Ben (4);
+}
+
+// { dg-final { scan-lang-dump-times {Written enum value '::Ben::Three'} 2 module } }
diff --git a/gcc/testsuite/g++.dg/modules/enum-1_b.C b/gcc/testsuite/g++.dg/modules/enum-1_b.C
new file mode 100644
index 00000000000..4b8c647e1b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-1_b.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-fmodules-ts" }
+import enUm;
+
+Bill x = Three;
+Ben y = Ben::Three;
+
+int main ()
+{
+ if (x != 3)
+ return 1;
+
+ if (int (y) != 3)
+ return 2;
+
+ if (int (func1 ()) != 3)
+ return 3;
+
+ if (int (func2 ()) != 4)
+ return 4;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/enum-2_a.C b/gcc/testsuite/g++.dg/modules/enum-2_a.C
new file mode 100644
index 00000000000..9e5e42a3b2e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-2_a.C
@@ -0,0 +1,21 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export struct X
+{
+ enum q
+ {
+ frob
+ };
+};
+
+export template struct TPL
+{
+ enum p
+ {
+ u,
+ v = I
+ };
+};
diff --git a/gcc/testsuite/g++.dg/modules/enum-2_b.C b/gcc/testsuite/g++.dg/modules/enum-2_b.C
new file mode 100644
index 00000000000..4e0aed48806
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-2_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+int i = X::frob;
+
+int k = TPL<2>::v;
+
+static_assert (!TPL<1>::u);
diff --git a/gcc/testsuite/g++.dg/modules/enum-3_a.C b/gcc/testsuite/g++.dg/modules/enum-3_a.C
new file mode 100644
index 00000000000..514bdd012ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-3_a.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+// from https://godbolt.org/beta/z/V45BSw
+
+export module m0;
+// { dg-module-cmi m0 }
+namespace m0_ns
+{
+template struct s0 {
+ enum t { a };
+};
+}
diff --git a/gcc/testsuite/g++.dg/modules/enum-3_b.C b/gcc/testsuite/g++.dg/modules/enum-3_b.C
new file mode 100644
index 00000000000..073611ca559
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-3_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodules-ts }
+module m0;
+
+static_assert (!m0_ns::s0::a);
diff --git a/gcc/testsuite/g++.dg/modules/enum-4_a.C b/gcc/testsuite/g++.dg/modules/enum-4_a.C
new file mode 100644
index 00000000000..96880b469cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-4_a.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+
+export module bob;
+// { dg-module-cmi bob }
+
+export template
+struct same
+{
+ enum { value = 0 };
+};
+
+template
+struct same
+{
+ enum { value = 1 };
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/enum-4_b.C b/gcc/testsuite/g++.dg/modules/enum-4_b.C
new file mode 100644
index 00000000000..0f88fa1ddd2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-4_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+import bob;
+
+static_assert (same::value == 0);
+static_assert (same::value == 1);
diff --git a/gcc/testsuite/g++.dg/modules/enum-5_a.H b/gcc/testsuite/g++.dg/modules/enum-5_a.H
new file mode 100644
index 00000000000..1f2e84faad1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-5_a.H
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+enum
+{
+ Zero,
+};
diff --git a/gcc/testsuite/g++.dg/modules/enum-5_b.C b/gcc/testsuite/g++.dg/modules/enum-5_b.C
new file mode 100644
index 00000000000..385c1d35c85
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-5_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodules-ts }
+import "enum-5_a.H";
+
+int i = Zero;
diff --git a/gcc/testsuite/g++.dg/modules/enum-6_a.H b/gcc/testsuite/g++.dg/modules/enum-6_a.H
new file mode 100644
index 00000000000..066904686bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-6_a.H
@@ -0,0 +1,10 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+enum { _S_chunk_size = 7 };
+
+template T getter ()
+{
+ return _S_chunk_size;
+}
diff --git a/gcc/testsuite/g++.dg/modules/enum-6_b.C b/gcc/testsuite/g++.dg/modules/enum-6_b.C
new file mode 100644
index 00000000000..04c1ee28b5f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-6_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import "enum-6_a.H";
+
+int main ()
+{
+ return !(getter () == 7);
+}
diff --git a/gcc/testsuite/g++.dg/modules/enum-7.C b/gcc/testsuite/g++.dg/modules/enum-7.C
new file mode 100644
index 00000000000..8cf31a9f804
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-7.C
@@ -0,0 +1,20 @@
+// { dg-additional-options -fmodules-ts }
+
+// ICE getting template info of a function-scope enum
+
+template void adl (T) {}
+
+template
+void frob (T arg)
+{
+ enum class case_conv {none};
+
+ case_conv x = case_conv::none;
+
+ adl (x);
+}
+
+void foo ()
+{
+ frob (1);
+}
diff --git a/gcc/testsuite/g++.dg/modules/enum-8_a.H b/gcc/testsuite/g++.dg/modules/enum-8_a.H
new file mode 100644
index 00000000000..90ccb914341
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-8_a.H
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodule-header }
+
+enum : char
+{
+ Foo = 1,
+};
diff --git a/gcc/testsuite/g++.dg/modules/enum-8_b.H b/gcc/testsuite/g++.dg/modules/enum-8_b.H
new file mode 100644
index 00000000000..021ad173fbd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-8_b.H
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodule-header }
+
+enum : int
+{
+ Foo = 2,
+};
diff --git a/gcc/testsuite/g++.dg/modules/enum-8_c.C b/gcc/testsuite/g++.dg/modules/enum-8_c.C
new file mode 100644
index 00000000000..d14469b533a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-8_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy} }
+
+export module Char;
+
+import "enum-8_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/enum-8_d.C b/gcc/testsuite/g++.dg/modules/enum-8_d.C
new file mode 100644
index 00000000000..665077325de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-8_d.C
@@ -0,0 +1,11 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy -fdump-lang-module-alias} }
+
+import "enum-8_b.H";
+
+import Char;
+
+
+// { dg-final { scan-lang-dump {Read:-1's enum merge key \(new\) type_decl:'#null#'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(new\) const_decl:'::._anon_0@[^\n]*/enum-8_b.H:1::Foo'} module } }
+// { dg-final { scan-lang-dump {Read:-1's enum merge key \(new\) type_decl:'#null#'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(new\) const_decl:'::._anon_1@[^\n]*/enum-8_a.H:2::Foo'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/enum-bad-1_a.H b/gcc/testsuite/g++.dg/modules/enum-bad-1_a.H
new file mode 100644
index 00000000000..2d8a7baf451
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-bad-1_a.H
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodule-header }
+
+// { dg-module-cmi {} }
+
+enum ONE {A};
+enum {TWO, THREE};
+enum FOUR {B = 5};
+enum FIVE {C, D, E};
diff --git a/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C b/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C
new file mode 100644
index 00000000000..b01cd66a14d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C
@@ -0,0 +1,26 @@
+// { dg-additional-options {-fmodules-ts} }
+
+enum ONE {Q};
+enum {TWO, DREI};
+enum FOUR {B = 3};
+enum FIVE {C, D};
+
+import "enum-bad-1_a.H";
+
+
+
+
+
+
+ONE one;
+// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:6: error: definition of 'enum ONE' does not match\n[^\n]*enum-bad-1_b.C:3:6: note: existing definition 'enum ONE'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:11: note: ... this enumerator 'A'\n[^\n]*enum-bad-1_b.C:3:11: note: enumerator 'Q' does not match ...\n[^\n]*enum-bad-1_b.C:15:1: note: during load of binding '::ONE'\n} }
+
+int i = TWO;
+// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:6: error: definition of 'enum' does not match\n[^\n]*enum-bad-1_b.C:4:6: note: existing definition 'enum'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:12: note: ... this enumerator 'THREE'\n[^\n]*enum-bad-1_b.C:4:12: note: enumerator 'DREI' does not match ...\n[^\n]*enum-bad-1_b.C:18:9: note: during load of binding '::TWO'\n} }
+
+FOUR four;
+// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:6: error: definition of 'enum FOUR' does not match\n[^\n]*enum-bad-1_b.C:5:6: note: existing definition 'enum FOUR'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:12: note: ... this enumerator 'B'\n[^\n]*enum-bad-1_b.C:5:12: note: enumerator 'B' does not match ...\n[^\n]*enum-bad-1_b.C:21:1: note: during load of binding '::FOUR'\n} }
+
+FIVE five;
+// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:8:6: error: definition of 'enum FIVE' does not match\n[^\n]*enum-bad-1_b.C:6:6: note: existing definition 'enum FIVE'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:8:18: note: additional enumerators beginning with 'E'\n[^\n]*enum-bad-1_b.C:24:1: note: during load of binding '::FIVE'\n} }
+
diff --git a/gcc/testsuite/g++.dg/modules/err-1_a.C b/gcc/testsuite/g++.dg/modules/err-1_a.C
new file mode 100644
index 00000000000..1f7ddecc6ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/err-1_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Foo;
+// { dg-module-cmi "Foo" }
+
+export int Frob (int, int, long);
+export int Frob (int, long, int);
diff --git a/gcc/testsuite/g++.dg/modules/err-1_b.C b/gcc/testsuite/g++.dg/modules/err-1_b.C
new file mode 100644
index 00000000000..6d5609c11d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/err-1_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Bar;
+// { dg-module-cmi "Bar" }
+
+export int Frob (long, int, int);
diff --git a/gcc/testsuite/g++.dg/modules/err-1_c.C b/gcc/testsuite/g++.dg/modules/err-1_c.C
new file mode 100644
index 00000000000..3a93cc6d18b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/err-1_c.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-fmodules-ts" }
+import Foo;
+
+void One ()
+{
+ Frob (0, 0, 0L);
+ Frob (0, 0L, 0);
+ Frob (0L, 0, 0); // { dg-error "ambiguous" }
+ // { dg-regexp {candidate: 'int Frob@Foo\(int, long int, int\)'} }
+ // { dg-regexp {candidate: 'int Frob@Foo\(int, int, long int\)'} }
+}
+
+import Bar;
+
+void Two ()
+{
+ Frob (0L, 0, 0);
+ Frob (0, 0, 0); // { dg-error "ambiguous" }
+ // { dg-regexp {candidate: 'int Frob@Foo\(int, long int, int\)'} }
+ // { dg-regexp {candidate: 'int Frob@Foo\(int, int, long int\)'} }
+ // { dg-regexp {candidate: 'int Frob@Bar\(long int, int, int\)'} }
+}
diff --git a/gcc/testsuite/g++.dg/modules/err-1_d.C b/gcc/testsuite/g++.dg/modules/err-1_d.C
new file mode 100644
index 00000000000..eb6b4ba7c99
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/err-1_d.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+import Foo;
+import Bar;
+
+
+void Three ()
+{
+ Frob (0L, 0, 0);
+
+ Frob (0, 0, 0); // { dg-error "ambiguous" }
+ // { dg-regexp {candidate: 'int Frob@Foo\(int, long int, int\)'} }
+ // { dg-regexp {candidate: 'int Frob@Foo\(int, int, long int\)'} }
+ // { dg-regexp {candidate: 'int Frob@Bar\(long int, int, int\)'} }
+}
diff --git a/gcc/testsuite/g++.dg/modules/except-1.C b/gcc/testsuite/g++.dg/modules/except-1.C
new file mode 100644
index 00000000000..6135c8feb7a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/except-1.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+export module bill;
+// { dg-module-cmi bill }
+
+// Make sure no deferred parse exception spec detritus remains
+
+template
+class bob
+{
+ void frob () noexcept(T::frob ());
+ template void frobber (int) noexcept (T::frob ());
+};
+
+
+class bill
+{
+ template void frobbest (int) noexcept (U::frob ());
+};
diff --git a/gcc/testsuite/g++.dg/modules/except-2.h b/gcc/testsuite/g++.dg/modules/except-2.h
new file mode 100644
index 00000000000..38355ec8b47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/except-2.h
@@ -0,0 +1,42 @@
+
+// Causes the CMI to have instantiated a deferred noexept spec that
+// the textually included file has not.
+
+typedef long unsigned int size_t;
+
+
+template
+struct integral_constant
+{
+ static constexpr _Tp value = __v;
+ typedef integral_constant<_Tp, __v> type;
+};
+template
+constexpr _Tp integral_constant<_Tp, __v>::value;
+
+template
+struct _Tuple_impl : _Head
+{
+ _Tuple_impl(_Tuple_impl&& __in)
+ noexcept (integral_constant(*(_Head *) (0))))>::type::value);
+};
+
+template
+struct __uniq_ptr_impl
+{
+ __uniq_ptr_impl (__uniq_ptr_impl&& __u) noexcept
+ : _M_t(static_cast <_Tuple_impl<_Dp> &&>(__u._M_t))
+ {}
+
+ _Tuple_impl<_Dp> _M_t;
+};
+
+struct _Impl_deleter {};
+
+typedef __uniq_ptr_impl<_Impl_deleter> up;
+
+inline void frob (up && p)
+{
+ up _M_cmpts (static_cast (p));
+}
diff --git a/gcc/testsuite/g++.dg/modules/except-2_a.H b/gcc/testsuite/g++.dg/modules/except-2_a.H
new file mode 100644
index 00000000000..966169ceae0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/except-2_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "except-2.h"
diff --git a/gcc/testsuite/g++.dg/modules/except-2_b.C b/gcc/testsuite/g++.dg/modules/except-2_b.C
new file mode 100644
index 00000000000..78ed8f8be9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/except-2_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+#include "except-2.h"
+import "except-2_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/except-3.h b/gcc/testsuite/g++.dg/modules/except-3.h
new file mode 100644
index 00000000000..8bf0f84d590
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/except-3.h
@@ -0,0 +1,24 @@
+
+template
+struct is_nothrow_move_constructible
+{
+ static constexpr bool value = false;
+};
+
+template
+struct _Tuple_impl
+{
+ _Tuple_impl () noexcept(is_nothrow_move_constructible<_Head>::value)
+ { }
+};
+
+template
+void TPL (_Tuple_impl &) noexcept
+{
+ _Tuple_impl m;
+}
+
+inline void foo (_Tuple_impl &p)
+{
+ TPL (p);
+}
diff --git a/gcc/testsuite/g++.dg/modules/except-3_a.H b/gcc/testsuite/g++.dg/modules/except-3_a.H
new file mode 100644
index 00000000000..2f9f00e6222
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/except-3_a.H
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+// We end up with instantiated noexcept specs in the CMI data matching
+// textually loaded fns with uninstantiated ones. Have to propagate,
+// not reinstantiate.
+#include "except-3.h"
diff --git a/gcc/testsuite/g++.dg/modules/except-3_b.C b/gcc/testsuite/g++.dg/modules/except-3_b.C
new file mode 100644
index 00000000000..0cb84725b5a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/except-3_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "except-3.h"
+import "except-3_a.H";
+
+// { dg-final { scan-lang-dump-times {merge key \(new\) function_decl:'::_Tuple_impl::__[cd]t '} 3 module } }
+// { dg-final { scan-lang-dump-times {Propagating instantiated noexcept to '::_Tuple_impl::__ct '} 1 module } }
diff --git a/gcc/testsuite/g++.dg/modules/exp-xlate-1_a.H b/gcc/testsuite/g++.dg/modules/exp-xlate-1_a.H
new file mode 100644
index 00000000000..2079f90c5b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/exp-xlate-1_a.H
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#define PROTECT 1
+int foo ();
diff --git a/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C b/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
new file mode 100644
index 00000000000..3295a6af050
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+export module evil;
+// { dg-module-cmi !evil }
+
+export // { dg-error "not part of following" }
+#include "exp-xlate-1_a.H" // { dg-error "must be contiguous" }
+// { dg-prune-output {not writing module} }
diff --git a/gcc/testsuite/g++.dg/modules/export-1.C b/gcc/testsuite/g++.dg/modules/export-1.C
new file mode 100644
index 00000000000..8ca696ebee0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/export-1.C
@@ -0,0 +1,22 @@
+// { dg-additional-options -fmodules-ts }
+
+export module frob;
+// { dg-module-cmi !frob }
+
+int x ();
+export int x (); // { dg-error "conflicting exporting declaration" }
+
+int y;
+export extern int y; // { dg-error "conflicting exporting declaration" }
+
+typedef int z;
+export typedef int z; // { dg-error "conflicting exporting declaration" }
+
+template int f (T);
+export template int f (T); // { dg-error "conflicting exporting declaration" }
+
+// doesn't go via duplicate_decls so we miss this for now
+class A;
+export class A; // { dg-error "conflicting exporting declaration" "" { xfail *-*-* } }
+
+// { dg-warning "due to errors" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-1_a.H b/gcc/testsuite/g++.dg/modules/extern-tpl-1_a.H
new file mode 100644
index 00000000000..93afc4eecfe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-1_a.H
@@ -0,0 +1,23 @@
+// { dg-module-do link }
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template struct TPL
+{
+ int Source ()
+ {
+ return I;
+ }
+};
+
+extern template class TPL<1>;
+
+struct Foo
+{
+ TPL<1> m;
+
+ Foo () {m.Source ();};
+
+};
+
+static Foo __ioinit;
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-1_b.C b/gcc/testsuite/g++.dg/modules/extern-tpl-1_b.C
new file mode 100644
index 00000000000..f3c0dc483c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options {-fmodules-ts -fmodule-mapper=|@g++-mapper-server} }
+
+// Have to textually include, because we currently get confused about
+// the explicit instantiations and think they conflict
+#include "extern-tpl-1_a.H"
+
+template class TPL<1>;
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-1_c.C b/gcc/testsuite/g++.dg/modules/extern-tpl-1_c.C
new file mode 100644
index 00000000000..d1b6cb6562f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-1_c.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+
+import "extern-tpl-1_a.H";
+
+int main ()
+{
+}
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-2_a.H b/gcc/testsuite/g++.dg/modules/extern-tpl-2_a.H
new file mode 100644
index 00000000000..a90d50ec6f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-2_a.H
@@ -0,0 +1,13 @@
+// { dg-module-do link }
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template struct TPL
+{
+ int Source ()
+ {
+ return I;
+ }
+};
+
+extern template class TPL<1>;
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-2_b.H b/gcc/testsuite/g++.dg/modules/extern-tpl-2_b.H
new file mode 100644
index 00000000000..5f9875c814a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-2_b.H
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+import "extern-tpl-2_a.H";
+
+struct Foo
+{
+ TPL<1> m;
+
+ Foo () {m.Source ();};
+
+};
+
+static Foo __ioinit;
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-2_c.C b/gcc/testsuite/g++.dg/modules/extern-tpl-2_c.C
new file mode 100644
index 00000000000..b73ec6e8cfc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-2_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodules-ts }
+
+import "extern-tpl-2_a.H";
+
+template class TPL<1>;
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-2_d.C b/gcc/testsuite/g++.dg/modules/extern-tpl-2_d.C
new file mode 100644
index 00000000000..25a977fb0ca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-2_d.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+
+import "extern-tpl-2_b.H";
+
+int main ()
+{
+}
diff --git a/gcc/testsuite/g++.dg/modules/flag-1_a.C b/gcc/testsuite/g++.dg/modules/flag-1_a.C
new file mode 100644
index 00000000000..9f733203067
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/flag-1_a.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -std=c++17" }
+export module opt;
+
+// { dg-module-cmi opt }
diff --git a/gcc/testsuite/g++.dg/modules/flag-1_b.C b/gcc/testsuite/g++.dg/modules/flag-1_b.C
new file mode 100644
index 00000000000..32bfd82f1a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/flag-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -std=c++2a" }
+
+// { dg-error "language dialect differs" "" { target *-*-* } 0 }
+
+import opt;
+
+// { dg-error "failed to read" "" { target *-*-* } 0 }
+// { dg-prune-output "compilation terminated" }
+// { dg-prune-output "fatal error" }
diff --git a/gcc/testsuite/g++.dg/modules/fn-inline-1_a.C b/gcc/testsuite/g++.dg/modules/fn-inline-1_a.C
new file mode 100644
index 00000000000..13e717bb394
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/fn-inline-1_a.C
@@ -0,0 +1,21 @@
+// { dg-require-weak "" }
+// { dg-additional-options "-fmodules-ts" }
+export module bob;
+// { dg-module-cmi "bob" }
+
+export inline int frob (int a)
+{
+ return -a;
+}
+
+inline int frob (int s, int a)
+{
+ while (s--)
+ a <<= 1;
+ return a;
+}
+
+export int Frob (int s, int a);
+
+// { dg-final { scan-assembler-not "_Z4frobi:" } }
+// { dg-final { scan-assembler-not "_ZW3bobE4frobii:" } }
diff --git a/gcc/testsuite/g++.dg/modules/fn-inline-1_b.C b/gcc/testsuite/g++.dg/modules/fn-inline-1_b.C
new file mode 100644
index 00000000000..72de1a9a514
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/fn-inline-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts" }
+module bob;
+
+int Frob (int n, int a)
+{
+ return frob (n, a);
+}
+
+// { dg-final { scan-assembler "_ZW3bobE4frobii:" } }
+// { dg-final { scan-assembler ".weak(_definition)?\[\t ]*_?_ZW3bobE4frobii" } }
+// { dg-final { scan-assembler "_Z4Frobii:" } }
diff --git a/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C b/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C
new file mode 100644
index 00000000000..55a7aaa26b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts" }
+import bob;
+
+int main ()
+{
+ if (frob (2) != -2)
+ return 1;
+ if (Frob (0, 2) != 2)
+ return 1;
+ if (Frob (2, 2) != 8)
+ return 1;
+ return 0;
+}
+
+// { dg-final { scan-assembler "_Z4frobi:" } }
+// { dg-final { scan-assembler ".weak(_definition)?\[\t ]*_?_Z4frobi" } }
diff --git a/gcc/testsuite/g++.dg/modules/freeze-1_a.C b/gcc/testsuite/g++.dg/modules/freeze-1_a.C
new file mode 100644
index 00000000000..f05dd3da163
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/freeze-1_a.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+export module bob;
+// { dg-module-cmi "bob" }
+
+export void bob ();
diff --git a/gcc/testsuite/g++.dg/modules/freeze-1_b.C b/gcc/testsuite/g++.dg/modules/freeze-1_b.C
new file mode 100644
index 00000000000..36d1323c2f3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/freeze-1_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+export module stuart;
+// { dg-module-cmi "stuart" }
+
+export void stuart ();
diff --git a/gcc/testsuite/g++.dg/modules/freeze-1_c.C b/gcc/testsuite/g++.dg/modules/freeze-1_c.C
new file mode 100644
index 00000000000..3941d30bb33
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/freeze-1_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+export module kevin;
+// { dg-module-cmi "kevin" }
+
+export void kevin ();
diff --git a/gcc/testsuite/g++.dg/modules/freeze-1_d.C b/gcc/testsuite/g++.dg/modules/freeze-1_d.C
new file mode 100644
index 00000000000..faeae148567
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/freeze-1_d.C
@@ -0,0 +1,21 @@
+// { dg-additional-options "-fmodules-ts --param lazy-modules=1 -fdump-lang-module" }
+
+import bob;
+import stuart;
+import kevin;
+
+int main ()
+{
+ stuart ();
+ bob ();
+ kevin ();
+
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Freezing 'bob.[^']*'} module } }
+// { dg-final { scan-lang-dump {Freezing 'stuart.[^']*'} module } }
+// { dg-final { scan-lang-dump {Freezing 'kevin.[^']*'} module } }
+// { dg-final { scan-lang-dump {Defrosting 'bob.[^']*'} module } }
+// { dg-final { scan-lang-dump {Defrosting 'stuart.[^']*'} module } }
+// { dg-final { scan-lang-dump {Defrosting 'kevin.[^']*'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/friend-1_a.C b/gcc/testsuite/g++.dg/modules/friend-1_a.C
new file mode 100644
index 00000000000..2cfab400be7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-1_a.C
@@ -0,0 +1,37 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+
+export module bob;
+// { dg-module-cmi bob }
+
+export struct peeker
+{
+ static int peek (void *);
+};
+
+
+export class hidey
+{
+protected:
+ int key;
+
+public:
+ hidey (int key) :key (key)
+ {
+ }
+
+ friend class peeker;
+};
+
+export class secret : public hidey
+{
+public:
+ secret (int key) : hidey (key)
+ {
+ }
+};
+
+// hidey, peeker & secret are all in different clusters
+
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl definition '::peeker'\n( \[.\]=[^\n]*'\n)* \[.\]=binding '::peeker'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl definition '::hidey'\n( \[.\]=[^\n]*'\n)* \[.\]=binding '::hidey'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl definition '::secret'\n( \[.\]=[^\n]*'\n)* \[.\]=binding '::secret'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/friend-1_b.C b/gcc/testsuite/g++.dg/modules/friend-1_b.C
new file mode 100644
index 00000000000..380bbc54b91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+module bob;
+
+int peeker::peek (void *data)
+{
+ return reinterpret_cast (data)->key;
+}
+
+// { dg-final { scan-lang-dump {Class '::hidey@bob:.' befriending record_type:'::peeker@bob:.'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/friend-1_c.C b/gcc/testsuite/g++.dg/modules/friend-1_c.C
new file mode 100644
index 00000000000..2fb2988aa7f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-1_c.C
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodules-ts }
+
+import bob;
+
+int main ()
+{
+ secret s (5);
+
+ if (peeker::peek (&s) != 5)
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/friend-2_a.C b/gcc/testsuite/g++.dg/modules/friend-2_a.C
new file mode 100644
index 00000000000..ed329d42bb3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-2_a.C
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodules-ts }
+
+export module bink;
+// { dg-module-cmi bink }
+
+class pusher
+{
+ friend void frob (pusher *){}
+public:
+ pusher (){}
+};
+
+inline void grabber (pusher *p)
+{
+ frob (p);
+}
diff --git a/gcc/testsuite/g++.dg/modules/friend-2_b.C b/gcc/testsuite/g++.dg/modules/friend-2_b.C
new file mode 100644
index 00000000000..27034c709d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-2_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+
+module bink;
+
+struct other {};
+
+void f (pusher *p, other *q)
+{
+ grabber (p);
+
+ frob (p); // ok, found by ADL
+
+ frob (q); // { dg-error "not declared" }
+}
diff --git a/gcc/testsuite/g++.dg/modules/friend-3.C b/gcc/testsuite/g++.dg/modules/friend-3.C
new file mode 100644
index 00000000000..48320eba46a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-3.C
@@ -0,0 +1,34 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi !foo }
+
+namespace bob {
+
+export void corge ();
+void grault ();
+
+export class Q
+{
+ friend void foo ();
+ friend void bar ();
+ friend void corge ();
+ friend void grault ();
+};
+
+export void foo ();
+void bar (); // exported
+
+class R
+{
+ friend void quux ();
+ friend void toto ();
+ friend void corge ();
+ friend void grault ();
+};
+
+export void quux (); // { dg-error "conflicting export" }
+void toto (); // not exported
+
+}
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/friend-4_a.C b/gcc/testsuite/g++.dg/modules/friend-4_a.C
new file mode 100644
index 00000000000..d9559c6577e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-4_a.C
@@ -0,0 +1,33 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+namespace bob {
+
+export void corge ();
+void grault ();
+
+export class Q
+{
+ friend void foo ();
+ friend void bar ();
+ friend void corge ();
+ friend void grault ();
+ friend void xyzzy (Q);
+};
+
+export void foo ();
+void bar (); // exported
+
+class R
+{
+ friend void toto ();
+ friend void corge ();
+ friend void grault ();
+ friend void xyzzy (R);
+};
+
+void toto (); // not exported
+export R getR ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/friend-4_b.C b/gcc/testsuite/g++.dg/modules/friend-4_b.C
new file mode 100644
index 00000000000..759dbb5c73b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-4_b.C
@@ -0,0 +1,19 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+using namespace bob;
+
+void doit ()
+{
+ corge ();
+ foo ();
+ bar ();
+
+ grault (); // { dg-error "not declared" }
+ toto (); // { dg-error "not declared" }
+ xyzzy (); // { dg-error "not declared" }
+
+ xyzzy (getR); // ADL
+ xyzzy (Q{}); // ADL
+}
diff --git a/gcc/testsuite/g++.dg/modules/friend-5_a.C b/gcc/testsuite/g++.dg/modules/friend-5_a.C
new file mode 100644
index 00000000000..4d005a876ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-5_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+// From Andrew Sutton
+
+export module foo;
+// { dg-module-cmi foo }
+export class A {
+ friend class B;
+};
diff --git a/gcc/testsuite/g++.dg/modules/friend-5_b.C b/gcc/testsuite/g++.dg/modules/friend-5_b.C
new file mode 100644
index 00000000000..f043d7a340d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-5_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+// From Andrew Sutton
+
+export module bar;
+import foo;
+
+class B { // { dg-error "in a different module" }
+ B() { object.value = 42; }
+ A object;
+};
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/gc-1_a.C b/gcc/testsuite/g++.dg/modules/gc-1_a.C
new file mode 100644
index 00000000000..5ee20c9e063
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gc-1_a.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts --param ggc-min-expand=0 --param ggc-min-heapsize=0" }
+
+export module bob;
+// { dg-module-cmi bob }
+
+export int bob ();
+
+void frink ()
+{
+}
diff --git a/gcc/testsuite/g++.dg/modules/gc-1_b.C b/gcc/testsuite/g++.dg/modules/gc-1_b.C
new file mode 100644
index 00000000000..d6ff09caaae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gc-1_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts" }
+export module stuart;
+
+export int stuart ();
diff --git a/gcc/testsuite/g++.dg/modules/gc-1_c.C b/gcc/testsuite/g++.dg/modules/gc-1_c.C
new file mode 100644
index 00000000000..289a9995e65
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gc-1_c.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts" }
+export module kevin;
+
+export int kevin ();
diff --git a/gcc/testsuite/g++.dg/modules/gc-1_d.C b/gcc/testsuite/g++.dg/modules/gc-1_d.C
new file mode 100644
index 00000000000..a27e5d46603
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gc-1_d.C
@@ -0,0 +1,28 @@
+// { dg-additional-options "-fmodules-ts --param ggc-min-expand=0 --param ggc-min-heapsize=0" }
+
+import bob;
+import stuart;
+import kevin;
+
+void frob ()
+{
+}
+
+void stuart (int);
+
+void quux ()
+{
+ bob ();
+}
+
+void toto ()
+{
+ stuart (1);
+}
+
+void fido ()
+{
+ stuart ();
+ kevin ();
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/gc-2.map b/gcc/testsuite/g++.dg/modules/gc-2.map
new file mode 100644
index 00000000000..58963bdb32d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gc-2.map
@@ -0,0 +1,2 @@
+$root .
+frob map-1_a.nms
diff --git a/gcc/testsuite/g++.dg/modules/gc-2_a.C b/gcc/testsuite/g++.dg/modules/gc-2_a.C
new file mode 100644
index 00000000000..a006fb394cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gc-2_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts --param ggc-min-expand=0 --param ggc-min-heapsize=0 -fno-module-lazy -fmodule-mapper=[srcdir]/gc-2.map" }
+// { dg-additional-files map-1.map }
+
+// Make sure the module hash table survives GC
+
+// { dg-module-cmi "=map-1_a.nms" }
+export module frob;
+
+int thing;
diff --git a/gcc/testsuite/g++.dg/modules/global-1_a.C b/gcc/testsuite/g++.dg/modules/global-1_a.C
new file mode 100644
index 00000000000..68e18e35342
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/global-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+module;
+# 4 "gmf" 1
+int bar ();
+# 6 "" 2
+export module thing;
+// { dg-module-cmi "thing" }
+
+export int baz ();
diff --git a/gcc/testsuite/g++.dg/modules/global-1_b.C b/gcc/testsuite/g++.dg/modules/global-1_b.C
new file mode 100644
index 00000000000..9a67fb17f20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/global-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+import thing;
+
+void bink ()
+{
+ baz ();
+ bar (); // { dg-error "not declared" "" }
+}
diff --git a/gcc/testsuite/g++.dg/modules/gmf-1_a.C b/gcc/testsuite/g++.dg/modules/gmf-1_a.C
new file mode 100644
index 00000000000..a340e3fd716
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gmf-1_a.C
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+
+module;
+
+# 6 "std" 1
+template
+class basic_string_view
+{
+public:
+ basic_string_view(const char* __str) noexcept;
+};
+
+# 14 "" 2
+export module hello;
+// { dg-module-cmi hello }
+export void greeter (basic_string_view const &name)
+{
+
+}
diff --git a/gcc/testsuite/g++.dg/modules/gmf-1_b.C b/gcc/testsuite/g++.dg/modules/gmf-1_b.C
new file mode 100644
index 00000000000..7162d2d1f11
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gmf-1_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+import hello;
+int main (void)
+{
+ greeter ("world");
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading definition of '::template basic_string_view@hello:1'} module } }
+// { dg-final { scan-lang-dump {Read declaration of '::basic_string_view@hello:1'} module } }
+// { dg-final { scan-lang-dump {Read declaration of '::greeter@hello:1'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/gmf-2_a.H b/gcc/testsuite/g++.dg/modules/gmf-2_a.H
new file mode 100644
index 00000000000..4318b166557
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gmf-2_a.H
@@ -0,0 +1,10 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#define MACRO(X) X
+
+inline int frob (int x)
+{
+ return x + 2;
+}
diff --git a/gcc/testsuite/g++.dg/modules/gmf-2_b.C b/gcc/testsuite/g++.dg/modules/gmf-2_b.C
new file mode 100644
index 00000000000..15fafd6f78b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gmf-2_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+module;
+
+import "gmf-2_a.H";
+
+export module Foo;
+// { dg-module-cmi Foo }
+
+export inline int MACRO (fn) (int i)
+{
+ return frob (i);
+}
+
+export int (MACRO) (int i);
diff --git a/gcc/testsuite/g++.dg/modules/gmf-2_c.C b/gcc/testsuite/g++.dg/modules/gmf-2_c.C
new file mode 100644
index 00000000000..4b4acc650ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gmf-2_c.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+module Foo;
+
+// We see no frob from primary's GMF
+int frob (int x)
+{
+ return fn (-x);
+}
+
+// We see no macro from primary's GMF
+int MACRO (int i)
+{
+ return frob (i);
+}
diff --git a/gcc/testsuite/g++.dg/modules/gmf-2_d.C b/gcc/testsuite/g++.dg/modules/gmf-2_d.C
new file mode 100644
index 00000000000..357c8e81404
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gmf-2_d.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+import Foo;
+
+// We see no MACRO
+
+int main ()
+{
+ return !(MACRO (5) == -3);
+}
diff --git a/gcc/testsuite/g++.dg/modules/gvar_a.C b/gcc/testsuite/g++.dg/modules/gvar_a.C
new file mode 100644
index 00000000000..2855b33e250
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gvar_a.C
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+module;
+# 3 __FILE__ 1
+
+int v1;
+
+# 9 "" 2
+export module b;
+// { dg-module-cmi b }
+
+export inline auto get ()
+{
+ return v1;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/gvar_b.C b/gcc/testsuite/g++.dg/modules/gvar_b.C
new file mode 100644
index 00000000000..e53e3f2d5c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/gvar_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+import b;
+
+int main ()
+{
+ get ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/hdr-1_a.H b/gcc/testsuite/g++.dg/modules/hdr-1_a.H
new file mode 100644
index 00000000000..4ce045b7153
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/hdr-1_a.H
@@ -0,0 +1,10 @@
+// { dg-additional-options {-fmodule-header -fdump-lang-module-blocks} }
+
+// { dg-module-cmi {} }
+
+class frob;
+
+template class FROB;
+
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl declaration '::frob'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl declaration '::template FROB'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/hdr-1_b.H b/gcc/testsuite/g++.dg/modules/hdr-1_b.H
new file mode 100644
index 00000000000..6817f938e1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/hdr-1_b.H
@@ -0,0 +1,21 @@
+// { dg-additional-options {-fmodule-header -fdump-lang-module-blocks} }
+
+// { dg-module-cmi {} }
+
+import "hdr-1_a.H";
+
+class frob
+{
+public:
+ int field;
+};
+
+template
+class FROB
+{
+public:
+ static constexpr int val = J;
+};
+
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl definition '::frob'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl definition '::template FROB'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/hdr-1_c.C b/gcc/testsuite/g++.dg/modules/hdr-1_c.C
new file mode 100644
index 00000000000..f8fa0934a58
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/hdr-1_c.C
@@ -0,0 +1,14 @@
+// { dg-additional-options {-fmodules-ts} }
+
+import "hdr-1_b.H";
+
+int foo (frob *p)
+{
+ return p->field;
+}
+
+int foo (FROB<2> *p)
+{
+ return p->val;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/hdr-init-1_a.H b/gcc/testsuite/g++.dg/modules/hdr-init-1_a.H
new file mode 100644
index 00000000000..25cbf3fc616
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/hdr-init-1_a.H
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+int bob ();
+
+static int var = bob ();
diff --git a/gcc/testsuite/g++.dg/modules/hdr-init-1_b.H b/gcc/testsuite/g++.dg/modules/hdr-init-1_b.H
new file mode 100644
index 00000000000..25cbf3fc616
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/hdr-init-1_b.H
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+int bob ();
+
+static int var = bob ();
diff --git a/gcc/testsuite/g++.dg/modules/hdr-init-1_c.C b/gcc/testsuite/g++.dg/modules/hdr-init-1_c.C
new file mode 100644
index 00000000000..efcc4854314
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/hdr-init-1_c.C
@@ -0,0 +1,24 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-alias} }
+
+import "hdr-init-1_a.H";
+import "hdr-init-1_b.H";
+
+int bob ()
+{
+ static int i;
+
+ return ++i;
+}
+
+int main ()
+{
+ return !(var == 1);
+}
+
+// { 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-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 } }
+
diff --git a/gcc/testsuite/g++.dg/modules/horcrux-1_a.C b/gcc/testsuite/g++.dg/modules/horcrux-1_a.C
new file mode 100644
index 00000000000..ff548d039ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/horcrux-1_a.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template
+struct integral_constant
+{};
+
+template
+using __bool_constant = integral_constant;
+
+template
+struct __is_constructible_impl
+ : public __bool_constant<__is_constructible(_Tp, _Args...)>
+{ };
+
diff --git a/gcc/testsuite/g++.dg/modules/horcrux-1_b.C b/gcc/testsuite/g++.dg/modules/horcrux-1_b.C
new file mode 100644
index 00000000000..842bf413585
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/horcrux-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+int main ()
+{
+ __is_constructible_impl x;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/ice-1.C b/gcc/testsuite/g++.dg/modules/ice-1.C
new file mode 100644
index 00000000000..128734d31e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/ice-1.C
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodules-ts" }
+// we ICED on malformed preambles ending at EOF.
+import bob // { dg-error "expected" }
diff --git a/gcc/testsuite/g++.dg/modules/imp-inline-1_a.C b/gcc/testsuite/g++.dg/modules/imp-inline-1_a.C
new file mode 100644
index 00000000000..56bbbdd0456
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-inline-1_a.C
@@ -0,0 +1,37 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+
+module;
+
+# 6 __FILE__ 1
+struct Bob
+{
+ // inline
+ static auto frob ()
+ {
+ }
+};
+
+# 14 "" 2
+
+export module Foo;
+// { dg-module-cmi Foo }
+
+export struct Bill
+{
+ // not inline
+ static auto dob ()
+ {
+ }
+ static inline auto frob ()
+ {
+ }
+};
+
+export inline auto GMF ()
+{
+ return Bob::frob ();
+}
+
+// { dg-final { scan-assembler-not {_ZN3Bob4frobEv:} } }
+// { dg-final { scan-assembler-not {_ZN4Bill4frobEv:} } }
+// { dg-final { scan-assembler {_ZN4Bill3dobEv:} } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-inline-1_b.C b/gcc/testsuite/g++.dg/modules/imp-inline-1_b.C
new file mode 100644
index 00000000000..c127f7005a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-inline-1_b.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-fmodules-ts -fno-inline" }
+
+import Foo;
+
+int main ()
+{
+ GMF ();
+ Bill::dob ();
+ Bill::frob ();
+
+ return 0;
+}
+
+// { dg-final { scan-assembler {_ZN3Bob4frobEv:} } }
+// { dg-final { scan-assembler {_ZN4Bill4frobEv:} } }
+// { dg-final { scan-assembler-not {_ZN4Bill3dobEv:} } }
+// { dg-final { scan-assembler {_Z3GMFv:} } }
+
+// { dg-final { scan-assembler {call[ \t]+_?_ZN3Bob4frobEv} { target i?86-*-* x86_64-*-* } } }
+// { dg-final { scan-assembler {call[ \t]+_?_Z3GMFv} { target i?86-*-* x86_64-*-* } } }
+// { dg-final { scan-assembler {call[ \t]+_?_ZN4Bill3dobEv} { target i?86-*-* x86_64-*-* } } }
+// { dg-final { scan-assembler {call[ \t]+_?_ZN4Bill4frobEv} { target i?86-*-* x86_64-*-* } } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-1_a.C b/gcc/testsuite/g++.dg/modules/imp-member-1_a.C
new file mode 100644
index 00000000000..4798ce5fb56
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-1_a.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+export module A;
+// { dg-module-cmi A }
+
+struct M
+{
+ M (){}
+};
+
+export struct C
+{
+ M m;
+ // lazy implicit ctor
+};
+
+// { dg-final { scan-lang-dump-not {'::C::__ct '} module } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-1_b.C b/gcc/testsuite/g++.dg/modules/imp-member-1_b.C
new file mode 100644
index 00000000000..849cf3c5be4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-1_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+export module B;
+// { dg-module-cmi B }
+export import A;
+
+export struct D
+{
+ C c;
+
+ // ctor causes C::C to exist, and we need to put it in out CMI
+ inline D (){}
+};
+
+// { dg-final { scan-lang-dump {\[.*\]=decl definition '::C@A:1::__ct '} module } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-1_c.C b/gcc/testsuite/g++.dg/modules/imp-member-1_c.C
new file mode 100644
index 00000000000..b354ca8cf98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-1_c.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-alias" }
+import B;
+
+void fn ()
+{
+ D d; // reads in C::C implicit ctor
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(new\) function_decl:'::C@A:.::__ct '\n} module } }
+// { dg-final { scan-lang-dump {Adding implicit member '::C@A:.::__ct @B:.} module } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-1_d.C b/gcc/testsuite/g++.dg/modules/imp-member-1_d.C
new file mode 100644
index 00000000000..c7f3158c80d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-1_d.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+import B;
+
+void fn ()
+{
+ C c; // creates C::C implicitly (we never read B's version)
+}
+
+// { dg-final { scan-lang-dump-not {Read:-1's named merge key \([a-z]*\) function_decl:'::C@A:.::__ct '\n} module } }
+// { dg-final { scan-lang-dump-not {Adding implicit member '::C@A:.::__ct @B:.} module } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-1_e.C b/gcc/testsuite/g++.dg/modules/imp-member-1_e.C
new file mode 100644
index 00000000000..b771850583f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-1_e.C
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-alias" }
+import B;
+
+void fn ()
+{
+ C c; // created C::C implicitly
+}
+
+void fn2 ()
+{
+ D d; // merges implicit C::C
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) function_decl:'::C@A:.::__ct '\n} module } }
+// { dg-final { scan-lang-dump-not {Adding implicit member '::C@A:.::__ct @B:.} module } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-2_a.C b/gcc/testsuite/g++.dg/modules/imp-member-2_a.C
new file mode 100644
index 00000000000..8d4d8396975
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-2_a.C
@@ -0,0 +1,28 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+// A more complete imp-member test
+export module A;
+// { dg-module-cmi A }
+
+struct M
+{
+ M (){}
+ M (M const &){}
+ M (M &&){}
+ ~M (){}
+ M &operator=(M const &){ return *this;}
+ M &operator=(M &&){ return *this;}
+};
+
+export struct C
+{
+ M m;
+ // lazy implicit ctors, dtors, assop
+};
+
+// C doesn't contain a lot
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl definition '::C'\n \[1\]=decl declaration '::C::C'\n \[2\]=binding '::C'\n} module } }
+
+// particularly not ...
+// { dg-final { scan-lang-dump-not {'::C::__ct '} module } }
+// { dg-final { scan-lang-dump-not {'::C::__dt '} module } }
+// { dg-final { scan-lang-dump-not {'::C::operator= '} module } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-2_b.C b/gcc/testsuite/g++.dg/modules/imp-member-2_b.C
new file mode 100644
index 00000000000..09795af0093
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-2_b.C
@@ -0,0 +1,21 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+export module B;
+// { dg-module-cmi B }
+export import A;
+
+export struct D
+{
+ C c;
+
+ // cause all C's implicit members to exist, and we need to put it in out CMI
+ inline D (){}
+ inline D (D const &v) : c (v.c) {}
+ inline D (D &&v) : c (static_cast (v.c)) {}
+ inline ~D () {}
+ inline D &operator= (D const &v) { c = v.c; return *this;}
+ inline D &operator= (D &&v) { c =static_cast (v.c); return *this;}
+};
+
+// { dg-final { scan-lang-dump-times {\[0\]=decl definition '::C@A:1::__dt '} 1 module } }
+// { dg-final { scan-lang-dump-times {\[0\]=decl definition '::C@A:1::__ct '} 3 module } }
+// { dg-final { scan-lang-dump-times {\[0\]=decl definition '::C@A:1::operator='} 2 module } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-2_c.C b/gcc/testsuite/g++.dg/modules/imp-member-2_c.C
new file mode 100644
index 00000000000..bb6b5dee5d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-2_c.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-alias" }
+import B;
+
+void fn ()
+{
+ D d; // reads in C::C implicits
+}
+
+// { dg-final { scan-lang-dump-times {Read:-[0-9]*'s named merge key \(new\) function_decl:'::C@A:.::__dt '\n} 1 module } }
+// { dg-final { scan-lang-dump-times {Adding implicit member '::C@A:.::__dt @B:.} 1 module } }
+// { dg-final { scan-lang-dump-times {Read:-[0-9]*'s named merge key \(new\) function_decl:'::C@A:.::__ct '\n} 3 module } }
+// { dg-final { scan-lang-dump-times {Adding implicit member '::C@A:.::__ct @B:.} 3 module } }
+// { dg-final { scan-lang-dump-times {Read:-[0-9]*'s named merge key \(new\) function_decl:'::C@A:.::operator='\n} 2 module } }
+// { dg-final { scan-lang-dump-times {Adding implicit member '::C@A:.::operator=@B:.} 2 module } }
diff --git a/gcc/testsuite/g++.dg/modules/imp-member-3.H b/gcc/testsuite/g++.dg/modules/imp-member-3.H
new file mode 100644
index 00000000000..d26b13ce0e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/imp-member-3.H
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+class bad_optional_access
+{
+public:
+
+ virtual ~bad_optional_access() noexcept = default; // { dg-bogus "" }
+};
+
+inline void
+__throw_bad_optional_access()
+{
+ throw bad_optional_access ();
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/import-1_a.C b/gcc/testsuite/g++.dg/modules/import-1_a.C
new file mode 100644
index 00000000000..b42153cd08d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/import-1_a.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Bar;
+// { dg-module-cmi "Bar" }
+
+export void Quux (int);
diff --git a/gcc/testsuite/g++.dg/modules/import-1_b.C b/gcc/testsuite/g++.dg/modules/import-1_b.C
new file mode 100644
index 00000000000..ec15856805e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/import-1_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Baz;
+// { dg-module-cmi "Baz" }
+
+export void Quux (int, int);
diff --git a/gcc/testsuite/g++.dg/modules/import-1_c.C b/gcc/testsuite/g++.dg/modules/import-1_c.C
new file mode 100644
index 00000000000..b01aa5e9d2b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/import-1_c.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+// { dg-final { scan-lang-dump "Writing exported import:.->. Baz" "module" } }
+// { dg-final { scan-lang-dump "Writing exported import:.->. Bar" "module" } }
+
+export module Foo;
+// { dg-module-cmi "Foo" }
+
+export import Bar;
+export import Baz;
+
diff --git a/gcc/testsuite/g++.dg/modules/import-1_d.C b/gcc/testsuite/g++.dg/modules/import-1_d.C
new file mode 100644
index 00000000000..45e63401f4a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/import-1_d.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Foop;
+// { dg-module-cmi "Foop" }
+
+import Bar;
+
+export int Thing ();
diff --git a/gcc/testsuite/g++.dg/modules/import-1_e.C b/gcc/testsuite/g++.dg/modules/import-1_e.C
new file mode 100644
index 00000000000..ae7cce2e4b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/import-1_e.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+import Foo;
+
+int main ()
+{
+ Quux (1); // from Bar
+ Quux (1, 2); // from Baz
+ return 0;
+}
+
+// { dg-final { scan-lang-dump "Found exported import:1 Bar->1" "module" } }
+// { dg-final { scan-lang-dump "Found exported import:2 Baz->2" "module" } }
diff --git a/gcc/testsuite/g++.dg/modules/import-1_f.C b/gcc/testsuite/g++.dg/modules/import-1_f.C
new file mode 100644
index 00000000000..8dbe9c02dfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/import-1_f.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+module Foop;
+
+int Thing ()
+{
+ Quux (1); // from Bar
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/import-1_g.C b/gcc/testsuite/g++.dg/modules/import-1_g.C
new file mode 100644
index 00000000000..556ba80c2c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/import-1_g.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts" }
+import Foop;
+
+int main ()
+{
+ Thing ();
+ Quux (1); // { dg-error "not declared" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/import-2.C b/gcc/testsuite/g++.dg/modules/import-2.C
new file mode 100644
index 00000000000..86a14941a44
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/import-2.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+// Don't segfault on missing module BMI
+
+// { dg-module-cmi "!bob" }
+// { dg-module-cmi "!bill" }
+
+import bill;
+// { dg-regexp "In module imported at \[^\n]*import-2.C:7:.:\nbill: error: failed to read compiled module: \[^\n]*\n" }
+
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "compilation terminated" }
+
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-1.map b/gcc/testsuite/g++.dg/modules/inc-xlate-1.map
new file mode 100644
index 00000000000..f2429bf3386
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-1.map
@@ -0,0 +1,2 @@
+
+
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-1_a.H b/gcc/testsuite/g++.dg/modules/inc-xlate-1_a.H
new file mode 100644
index 00000000000..cd906a5b40c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-1_a.H
@@ -0,0 +1,15 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#ifndef _STDARG_H
+#define _STDARG_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void frob ();
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-1_b.H b/gcc/testsuite/g++.dg/modules/inc-xlate-1_b.H
new file mode 100644
index 00000000000..50b27efa7ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-1_b.H
@@ -0,0 +1,21 @@
+// { dg-do preprocess }
+// { dg-additional-options -fmodule-header }
+
+#ifndef _STDIO_H
+#define _STDIO_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Yes, inside extern "C" block :(
+ #include "inc-xlate-1_a.H"
+ #ifndef _STDARG_H
+ #error barf
+ #endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+// { dg-final { scan-file inc-xlate-1_b.i {import "[^\n]*inc-xlate-1_a.H" \[\[__translated\]\];\n} } }
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-1_c.C b/gcc/testsuite/g++.dg/modules/inc-xlate-1_c.C
new file mode 100644
index 00000000000..e1247e645d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-1_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+extern "C" {
+ #include "inc-xlate-1_a.H"
+}
+
+int main ()
+{
+ frob ();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C b/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C
new file mode 100644
index 00000000000..f33c464bee9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=|@g++-mapper-server\\ -t\\ [srcdir]/inc-xlate-1.map" }
+export module bad;
+#include "inc-xlate-1_a.H" // { dg-error "not be include-translated" }
+
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/indirect-1_a.C b/gcc/testsuite/g++.dg/modules/indirect-1_a.C
new file mode 100644
index 00000000000..f2417172fdc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-1_a.C
@@ -0,0 +1,41 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+// indirect references to import. Non-template cases
+
+export module foo;
+// { dg-module-cmi foo }
+
+namespace foo {
+
+ export int frob (int i)
+ {
+ return i;
+ }
+
+
+ export class X
+ {
+ int i;
+
+ public:
+ X (int i) :i(i) { }
+ operator int () const { return i; }
+ };
+
+ export class Y : public virtual X
+ {
+ int j;
+ public:
+ Y (int i, int j) : X(i), j(j){}
+ virtual int frob () const;
+ };
+
+ int Y::frob () const
+ {
+ return *this + j;
+ }
+
+ export enum Plain {A, B, C, D};
+ export enum class Scoped {A, B, C, D};
+}
diff --git a/gcc/testsuite/g++.dg/modules/indirect-1_b.C b/gcc/testsuite/g++.dg/modules/indirect-1_b.C
new file mode 100644
index 00000000000..c450fa9481c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-1_b.C
@@ -0,0 +1,54 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+
+export module bar;
+// { dg-module-cmi bar }
+
+import foo;
+
+namespace bar
+{
+ export int frob (int i = foo::frob (0))
+ {
+ return i;
+ }
+
+ export int quux (int i = foo::X (0) )
+ {
+ return i;
+ }
+
+ export class Z : public foo::Y
+ {
+ public:
+ Z (int i, int j) : X(i), Y(i, j)
+ {
+ }
+ };
+
+ export constexpr auto Plain_One (bool b) { return b ? foo::B : foo::C; }
+ export constexpr auto Scoped_One (bool b) { return b ? foo::Scoped::B
+ : foo::Scoped::C; }
+
+ export extern auto const Plain_Const_Three = foo::D;
+ export extern auto const Scoped_Const_Three = foo::Scoped::D;
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::frob'@'foo' section:} module } }
+// { dg-final { scan-lang-dump-not {namespace:-[0-9]* namespace_decl:'::foo'} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* function_decl:'::foo@foo:.::frob@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::X'@'foo' section:} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* type_decl:'::foo@foo:.::X@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::Y'@'foo' section:} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* type_decl:'::foo@foo:.::Y@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::B'@'foo' section:} module } }
+// { dg-final { scan-lang-dump-not {Lazily binding '::foo@foo:.::C@foo:.'@'foo' section:} module } }
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::Scoped'@'foo' section:} module } }
+// { dg-final { scan-lang-dump-not {Lazily binding '::foo@foo:.::Scoped@foo:.::[ABCD]'@'foo' section:} module } }
+
+// { dg_final { scan-lang-dump {Wrote named import:-[0-9]* const_decl:'::foo::Plain@\(foo\)::C'@foo} module } }
+// { dg_final { scan-lang-dump {Wrote named import:-[0-9]* const_decl:'::foo::Plain@\(foo\)::B'@foo} module } }
+// { dg_final { scan-lang-dump {Wrote named import:-[0-9]* const_decl:'::foo::Scoped@\(foo\)::C'@foo} module } }
+// { dg_final { scan-lang-dump {Wrote named import:-[0-9]* const_decl:'::foo::Scoped@\(foo\)::B'@foo} module } }
diff --git a/gcc/testsuite/g++.dg/modules/indirect-1_c.C b/gcc/testsuite/g++.dg/modules/indirect-1_c.C
new file mode 100644
index 00000000000..73d5974c846
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-1_c.C
@@ -0,0 +1,49 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+import bar;
+
+
+int main ()
+{
+ if (bar::frob ())
+ return 1;
+ if (bar::quux ())
+ return 2;
+
+ if (bar::Z (1, 2).frob () != 3)
+ return 3;
+
+ static_assert (bar::Plain_One (true) == 1);
+ static_assert (bar::Plain_One (false) == 2);
+ static_assert (int (bar::Scoped_One (true)) == 1);
+ static_assert (int (bar::Scoped_One (false)) == 2);
+
+ static_assert (bar::Plain_Const_Three == 3);
+ static_assert (int (bar::Scoped_Const_Three) == 3);
+
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::frob'@'bar' section:} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[14\] section:4} module } }
+// { dg-final { scan-lang-dump {Named:-[0-9]* namespace_decl:'::foo@foo:1'@foo} module } }
+// { dg-final { scan-lang-dump {Imported:-[0-9]* function_decl:'::foo@foo:.::frob@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::quux'@'bar' section:} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[1\] section:1} module } }
+// { dg-final { scan-lang-dump {Imported:-[0-9]* type_decl:'::foo@foo:.::X@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::Z'@'bar' section:} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[8\] section:2} module } }
+// { dg-final { scan-lang-dump {Imported:-[0-9]* type_decl:'::foo@foo:.::Y@foo:.'@foo} module } }
+// { dg-final { scan-lang-dump {Read member:-[0-9]* field_decl:'::foo@foo:.::Y@foo:.::_vptr.Y'} module } }
+// { dg-final { scan-lang-dump {Imported:-[0-9]* function_decl:'::foo@foo:.::Y@foo:.::frob@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::Plain_One'@'bar' section:} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[13\] section:3} module } }
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::Scoped_One'@'bar' section} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[15\] section:5} module } }
+// { dg-final { scan-lang-dump-not {Lazily binding '::foo@foo:.::[ABC]'@'foo' section:} module } }
+// { dg-final { scan-lang-dump-not {Lazily binding '::foo@foo:.::Scoped@\(foo\)::[ABC]'@'foo' section:} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::Plain_Const_Three'@'bar' section:} module } }
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::Scoped_Const_Three'@'bar' section} module } }
diff --git a/gcc/testsuite/g++.dg/modules/indirect-2_a.C b/gcc/testsuite/g++.dg/modules/indirect-2_a.C
new file mode 100644
index 00000000000..20febb935b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-2_a.C
@@ -0,0 +1,24 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+// indirect references to import, simple templates
+
+export module foo;
+// { dg-module-cmi foo }
+
+namespace foo
+{
+ export template int frob ()
+ {
+ return I;
+ }
+
+ export template class X
+ {
+ int i = I;
+
+ public:
+ operator int () const { return i; }
+ };
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/indirect-2_b.C b/gcc/testsuite/g++.dg/modules/indirect-2_b.C
new file mode 100644
index 00000000000..16e060a2210
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-2_b.C
@@ -0,0 +1,31 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-alias-uid" }
+export module bar;
+// { dg-module-cmi bar }
+
+import foo;
+
+namespace bar
+{
+ export int frob (int i = foo::frob<0> ())
+ {
+ return i;
+ }
+
+ export int quux (int i = foo::X<0> ())
+ {
+ return i;
+ }
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::frob'@'foo' section} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* template_decl:'::foo@foo:.::template frob@foo:.'@foo} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) function_decl:'::foo@foo:.::frob<0x0>'} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::X'@'foo' section:} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* template_decl:'::foo@foo:.::template X@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::foo@foo:.::X<0x0>'\n \[1\]=specialization declaration '::foo@foo:.::X<0x0>::__conv_op <0x0>'\n \[2\]=specialization declaration '::foo@foo:.::X<0x0>::X<0x0>'\n( \[.\]=[^\n]* '\n)*} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s type spec merge key \(specialization\) type_decl:'::foo@foo:.::X<0x0>'} module } }
+// { dg-final { scan-lang-dump {Depset:. specialization entity:. type_decl:'::foo@foo:.::X<0x0>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s type spec merge key \(specialization\) type_decl:'::foo@foo:.::X<0x0>'} module } }
+// { dg-final { scan-lang-dump {Wrote purview:-[0-9]* type_decl:'::foo@foo:.::X<0x0>'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/indirect-2_c.C b/gcc/testsuite/g++.dg/modules/indirect-2_c.C
new file mode 100644
index 00000000000..a5cf44ba785
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-2_c.C
@@ -0,0 +1,25 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+import bar;
+
+int main ()
+{
+
+ if (bar::frob ())
+ return 1;
+
+ if (bar::quux ())
+ return 2;
+
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::frob'@'bar' section:} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[4\] section:2} module } }
+// { dg-final { scan-lang-dump {Imported:-[0-9]* template_decl:'::foo@foo:.::template frob@foo:.'@foo} module } }
+// { dg-final { scan-lang-dump-not {Wrote mergeable} module } }
+
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::quux'@'bar' section:} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[1\] section:1} module } }
+// { dg-final { scan-lang-dump {Imported:-[0-9]* template_decl:'::foo@foo:.::template X@foo:.'@foo} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]* function_decl:'::foo@foo:.::frob<0x0>'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/indirect-3_a.C b/gcc/testsuite/g++.dg/modules/indirect-3_a.C
new file mode 100644
index 00000000000..fad9ecf1548
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-3_a.C
@@ -0,0 +1,23 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+// indirect references to import, template member non-template or
+// non-template member of template cases
+
+export module foo;
+// { dg-module-cmi foo }
+
+namespace foo
+{
+ export class X
+ {
+ public:
+ template int frob () const { return I; }
+ };
+
+ export template class TPL
+ {
+ public:
+ int frob () const { return I; }
+ };
+}
diff --git a/gcc/testsuite/g++.dg/modules/indirect-3_b.C b/gcc/testsuite/g++.dg/modules/indirect-3_b.C
new file mode 100644
index 00000000000..5bdfc1d36a8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-3_b.C
@@ -0,0 +1,30 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-uid-alias" }
+export module bar;
+// { dg-module-cmi bar }
+
+import foo;
+
+namespace bar
+{
+ export int quux (int i = foo::X().frob<0> ())
+ {
+ return i;
+ }
+
+ export int toto (int i = foo::TPL<0>().frob ())
+ {
+ return i;
+ }
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::X'@'foo' section} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* template_decl:'::foo@foo:.::X@foo:.::template frob@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::TPL'@'foo' section} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* template_decl:'::foo@foo:.::template TPL@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::foo@foo:.::TPL<0x0>'\n \[1\]=specialization declaration '::foo@foo:.::TPL<0x0>::TPL<0x0>'\n( \[.\]=[^\n]* '\n)* \[.\]=decl definition '::foo@foo:.::TPL<0x0>::frob<0x0>'\n} module } }
+
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::foo@foo:.::X@foo:.::frob<0x0>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s type spec merge key \(specialization\) type_decl:'::foo@foo:.::TPL<0x0>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) function_decl:'::foo@foo:.::X@foo:.::frob<0x0>'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/indirect-3_c.C b/gcc/testsuite/g++.dg/modules/indirect-3_c.C
new file mode 100644
index 00000000000..9c5cb230ad2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-3_c.C
@@ -0,0 +1,24 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+import bar;
+
+int main ()
+{
+
+ if (bar::quux ())
+ return 1;
+
+ if (bar::toto ())
+ return 2;
+
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar@bar:.::quux'@'bar' section:} module } }
+// { dg-final { scan-lang-dump {>Loading entity foo\[5\] section:2} module } }
+// { dg-final { scan-lang-dump {Imported:-[0-9]* template_decl:'::foo@foo:.::X@foo:.::template frob@foo:.'@foo} module } }
+// { 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 {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 } }
diff --git a/gcc/testsuite/g++.dg/modules/indirect-4_a.C b/gcc/testsuite/g++.dg/modules/indirect-4_a.C
new file mode 100644
index 00000000000..44f4b660a6e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-4_a.C
@@ -0,0 +1,20 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+// indirect references to import, template member of template case
+
+export module foo;
+// { dg-module-cmi foo }
+
+namespace foo
+{
+ export template class TPL
+ {
+ public:
+ template int frob () const
+ {
+ return I + J;
+ }
+ };
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/indirect-4_b.C b/gcc/testsuite/g++.dg/modules/indirect-4_b.C
new file mode 100644
index 00000000000..8c51ce8097b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-4_b.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-alias-uid" }
+export module bar;
+// { dg-module-cmi bar }
+
+import foo;
+
+namespace bar
+{
+ export int quux (int i = foo::TPL<1> ().frob<2> ())
+ {
+ return i;
+ }
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::TPL'@'foo' section:} module } }
+// { dg-final { scan-lang-dump {Wrote import:-[0-9]* template_decl:'::foo@foo:.::template TPL@foo:.'@foo} module } }
+
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::foo@foo:.::TPL<0x1>'\n \[1\]=specialization declaration '::foo@foo:.::TPL<0x1>::template frob<#unnamed#>'\n \[2\]=specialization declaration '::foo@foo:.::TPL<0x1>::TPL<0x1>'\n( \[.\]=[^\n]* '\n)*} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::foo@foo:.::TPL<0x1>::frob<0x2>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s type spec merge key \(specialization\) type_decl:'::foo@foo:.::TPL<0x1>'} module } }
+// { dg-final { scan-lang-dump {Wrote purview:-[0-9]* type_decl:'::foo@foo:.::TPL<0x1>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) function_decl:'::foo@foo:.::TPL<0x1>::frob<0x2>'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/indirect-4_c.C b/gcc/testsuite/g++.dg/modules/indirect-4_c.C
new file mode 100644
index 00000000000..7efcc115e71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/indirect-4_c.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid-alias" }
+import bar;
+
+int main ()
+{
+ if (bar::quux () != 3)
+ return 1;
+
+ return 0;
+}
+
+// { 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 {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 } }
+// { dg-final { scan-lang-dump {Reading definition type_decl '::foo@foo:.::TPL@bar:.<0x1>'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inext-1.H b/gcc/testsuite/g++.dg/modules/inext-1.H
new file mode 100644
index 00000000000..7708c391618
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inext-1.H
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodule-header -isystem [srcdir] -isystem [srcdir]/sys -fdump-lang-module" }
+
+#ifndef _PROTECT
+#define _PROTECT
+
+/* We were found on the system inc path, so have been turned into a
+ system header, so no warning on the following extension. */
+#include_next
+
+#endif
+
diff --git a/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1.h b/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1.h
new file mode 100644
index 00000000000..13f769f12d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1.h
@@ -0,0 +1,35 @@
+
+template
+struct Base
+{
+ // template constructor
+ template Base(_Tp *__p, _Del __d);
+};
+
+template
+struct Derived : Base<_Tp>
+{
+ // Inheriting the template constructor
+ using Base<_Tp>::Base;
+};
+
+template
+class unique_ptr
+{
+ Derived<_Tp, int> _M_t;
+
+public:
+ // Instantiates Derived::Derived
+ template unique_ptr(unique_ptr<_Up>&& __u) noexcept
+ : _M_t ((_Tp *)0, 1) { }
+};
+
+struct ResultBase { };
+struct ResultDerived : ResultBase { };
+
+void Frob (unique_ptr &&__res) ;
+
+inline void X (unique_ptr &parm)
+{
+ Frob (static_cast &&> (parm));
+}
diff --git a/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_a.H b/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_a.H
new file mode 100644
index 00000000000..822221229c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "inh-tmpl-ctor-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_b.C b/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_b.C
new file mode 100644
index 00000000000..ae1612c1475
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+#include "inh-tmpl-ctor-1.h"
+import "inh-tmpl-ctor-1_a.H";
+
diff --git a/gcc/testsuite/g++.dg/modules/init-1_a.C b/gcc/testsuite/g++.dg/modules/init-1_a.C
new file mode 100644
index 00000000000..b5727d7e3b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/init-1_a.C
@@ -0,0 +1,11 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -fno-inline" }
+export module Foo;
+// { dg-module-cmi Foo }
+
+int Frob (int i)
+{
+ return i;
+}
+
+export int j = Frob (5);
diff --git a/gcc/testsuite/g++.dg/modules/init-1_b.C b/gcc/testsuite/g++.dg/modules/init-1_b.C
new file mode 100644
index 00000000000..3d2239f9982
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/init-1_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fno-inline" }
+import Foo;
+
+int frob (int j)
+{
+ return j + 1;
+}
+
+int q = frob (j);
+
+int main ()
+{
+ return !(q == 6);
+}
diff --git a/gcc/testsuite/g++.dg/modules/init-2_a.C b/gcc/testsuite/g++.dg/modules/init-2_a.C
new file mode 100644
index 00000000000..1e9093ef13d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/init-2_a.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -fno-inline" }
+export module Foo;
+// { dg-module-cmi Foo }
+
+// { dg-final { scan-assembler {_ZGIW3FooEv:} } }
diff --git a/gcc/testsuite/g++.dg/modules/init-2_b.C b/gcc/testsuite/g++.dg/modules/init-2_b.C
new file mode 100644
index 00000000000..b9692ca862c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/init-2_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-inline" }
+export module Bar;
+// { dg-module-cmi Bar }
+
+import Foo;
+
+// { dg-final { scan-assembler {_?_ZGIW3BarEv:} } }
+// { dg-final { scan-assembler {call[ \t]+_?_ZGIW3FooEv} { target i?86-*-* x86_64-*-* } } }
diff --git a/gcc/testsuite/g++.dg/modules/init-2_c.C b/gcc/testsuite/g++.dg/modules/init-2_c.C
new file mode 100644
index 00000000000..c1fa5d80cd4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/init-2_c.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-inline" }
+
+import Foo;
+import Bar;
+
+// We know Bar imports Foo, so only call Bar's Global Init
+// { dg-final { scan-assembler {call[ \t]+_?_ZGIW3BarEv} { target i?86-*-* x86_64-*-* } } }
+// { dg-final { scan-assembler-not {call[ \t]+_?_ZGIW3FooEv} { target i?86-*-* x86_64-*-* } } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-1_a.C b/gcc/testsuite/g++.dg/modules/inst-1_a.C
new file mode 100644
index 00000000000..e1d438b5c19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-1_a.C
@@ -0,0 +1,42 @@
+// { dg-module-do run }
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks} }
+
+export module foo;
+// { dg-module-cmi foo }
+
+int i_baz (int i)
+{
+ return i;
+}
+
+inline int baz (int i)
+{
+ return i_baz (i);
+}
+
+int f_baz (float f)
+{
+ return int (f);
+}
+
+inline int baz (float f)
+{
+ return f_baz (f);
+}
+
+export template
+int foo (T t)
+{
+ return baz (t);
+}
+
+export inline void user ()
+{
+ foo (1);
+ foo (1.0f);
+}
+
+// { dg-final { scan-lang-dump {Depending definition function_decl:'::foo'} module } }
+// { dg-final { scan-lang-dump {Depending definition function_decl:'::foo'} module } }
+// { dg-final { scan-lang-dump {\[0\]=specialization definition '::foo'} module } }
+// { dg-final { scan-lang-dump {\[0\]=specialization definition '::foo'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-1_b.C b/gcc/testsuite/g++.dg/modules/inst-1_b.C
new file mode 100644
index 00000000000..08a92aef63a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-1_b.C
@@ -0,0 +1,16 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-uid-alias} }
+import foo;
+
+int main ()
+{
+ user ();
+ foo ('a'); // new inst
+ foo (1); // find foo's inst
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading definition function_decl '::foo@foo:.'} module } }
+// { dg-final { scan-lang-dump {Reading definition function_decl '::foo@foo:.'} module } }
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(unique\) function_decl:'::baz'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(unique\) function_decl:'::baz'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-2_a.C b/gcc/testsuite/g++.dg/modules/inst-2_a.C
new file mode 100644
index 00000000000..40d6229d4b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-2_a.C
@@ -0,0 +1,26 @@
+// { dg-module-do run }
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-blocks-uid-alias} }
+
+export module foo;
+// { dg-module-cmi foo }
+
+inline int baz (int i)
+{
+ return i;
+}
+
+export template
+inline int foo (T t)
+{
+ return baz (t);
+}
+
+export inline void user ()
+{
+ foo (1);
+}
+
+// { dg-final { scan-lang-dump {\[0\]=specialization definition '::foo'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s named merge key \(decl\) function_decl:'::baz'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) function_decl:'::foo'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) function_decl:'::foo'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-2_b.C b/gcc/testsuite/g++.dg/modules/inst-2_b.C
new file mode 100644
index 00000000000..3e918bcfb31
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-2_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-uid-alias} }
+import foo;
+
+int main ()
+{
+ foo (1); // read pending inst
+ user (); //
+ foo (1); // reuse inst
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading 1 pending specializations} module } }
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s decl spec merge key \(new\) function_decl:'::foo'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-3_a.C b/gcc/testsuite/g++.dg/modules/inst-3_a.C
new file mode 100644
index 00000000000..3305805b5b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-3_a.C
@@ -0,0 +1,21 @@
+// { dg-module-do run }
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks-alias} }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export template struct TPL
+{
+ T m;
+};
+
+export inline int user (int i)
+{
+ TPL x;
+ x.m = i;
+ return x.m;
+}
+
+// { dg-final { scan-lang-dump {Cluster members:\n( \[.\]=[^\n]*'\n)* \[.\]=specialization definition '::TPL'\n \[.\]=specialization declaration '::TPL::TPL'\n} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s type spec merge key \(specialization\) type_decl:'::TPL'} module } }
+// { dg-final { scan-lang-dump {Depset:. specialization entity:. type_decl:'::TPL'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-3_b.C b/gcc/testsuite/g++.dg/modules/inst-3_b.C
new file mode 100644
index 00000000000..80a9946587c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-3_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-alias-uid} }
+import foo;
+
+int main ()
+{
+ if (user (1) != 1)
+ return 1;
+ TPL x;
+ TPL y;
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s type spec merge key \(new\) type_decl:'::TPL'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s decl spec merge key \(new\) type_decl:'::template TPL@foo:.::TPL'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-4_a.C b/gcc/testsuite/g++.dg/modules/inst-4_a.C
new file mode 100644
index 00000000000..e7435ec2ee1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-4_a.C
@@ -0,0 +1,20 @@
+// { dg-module-do run }
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks-alias} }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export template struct TPL
+{
+ T m;
+};
+
+export inline int user (int i)
+{
+ TPL x;
+ x.m = i;
+ return x.m;
+}
+
+// { dg-final { scan-lang-dump {Specialization '::TPL' entity:. keyed to foo\[.\] '::template TPL'} module } }
+// { dg-final { scan-lang-dump {Specialization '::TPL::TPL' entity:. keyed to foo\[.\] '::template TPL::template TPL'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-4_b.C b/gcc/testsuite/g++.dg/modules/inst-4_b.C
new file mode 100644
index 00000000000..c83e1c1437c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-4_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-alias-uid} }
+import foo;
+
+int main ()
+{
+ TPL x;
+ if (user (1) != 1)
+ return 1;
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading 1 pending specializations keyed to foo\[.\] '::template TPL@foo:.'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s type spec merge key \(new\) type_decl:'::TPL'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/inst-5_a.H b/gcc/testsuite/g++.dg/modules/inst-5_a.H
new file mode 100644
index 00000000000..46d9432fe7c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-5_a.H
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template int fn ()
+{
+ return I;
+}
+
+inline void g ()
+{
+ fn<1> (); // instantiation gets emitted
+}
diff --git a/gcc/testsuite/g++.dg/modules/inst-5_b.C b/gcc/testsuite/g++.dg/modules/inst-5_b.C
new file mode 100644
index 00000000000..7cc94c83be3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-5_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+template int fn ()
+{
+ return I;
+}
+
+void f ()
+{
+ fn<1> ();
+}
+
+import "inst-5_a.H";
+// no longer need to instantate
diff --git a/gcc/testsuite/g++.dg/modules/internal-1.C b/gcc/testsuite/g++.dg/modules/internal-1.C
new file mode 100644
index 00000000000..45d3bf06f28
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-1.C
@@ -0,0 +1,21 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module frob; // { dg-error "failed to write" }
+// { dg-module-cmi !frob }
+
+namespace {
+// We shouldn't be complaining about members of internal linkage
+// entities
+class X // { dg-bogus "internal linkage" "" { xfail *-*-* } }
+{ // { dg-bogus "internal linkage" "" { xfail *-*-* } }
+};
+
+}
+
+static int frob ()
+{
+ return 1;
+}
+
+export int f (int = frob ()); // { dg-error "references internal linkage" }
+int goof (X &); // { dg-error "references internal linkage" }
diff --git a/gcc/testsuite/g++.dg/modules/internal-2_a.H b/gcc/testsuite/g++.dg/modules/internal-2_a.H
new file mode 100644
index 00000000000..4b530bdc72c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-2_a.H
@@ -0,0 +1,10 @@
+// { dg-module-do run }
+// { dg-additional-options {-fmodule-header -fdump-lang-module-blocks} }
+// { dg-module-cmi {} }
+
+static int bob (int x)
+{
+ return x;
+}
+
+// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::bob'\n \[1\]=binding '::bob'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/internal-2_b.H b/gcc/testsuite/g++.dg/modules/internal-2_b.H
new file mode 100644
index 00000000000..cdcbe77e0d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-2_b.H
@@ -0,0 +1,7 @@
+// { dg-additional-options {-fmodule-header} }
+// { dg-module-cmi {} }
+
+static int bob (int x)
+{
+ return x;
+}
diff --git a/gcc/testsuite/g++.dg/modules/internal-2_c.C b/gcc/testsuite/g++.dg/modules/internal-2_c.C
new file mode 100644
index 00000000000..c0bc46dd8a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-2_c.C
@@ -0,0 +1,12 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-alias} }
+
+import "internal-2_a.H";
+import "internal-2_b.H";
+
+int main ()
+{
+ bob (2);
+}
+
+// { dg-final { scan-lang-dump { Read:-1's named merge key \(new\) function_decl:'::bob'} module } }
+// { dg-final { scan-lang-dump { Read:-1's named merge key \(matched\) function_decl:'::bob'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/isalnum.H b/gcc/testsuite/g++.dg/modules/isalnum.H
new file mode 100644
index 00000000000..2fac358d7fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/isalnum.H
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+extern "C"
+{
+ extern int isalnum (int) __attribute__ ((__nothrow__, __leaf__));
+}
+
+namespace std
+{
+using ::isalnum;
+}
diff --git a/gcc/testsuite/g++.dg/modules/keyword-1_a.C b/gcc/testsuite/g++.dg/modules/keyword-1_a.C
new file mode 100644
index 00000000000..190f5739072
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/keyword-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module bob;
+// { dg-module-cmi bob }
+
+export struct import {};
+export ::import *a;
+export ::import (b);
diff --git a/gcc/testsuite/g++.dg/modules/keyword-1_b.C b/gcc/testsuite/g++.dg/modules/keyword-1_b.C
new file mode 100644
index 00000000000..24a5b5b448c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/keyword-1_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import bob;
+
+::import (d); // not import
+import (e); // not import
+
+void foo ()
+{
+ void *c = a;
+ void *e = &b;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/lambda-1_a.C b/gcc/testsuite/g++.dg/modules/lambda-1_a.C
new file mode 100644
index 00000000000..1b97187da96
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-1_a.C
@@ -0,0 +1,15 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+export module tom.riddle;
+// { dg-module-cmi tom.riddle }
+
+export inline auto One (int a)
+{
+ return [=] (int b) { return a + b; };
+}
+
+// Look Ma! this isn't inline!
+export auto Two (int a)
+{
+ return [=] (int b) { return a * b; };
+}
diff --git a/gcc/testsuite/g++.dg/modules/lambda-1_b.C b/gcc/testsuite/g++.dg/modules/lambda-1_b.C
new file mode 100644
index 00000000000..af213492153
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-1_b.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts" }
+import tom.riddle;
+
+int main ()
+{
+ auto one = One (2);
+
+ if (one (1) != 3)
+ return 1;
+
+ auto two = Two (3);
+ if (two (2) != 6)
+ return 2;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/lambda-2.h b/gcc/testsuite/g++.dg/modules/lambda-2.h
new file mode 100644
index 00000000000..3433686b36d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-2.h
@@ -0,0 +1,2 @@
+// The lambda is attached to 'all', and should be merged keyed by that.
+inline constexpr auto all = [] () {};
diff --git a/gcc/testsuite/g++.dg/modules/lambda-2_a.H b/gcc/testsuite/g++.dg/modules/lambda-2_a.H
new file mode 100644
index 00000000000..79401209049
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-2_a.H
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodule-header -fdump-lang-module-alias" }
+// { dg-module-cmi {} }
+
+#include "lambda-2.h"
+
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s attached merge key \(decl\) type_decl:'::._anon_0'} module } }
+// { dg-final { scan-lang-dump {Written -[0-9]*\[0\] attached decl '::._anon_0'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/lambda-2_b.C b/gcc/testsuite/g++.dg/modules/lambda-2_b.C
new file mode 100644
index 00000000000..56ec9e3aa30
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-2_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+// Not an ODR violation!
+#include "lambda-2.h"
+import "lambda-2_a.H";
+
+// { dg-bogus "conflicting" "not an odr violation" }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s attached merge key \(matched\) type_decl:'#null#'} module } }
+// { dg-final { scan-lang-dump {Read -[0-9]*\[0\] matched attached decl '::._anon_0'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/lambda-2_c.C b/gcc/testsuite/g++.dg/modules/lambda-2_c.C
new file mode 100644
index 00000000000..c626b9dd850
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-2_c.C
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+import "lambda-2_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/lambda-3.h b/gcc/testsuite/g++.dg/modules/lambda-3.h
new file mode 100644
index 00000000000..8f60a824ab4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-3.h
@@ -0,0 +1,5 @@
+
+template inline constexpr auto tmpl = [] {return I;};
+
+inline const auto tpl_1 = tmpl<1>;
+inline const auto tpl_2 = tmpl<2>;
diff --git a/gcc/testsuite/g++.dg/modules/lambda-3_a.H b/gcc/testsuite/g++.dg/modules/lambda-3_a.H
new file mode 100644
index 00000000000..171a2637969
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-3_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -fdump-lang-module-alias" }
+// { dg-module-cmi {} }
+
+#include "lambda-3.h"
diff --git a/gcc/testsuite/g++.dg/modules/lambda-3_b.C b/gcc/testsuite/g++.dg/modules/lambda-3_b.C
new file mode 100644
index 00000000000..25a418bb44a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-3_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "lambda-3.h"
+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 } }
diff --git a/gcc/testsuite/g++.dg/modules/lambda-3_c.C b/gcc/testsuite/g++.dg/modules/lambda-3_c.C
new file mode 100644
index 00000000000..69efa50be0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-3_c.C
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+import "lambda-3_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/lambda-4.h b/gcc/testsuite/g++.dg/modules/lambda-4.h
new file mode 100644
index 00000000000..fe9a06bbd0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-4.h
@@ -0,0 +1,2 @@
+
+inline void (*all) (int) = [] (auto) {};
diff --git a/gcc/testsuite/g++.dg/modules/lambda-4_a.H b/gcc/testsuite/g++.dg/modules/lambda-4_a.H
new file mode 100644
index 00000000000..738ea8b4e36
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-4_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -fdump-lang-module-alias" }
+// { dg-module-cmi {} }
+
+#include "lambda-4.h"
diff --git a/gcc/testsuite/g++.dg/modules/lambda-4_b.C b/gcc/testsuite/g++.dg/modules/lambda-4_b.C
new file mode 100644
index 00000000000..772045d9efb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-4_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "lambda-4.h"
+import "lambda-4_a.H";
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
+// { dg-final { scan-lang-dump {named merge key \(matched\) template_decl:'::._anon_0::template _FUN'} module } }
+// { dg-final { scan-lang-dump {named merge key \(matched\) template_decl:'::._anon_0::template __conv_op '} module } }
diff --git a/gcc/testsuite/g++.dg/modules/lang-1_a.H b/gcc/testsuite/g++.dg/modules/lang-1_a.H
new file mode 100644
index 00000000000..8131d3ffe79
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lang-1_a.H
@@ -0,0 +1,15 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+extern "C"
+{
+ int cfunc ();
+}
+
+extern "C++"
+{
+ int cxxfunc ();
+}
+
+
+
diff --git a/gcc/testsuite/g++.dg/modules/lang-1_b.C b/gcc/testsuite/g++.dg/modules/lang-1_b.C
new file mode 100644
index 00000000000..0db144c8ff3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lang-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+extern "C"
+{
+ import "lang-1_a.H";
+}
+
+extern "C" int cfunc (int); // { dg-error "conflicting declaration" }
+extern "C" int cxxfunc (int);
diff --git a/gcc/testsuite/g++.dg/modules/lang-1_c.C b/gcc/testsuite/g++.dg/modules/lang-1_c.C
new file mode 100644
index 00000000000..e3b939df373
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lang-1_c.C
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodules-ts }
+
+extern "C++"
+{
+ import "lang-1_a.H";
+}
+
+extern "C"
+import "lang-1_a.H"; // { dg-error "cannot appear directly" }
+
+extern "C" int cfunc (int); // { dg-error "conflicting declaration" }
+extern "C" int cxxfunc (int);
diff --git a/gcc/testsuite/g++.dg/modules/lang-2_a.C b/gcc/testsuite/g++.dg/modules/lang-2_a.C
new file mode 100644
index 00000000000..a3bbe727168
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lang-2_a.C
@@ -0,0 +1,3 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
diff --git a/gcc/testsuite/g++.dg/modules/lang-2_b.C b/gcc/testsuite/g++.dg/modules/lang-2_b.C
new file mode 100644
index 00000000000..0a7a0d2f8e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lang-2_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+extern "C"
+{
+ import foo; // { dg-warning "inside language-linkage" }
+}
+extern "C++"
+{
+ import foo; // { dg-warning "inside language-linkage" }
+}
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-1.H b/gcc/testsuite/g++.dg/modules/late-ret-1.H
new file mode 100644
index 00000000000..fb73e51c0ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-1.H
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template
+struct reverse_iterator
+{
+ _Iterator base() const;
+};
+
+template
+reverse_iterator<_Iterator> __make_reverse_iterator (_Iterator __i);
+
+template
+auto __niter_base(reverse_iterator<_Iterator> __it)
+ -> decltype (__make_reverse_iterator(__niter_base(__it.base())))
+{ return __make_reverse_iterator(__niter_base(__it.base())); }
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-2_a.H b/gcc/testsuite/g++.dg/modules/late-ret-2_a.H
new file mode 100644
index 00000000000..0ff435ff0fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-2_a.H
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodule-header -fdump-lang-module-blocks" }
+// { dg-module-cmi {} }
+
+template struct TPL {operator T () const {return 0;}};
+
+template
+auto Foo (T *arg)
+ -> TPL {return TPL ();}
+
+template
+auto Bar (T *arg)
+ -> TPL ;
+
+// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::template Foo'\n \[1\]=specialization declaration '::TPL<#null#>'\n \[2\]=binding '::Foo'\n} module } }
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-2_b.H b/gcc/testsuite/g++.dg/modules/late-ret-2_b.H
new file mode 100644
index 00000000000..80b83f40e3c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-2_b.H
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template struct TPL {operator T () const {return 0;}};
+
+template
+auto Foo (T *arg)
+ -> TPL {return TPL ();}
+
+// Deliberately different to 2_a's Bar
+template
+auto Bar (T *arg)
+ -> TPL ;
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-2_c.C b/gcc/testsuite/g++.dg/modules/late-ret-2_c.C
new file mode 100644
index 00000000000..c5898fb236e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-2_c.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" }
+
+import "late-ret-2_a.H";
+import "late-ret-2_b.H";
+
+int main ()
+{
+ int *p = 0;
+ int j = Foo (p);
+
+ Bar (p); // { dg-error "ambiguous" }
+
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::template Foo'\n Deduping '::template Foo@[^\n]*/late-ret-2_a.H:.'\n} module } }
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-3_a.H b/gcc/testsuite/g++.dg/modules/late-ret-3_a.H
new file mode 100644
index 00000000000..54f95db0456
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-3_a.H
@@ -0,0 +1,20 @@
+// { dg-additional-options "-fmodule-header -fdump-lang-module-blocks" }
+// { dg-module-cmi {} }
+
+template struct TPL_1 { using type = T;};
+
+template struct TPL_2 { using type = int;};
+
+template using TPL_3 = typename TPL_2::type;
+
+template
+auto Foo (const A& arg)
+ -> TPL_3::type>
+ {return 3;}
+
+template
+auto Bar (const A& arg)
+ -> TPL_3::type>
+ {return 3;}
+
+// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::template Foo'\n \[1\]=specialization declaration '::TPL_1<#null#>'\n \[2\]=specialization declaration '::TPL_3<::TPL_1<#null#>::type>'\n \[3\]=specialization declaration '::TPL_2<::TPL_1<#null#>::type>'\n \[4\]=binding '::Foo'\n} module } }
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-3_b.H b/gcc/testsuite/g++.dg/modules/late-ret-3_b.H
new file mode 100644
index 00000000000..2ec63ac65f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-3_b.H
@@ -0,0 +1,20 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template struct TPL_1 { using type = T;};
+
+template struct TPL_2 { using type = int;};
+
+template using TPL_3 = typename TPL_2::type;
+
+template
+auto Foo (const A& arg)
+ -> TPL_3::type>
+ {return 3;}
+
+// Deliberately different to 3_a's Bar
+template
+auto Bar (const A& arg)
+ -> TPL_3::type>
+ {return 3;}
+
diff --git a/gcc/testsuite/g++.dg/modules/late-ret-3_c.C b/gcc/testsuite/g++.dg/modules/late-ret-3_c.C
new file mode 100644
index 00000000000..fae956542f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/late-ret-3_c.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" }
+
+import "late-ret-3_a.H";
+import "late-ret-3_b.H";
+
+struct Arg
+{
+ int type;
+};
+
+int main ()
+{
+ Arg arg;
+
+ int j = Foo (arg);
+
+ Bar (arg); // { dg-error "ambiguous" }
+
+ 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 } }
diff --git a/gcc/testsuite/g++.dg/modules/lazy-1_a.C b/gcc/testsuite/g++.dg/modules/lazy-1_a.C
new file mode 100644
index 00000000000..0f7c7c9173c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lazy-1_a.C
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fmodules-ts" }
+export module foo;
+// { dg-module-cmi "foo" }
+
+export int bar ()
+{
+ return 1;
+}
+
+export int baz ()
+{
+ return 2;
+}
+
+export int quux ()
+{
+ return 3;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/lazy-1_b.C b/gcc/testsuite/g++.dg/modules/lazy-1_b.C
new file mode 100644
index 00000000000..af213d59a3d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lazy-1_b.C
@@ -0,0 +1,21 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+// Check some lazy loading
+
+import foo;
+
+int main ()
+{
+ bar ();
+
+ baz ();
+
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::bar'@'foo' section} "module" } }
+// { dg-final { scan-lang-dump {Lazily binding '::baz'@'foo' section} "module" } }
+// quux is not referenced, so never loaded
+// { dg-final { scan-lang-dump {Bindings '::quux' section} "module" } }
+// { dg-final { scan-lang-dump-not {Lazily binding '::quux'@'foo' section} "module" } }
+// { dg-final { scan-lang-dump-not {Read -[0-9]* function_decl:'::quux'} "module" } }
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-1_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-1_a.H
new file mode 100644
index 00000000000..e7506b50874
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-1_a.H
@@ -0,0 +1,5 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+int bob (int);
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-1_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-1_b.H
new file mode 100644
index 00000000000..07ae824d358
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-1_b.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+int bob (int);
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-1_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-1_c.C
new file mode 100644
index 00000000000..b204d54ccc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-1_c.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+import "leg-merge-1_a.H";
+import "leg-merge-1_b.H";
+
+int main ()
+{
+ return bob (0);
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-1_d.C b/gcc/testsuite/g++.dg/modules/leg-merge-1_d.C
new file mode 100644
index 00000000000..f7854524d45
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-1_d.C
@@ -0,0 +1,4 @@
+int bob (int i)
+{
+ return i;
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-2_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-2_a.H
new file mode 100644
index 00000000000..d891c8966ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-2_a.H
@@ -0,0 +1,5 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+class X;
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-2_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-2_b.H
new file mode 100644
index 00000000000..b9be14d83d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-2_b.H
@@ -0,0 +1,5 @@
+// { dg-module-do link }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+class X;
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-2_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-2_c.C
new file mode 100644
index 00000000000..d5a4da9bd63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-2_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+import "leg-merge-2_a.H";
+import "leg-merge-2_b.H";
+
+int main ()
+{
+ X *ptr = 0;
+
+ return ptr != 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-3_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-3_a.H
new file mode 100644
index 00000000000..9142340bc84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-3_a.H
@@ -0,0 +1,5 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+extern int bob;
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-3_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-3_b.H
new file mode 100644
index 00000000000..2ba847b6601
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-3_b.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+extern int bob;
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-3_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-3_c.C
new file mode 100644
index 00000000000..c6b71b57c22
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-3_c.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+import "leg-merge-3_a.H";
+import "leg-merge-3_b.H";
+
+int main ()
+{
+ return !(bob == 17);
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-3_d.C b/gcc/testsuite/g++.dg/modules/leg-merge-3_d.C
new file mode 100644
index 00000000000..36f028c4f04
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-3_d.C
@@ -0,0 +1 @@
+int bob = 17;
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-4_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-4_a.H
new file mode 100644
index 00000000000..9c61ea2356f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-4_a.H
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+extern int bob;
+void frob ();
+class X;
+
+extern int ok;
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-4_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-4_b.H
new file mode 100644
index 00000000000..09c895fdcd4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-4_b.H
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+extern float bob;
+int frob ();
+union X;
+
+int ok ();
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C
new file mode 100644
index 00000000000..f1b1aeb5b37
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+
+import "leg-merge-4_a.H";
+import "leg-merge-4_b.H";
+
+void foo ()
+{
+ 2[0]; // { dg-error "" }
+ bob = 5;
+ frob ();
+ X *p;
+}
+
+// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:4:\[0-9]*: error: conflicting global module declaration 'float bob'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:4:\[0-9]*: note: existing declaration 'int bob'\n\[^\n]*leg-merge-4_c.C:9:\[0-9]*: note: during load of binding '::bob'$" }
+
+// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:5:\[0-9]*: error: conflicting global module declaration 'int frob\\(\\)'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:5:\[0-9]*: note: existing declaration 'void frob\\(\\)'\n\[^\n]*leg-merge-4_c.C:10:\[0-9]*: note: during load of binding '::frob'$" }
+
+// { dg-regexp "In module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:6:\[0-9]*: error: conflicting global module declaration 'union X'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:6:\[0-9]*: note: existing declaration 'class X'\n\[^\n]*leg-merge-4_c.C:11:\[0-9]*: note: during load of binding '::X'$" }
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-5_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-5_a.H
new file mode 100644
index 00000000000..ba92696ed1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-5_a.H
@@ -0,0 +1,9 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+inline int bob (int x)
+{
+ return x;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-5_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-5_b.H
new file mode 100644
index 00000000000..b77efb3f85e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-5_b.H
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+inline int bob (int x)
+{
+ return x;
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-5_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-5_c.C
new file mode 100644
index 00000000000..cd1e757b340
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-5_c.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+import "leg-merge-5_a.H";
+import "leg-merge-5_b.H";
+
+int main ()
+{
+ return bob (0);
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-6_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-6_a.H
new file mode 100644
index 00000000000..64e8d2861be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-6_a.H
@@ -0,0 +1,10 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+struct X
+{
+ int m;
+ X (int m) :m(m) {}
+ operator int () const { return m; }
+};
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-6_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-6_b.H
new file mode 100644
index 00000000000..2179d9002b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-6_b.H
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+struct X
+{
+ int m;
+ X (int m) :m(m) {}
+ operator int () const { return m; }
+};
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-6_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-6_c.C
new file mode 100644
index 00000000000..dddd88cb0ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-6_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+import "leg-merge-6_a.H";
+import "leg-merge-6_b.H";
+
+int main ()
+{
+ X x (75);
+
+ return !(int (x) == 75);
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-7_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-7_a.H
new file mode 100644
index 00000000000..d8ea85943f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-7_a.H
@@ -0,0 +1,8 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template int foo (int i)
+{
+ return I == i;
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-7_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-7_b.H
new file mode 100644
index 00000000000..9ec045be468
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-7_b.H
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template int foo (int i)
+{
+ return I == i;
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-7_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-7_c.C
new file mode 100644
index 00000000000..0efdc0af1f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-7_c.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+import "leg-merge-7_a.H";
+import "leg-merge-7_b.H";
+
+int main ()
+{
+ return !foo<2> (2);
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-8_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-8_a.H
new file mode 100644
index 00000000000..ad9a2f9e543
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-8_a.H
@@ -0,0 +1,13 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template struct Tpl
+{
+ int i;
+ Tpl () : i (I){}
+ operator int () const
+ {
+ return i;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-8_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-8_b.H
new file mode 100644
index 00000000000..845984c480c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-8_b.H
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template struct Tpl
+{
+ int i;
+ Tpl () : i (I){}
+ operator int () const
+ {
+ return i;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-8_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-8_c.C
new file mode 100644
index 00000000000..fa67db99a80
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-8_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+import "leg-merge-8_a.H";
+import "leg-merge-8_b.H";
+
+int main ()
+{
+ Tpl<1> one;
+
+ return !(one == 1);
+}
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-9_a.H b/gcc/testsuite/g++.dg/modules/leg-merge-9_a.H
new file mode 100644
index 00000000000..518ecbd11f7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-9_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+typedef int X;
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-9_b.H b/gcc/testsuite/g++.dg/modules/leg-merge-9_b.H
new file mode 100644
index 00000000000..518ecbd11f7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-9_b.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+typedef int X;
diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-9_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-9_c.C
new file mode 100644
index 00000000000..3c75dc8162c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/leg-merge-9_c.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+import "leg-merge-9_a.H";
+import "leg-merge-9_b.H";
+
+X an_int;
+
diff --git a/gcc/testsuite/g++.dg/modules/legacy-1_a.H b/gcc/testsuite/g++.dg/modules/legacy-1_a.H
new file mode 100644
index 00000000000..3ab0856bcbc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-1_a.H
@@ -0,0 +1,10 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#ifndef HEADER_H
+#define HEADER_H
+
+int frob (int);
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/legacy-1_b.C b/gcc/testsuite/g++.dg/modules/legacy-1_b.C
new file mode 100644
index 00000000000..f758e3a3f8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-1_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+int frob (int a)
+{
+ return a + 2;
+}
diff --git a/gcc/testsuite/g++.dg/modules/legacy-1_c.C b/gcc/testsuite/g++.dg/modules/legacy-1_c.C
new file mode 100644
index 00000000000..277231c87ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-1_c.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import "legacy-1_a.H";
+
+int main ()
+{
+ return !(frob (-2) == 0);
+}
diff --git a/gcc/testsuite/g++.dg/modules/legacy-2.h b/gcc/testsuite/g++.dg/modules/legacy-2.h
new file mode 100644
index 00000000000..2bac5c74b84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-2.h
@@ -0,0 +1 @@
+#define FROB frob
diff --git a/gcc/testsuite/g++.dg/modules/legacy-2.map b/gcc/testsuite/g++.dg/modules/legacy-2.map
new file mode 100644
index 00000000000..9de5392f593
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-2.map
@@ -0,0 +1 @@
+"legacy-2_a.H"
diff --git a/gcc/testsuite/g++.dg/modules/legacy-2_a.H b/gcc/testsuite/g++.dg/modules/legacy-2_a.H
new file mode 100644
index 00000000000..076bdbe4689
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-2_a.H
@@ -0,0 +1,8 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+// this is a legacy header
+
+int frob (int);
+
diff --git a/gcc/testsuite/g++.dg/modules/legacy-2_b.H b/gcc/testsuite/g++.dg/modules/legacy-2_b.H
new file mode 100644
index 00000000000..0d4ae071158
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-2_b.H
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodule-header -fmodule-mapper=|@g++-mapper-server\\ -mt\\ $srcdir/g++.dg/modules/legacy-2.map" }
+// { dg-module-cmi {} }
+
+#define frob FROB
+
+// this should be diverted, if it isn't the above #define will break us
+#include "legacy-2_a.H"
+int move (int X = __LINE__); // Capture __LINE__ in a non-definition
+
+// this should not be diverted
+#include "legacy-2.h"
+
+
diff --git a/gcc/testsuite/g++.dg/modules/legacy-2_c.C b/gcc/testsuite/g++.dg/modules/legacy-2_c.C
new file mode 100644
index 00000000000..ff31bd41297
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-2_c.C
@@ -0,0 +1,8 @@
+int frob (int a)
+{
+ return a * 2;
+}
+int move (int a)
+{
+ return a;
+}
diff --git a/gcc/testsuite/g++.dg/modules/legacy-2_d.C b/gcc/testsuite/g++.dg/modules/legacy-2_d.C
new file mode 100644
index 00000000000..5384d321128
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-2_d.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import "legacy-2_b.H";
+
+int main ()
+{
+ if (frob (2) != 4)
+ return 1;
+ /* Check line number is not disturbed. */
+ if (move () != 8)
+ return 2;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/legacy-3.h b/gcc/testsuite/g++.dg/modules/legacy-3.h
new file mode 100644
index 00000000000..2bac5c74b84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-3.h
@@ -0,0 +1 @@
+#define FROB frob
diff --git a/gcc/testsuite/g++.dg/modules/legacy-3_a.H b/gcc/testsuite/g++.dg/modules/legacy-3_a.H
new file mode 100644
index 00000000000..74d275536f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-3_a.H
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+// this is a legacy header
+
+int frob (int);
+
diff --git a/gcc/testsuite/g++.dg/modules/legacy-3_b.H b/gcc/testsuite/g++.dg/modules/legacy-3_b.H
new file mode 100644
index 00000000000..3bf819db661
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-3_b.H
@@ -0,0 +1,16 @@
+// { dg-do preprocess }
+// { dg-additional-options -fmodule-header }
+
+#define frob FROB
+
+// Enough blank lines to force a line sync before the legacy import
+
+// this should be diverted, if it isn't the above #define will break us
+#include "legacy-3_a.H"
+int move (int X = __LINE__); // Capture __LINE__ in a non-definition
+
+// this should not be diverted
+#include "legacy-3.h"
+
+// { dg-final { scan-file legacy-3_b.i {\n# 9 "[^\n]*legacy-3_b.H"\nimport "[^\n]*legacy-3_a.H" \[\[__translated\]\];\nint move \(int X = 10\);\n} } }
+
diff --git a/gcc/testsuite/g++.dg/modules/legacy-3_c.H b/gcc/testsuite/g++.dg/modules/legacy-3_c.H
new file mode 100644
index 00000000000..56b81722997
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-3_c.H
@@ -0,0 +1,25 @@
+// { dg-do preprocess }
+// { dg-additional-options -fmodule-header }
+
+#define frob FROB
+
+// this should be translated, if it isn't the above #define will break
+// us
+MARK1 __LINE__
+#include "legacy-3_a.H"
+MARK2 __LINE__
+int move (int X = __LINE__); // Capture __LINE__ in a non-definition
+// this should also be translated, but elided too
+MARK2 __LINE__
+#include "legacy-3_a.H"
+MARK3 __LINE__
+
+// this should not be translated
+#include "legacy-3.h"
+
+// { dg-final { scan-file legacy-3_c.i {MARK1 8\nimport "[^\n]*legacy-3_a.H" \[\[__translated\]\];\nMARK2 10\n} } }
+// We should have stopped.
+// { dg-final { scan-file legacy-3_c.i {move} } }
+// { dg-final { scan-file legacy-3_c.i {MARK2 13\n\nMARK3 15\n} } }
+// { dg-final { scan-file-not legacy-3_c.i {# [^\n]*legacy-3_a.H} } }
+// { dg-final { scan-file legacy-3_c.i {# [^\n]*legacy-3.h} } }
diff --git a/gcc/testsuite/g++.dg/modules/legacy-6.map b/gcc/testsuite/g++.dg/modules/legacy-6.map
new file mode 100644
index 00000000000..8199bf9e190
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-6.map
@@ -0,0 +1,2 @@
+./legacy-6_a.H
+./legacy-6_b.H
diff --git a/gcc/testsuite/g++.dg/modules/legacy-6_a.H b/gcc/testsuite/g++.dg/modules/legacy-6_a.H
new file mode 100644
index 00000000000..7d7e970cdff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-6_a.H
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+// this is a legacy user header
+
+int frob (int);
diff --git a/gcc/testsuite/g++.dg/modules/legacy-6_b.H b/gcc/testsuite/g++.dg/modules/legacy-6_b.H
new file mode 100644
index 00000000000..1a52d42f613
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-6_b.H
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+// this is a legacy user header
+
+int frob (float);
diff --git a/gcc/testsuite/g++.dg/modules/legacy-6_c.C b/gcc/testsuite/g++.dg/modules/legacy-6_c.C
new file mode 100644
index 00000000000..0b5bd7f2eb2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-6_c.C
@@ -0,0 +1,8 @@
+// { dg-do preprocess }
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=|@g++-mapper-server\\ -mt\\ [srcdir]/legacy-6.map" }
+
+#include "legacy-6_a.H"
+#include "legacy-6_b.H"
+int i;
+
+// { dg-final { scan-file legacy-6_c.i {import "[^\n]*legacy-6_a.H" \[\[__translated\]\];\nimport "[^\n]*legacy-6_b.H" \[\[__translated\]\];\nint i;} } }
diff --git a/gcc/testsuite/g++.dg/modules/legacy-6_d.C b/gcc/testsuite/g++.dg/modules/legacy-6_d.C
new file mode 100644
index 00000000000..58ca21dbccf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-6_d.C
@@ -0,0 +1,9 @@
+// { dg-do preprocess }
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=|@g++-mapper-server\\ -mt\\ [srcdir]/legacy-6.map" }
+
+#include "legacy-6_a.H"
+int i;
+#include "legacy-6_b.H"
+
+// { dg-final { scan-file legacy-6_d.i {import "[^\n]*legacy-6_a.H" \[\[__translated\]\];\nint i;} } }
+// { dg-final { scan-file legacy-6_d.i {int i;\nimport "[^\n]*legacy-6_b.H" \[\[__translated\]\];\n} } }
diff --git a/gcc/testsuite/g++.dg/modules/legacy-6_e.C b/gcc/testsuite/g++.dg/modules/legacy-6_e.C
new file mode 100644
index 00000000000..9d4dd9218dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-6_e.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodule-mapper=|@mapper-server\\ -f\\ [srcdir]/legacy-6.map" }
+
+#include "legacy-6_a.H"
+#include "legacy-6_b.H"
+int i;
diff --git a/gcc/testsuite/g++.dg/modules/legacy-6_f.C b/gcc/testsuite/g++.dg/modules/legacy-6_f.C
new file mode 100644
index 00000000000..c15eadec6da
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-6_f.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodule-mapper=|@mapper-server\\ -f\\ [srcdir]/legacy-6.map" }
+
+#include "legacy-6_a.H"
+int i;
+#include "legacy-6_b.H"
+
diff --git a/gcc/testsuite/g++.dg/modules/legacy-7_a.H b/gcc/testsuite/g++.dg/modules/legacy-7_a.H
new file mode 100644
index 00000000000..49578a929e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-7_a.H
@@ -0,0 +1,6 @@
+// { dg-additional-options "-std=c++2a -fmodule-header" }
+// { dg-module-cmi {} }
+
+#define throw(...) /* { dg-warning "-:not exporting" } */ \
+ noexcept(__VA_OPT__(false))
+
diff --git a/gcc/testsuite/g++.dg/modules/legacy-7_b.C b/gcc/testsuite/g++.dg/modules/legacy-7_b.C
new file mode 100644
index 00000000000..d78f45c2128
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-7_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -std=c++2a" }
+
+import "legacy-7_a.H";
+
+#ifdef throw
+#error barf
+#endif
+
diff --git a/gcc/testsuite/g++.dg/modules/legacy-8_a.H b/gcc/testsuite/g++.dg/modules/legacy-8_a.H
new file mode 100644
index 00000000000..a30cd880d9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-8_a.H
@@ -0,0 +1,5 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+int sqr (int);
diff --git a/gcc/testsuite/g++.dg/modules/legacy-8_b.H b/gcc/testsuite/g++.dg/modules/legacy-8_b.H
new file mode 100644
index 00000000000..62366e11a0f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-8_b.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+float sqr (float);
diff --git a/gcc/testsuite/g++.dg/modules/legacy-8_c.C b/gcc/testsuite/g++.dg/modules/legacy-8_c.C
new file mode 100644
index 00000000000..88300b28582
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-8_c.C
@@ -0,0 +1,13 @@
+#include "legacy-8_a.H"
+#include "legacy-8_a.H"
+
+int sqr (int a)
+{
+ return a * a;
+}
+
+
+float sqr (float a)
+{
+ return a * a;
+}
diff --git a/gcc/testsuite/g++.dg/modules/legacy-8_d.C b/gcc/testsuite/g++.dg/modules/legacy-8_d.C
new file mode 100644
index 00000000000..85377d9f7d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-8_d.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts" }
+export module foo;
+// { dg-module-cmi foo }
+
+import "legacy-8_a.H";
+import "legacy-8_b.H";
+
+export inline int Sqr (int a)
+{
+ return sqr (a);
+}
+
+export inline float Sqr (float a)
+{
+ return sqr (a);
+}
diff --git a/gcc/testsuite/g++.dg/modules/legacy-8_e.C b/gcc/testsuite/g++.dg/modules/legacy-8_e.C
new file mode 100644
index 00000000000..afeb19a94c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/legacy-8_e.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import foo;
+
+int main ()
+{
+ int (*ifp) (int) = Sqr;
+ float (*ffp) (float) = Sqr;
+
+ if (ifp (2) != 4)
+ return 1;
+
+ // Comparing these two floats is ok
+ if (ffp (2.0f) != 4.0f)
+ return 2;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/libfn-1_a.C b/gcc/testsuite/g++.dg/modules/libfn-1_a.C
new file mode 100644
index 00000000000..a8a8ee8ea71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/libfn-1_a.C
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodules-ts }
+// Make sure we're not confused by an imported declaration of a
+// library fn
+export module foo;
+// { dg-module-cmi foo }
+
+export inline void thrower ()
+{
+ try
+ {
+ throw 1;
+ }
+ catch (...)
+ {
+ }
+}
diff --git a/gcc/testsuite/g++.dg/modules/libfn-1_b.C b/gcc/testsuite/g++.dg/modules/libfn-1_b.C
new file mode 100644
index 00000000000..0e8346b5b71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/libfn-1_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+import foo;
+
+void bar ()
+{
+ thrower ();
+}
+
+void baz ()
+{
+ try
+ {
+ throw 1;
+ }
+ catch (...)
+ {
+ }
+}
diff --git a/gcc/testsuite/g++.dg/modules/literals-1_a.C b/gcc/testsuite/g++.dg/modules/literals-1_a.C
new file mode 100644
index 00000000000..9fb2aea5c82
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/literals-1_a.C
@@ -0,0 +1,51 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -Wno-pedantic -Wno-psabi" }
+
+// Make sure e can serialize various literals. */
+
+export module real2reel;
+// { dg-module-cmi real2reel }
+
+export inline float assassing ()
+{
+ return 2.0f;
+}
+
+export inline double market (float square, double heroes)
+{
+ return 4.0 * square * heroes;
+}
+
+using cplx_i = __complex__ int;
+using cplx_f = __complex__ float;
+using cplx_d = __complex__ double;
+
+export inline cplx_i cinderella_search ()
+{
+ return (cplx_i) {1, 2};
+}
+export inline cplx_f emerald_lies ()
+{
+ return (cplx_f) {3, 4};
+}
+export inline cplx_d forgotten_sons ()
+{
+ return (cplx_d) {5, 6};
+}
+
+export inline int garden_party (unsigned ix)
+{
+ return "invites call the debs to play"[ix];
+}
+
+using vec = int __attribute__((vector_size (sizeof (int) * 4)));
+
+export inline vec incubus ()
+{
+ return (vec){1,7,3,9}; // Not an arithmetic series
+}
+
+export inline vec charting_the_single ()
+{
+ return (vec){1,2,3,4}; // An arithmetic series
+}
diff --git a/gcc/testsuite/g++.dg/modules/literals-1_b.C b/gcc/testsuite/g++.dg/modules/literals-1_b.C
new file mode 100644
index 00000000000..5468944fad3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/literals-1_b.C
@@ -0,0 +1,39 @@
+// { dg-additional-options {-fmodules-ts -Wno-psabi} }
+
+import real2reel;
+
+int main ()
+{
+ if (assassing () != 2.0f)
+ return 1;
+
+ if (market (/*square=*/2.0f, /*heroes=*/7.0) != 56.0)
+ return 2;
+
+ auto c_i = cinderella_search ();
+ if (__real__ (c_i) != 1 || __imag__ (c_i) != 2)
+ return 3;
+
+ auto c_f = emerald_lies ();
+ if (__real__ (c_f) != 3.0f || __imag__ (c_f) != 4.0f)
+ return 4;
+
+ auto c_d = forgotten_sons ();
+ if (__real__ (c_d) != 5.0 || __imag__ (c_d) != 6.0)
+ return 5;
+
+
+ if (garden_party (7) != ' ')
+ return 6;
+
+ auto v = incubus ();
+ if (v[0] != 1 || v[1] != 7 || v[2] != 3 || v[3] != 9)
+ return 7;
+
+ v = charting_the_single ();
+ if (v[0] != 1 || v[1] != 2 || v[2] != 3 || v[3] != 4)
+ return 8;
+
+ return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/loc-1_a.C b/gcc/testsuite/g++.dg/modules/loc-1_a.C
new file mode 100644
index 00000000000..8155181b009
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-1_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module bob;
+// { dg-module-cmi bob }
+
+export int frob (int *); // line 5
diff --git a/gcc/testsuite/g++.dg/modules/loc-1_b.C b/gcc/testsuite/g++.dg/modules/loc-1_b.C
new file mode 100644
index 00000000000..0a0b85ed78c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module stuart;
+// { dg-module-cmi stuart }
+
+
+export int frob (float *); // line 6
+
diff --git a/gcc/testsuite/g++.dg/modules/loc-1_c.C b/gcc/testsuite/g++.dg/modules/loc-1_c.C
new file mode 100644
index 00000000000..f9522597e9e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-1_c.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import bob;
+import stuart;
+
+void kevin ()
+{
+ frob (nullptr); // { dg-error "call of overload" }
+}
+
+// { dg-regexp "In module stuart, imported at \[^\n]*loc-1_c.C:4:\n\[^\n]*loc-1_b.C:7:12: note:.*" }
+// { dg-regexp "In module bob, imported at \[^\n]*loc-1_c.C:3:\n\[^\n]*loc-1_a.C:6:12: note:.*" }
+
+
diff --git a/gcc/testsuite/g++.dg/modules/loc-2_a.C b/gcc/testsuite/g++.dg/modules/loc-2_a.C
new file mode 100644
index 00000000000..a4bbce36a2a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-2_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module bob;
+// { dg-module-cmi bob }
+
+export int frob (int *);
diff --git a/gcc/testsuite/g++.dg/modules/loc-2_b.C b/gcc/testsuite/g++.dg/modules/loc-2_b.C
new file mode 100644
index 00000000000..42640098d8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-2_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module stuart;
+// { dg-module-cmi stuart }
+
+export import bob;
diff --git a/gcc/testsuite/g++.dg/modules/loc-2_c.C b/gcc/testsuite/g++.dg/modules/loc-2_c.C
new file mode 100644
index 00000000000..e731d50933b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-2_c.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module kevin;
+// { dg-module-cmi kevin }
+
+export import stuart;
+export import bob; // Bob should be reseated in the export map
+export import stuart;
diff --git a/gcc/testsuite/g++.dg/modules/loc-2_d.C b/gcc/testsuite/g++.dg/modules/loc-2_d.C
new file mode 100644
index 00000000000..4ae8a690c9e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-2_d.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import stuart;
+
+void foo ()
+{
+ frob (2); /* { dg-error "invalid conversion" } */
+}
+
+// { dg-regexp "In module bob, imported at \[^\n]*loc-2_b.C:6,\nof module stuart, imported at \[^\n]*loc-2_d.C:3:\n\[^\n]*loc-2_a.C:6:18: note:.*" }
diff --git a/gcc/testsuite/g++.dg/modules/loc-2_e.C b/gcc/testsuite/g++.dg/modules/loc-2_e.C
new file mode 100644
index 00000000000..c4d0acb7db8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-2_e.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import stuart;
+import bob;
+import stuart;
+
+void foo ()
+{
+ frob (2); // { dg-error "invalid conversion" }
+}
+
+// { dg-regexp "In module bob, imported at \[^\n]*loc-2_e.C:4:\n\[^\n]*loc-2_a.C:6:18: note:.*" }
diff --git a/gcc/testsuite/g++.dg/modules/loc-2_f.C b/gcc/testsuite/g++.dg/modules/loc-2_f.C
new file mode 100644
index 00000000000..2888d048861
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-2_f.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import kevin;
+
+void foo ()
+{
+ frob (2); // { dg-error "invalid conversion" }
+}
+
+// { dg-regexp "In module bob, imported at \[^\n]*loc-2_c.C:7,\nof module kevin, imported at \[^\n]*loc-2_f.C:3:\n\[^\n]*loc-2_a.C:6:18: note:.*" }
diff --git a/gcc/testsuite/g++.dg/modules/loc-wrapper-1.h b/gcc/testsuite/g++.dg/modules/loc-wrapper-1.h
new file mode 100644
index 00000000000..04e62d46f8f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-wrapper-1.h
@@ -0,0 +1,14 @@
+template
+struct __is_integer
+{
+ enum { __value = 0 };
+};
+
+template
+struct __is_integer_nonstrict
+
+{
+ using __is_integer<_Tp>::__value;
+
+ enum { __width = __value ? sizeof(_Tp) * 8 : 0 };
+};
diff --git a/gcc/testsuite/g++.dg/modules/loc-wrapper-1_a.H b/gcc/testsuite/g++.dg/modules/loc-wrapper-1_a.H
new file mode 100644
index 00000000000..cddb46f5fab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-wrapper-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+
+// { dg-module-cmi {} }
+#include "loc-wrapper-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/loc-wrapper-1_b.C b/gcc/testsuite/g++.dg/modules/loc-wrapper-1_b.C
new file mode 100644
index 00000000000..6d0229a8193
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/loc-wrapper-1_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+// ICEd comparing VIEW_CONVERT_EXPR location wrappers with null types
+#include "loc-wrapper-1.h"
+import "loc-wrapper-1_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/local-1_a.C b/gcc/testsuite/g++.dg/modules/local-1_a.C
new file mode 100644
index 00000000000..c1a3343478b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/local-1_a.C
@@ -0,0 +1,13 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module the.shop;
+// { dg-module-cmi the.shop }
+
+export int for_local_people ()
+{
+ struct X {int a;};
+ X m;
+ m.a = 5;
+ return m.a;
+}
diff --git a/gcc/testsuite/g++.dg/modules/local-1_b.C b/gcc/testsuite/g++.dg/modules/local-1_b.C
new file mode 100644
index 00000000000..37a9461706d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/local-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+import the.shop;
+
+int main ()
+{
+ if (for_local_people () != 5)
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/local-extern-1.C b/gcc/testsuite/g++.dg/modules/local-extern-1.C
new file mode 100644
index 00000000000..7b016053d36
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/local-extern-1.C
@@ -0,0 +1,20 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+
+module;
+# 4 __FILE__ 1
+inline void frob ()
+{
+ extern int bob; // OK
+}
+
+# 11 "" 2
+export module bob;
+// { dg-module-cmi !bob }
+
+inline void dob ()
+{
+ extern int bob; // { dg-error "block-scope extern" }
+}
+
+
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/local-extern-2.H b/gcc/testsuite/g++.dg/modules/local-extern-2.H
new file mode 100644
index 00000000000..dab5ee4fb84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/local-extern-2.H
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodule-header }
+
+// { dg-module-cmi {} }
+
+inline int *wcstok(int *__wcstok_ws1)
+{
+ extern int *__iso_wcstok(int * bob);
+
+ return __iso_wcstok(__wcstok_ws1);
+}
diff --git a/gcc/testsuite/g++.dg/modules/local-struct-1_a.C b/gcc/testsuite/g++.dg/modules/local-struct-1_a.C
new file mode 100644
index 00000000000..b4323b63e67
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/local-struct-1_a.C
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export inline int __inline_signbitf (float __x)
+{
+ union x { float __f; unsigned int __u; } __u;
+
+ __u.__f = __x;
+
+ return int (__u.__u >> 31);
+}
diff --git a/gcc/testsuite/g++.dg/modules/local-struct-1_b.C b/gcc/testsuite/g++.dg/modules/local-struct-1_b.C
new file mode 100644
index 00000000000..96968e254ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/local-struct-1_b.C
@@ -0,0 +1,3 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy} }
+
+import foo;
diff --git a/gcc/testsuite/g++.dg/modules/macloc-1_a.C b/gcc/testsuite/g++.dg/modules/macloc-1_a.C
new file mode 100644
index 00000000000..a152b5191d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macloc-1_a.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module agnes;
+// { dg-module-cmi agnes }
+
+int a;
+
+#define BOB(X) int X ()
+#define KEVIN(X) int X ()
+
+export BOB(me);
+export KEVIN(you);
+
diff --git a/gcc/testsuite/g++.dg/modules/macloc-1_b.C b/gcc/testsuite/g++.dg/modules/macloc-1_b.C
new file mode 100644
index 00000000000..8f8f1f55464
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macloc-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module edith;
+// { dg-module-cmi edith }
+
+#define STUART(X) X
+
+import STUART(agnes);
+
+export void STUART(gru) ();
diff --git a/gcc/testsuite/g++.dg/modules/macloc-1_c.C b/gcc/testsuite/g++.dg/modules/macloc-1_c.C
new file mode 100644
index 00000000000..9b8f7fb9d59
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macloc-1_c.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module edith;
+
+void gru ()
+{
+ me (1);
+ you (1);
+}
+
+// { dg-regexp "\[^\n]*macloc-1_c.C:7:8: error: too many arguments to function 'int me@agnes\\(\\)'\nIn module agnes, imported at \[^\n]*macloc-1_b.C:8,\nof module edith, imported at \[^\n]*macloc-1_c.C:3:\n\[^\n]*macloc-1_a.C:11:12: note: declared here\n\[^\n]*macloc-1_a.C:8:20: note: in definition of macro 'BOB'\n" }
+
+// { dg-regexp "\[^\n]*macloc-1_c.C:8:9: error: too many arguments to function 'int you@agnes\\(\\)'\nIn module agnes, imported at \[^\n]*macloc-1_b.C:8,\nof module edith, imported at \[^\n]*macloc-1_c.C:3:\n\[^\n]*macloc-1_a.C:12:14: note: declared here\n\[^\n]*macloc-1_a.C:9:22: note: in definition of macro 'KEVIN'\n" }
diff --git a/gcc/testsuite/g++.dg/modules/macloc-1_d.C b/gcc/testsuite/g++.dg/modules/macloc-1_d.C
new file mode 100644
index 00000000000..5b2b7ba3034
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macloc-1_d.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import edith;
+import agnes;
+
+void margo ()
+{
+ me (1);
+ gru (2);
+}
+
+// { dg-regexp "\[^\n]*macloc-1_d.C:8:8: error: too many arguments to function 'int me@agnes\\(\\)'\nIn module agnes, imported at \[^\n]*macloc-1_d.C:4:\n\[^\n]*macloc-1_a.C:11:12: note: declared here\n\[^\n]*macloc-1_a.C:8:20: note: in definition of macro 'BOB'\n" }
+// { dg-regexp "\[^\n]*macloc-1_d.C:9:9: error: too many arguments to function 'void gru@edith\\(\\)'\nIn module edith, imported at \[^\n]*macloc-1_d.C:3:\n\[^\n]*macloc-1_b.C:10:20: note: declared here\n\[^\n]*macloc-1_b.C:6:19: note: in definition of macro 'STUART'\n" }
diff --git a/gcc/testsuite/g++.dg/modules/macloc-2_a.H b/gcc/testsuite/g++.dg/modules/macloc-2_a.H
new file mode 100644
index 00000000000..99f08840280
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macloc-2_a.H
@@ -0,0 +1,9 @@
+// { dg-additional-options {-fmodule-header -nostdinc} }
+// { dg-module-cmi {} }
+
+#define MACRO(X) X
+
+inline int frob (int x)
+{
+ return x + 2;
+}
diff --git a/gcc/testsuite/g++.dg/modules/macloc-2_b.C b/gcc/testsuite/g++.dg/modules/macloc-2_b.C
new file mode 100644
index 00000000000..601a4779c28
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macloc-2_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options {-fmodules-ts -nostdinc} }
+module;
+
+import "macloc-2_a.H";
+
+export module Foo;
+// { dg-module-cmi Foo }
+
+export inline int MACRO (fn) (int i)
+{
+ return frob (i);
+}
+
+export int (MACRO) (int i);
diff --git a/gcc/testsuite/g++.dg/modules/macro-1_a.H b/gcc/testsuite/g++.dg/modules/macro-1_a.H
new file mode 100644
index 00000000000..5b212a6d487
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-1_a.H
@@ -0,0 +1,12 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#ifndef MACRO_1_H
+#define MACRO_1_H
+#define foo bar baz
+#define kevin(X) stuart (X)
+#define stuart(X) bob ("banana", X) // Yes we have X bananas
+#define bob(...) {__VA_ARGS__}
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/macro-1_b.C b/gcc/testsuite/g++.dg/modules/macro-1_b.C
new file mode 100644
index 00000000000..afbcab281d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-1_b.C
@@ -0,0 +1,25 @@
+// { dg-additional-options "-fmodules-ts" }
+import "macro-1_a.H";
+
+#define baz = + 1
+int foo;
+struct X
+{
+ const char *s;
+ int v;
+}
+;
+X x kevin (5);
+
+int main ()
+{
+ if (foo != 1)
+ return 1;
+ if (x.v != 5)
+ return 2;
+ const char *banana = "banana";
+ for (unsigned ix = 0; banana[ix]; ix++)
+ if (banana[ix] != x.s[ix])
+ return 3;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/macro-2_a.H b/gcc/testsuite/g++.dg/modules/macro-2_a.H
new file mode 100644
index 00000000000..89d66a5f405
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-2_a.H
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#ifndef MACRO_2a_H
+#define MACRO_2a_H
+
+#define FOO_OK foo
+#define BAR_OK(BAZ) BINKY(2)
+
+#define FOO_BAD foo
+#define BAR_BAD(BAZ) BINKY(2)
+
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/macro-2_b.H b/gcc/testsuite/g++.dg/modules/macro-2_b.H
new file mode 100644
index 00000000000..5690712607b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-2_b.H
@@ -0,0 +1,24 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+
+
+
+// Make line numbers distinct from macro-2_a.H
+
+
+
+
+
+
+#ifndef MACRO_2b_H
+#define MACRO_2b_H
+
+#define FOO_OK foo
+#define BAR_OK(BAZ) BINKY(2)
+
+#define FOO_BAD foot
+#define BAR_BAD(BAZ) BINKY(3)
+
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/macro-2_c.H b/gcc/testsuite/g++.dg/modules/macro-2_c.H
new file mode 100644
index 00000000000..ed053236a5b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-2_c.H
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodule-header -fdump-lang-module" }
+// { dg-module-cmi {} }
+
+#ifndef MACRO_2c_H
+#define MACRO_2c_H
+import "macro-2_a.H";
+
+#endif
+
+// { dg-final { scan-lang-dump-not {Read new macro #define MACRO_2a_H at} module } }
diff --git a/gcc/testsuite/g++.dg/modules/macro-2_d.C b/gcc/testsuite/g++.dg/modules/macro-2_d.C
new file mode 100644
index 00000000000..04b80fb3058
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-2_d.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+
+#define BINKY(X) X
+
+import "macro-2_a.H";
+import "macro-2_b.H";
+
+int FOO_OK = BAR_OK(1);
+
+int BAR_BAD;
+// { dg-regexp {[^\n]*macro-2_d.C:10:5: error: inconsistent imported macro definition 'BAR_BAD'\nIn module [^\n]*macro-2_a.H, imported at [^\n]*macro-2_d.C:5:\n[^\n]*macro-2_a.H:11: note: '#define BAR_BAD\(BAZ\) BINKY\(2\)'\nIn module [^\n]*macro-2_b.H, imported at [^\n]*macro-2_d.C:6:\n[^\n]*macro-2_b.H:21: note: '#define BAR_BAD\(BAZ\) BINKY\(3\)'\n} }
+
+int FOO_BAD;
+// { dg-regexp {[^\n]*macro-2_d.C:13:5: error: inconsistent imported macro definition 'FOO_BAD'\nIn module [^\n]*macro-2_a.H, imported at [^\n]*macro-2_d.C:5:\n[^\n]*macro-2_a.H:10: note: '#define FOO_BAD foo'\nIn module [^\n]*macro-2_b.H, imported at [^\n]*macro-2_d.C:6:\n[^\n]*macro-2_b.H:20: note: '#define FOO_BAD foot'\n} }
diff --git a/gcc/testsuite/g++.dg/modules/macro-3_a.H b/gcc/testsuite/g++.dg/modules/macro-3_a.H
new file mode 100644
index 00000000000..6582e3cb26c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-3_a.H
@@ -0,0 +1,19 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header -fdump-lang-module-vops" }
+// { dg-module-cmi {} }
+
+#ifndef MACRO_3a_H
+#define MACRO_3a_H
+
+#undef nothing
+#define bob x
+#undef bob
+#define foo 1
+#define bar 2
+
+#endif
+
+// { dg-final { scan-lang-dump {Writing macro #define foo at} module } }
+// { dg-final { scan-lang-dump {Writing macro #define bar at} module } }
+// { dg-final { scan-lang-dump-not {Writing macro #define bob at} module } }
+// { dg-final { scan-lang-dump-not {Writing macro #undef nothing at} module } }
diff --git a/gcc/testsuite/g++.dg/modules/macro-3_b.H b/gcc/testsuite/g++.dg/modules/macro-3_b.H
new file mode 100644
index 00000000000..2af92ac51e9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-3_b.H
@@ -0,0 +1,24 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodule-header -fdump-lang-module-vops" }
+// { dg-module-cmi {} }
+
+import "macro-3_a.H";
+
+// Not the controlling macro, because of above tokens
+#ifndef MACRO_3b_H
+#define MACRO_3b_H
+
+#define bob 1
+#undef foo
+#undef bar
+#define bar 3
+
+#endif
+
+// { dg-final { scan-lang-dump {Read new macro #define foo at} module } }
+// { dg-final { scan-lang-dump {Read new macro #define bar at} module } }
+// { dg-final { scan-lang-dump-not {Read [^ ]* macro #define bob at} module } }
+
+// { dg-final { scan-lang-dump {Writing macro #define bob at} module } }
+// { dg-final { scan-lang-dump {Writing macro #undef & #define bar at} module } }
+// { dg-final { scan-lang-dump {Writing macro #undef foo at} module } }
diff --git a/gcc/testsuite/g++.dg/modules/macro-3_c.C b/gcc/testsuite/g++.dg/modules/macro-3_c.C
new file mode 100644
index 00000000000..f0795807878
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-3_c.C
@@ -0,0 +1,24 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-vops" }
+
+import "macro-3_b.H";
+import "macro-3_a.H";
+
+int main ()
+{
+#ifdef foo
+ return 1;
+#endif
+ if (bar != 3)
+ return 2;
+#define foo 2
+ if (foo != 2)
+ return 3;
+ return 0;
+}
+
+// { dg-final { scan-lang-dump {Read new macro #define foo at} module } }
+// { dg-final { scan-lang-dump {Read new macro #define bar at} module } }
+
+// { dg-final { scan-lang-dump {Read add macro #undef foo} module } }
+// { dg-final { scan-lang-dump {Read new macro #define bob} module } }
+// { dg-final { scan-lang-dump {Read add macro #undef & #define bar} module } }
diff --git a/gcc/testsuite/g++.dg/modules/macro-4_a.H b/gcc/testsuite/g++.dg/modules/macro-4_a.H
new file mode 100644
index 00000000000..c04854ea594
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-4_a.H
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodule-header -Winvalid-imported-macros" }
+// { dg-module-cmi {} }
+
+#ifndef MACRO_4_a
+#define MACRO_4_a
+
+#define ONE 1
+#define TWO 2
+#define THREE 3
+#define FOUR 4
+#define FIVE 5
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/macro-4_b.H b/gcc/testsuite/g++.dg/modules/macro-4_b.H
new file mode 100644
index 00000000000..04039389045
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-4_b.H
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodule-header -Winvalid-imported-macros" }
+// { dg-module-cmi {} }
+
+#ifndef MACRO_4_b
+#define MACRO_4_b
+
+#define ONE 1
+#define TWO 2a
+#undef THREE // no effect
+#define THREE 3b
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/macro-4_c.H b/gcc/testsuite/g++.dg/modules/macro-4_c.H
new file mode 100644
index 00000000000..ec2bed91ccd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-4_c.H
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodule-header -Winvalid-imported-macros" }
+// { dg-module-cmi {} }
+
+#ifndef MACRO_4_c
+#define MACRO_4_c
+
+#undef FIVE // no effect
+import "macro-4_a.H";
+int a;
+#undef THREE
+#undef FOUR
+#define FOUR 4c
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/macro-4_d.C b/gcc/testsuite/g++.dg/modules/macro-4_d.C
new file mode 100644
index 00000000000..bff9494281b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-4_d.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -Winvalid-imported-macros" }
+
+import "macro-4_b.H";
+import "macro-4_a.H";
+
+// { dg-regexp {[^\n]*macro-4_d.C: warning: inconsistent imported macro definition 'TWO' \[-Winvalid-imported-macros\]\nIn module [^\n]*macro-4_b.H, imported at [^\n]*macro-4_d.C:[0-9]*:\n[^\n]*macro-4_b.H:[0-9]*: note: .#define TWO 2a.\nIn module [^\n]*macro-4_a.H, imported at [^\n]*macro-4_d.C:[0-9]*:\n[^\n]*macro-4_a.H:[0-9]*: note: .#define TWO 2.\n} }
+
+// { dg-regexp {[^\n]*macro-4_d.C: warning: inconsistent imported macro definition 'THREE' \[-Winvalid-imported-macros\]\nIn module [^\n]*macro-4_b.H, imported at [^\n]*macro-4_d.C:[0-9]*:\n[^\n]*macro-4_b.H:[0-9]*: note: .#define THREE 3b.\nIn module [^\n]*macro-4_a.H, imported at [^\n]*macro-4_d.C:[0-9]*:\n[^\n]*macro-4_a.H:[0-9]*: note: .#define THREE 3.\n} }
diff --git a/gcc/testsuite/g++.dg/modules/macro-4_e.C b/gcc/testsuite/g++.dg/modules/macro-4_e.C
new file mode 100644
index 00000000000..38fa6c7feeb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-4_e.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts -Winvalid-imported-macros" }
+
+import "macro-4_b.H";
+import "macro-4_a.H";
+import "macro-4_c.H";
+
+int stop;
+
+#ifndef FIVE
+#error bah!
+#endif
+
+// { dg-regexp {[^\n]*macro-4_e.C: warning: inconsistent imported macro definition 'TWO' \[-Winvalid-imported-macros\]\nIn module [^\n]*macro-4_b.H, imported at [^\n]*macro-4_e.C:[0-9]*:\n[^\n]*macro-4_b.H:[0-9]*: note: .#define TWO 2a.\nIn module [^\n]*macro-4_a.H, imported at [^\n]*macro-4_e.C:[0-9]*:\n[^\n]*macro-4_a.H:[0-9]*: note: .#define TWO 2.\n} }
diff --git a/gcc/testsuite/g++.dg/modules/macro-4_f.C b/gcc/testsuite/g++.dg/modules/macro-4_f.C
new file mode 100644
index 00000000000..1279de271c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-4_f.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module bob;
+// { dg-module-cmi bob }
+export import "macro-4_b.H";
diff --git a/gcc/testsuite/g++.dg/modules/macro-4_g.C b/gcc/testsuite/g++.dg/modules/macro-4_g.C
new file mode 100644
index 00000000000..f3ff0e49f06
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-4_g.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -Winvalid-imported-macros" }
+
+import bob;
+import "macro-4_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/macro-5_a.H b/gcc/testsuite/g++.dg/modules/macro-5_a.H
new file mode 100644
index 00000000000..d0913d1c53e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-5_a.H
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodule-header -Dfoo=bar -Dbaz=1 -fdump-lang-module-vops" }
+// command line macros are not exported
+// { dg-module-cmi {} }
+
+// { dg-final { scan-lang-dump-not {Writing macro #define [_a-zA-Z0-9]* at [0-9]*} module } }
diff --git a/gcc/testsuite/g++.dg/modules/macro-5_b.H b/gcc/testsuite/g++.dg/modules/macro-5_b.H
new file mode 100644
index 00000000000..656d51143a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-5_b.H
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodule-header -Dfoo=bar -Dbaz=2 -fdump-lang-module-vops" }
+// { dg-module-cmi {} }
+
+#undef baz // not exported
+#define baz 3 // exported
+
+
+// { dg-final { scan-lang-dump {Writing macro #define baz at [0-9]*} module } }
diff --git a/gcc/testsuite/g++.dg/modules/macro-5_c.C b/gcc/testsuite/g++.dg/modules/macro-5_c.C
new file mode 100644
index 00000000000..17f6fe29913
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-5_c.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -Winvalid-imported-macros" }
+
+import "macro-5_a.H";
+import "macro-5_b.H";
+
+#if baz != 3
+#error
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/macro-6_a.H b/gcc/testsuite/g++.dg/modules/macro-6_a.H
new file mode 100644
index 00000000000..4947e2ee76f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-6_a.H
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#ifndef MACRO_6_H
+#define MACRO_6_H
+#define foo bar baz
+
+#endif
diff --git a/gcc/testsuite/g++.dg/modules/macro-6_b.C b/gcc/testsuite/g++.dg/modules/macro-6_b.C
new file mode 100644
index 00000000000..cbc3b2a68e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-6_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+export module macro;
+// { dg-module-cmi {macro} }
+import "macro-6_a.H";
+
+#ifndef foo
+#error bad
+#endif
+
+// { dg-final { scan-lang-dump {Reading macro table [^\n]*macro-6_a.H} module } }
diff --git a/gcc/testsuite/g++.dg/modules/macro-6_c.C b/gcc/testsuite/g++.dg/modules/macro-6_c.C
new file mode 100644
index 00000000000..a9a6f4f5db7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-6_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+// Macro tables are only loaded when transitively reachable from top
+// level
+
+import macro;
+
+#ifdef foo
+#error bad
+#endif
+
+// { dg-final { scan-lang-dump-not {>Reading macro table "macro-6_a.H"} module } }
diff --git a/gcc/testsuite/g++.dg/modules/macro-7_a.C b/gcc/testsuite/g++.dg/modules/macro-7_a.C
new file mode 100644
index 00000000000..f336f006d5f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-7_a.C
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+#define MACRO(X) X
+
+export template int Factory ()
+{
+ // this macro expansion location ends up in the instantiation
+ // emitted by an importer
+ return MACRO(I);
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/macro-7_b.C b/gcc/testsuite/g++.dg/modules/macro-7_b.C
new file mode 100644
index 00000000000..025f5ebd29a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-7_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+export module bar;
+// { dg-module-cmi bar }
+
+import foo;
+
+export inline int One ()
+{
+ return Factory<1> ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/macro-7_c.C b/gcc/testsuite/g++.dg/modules/macro-7_c.C
new file mode 100644
index 00000000000..902f1a8a803
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/macro-7_c.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+import bar;
+
+int main ()
+{
+ return !(One () == 1);
+}
diff --git a/gcc/testsuite/g++.dg/modules/map-1.map b/gcc/testsuite/g++.dg/modules/map-1.map
new file mode 100644
index 00000000000..58963bdb32d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/map-1.map
@@ -0,0 +1,2 @@
+$root .
+frob map-1_a.nms
diff --git a/gcc/testsuite/g++.dg/modules/map-1_a.C b/gcc/testsuite/g++.dg/modules/map-1_a.C
new file mode 100644
index 00000000000..f714672d05e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/map-1_a.C
@@ -0,0 +1,13 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=[srcdir]/map-1.map" }
+
+// Ick! no cross-host testing for you!
+// { dg-additional-files map-1.map }
+
+export module frob;
+// { dg-module-cmi "=map-1_a.nms" }
+
+export int frob (int i)
+{
+ return -i;
+}
diff --git a/gcc/testsuite/g++.dg/modules/map-1_b.C b/gcc/testsuite/g++.dg/modules/map-1_b.C
new file mode 100644
index 00000000000..0e306d8ba1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/map-1_b.C
@@ -0,0 +1,13 @@
+// Ick!
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=[srcdir]/map-1_b.map?MAP" }
+// { dg-additional-files map-1.map }
+
+import frob;
+
+int main ()
+{
+ if (frob (-2) != 2)
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/map-1_b.map b/gcc/testsuite/g++.dg/modules/map-1_b.map
new file mode 100644
index 00000000000..f125dc8bda1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/map-1_b.map
@@ -0,0 +1,3 @@
+MAP $root .
+MAP frob map-1_a.nms
+I can't see you
diff --git a/gcc/testsuite/g++.dg/modules/map-2.C b/gcc/testsuite/g++.dg/modules/map-2.C
new file mode 100644
index 00000000000..dceb1834196
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/map-2.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fmodule-mapper=[srcdir]/map-2.map" }
+
+
+// Ick! no cross-host testing for you!
+// { dg-additional-files map-2.map }
+
+export module foo;
+// { dg-error "Interface: no such module" "" { target *-*-* } .-1 }
+// { dg-error "failed reading mapper" "" { target *-*-* } 0 }
+
+// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/map-2.map b/gcc/testsuite/g++.dg/modules/map-2.map
new file mode 100644
index 00000000000..43aecde4b7f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/map-2.map
@@ -0,0 +1 @@
+$bad .
diff --git a/gcc/testsuite/g++.dg/modules/member-def-1_a.C b/gcc/testsuite/g++.dg/modules/member-def-1_a.C
new file mode 100644
index 00000000000..f7a508cbea9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/member-def-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo:part1;
+// { dg-module-cmi {foo:part1} }
+struct frob
+{
+ struct inner;
+};
diff --git a/gcc/testsuite/g++.dg/modules/member-def-1_b.C b/gcc/testsuite/g++.dg/modules/member-def-1_b.C
new file mode 100644
index 00000000000..fbe1ac44cf2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/member-def-1_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+
+export module foo:part2;
+// { dg-module-cmi {foo:part2} }
+
+import :part1;
+
+struct frob::inner
+{
+ int i;
+};
+
+// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::frob@foo:part1:1::inner'\n \[1\]=decl declaration '::frob@foo:part1:1::inner::inner'\n} module } }
+// { dg-final { scan-lang-dump {Member '::frob@foo:part1:1::inner' entity:0 keyed to foo:part1\[0\] '::frob@foo:part1:1'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/member-def-1_c.C b/gcc/testsuite/g++.dg/modules/member-def-1_c.C
new file mode 100644
index 00000000000..c7c3f6eb194
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/member-def-1_c.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-alias" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export import :part2;
+export import :part1;
+
+export auto foo ()
+{
+ return frob::inner ();
+}
+
+// { dg-final { scan-lang-dump {Reading 1 pending members keyed to foo:part1\[0\] '::frob@foo:part1:1'} module } }
+// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::frob@foo:part1:1'\n \[1\]=decl definition '::frob@foo:part1:1::inner@foo:part1:1'\n \[2\]=decl declaration '::frob@foo:part1:1::inner@foo:part1:1::__dt '\n( \[.\]=decl declaration '::frob@foo:part1:1::inner@foo:part1:1::__ct '\n)* \[6\]=decl declaration '::frob@foo:part1:1::inner@foo:part1:1::inner@foo:part2:2'\n \[7\]=decl declaration '::frob@foo:part1:1::frob@foo:part1:1'\n \[8\]=decl declaration '::frob@foo:part1:1::__as_base @foo:part1:1'\n \[9\]=binding '::frob'\n} module } }
+// { dg-final { scan-lang-dump {Pendings 0} module } }
diff --git a/gcc/testsuite/g++.dg/modules/member-def-1_d.C b/gcc/testsuite/g++.dg/modules/member-def-1_d.C
new file mode 100644
index 00000000000..5609d47b075
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/member-def-1_d.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+module foo;
+
+void f ()
+{
+ frob::inner x;
+ x.i = 17;
+}
+
+// { dg-final { scan-lang-dump {Loaded 1 clusters} module } }
diff --git a/gcc/testsuite/g++.dg/modules/member-def-2_a.C b/gcc/testsuite/g++.dg/modules/member-def-2_a.C
new file mode 100644
index 00000000000..b4904dabbec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/member-def-2_a.C
@@ -0,0 +1,10 @@
+// { dg-module-do link }
+// { dg-additional-options -fmodules-ts }
+
+export module foo:part1;
+// { dg-module-cmi {foo:part1} }
+
+export struct frob
+{
+ void member ();
+};
diff --git a/gcc/testsuite/g++.dg/modules/member-def-2_b.C b/gcc/testsuite/g++.dg/modules/member-def-2_b.C
new file mode 100644
index 00000000000..dedcbe70fcd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/member-def-2_b.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+
+export module foo:part2;
+// { dg-module-cmi {foo:part2} }
+
+import :part1;
+
+inline void frob::member ()
+{
+}
+
+// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::frob@foo:part1:1::member'\n} module } }
+// { dg-final { scan-lang-dump {Pendings 1} module } }
+// { dg-final { scan-lang-dump {Bindings 0} module } }
+
+// { dg-final { scan-assembler-not {_ZN4frob6memberEv:} } }
diff --git a/gcc/testsuite/g++.dg/modules/member-def-2_c.C b/gcc/testsuite/g++.dg/modules/member-def-2_c.C
new file mode 100644
index 00000000000..f0a193f34ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/member-def-2_c.C
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks-alias" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export import :part2;
+export import :part1;
+
+
+// { dg-final { scan-lang-dump { Cluster members:\n \[0\]=decl definition '::frob@foo:part1:1'\n \[1\]=decl declaration '::frob@foo:part1:1::frob@foo:part1:1'\n \[2\]=decl definition '::frob@foo:part1:1::member@foo:part1:1'\n \[3\]=decl declaration '::frob@foo:part1:1::__as_base @foo:part1:1'\n \[4\]=binding '::frob'\n} module } }
+// { dg-final { scan-lang-dump {Bindings 1} module } }
+// { dg-final { scan-lang-dump {Pendings 0} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key .matched. function_decl:'::frob@foo:part1:1::member'} module } }
+
+// { dg-final { scan-assembler-not {_ZN4frob6memberEv:} } }
diff --git a/gcc/testsuite/g++.dg/modules/member-def-2_d.C b/gcc/testsuite/g++.dg/modules/member-def-2_d.C
new file mode 100644
index 00000000000..c2b9c3e655b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/member-def-2_d.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+import foo;
+
+int main ()
+{
+ frob x;
+ x.member ();
+}
+
+// { dg-final { scan-lang-dump {Reading function definition '::frob@foo:1::member@foo:1'} module } }
+
+// { dg-final { scan-assembler {_ZN4frob6memberEv:} } }
diff --git a/gcc/testsuite/g++.dg/modules/memref-1_a.C b/gcc/testsuite/g++.dg/modules/memref-1_a.C
new file mode 100644
index 00000000000..e780999778d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/memref-1_a.C
@@ -0,0 +1,24 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Foo;
+// { dg-module-cmi Foo }
+
+export class Bit
+{
+private:
+ unsigned _M_msb:1;
+};
+
+Bit Make () noexcept;
+
+export class Container
+{
+public:
+ void Frob ()
+ {
+ _M_rep = Make ();
+ }
+
+private:
+ Bit _M_rep;
+};
diff --git a/gcc/testsuite/g++.dg/modules/memref-1_b.C b/gcc/testsuite/g++.dg/modules/memref-1_b.C
new file mode 100644
index 00000000000..82c52faed7a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/memref-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+import Foo;
+
+void X ()
+{
+ Container c;
+ c.Frob ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/merge-10.h b/gcc/testsuite/g++.dg/modules/merge-10.h
new file mode 100644
index 00000000000..9df9d2cb75b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-10.h
@@ -0,0 +1,8 @@
+
+struct timex
+{
+ unsigned modes;
+ int :32;
+ int :32;
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/merge-10_a.H b/gcc/testsuite/g++.dg/modules/merge-10_a.H
new file mode 100644
index 00000000000..dc4be18f076
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-10_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-10.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-10_b.C b/gcc/testsuite/g++.dg/modules/merge-10_b.C
new file mode 100644
index 00000000000..9df07ee962a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-10_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-10.h"
+import "merge-10_a.H";
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git a/gcc/testsuite/g++.dg/modules/merge-11.h b/gcc/testsuite/g++.dg/modules/merge-11.h
new file mode 100644
index 00000000000..87342e18880
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-11.h
@@ -0,0 +1,15 @@
+
+
+
+template
+struct __is_nt_convertible_helper;
+
+template
+class __is_nt_convertible_helper<_From, false>
+{
+ template static int __test (int);
+ template static void __test(...);
+
+public:
+ using type = decltype(__test<_From>(0));
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-11_a.H b/gcc/testsuite/g++.dg/modules/merge-11_a.H
new file mode 100644
index 00000000000..6de063d1a7f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-11_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-11.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-11_b.C b/gcc/testsuite/g++.dg/modules/merge-11_b.C
new file mode 100644
index 00000000000..2c30e341f53
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-11_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-11.h"
+import "merge-11_a.H";
+
+// { 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-12.h b/gcc/testsuite/g++.dg/modules/merge-12.h
new file mode 100644
index 00000000000..96b2ba30265
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-12.h
@@ -0,0 +1,23 @@
+
+template
+struct invoke_result;
+
+template
+struct is_invocable;
+
+template
+concept invocable = is_invocable<_Fn, _Args...>::value;
+
+template
+requires invocable<_Fn, _Is>
+ using indirect_result_t = typename invoke_result<_Fn, _Is>::type;
+
+template
+struct remove_cv;
+
+template
+struct projected
+{
+ using value_type = remove_cv>;
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/merge-12_a.H b/gcc/testsuite/g++.dg/modules/merge-12_a.H
new file mode 100644
index 00000000000..4ee061f590e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-12_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -fconcepts" }
+// { dg-module-cmi {} }
+
+#include "merge-12.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-12_b.C b/gcc/testsuite/g++.dg/modules/merge-12_b.C
new file mode 100644
index 00000000000..4bafbddb816
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-12_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fconcepts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-12.h"
+import "merge-12_a.H";
+
+// { 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-13.h b/gcc/testsuite/g++.dg/modules/merge-13.h
new file mode 100644
index 00000000000..ad282a0ed62
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-13.h
@@ -0,0 +1,10 @@
+template class Base;
+
+template class Derived : Base
+{
+ using Base_ = Base;
+ using typename Base_::base_member;
+
+public:
+ base_member Func ();
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-13_a.H b/gcc/testsuite/g++.dg/modules/merge-13_a.H
new file mode 100644
index 00000000000..ecf0c319e49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-13_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -fconcepts" }
+// { dg-module-cmi {} }
+
+#include "merge-13.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-13_b.C b/gcc/testsuite/g++.dg/modules/merge-13_b.C
new file mode 100644
index 00000000000..b62101fefb1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-13_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fconcepts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-13.h"
+import "merge-13_a.H";
+
+// { 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-14.h b/gcc/testsuite/g++.dg/modules/merge-14.h
new file mode 100644
index 00000000000..0b867b68826
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-14.h
@@ -0,0 +1,7 @@
+template
+struct TPL
+{
+ T val = 0;
+};
+
+inline TPL x;
diff --git a/gcc/testsuite/g++.dg/modules/merge-14_a.H b/gcc/testsuite/g++.dg/modules/merge-14_a.H
new file mode 100644
index 00000000000..c197ec85e2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-14_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-14.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-14_b.C b/gcc/testsuite/g++.dg/modules/merge-14_b.C
new file mode 100644
index 00000000000..4d92b084b95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-14_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-14.h"
+import "merge-14_a.H";
+
+// { 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-15.h b/gcc/testsuite/g++.dg/modules/merge-15.h
new file mode 100644
index 00000000000..ccf3b844d69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-15.h
@@ -0,0 +1,5 @@
+struct optional
+{
+ int &get () &;
+ int &&get () &&;
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-15_a.H b/gcc/testsuite/g++.dg/modules/merge-15_a.H
new file mode 100644
index 00000000000..afef95dbcbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-15_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-15.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-15_b.C b/gcc/testsuite/g++.dg/modules/merge-15_b.C
new file mode 100644
index 00000000000..07378d65368
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-15_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-15.h"
+import "merge-15_a.H";
+
+// { 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-1_a.C b/gcc/testsuite/g++.dg/modules/merge-1_a.C
new file mode 100644
index 00000000000..966fd4bc4df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-1_a.C
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template
+struct integral_constant
+{
+};
+
+typedef integral_constant true_type;
+
+void __throw_with_nested_impl (true_type);
diff --git a/gcc/testsuite/g++.dg/modules/merge-1_b.C b/gcc/testsuite/g++.dg/modules/merge-1_b.C
new file mode 100644
index 00000000000..c7f533ff1ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+void frob ()
+{
+ __throw_with_nested_impl (integral_constant ());
+}
diff --git a/gcc/testsuite/g++.dg/modules/merge-2_a.H b/gcc/testsuite/g++.dg/modules/merge-2_a.H
new file mode 100644
index 00000000000..ac6d06a1d8f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-2_a.H
@@ -0,0 +1,29 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template class istreambuf_iterator;
+
+void move(char __t);
+void move(istreambuf_iterator &__u);
+
+template struct allocator {};
+
+template struct __alloc_traits
+{
+ static void _S_on_swap(_Alloc& __b)
+ {
+ move (__b);
+ }
+
+ typedef allocator other;
+};
+
+template class basic_string
+{
+ typedef __alloc_traits::other _Char_alloc_type;
+};
+
+template class istreambuf_iterator
+{
+ void frob (const basic_string& __s);
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-2_b.C b/gcc/testsuite/g++.dg/modules/merge-2_b.C
new file mode 100644
index 00000000000..21bbd048f2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-2_b.C
@@ -0,0 +1,2 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy} }
+import "merge-2_a.H";
diff --git a/gcc/testsuite/g++.dg/modules/merge-3_a.H b/gcc/testsuite/g++.dg/modules/merge-3_a.H
new file mode 100644
index 00000000000..80dfd9cc9a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-3_a.H
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module_cmi {} }
+
+struct bob
+{
+ int i;
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-3_b.C b/gcc/testsuite/g++.dg/modules/merge-3_b.C
new file mode 100644
index 00000000000..1e863f8c1e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-3_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+struct bob;
+import "merge-3_a.H";
+
+bob b = {1};
+
+void frob ()
+{
+ b.i = 7;
+}
diff --git a/gcc/testsuite/g++.dg/modules/merge-4.h b/gcc/testsuite/g++.dg/modules/merge-4.h
new file mode 100644
index 00000000000..842fedc5718
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-4.h
@@ -0,0 +1,7 @@
+template struct Bob
+{
+ struct M
+ {
+ int m;
+ };
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-4_a.H b/gcc/testsuite/g++.dg/modules/merge-4_a.H
new file mode 100644
index 00000000000..78b0ec74edd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-4_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-4.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-4_b.C b/gcc/testsuite/g++.dg/modules/merge-4_b.C
new file mode 100644
index 00000000000..89b69619ee2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-4_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-4.h"
+import "merge-4_a.H";
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::template Bob'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::template Bob::template M'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/merge-5.h b/gcc/testsuite/g++.dg/modules/merge-5.h
new file mode 100644
index 00000000000..5db1b0a8115
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-5.h
@@ -0,0 +1,8 @@
+
+template struct __truth_type;
+
+template struct __traitor
+{
+ enum X { __value = true };
+ typedef typename __truth_type<__value>::__type __type;
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-5_a.H b/gcc/testsuite/g++.dg/modules/merge-5_a.H
new file mode 100644
index 00000000000..e3d8c690921
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-5_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-5.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-5_b.C b/gcc/testsuite/g++.dg/modules/merge-5_b.C
new file mode 100644
index 00000000000..58c2a348c0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-5_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-5.h"
+import "merge-5_a.H";
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) const_decl:'::template __traitor::template X::__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.h b/gcc/testsuite/g++.dg/modules/merge-6.h
new file mode 100644
index 00000000000..6a1d6542c51
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-6.h
@@ -0,0 +1,10 @@
+
+template
+struct __truth_type;
+
+template
+struct __traitor
+{
+ enum { __value = true }; // Oh, an anonymous templatey thing!
+ typedef typename __truth_type<__value>::__type __type;
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-6_a.H b/gcc/testsuite/g++.dg/modules/merge-6_a.H
new file mode 100644
index 00000000000..4e0b81c5a4a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-6_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-6.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-6_b.C b/gcc/testsuite/g++.dg/modules/merge-6_b.C
new file mode 100644
index 00000000000..11fe63153d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-6_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-6.h"
+import "merge-6_a.H";
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s field merge key \(matched\) template_decl:'::template __traitor::template #null#'} 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-7.h b/gcc/testsuite/g++.dg/modules/merge-7.h
new file mode 100644
index 00000000000..6350e743f72
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-7.h
@@ -0,0 +1,5 @@
+template
+struct __promote_2
+{
+ typedef __typeof__(_Tp2() + _Up2()) __type;
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-7_a.H b/gcc/testsuite/g++.dg/modules/merge-7_a.H
new file mode 100644
index 00000000000..3c32b33ada8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-7_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-7.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-7_b.C b/gcc/testsuite/g++.dg/modules/merge-7_b.C
new file mode 100644
index 00000000000..da9632d71bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-7_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-7.h"
+import "merge-7_a.H";
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::template __promote_2<_Tp2,_Up2>::template __type'} 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-8.h b/gcc/testsuite/g++.dg/modules/merge-8.h
new file mode 100644
index 00000000000..d2539021ce3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-8.h
@@ -0,0 +1,17 @@
+
+struct __do_is_destructible_impl
+{
+ template
+ static bool __test(int);
+
+ template
+ static float __test(...);
+};
+
+template
+struct __is_destructible_impl
+ : public __do_is_destructible_impl
+{
+ // Requires BINFO merging
+ typedef decltype(__test<_Tp>(0)) type;
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-8_a.H b/gcc/testsuite/g++.dg/modules/merge-8_a.H
new file mode 100644
index 00000000000..d2add6bfdd8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-8_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-8.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-8_b.C b/gcc/testsuite/g++.dg/modules/merge-8_b.C
new file mode 100644
index 00000000000..c489e30a8ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-8_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-8.h"
+import "merge-8_a.H";
+
+// { dg-final { scan-lang-dump {Deduping binfo '::__do_is_destructible_impl'\[0\]} module } }
+// { dg-final { scan-lang-dump {Deduping binfo '::template __is_destructible_impl<_Tp>'\[0\]} module } }
+// { dg-final { scan-lang-dump {Deduping binfo '::template __is_destructible_impl<_Tp>'\[1\]} module } }
diff --git a/gcc/testsuite/g++.dg/modules/merge-9.h b/gcc/testsuite/g++.dg/modules/merge-9.h
new file mode 100644
index 00000000000..19447799fea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-9.h
@@ -0,0 +1,9 @@
+using size_t = __SIZE_TYPE__;
+
+namespace std
+{
+// This is a builtin, but should not be a global tree
+ enum class align_val_t: size_t {};
+ // as is this
+ class type_info;
+}
diff --git a/gcc/testsuite/g++.dg/modules/merge-9_a.H b/gcc/testsuite/g++.dg/modules/merge-9_a.H
new file mode 100644
index 00000000000..69f32cb3671
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-9_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "merge-9.h"
diff --git a/gcc/testsuite/g++.dg/modules/merge-9_b.C b/gcc/testsuite/g++.dg/modules/merge-9_b.C
new file mode 100644
index 00000000000..0a92cf344df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-9_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "merge-9.h"
+import "merge-9_a.H";
+
+// { dg-final { scan-lang-dump {Read:-[10-9]*'s named merge key \(matched\) type_decl:'::std::align_val_t'} 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/mod-exp-1_a.C b/gcc/testsuite/g++.dg/modules/mod-exp-1_a.C
new file mode 100644
index 00000000000..800752dc871
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-exp-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Baz;
+// { dg-module-cmi "Baz" }
+
+void Quux (void);
+
+export void Bar (void);
+
+void Foo (void);
diff --git a/gcc/testsuite/g++.dg/modules/mod-exp-1_b.C b/gcc/testsuite/g++.dg/modules/mod-exp-1_b.C
new file mode 100644
index 00000000000..efea205a50d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-exp-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+module;
+# 4 "gmf" 1
+void Frob (void);
+# 6 "" 2
+
+module Baz;
diff --git a/gcc/testsuite/g++.dg/modules/mod-imp-1_a.C b/gcc/testsuite/g++.dg/modules/mod-imp-1_a.C
new file mode 100644
index 00000000000..cf9e1d7a2cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-imp-1_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+export module Foo;
+// { dg-module-cmi "Foo" }
+
+// { dg-final { scan-lang-dump "Starting module Foo" "module" } }
diff --git a/gcc/testsuite/g++.dg/modules/mod-imp-1_b.C b/gcc/testsuite/g++.dg/modules/mod-imp-1_b.C
new file mode 100644
index 00000000000..0dc4bdb58a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-imp-1_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+module Foo;
+// { dg-final { scan-lang-dump "Starting module Foo" "module" } }
diff --git a/gcc/testsuite/g++.dg/modules/mod-imp-1_c.C b/gcc/testsuite/g++.dg/modules/mod-imp-1_c.C
new file mode 100644
index 00000000000..e32aaaf7461
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-imp-1_c.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+export module Baz;
+// { dg-module-cmi "Baz" }
+
+import Foo;
+
+// { dg-final { scan-lang-dump "Starting module Foo" "module" } }
+// { dg-final { scan-lang-dump "Starting module Baz" "module" } }
+// { dg-final { scan-lang-dump "Writing import:1->1 Foo" "module" } }
diff --git a/gcc/testsuite/g++.dg/modules/mod-imp-1_d.C b/gcc/testsuite/g++.dg/modules/mod-imp-1_d.C
new file mode 100644
index 00000000000..ca6f64914c2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-imp-1_d.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+module Baz;
+
+// { dg-final { scan-lang-dump "Starting module Baz" "module" } }
+// { dg-final { scan-lang-dump "Found import:1 Foo->1" "module" } }
+// { dg-final { scan-lang-dump "Starting module Foo" "module" } }
diff --git a/gcc/testsuite/g++.dg/modules/mod-impl-1_a.C b/gcc/testsuite/g++.dg/modules/mod-impl-1_a.C
new file mode 100644
index 00000000000..9f9dfd42806
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-impl-1_a.C
@@ -0,0 +1,12 @@
+// { dg-module-do "run" }
+// { dg-additional-options "-fmodules-ts" }
+
+export module baz;
+// { dg-module-cmi "baz" }
+
+export int Square (int);
+
+float Square (int, int);
+export int Square (int, int, int);
+
+int Prod (int, int);
diff --git a/gcc/testsuite/g++.dg/modules/mod-impl-1_b.C b/gcc/testsuite/g++.dg/modules/mod-impl-1_b.C
new file mode 100644
index 00000000000..c1f9a5c9233
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-impl-1_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+module baz;
+
+int Square (int a)
+{
+ return Prod (a, a);
+}
+
+float Square (int a, int b)
+{
+ return a * b * 1.5f;
+}
diff --git a/gcc/testsuite/g++.dg/modules/mod-impl-1_c.C b/gcc/testsuite/g++.dg/modules/mod-impl-1_c.C
new file mode 100644
index 00000000000..c50aade4212
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-impl-1_c.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+module baz;
+
+int Prod (int a, int b)
+{
+ return a * b;
+}
+
+int Square (int a, int b, int c)
+{
+ return Prod (Square (a, b), c);
+}
diff --git a/gcc/testsuite/g++.dg/modules/mod-impl-1_d.C b/gcc/testsuite/g++.dg/modules/mod-impl-1_d.C
new file mode 100644
index 00000000000..4f05a76159b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-impl-1_d.C
@@ -0,0 +1,27 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import baz;
+
+int Prod (int a, int b)
+{
+ return -a * b; // What kind of crazy math is this?
+}
+
+int Square (float a)
+{
+ return Prod (int (a), int (a));
+}
+
+int main ()
+{
+ if (Square (2) != 4)
+ return 1;
+
+ if (Square (2.0f) != -4)
+ return 1;
+
+ if (Square (2, 3, 4) != 9 * 4)
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/mod-indirect-1_a.C b/gcc/testsuite/g++.dg/modules/mod-indirect-1_a.C
new file mode 100644
index 00000000000..a27153cb9ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-indirect-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-do run }
+
+export module Foo;
+// { dg-module-cmi "Foo" }
+
+export int bob (int);
+export float bob (float);
diff --git a/gcc/testsuite/g++.dg/modules/mod-indirect-1_b.C b/gcc/testsuite/g++.dg/modules/mod-indirect-1_b.C
new file mode 100644
index 00000000000..7e466f1d897
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-indirect-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module Bar;
+// { dg-module-cmi "Bar" }
+
+import Foo;
+
+export int frob (int, float);
diff --git a/gcc/testsuite/g++.dg/modules/mod-indirect-1_c.C b/gcc/testsuite/g++.dg/modules/mod-indirect-1_c.C
new file mode 100644
index 00000000000..e19f41d4601
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-indirect-1_c.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+module Foo;
+
+int bob (int a)
+{
+ return a * 2;
+}
+
+float bob (float b)
+{
+ return b * 1.5f;
+}
diff --git a/gcc/testsuite/g++.dg/modules/mod-indirect-1_d.C b/gcc/testsuite/g++.dg/modules/mod-indirect-1_d.C
new file mode 100644
index 00000000000..304be95561e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-indirect-1_d.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+module Bar;
+
+int frob (int a, float b)
+{
+ return bob (a) * bob (b);
+}
diff --git a/gcc/testsuite/g++.dg/modules/mod-indirect-1_e.C b/gcc/testsuite/g++.dg/modules/mod-indirect-1_e.C
new file mode 100644
index 00000000000..23241b1601f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-indirect-1_e.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+import Bar;
+
+int main ()
+{
+ return frob (2, 4) != 4 * 6;
+}
diff --git a/gcc/testsuite/g++.dg/modules/mod-stamp-1_a.C b/gcc/testsuite/g++.dg/modules/mod-stamp-1_a.C
new file mode 100644
index 00000000000..cf8e73f85d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-stamp-1_a.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module Foo;
+// { dg-module-cmi "Foo" }
+
+export int bob ();
+
diff --git a/gcc/testsuite/g++.dg/modules/mod-stamp-1_b.C b/gcc/testsuite/g++.dg/modules/mod-stamp-1_b.C
new file mode 100644
index 00000000000..3a5e8e20ba5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-stamp-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module Bar;
+// { dg-module-cmi "Bar" }
+
+import Foo;
+
+export int bill ();
diff --git a/gcc/testsuite/g++.dg/modules/mod-stamp-1_c.C b/gcc/testsuite/g++.dg/modules/mod-stamp-1_c.C
new file mode 100644
index 00000000000..554ba3f26eb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-stamp-1_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module Foo;
+
+export int bob (int);
diff --git a/gcc/testsuite/g++.dg/modules/mod-stamp-1_d.C b/gcc/testsuite/g++.dg/modules/mod-stamp-1_d.C
new file mode 100644
index 00000000000..f16833ed5c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-stamp-1_d.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import Bar;
+// { dg-error "CRC mismatch" "" { target *-*-* } 0 }
+// { dg-regexp "Foo: error: failed to read compiled module: Bad file data\n" }
+// { dg-regexp "Bar: error: failed to read compiled module: Bad import dependency\n" }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "compilation terminated" }
+
+int bill ();
diff --git a/gcc/testsuite/g++.dg/modules/mod-sym-1.C b/gcc/testsuite/g++.dg/modules/mod-sym-1.C
new file mode 100644
index 00000000000..b20710189d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-sym-1.C
@@ -0,0 +1,34 @@
+// { dg-additional-options "-fmodules-ts" }
+export module linkage;
+// { dg-module-cmi "linkage" }
+
+inline void Foo () {}
+
+export inline void Baz () __attribute__((used));
+
+inline void Bink () {}
+
+export inline void Baz () { Foo (); Bink (); }
+
+extern "C" inline void cfunc (void) __attribute__((used));
+extern "C" inline void cfunc (void) {}
+
+namespace Inner
+{
+ inline void Foo2 () {}
+
+ export inline void Baz2 () __attribute__((used));
+
+ inline void Bink2 () {}
+
+ export inline void Baz2 () { Foo2 (); Bink2 (); }
+}
+
+// These fail until namespace hack is removed
+// { dg-final { scan-assembler "_ZW7linkageE3Foov:" } }
+// { dg-final { scan-assembler "_ZW7linkageE4Binkv:" } }
+// { dg-final { scan-assembler "_ZW7linkageEN5Inner4Foo2Ev:" } }
+// { dg-final { scan-assembler "_ZW7linkageEN5Inner5Bink2Ev:" } }
+// { dg-final { scan-assembler "_Z3Bazv:" } }
+// { dg-final { scan-assembler "_ZN5Inner4Baz2Ev:" } }
+// { dg-final { scan-assembler "cfunc:" } }
diff --git a/gcc/testsuite/g++.dg/modules/mod-sym-2.C b/gcc/testsuite/g++.dg/modules/mod-sym-2.C
new file mode 100644
index 00000000000..ef0c3f03317
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-sym-2.C
@@ -0,0 +1,23 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+module;
+# 4 "header" 1
+inline void Foo () {}
+# 6 "" 2
+export module okely.dokely;
+// { dg-module-cmi "okely.dokely" }
+
+namespace One {
+ namespace Two {
+ inline namespace Three
+ {
+ inline void Foo2 () {}
+
+ export inline void Baz2 () __attribute__((used));
+ export inline void Baz2 () { Foo (); Foo2 (); }
+ }
+ }
+}
+
+// { dg-final { scan-assembler "_Z3Foov:" } }
+// { dg-final { scan-assembler "_ZW5okely6dokelyEN3One3Two5Three4Foo2Ev:" } }
+// { dg-final { scan-assembler "_ZN3One3Two5Three4Baz2Ev:" } }
diff --git a/gcc/testsuite/g++.dg/modules/mod-sym-3.C b/gcc/testsuite/g++.dg/modules/mod-sym-3.C
new file mode 100644
index 00000000000..9481ad1e719
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-sym-3.C
@@ -0,0 +1,26 @@
+// { dg-additional-options "-fmodules-ts" }
+export module bob;
+// { dg-module-cmi "bob" }
+
+namespace X
+{
+ inline void Foo () __attribute__((used));
+ export inline void Baz () __attribute__((used));
+
+ namespace Y
+ {
+ inline void Quux () __attribute__((used));
+ export inline void Bar () __attribute__((used));
+ }
+
+ inline void Y::Quux () {}
+ inline void Y::Bar () {}
+}
+
+inline void X::Foo () {}
+inline void X::Baz () {}
+
+// { dg-final { scan-assembler "_ZW3bobEN1X3FooEv:" } }
+// { dg-final { scan-assembler "_ZN1X3BazEv:" } }
+// { dg-final { scan-assembler "_ZW3bobEN1X1Y4QuuxEv:" } }
+// { dg-final { scan-assembler "_ZN1X1Y3BarEv:" } }
diff --git a/gcc/testsuite/g++.dg/modules/mod-tpl-1_a.C b/gcc/testsuite/g++.dg/modules/mod-tpl-1_a.C
new file mode 100644
index 00000000000..f48e1237d01
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-tpl-1_a.C
@@ -0,0 +1,12 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module Frob;
+// { dg-module-cmi "Frob" }
+
+export template
+T twice (T x)
+{
+ return x * 2;
+}
+
diff --git a/gcc/testsuite/g++.dg/modules/mod-tpl-1_b.C b/gcc/testsuite/g++.dg/modules/mod-tpl-1_b.C
new file mode 100644
index 00000000000..669f2c68881
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-tpl-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+import Frob;
+
+int main ()
+{
+ return twice (2) != 4;
+}
diff --git a/gcc/testsuite/g++.dg/modules/mod-tpl-2_a.C b/gcc/testsuite/g++.dg/modules/mod-tpl-2_a.C
new file mode 100644
index 00000000000..86281bb97a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-tpl-2_a.C
@@ -0,0 +1,16 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module frob;
+// { dg-module-cmi "frob" }
+
+export template
+class X
+{
+ T m;
+
+public:
+ void frob (T v) { m = v; }
+
+ T frobber (T v) { return v + m; }
+};
diff --git a/gcc/testsuite/g++.dg/modules/mod-tpl-2_b.C b/gcc/testsuite/g++.dg/modules/mod-tpl-2_b.C
new file mode 100644
index 00000000000..8452c7d7875
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mod-tpl-2_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import frob;
+
+int main ()
+{
+ X x;
+
+ x.frob (3);
+
+ return ! (x.frobber (-3) == 0);
+}
diff --git a/gcc/testsuite/g++.dg/modules/mutual-friend.ii b/gcc/testsuite/g++.dg/modules/mutual-friend.ii
new file mode 100644
index 00000000000..b42b9798998
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/mutual-friend.ii
@@ -0,0 +1,11 @@
+class exception_ptr;
+
+
+void rethrow_exception(exception_ptr);
+
+
+class exception_ptr
+{
+ friend void rethrow_exception(exception_ptr);
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/namespace-1_a.C b/gcc/testsuite/g++.dg/modules/namespace-1_a.C
new file mode 100644
index 00000000000..1929acc167a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-1_a.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Frob;
+// { dg-module-cmi Frob }
+
+namespace impl
+{
+ export int doit (int);
+}
+
+namespace ompl
+{
+ export int doneit (int);
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-1_b.C b/gcc/testsuite/g++.dg/modules/namespace-1_b.C
new file mode 100644
index 00000000000..096e6ce41ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+export module Frink;
+// { dg-module-cmi Frink }
+
+import Frob;
+
+export int frab (int x)
+{
+ return impl::doit (x) + ompl::doneit (x);
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-1_c.C b/gcc/testsuite/g++.dg/modules/namespace-1_c.C
new file mode 100644
index 00000000000..748ef5d79a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-1_c.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+// The indirect import of frob, with namespaces impl and ompl doesn't
+// affect us.
+static int impl;
+import Frink;
+
+static int ompl;
+
+void corge (int x)
+{
+ impl = x;
+ ompl = frab (x);
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-2_a.C b/gcc/testsuite/g++.dg/modules/namespace-2_a.C
new file mode 100644
index 00000000000..18327e205ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-2_a.C
@@ -0,0 +1,40 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module -Wno-pedantic" }
+
+module;
+# 5 "gmf" 1
+namespace not_exported
+{
+ // not in purview
+}
+# 10 "" 2
+export module foo;
+// { dg-module-cmi foo }
+
+namespace explicit_export
+{
+}
+
+namespace implicit_export
+{
+ export int bob ();
+}
+
+namespace also_not_exported
+{
+ int bob ();
+}
+
+export namespace explicit_export
+{
+ namespace also_exported
+ {
+ }
+}
+
+// { dg-final { scan-lang-dump-not {Writable bindings at '::not_exported'} "module" } }
+// { dg-final { scan-lang-dump {Writing namespace:[0-9] '::implicit_export', export, public} "module" } }
+// { dg-final { scan-lang-dump {Writing namespace:[0-9] '::explicit_export', export, public} "module" } }
+// { dg-final { scan-lang-dump {Writing namespace:[0-9] '::also_not_exported', public} "module" } }
+// { dg-final { scan-lang-dump {Writing namespace:[0-9] '::explicit_export::also_exported', export, public} "module" } }
+// { dg-final { scan-lang-dump-not {Writing namespace:[0-9] '::not_exported'} "module" } }
+// { dg-final { scan-lang-dump-not {Writing namespace:[0-9] '::std'} "module" } }
diff --git a/gcc/testsuite/g++.dg/modules/namespace-2_b.C b/gcc/testsuite/g++.dg/modules/namespace-2_b.C
new file mode 100644
index 00000000000..6ab5113c23a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-2_b.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import foo;
+
+static int also_not_exported; // ok
+
+void X ()
+{
+ implicit_export::bob ();
+}
+
+static int implicit_export; // { dg-error "different kind" }
+
+void Y ()
+{
+ also_not_exported = 1;
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-3_a.C b/gcc/testsuite/g++.dg/modules/namespace-3_a.C
new file mode 100644
index 00000000000..8e9508d7ff8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-3_a.C
@@ -0,0 +1,21 @@
+// Check namespace needed only by internal reference is not made visible
+// { dg-additional-options "-fmodules-ts" }
+
+export module frob;
+// { dg-module-cmi frob }
+
+namespace silent
+{
+ namespace inner
+ {
+ static int X ()
+ {
+ return 1;
+ }
+ }
+}
+
+export int f (int y)
+{
+ return y + silent::inner::X ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-3_b.C b/gcc/testsuite/g++.dg/modules/namespace-3_b.C
new file mode 100644
index 00000000000..f779ffe8c8f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-3_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import frob;
+
+int x = silent; // { dg-error "not declared" }
+
+static int silent;
+
+int user ()
+{
+ return f (silent);
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-4_a.C b/gcc/testsuite/g++.dg/modules/namespace-4_a.C
new file mode 100644
index 00000000000..b49e0ea7ce6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-4_a.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module frob;
+// { dg-module-cmi frob }
+
+namespace
+{
+ int nope;
+}
+
+export int f (int)
+{
+ return nope;
+}
+
+int g (int *a);
diff --git a/gcc/testsuite/g++.dg/modules/namespace-4_b.C b/gcc/testsuite/g++.dg/modules/namespace-4_b.C
new file mode 100644
index 00000000000..3530bcd9def
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-4_b.C
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module frob;
+
+namespace
+{
+void *nope; // ok, different nope
+}
+
+void *q (int)
+{
+ f (bool (nope));
+ g (static_cast (nope));
+ return nope; // Ok sees above nope
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-4_c.C b/gcc/testsuite/g++.dg/modules/namespace-4_c.C
new file mode 100644
index 00000000000..2526289ec3e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-4_c.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import frob;
+
+namespace
+{
+ float *nope;
+}
+
+float *q ()
+{
+ f (int (*nope));
+ return nope;
+}
diff --git a/gcc/testsuite/g++.dg/modules/nest-1_a.C b/gcc/testsuite/g++.dg/modules/nest-1_a.C
new file mode 100644
index 00000000000..4788d5da601
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nest-1_a.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+export module foo;
+// { dg-module-cmi foo }
+
+namespace foo {
+
+ export int frob (int i)
+ {
+ return i;
+ }
+
+}
diff --git a/gcc/testsuite/g++.dg/modules/nest-1_b.C b/gcc/testsuite/g++.dg/modules/nest-1_b.C
new file mode 100644
index 00000000000..cc302781248
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nest-1_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+export module bar;
+// { dg-module-cmi bar }
+
+import foo;
+
+namespace bar
+{
+ export int frob (int i)
+ {
+ return i;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/modules/nest-1_c.C b/gcc/testsuite/g++.dg/modules/nest-1_c.C
new file mode 100644
index 00000000000..05ca02ffc61
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nest-1_c.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts --param lazy-modules=1" }
+import bar;
+
+int main ()
+{
+ return bar::frob (0);
+}
diff --git a/gcc/testsuite/g++.dg/modules/nested-1_a.C b/gcc/testsuite/g++.dg/modules/nested-1_a.C
new file mode 100644
index 00000000000..31726571ae8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-1_a.C
@@ -0,0 +1,19 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module blinky;
+// { dg-module-cmi blinky }
+
+export struct X
+{
+ struct Inner
+ {
+ int m;
+ Inner (int);
+ int getter () const
+ {
+ return m;
+ }
+ };
+};
+
diff --git a/gcc/testsuite/g++.dg/modules/nested-1_b.C b/gcc/testsuite/g++.dg/modules/nested-1_b.C
new file mode 100644
index 00000000000..9f775b16c17
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module blinky;
+
+X::Inner::Inner (int m_)
+ :m (m_)
+{
+}
diff --git a/gcc/testsuite/g++.dg/modules/nested-1_c.C b/gcc/testsuite/g++.dg/modules/nested-1_c.C
new file mode 100644
index 00000000000..f46e6dfde3d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-1_c.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import blinky;
+
+int main ()
+{
+ X::Inner i (7);
+
+ if (i.getter () != 7)
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/nested-2_a.C b/gcc/testsuite/g++.dg/modules/nested-2_a.C
new file mode 100644
index 00000000000..e21973593d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-2_a.C
@@ -0,0 +1,24 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module bob;
+// { dg-module-cmi bob }
+
+export struct X
+{
+ typedef X *iter;
+
+ int m;
+ X() :m(-1)
+ {
+ }
+
+ void set (int m_)
+ {
+ m = m_;
+ }
+ operator int () const
+ {
+ return m;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/nested-2_b.C b/gcc/testsuite/g++.dg/modules/nested-2_b.C
new file mode 100644
index 00000000000..1ca02bdc2fe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-2_b.C
@@ -0,0 +1,20 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+import bob;
+
+int main ()
+{
+ X ary[10];
+ X::iter iter;
+ unsigned ix;
+
+ for (ix = 10, iter = ary; ix--; iter++)
+ iter->set (ix);
+
+ for (ix = 10; ix--;)
+ if (ary[ix] + ix != 9)
+ return 1;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/modules/nested-constr-1.h b/gcc/testsuite/g++.dg/modules/nested-constr-1.h
new file mode 100644
index 00000000000..6962ccad850
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-constr-1.h
@@ -0,0 +1,15 @@
+
+template
+struct traits
+{
+ template
+ struct nested
+ { using type = void; };
+
+ template requires requires { typename U::type; }
+ struct nested
+ { using type = typename U::type; };
+};
+
+using V = traits::nested::type;
+
diff --git a/gcc/testsuite/g++.dg/modules/nested-constr-1_a.H b/gcc/testsuite/g++.dg/modules/nested-constr-1_a.H
new file mode 100644
index 00000000000..9398986dd42
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-constr-1_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-std=c++2a -fmodule-header" }
+// { dg-module-cmi {} }
+#include "nested-constr-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/nested-constr-1_b.C b/gcc/testsuite/g++.dg/modules/nested-constr-1_b.C
new file mode 100644
index 00000000000..7043ffa8554
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-constr-1_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-std=c++2a -fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "nested-constr-1.h"
+import "nested-constr-1_a.H";
+
+struct X
+{
+ using type = int;
+};
+
+traits::nested::type b;
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git a/gcc/testsuite/g++.dg/modules/nested-constr-2_a.C b/gcc/testsuite/g++.dg/modules/nested-constr-2_a.C
new file mode 100644
index 00000000000..b29d670a570
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-constr-2_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-std=c++2a -fmodules-ts" }
+export module foo;
+// { dg-module-cmi foo }
+
+export template
+struct traits
+{
+ template
+ struct nested
+ { using type = void; };
+
+ template requires requires { typename U::type; }
+ struct nested
+ { using type = typename U::type; };
+};
+
+export using V = traits::nested::type;
+
diff --git a/gcc/testsuite/g++.dg/modules/nested-constr-2_b.C b/gcc/testsuite/g++.dg/modules/nested-constr-2_b.C
new file mode 100644
index 00000000000..a34ef523f90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-constr-2_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-std=c++2a -fmodules-ts" }
+export module bar;
+// { dg-module-cmi bar }
+import foo;
+
+struct X
+{
+ using type = int;
+};
+
+export traits::nested::type b;
diff --git a/gcc/testsuite/g++.dg/modules/nested-constr-2_c.C b/gcc/testsuite/g++.dg/modules/nested-constr-2_c.C
new file mode 100644
index 00000000000..5c81b3b6c09
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nested-constr-2_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-std=c++2a -fmodules-ts" }
+
+import bar;
+
+decltype(b) c;
diff --git a/gcc/testsuite/g++.dg/modules/nodes-1_a.C b/gcc/testsuite/g++.dg/modules/nodes-1_a.C
new file mode 100644
index 00000000000..446461c8a6b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/nodes-1_a.C
@@ -0,0 +1,46 @@
+// { dg-additional-options -fmodules-ts }
+// { dg-module-do run }
+
+export module node;
+// { dg-module-cmi node }
+
+export template