diff --git c/gcc/testsuite/g++.dg/modules/access-1_a.C w/gcc/testsuite/g++.dg/modules/access-1_a.C
new file mode 100644
index 00000000000..241701728a2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/access-1_b.C w/gcc/testsuite/g++.dg/modules/access-1_b.C
new file mode 100644
index 00000000000..454dea5332f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/access-1_c.C w/gcc/testsuite/g++.dg/modules/access-1_c.C
new file mode 100644
index 00000000000..27b84c2ce1c
--- /dev/null
+++ w/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<Base *> (d)->m = 1; //ok
+}
diff --git c/gcc/testsuite/g++.dg/modules/adhoc-1_a.C w/gcc/testsuite/g++.dg/modules/adhoc-1_a.C
new file mode 100644
index 00000000000..50067acbf13
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adhoc-1_b.C w/gcc/testsuite/g++.dg/modules/adhoc-1_b.C
new file mode 100644
index 00000000000..59907a01d20
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-1_a.C w/gcc/testsuite/g++.dg/modules/adl-1_a.C
new file mode 100644
index 00000000000..d4a53cb9cb2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-1_b.C w/gcc/testsuite/g++.dg/modules/adl-1_b.C
new file mode 100644
index 00000000000..6cf123e41fb
--- /dev/null
+++ w/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 <typename T>
+int TPL (T &t)
+{
+  return fn (t);
+}
diff --git c/gcc/testsuite/g++.dg/modules/adl-1_c.C w/gcc/testsuite/g++.dg/modules/adl-1_c.C
new file mode 100644
index 00000000000..8be02e74937
--- /dev/null
+++ w/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<details::X>(T&)
+    return 1;
+
+  // hidden::fn@inter is visible from TPL@inter
+  if (TPL (y) != -2) // instantiate TPL<hidden::Y>(T&)
+    return 2;
+
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/adl-2_a.C w/gcc/testsuite/g++.dg/modules/adl-2_a.C
new file mode 100644
index 00000000000..d8f481cad97
--- /dev/null
+++ w/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 <typename T>
+int TPL (T const &t)
+{
+  return frob (t);
+}
diff --git c/gcc/testsuite/g++.dg/modules/adl-2_b.C w/gcc/testsuite/g++.dg/modules/adl-2_b.C
new file mode 100644
index 00000000000..60e794343ce
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-2_c.C w/gcc/testsuite/g++.dg/modules/adl-2_c.C
new file mode 100644
index 00000000000..9c75b6d14a7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-3_a.C w/gcc/testsuite/g++.dg/modules/adl-3_a.C
new file mode 100644
index 00000000000..a2639789438
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-3_b.C w/gcc/testsuite/g++.dg/modules/adl-3_b.C
new file mode 100644
index 00000000000..1f3011fdbb9
--- /dev/null
+++ w/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 <typename T>
+int TPL (T &t)
+{
+  return fn (t);
+}
diff --git c/gcc/testsuite/g++.dg/modules/adl-3_c.C w/gcc/testsuite/g++.dg/modules/adl-3_c.C
new file mode 100644
index 00000000000..c4dc0adc00c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-4_a.C w/gcc/testsuite/g++.dg/modules/adl-4_a.C
new file mode 100644
index 00000000000..5d956c057e2
--- /dev/null
+++ w/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 <typename T>
+int TPL (T &t)
+{
+  return fn (t);
+}
diff --git c/gcc/testsuite/g++.dg/modules/adl-4_b.C w/gcc/testsuite/g++.dg/modules/adl-4_b.C
new file mode 100644
index 00000000000..aa1396f7ce2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-5_a.c w/gcc/testsuite/g++.dg/modules/adl-5_a.c
new file mode 100644
index 00000000000..5b8692211d4
--- /dev/null
+++ w/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 <typename T>
+int TPL (T const &t)
+{
+  return frob (t);
+}
diff --git c/gcc/testsuite/g++.dg/modules/adl-5_b.C w/gcc/testsuite/g++.dg/modules/adl-5_b.C
new file mode 100644
index 00000000000..3c64cd4a75e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-5_c.C w/gcc/testsuite/g++.dg/modules/adl-5_c.C
new file mode 100644
index 00000000000..e047aec4b1a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/adl-5_d.C w/gcc/testsuite/g++.dg/modules/adl-5_d.C
new file mode 100644
index 00000000000..9c75b6d14a7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/alias-1_a.H w/gcc/testsuite/g++.dg/modules/alias-1_a.H
new file mode 100644
index 00000000000..8c5683608ad
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/alias-1_b.C w/gcc/testsuite/g++.dg/modules/alias-1_b.C
new file mode 100644
index 00000000000..b3d7c2df353
--- /dev/null
+++ w/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 <alias-1_a.H>;
+
+int main ()
+{
+  frob ();
+}
+
+// { dg-final { scan-lang-dump-times {CMI is } 1 module } }
diff --git c/gcc/testsuite/g++.dg/modules/alias-1_c.C w/gcc/testsuite/g++.dg/modules/alias-1_c.C
new file mode 100644
index 00000000000..6f9f1aa06c0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/alias-1_d.C w/gcc/testsuite/g++.dg/modules/alias-1_d.C
new file mode 100644
index 00000000000..9b481e5b185
--- /dev/null
+++ w/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 <alias-1_a.H>;
diff --git c/gcc/testsuite/g++.dg/modules/alias-1_e.C w/gcc/testsuite/g++.dg/modules/alias-1_e.C
new file mode 100644
index 00000000000..862ae32882f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/alias-1_f.C w/gcc/testsuite/g++.dg/modules/alias-1_f.C
new file mode 100644
index 00000000000..4c694d1a903
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/alias-2_a.H w/gcc/testsuite/g++.dg/modules/alias-2_a.H
new file mode 100644
index 00000000000..1befe85cf49
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/alias-2_b.C w/gcc/testsuite/g++.dg/modules/alias-2_b.C
new file mode 100644
index 00000000000..00eff590e3b
--- /dev/null
+++ w/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 <alias-2_a.H>;
+
+int main ()
+{
+  frob ();
+  frob (1);
+}
+
+// { dg-final { scan-lang-dump-times {CMI is} 2 module } }
diff --git c/gcc/testsuite/g++.dg/modules/align-type-1_a.C w/gcc/testsuite/g++.dg/modules/align-type-1_a.C
new file mode 100644
index 00000000000..71240341469
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/align-type-1_b.C w/gcc/testsuite/g++.dg/modules/align-type-1_b.C
new file mode 100644
index 00000000000..8372e6f3e1b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/ambig-1_a.C w/gcc/testsuite/g++.dg/modules/ambig-1_a.C
new file mode 100644
index 00000000000..fbb3db2ac47
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/ambig-1_b.C w/gcc/testsuite/g++.dg/modules/ambig-1_b.C
new file mode 100644
index 00000000000..c1de9192323
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/anon-1_a.C w/gcc/testsuite/g++.dg/modules/anon-1_a.C
new file mode 100644
index 00000000000..e56b85ce720
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/anon-1_b.C w/gcc/testsuite/g++.dg/modules/anon-1_b.C
new file mode 100644
index 00000000000..66d25053049
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/anon-1_c.C w/gcc/testsuite/g++.dg/modules/anon-1_c.C
new file mode 100644
index 00000000000..cbe89e15ed9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/anon-2.h w/gcc/testsuite/g++.dg/modules/anon-2.h
new file mode 100644
index 00000000000..81c793c7ffc
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/anon-2.h
@@ -0,0 +1,6 @@
+
+
+struct __pthread_cond_s
+{
+  union {};
+};
diff --git c/gcc/testsuite/g++.dg/modules/anon-2_a.H w/gcc/testsuite/g++.dg/modules/anon-2_a.H
new file mode 100644
index 00000000000..6861c194fce
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/anon-2_b.C w/gcc/testsuite/g++.dg/modules/anon-2_b.C
new file mode 100644
index 00000000000..24bb61b5f14
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-decl-0_a.C w/gcc/testsuite/g++.dg/modules/atom-decl-0_a.C
new file mode 100644
index 00000000000..d226f32cea1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-decl-0_b.C w/gcc/testsuite/g++.dg/modules/atom-decl-0_b.C
new file mode 100644
index 00000000000..8ca006d64ee
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-decl-0_c.C w/gcc/testsuite/g++.dg/modules/atom-decl-0_c.C
new file mode 100644
index 00000000000..96e74956e90
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-decl-2.C w/gcc/testsuite/g++.dg/modules/atom-decl-2.C
new file mode 100644
index 00000000000..b463dc8e214
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-decl-3.C w/gcc/testsuite/g++.dg/modules/atom-decl-3.C
new file mode 100644
index 00000000000..6eb6e6bd93f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-pragma-1.C w/gcc/testsuite/g++.dg/modules/atom-pragma-1.C
new file mode 100644
index 00000000000..133382e8886
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-pragma-3.C w/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
new file mode 100644
index 00000000000..b95b2c8ad75
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-1.C w/gcc/testsuite/g++.dg/modules/atom-preamble-1.C
new file mode 100644
index 00000000000..1161d41b561
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C w/gcc/testsuite/g++.dg/modules/atom-preamble-2_a.C
new file mode 100644
index 00000000000..02fbd84afff
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-2_b.C w/gcc/testsuite/g++.dg/modules/atom-preamble-2_b.C
new file mode 100644
index 00000000000..a97d9758fd2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-2_c.C w/gcc/testsuite/g++.dg/modules/atom-preamble-2_c.C
new file mode 100644
index 00000000000..d3804c2b0bc
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C w/gcc/testsuite/g++.dg/modules/atom-preamble-2_d.C
new file mode 100644
index 00000000000..0c3b290499a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-2_e.C w/gcc/testsuite/g++.dg/modules/atom-preamble-2_e.C
new file mode 100644
index 00000000000..074f8ebadb4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C w/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C
new file mode 100644
index 00000000000..28e54b808b2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-3.C w/gcc/testsuite/g++.dg/modules/atom-preamble-3.C
new file mode 100644
index 00000000000..74dba7d23a6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/atom-preamble-4.C w/gcc/testsuite/g++.dg/modules/atom-preamble-4.C
new file mode 100644
index 00000000000..21a8d57da65
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/auto-1.h w/gcc/testsuite/g++.dg/modules/auto-1.h
new file mode 100644
index 00000000000..f8ae751df32
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/auto-1.h
@@ -0,0 +1,19 @@
+
+template <typename T> auto frob (T t)
+{
+  return t;
+}
+
+struct Bob 
+{
+  operator auto () 
+  {
+    return 0;
+  }
+};
+
+inline auto foo ()
+{
+  return frob (1) + int (Bob ());
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/auto-1_a.H w/gcc/testsuite/g++.dg/modules/auto-1_a.H
new file mode 100644
index 00000000000..4d3bc77dbb1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/auto-1_b.C w/gcc/testsuite/g++.dg/modules/auto-1_b.C
new file mode 100644
index 00000000000..96350662fed
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/auto-2.h w/gcc/testsuite/g++.dg/modules/auto-2.h
new file mode 100644
index 00000000000..4759ab8bbc1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/auto-2.h
@@ -0,0 +1,13 @@
+
+template<typename _Callable>
+struct _RangeAdaptor
+{
+  constexpr _RangeAdaptor(const _Callable &) { }
+};
+
+template<typename _Callable>
+_RangeAdaptor(_Callable) -> _RangeAdaptor<_Callable>;
+
+template<unsigned _Nm>
+inline constexpr _RangeAdaptor elements = [] (auto&& __r) {};
+
diff --git c/gcc/testsuite/g++.dg/modules/auto-2_a.H w/gcc/testsuite/g++.dg/modules/auto-2_a.H
new file mode 100644
index 00000000000..46bd74697a5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/auto-2_b.C w/gcc/testsuite/g++.dg/modules/auto-2_b.C
new file mode 100644
index 00000000000..5ed882f7416
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bad-mapper-1.C w/gcc/testsuite/g++.dg/modules/bad-mapper-1.C
new file mode 100644
index 00000000000..7ed75b824b4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bad-mapper-2.C w/gcc/testsuite/g++.dg/modules/bad-mapper-2.C
new file mode 100644
index 00000000000..f35d16bace3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bad-mapper-3.C w/gcc/testsuite/g++.dg/modules/bad-mapper-3.C
new file mode 100644
index 00000000000..9dab332ccb2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/ben-1.map w/gcc/testsuite/g++.dg/modules/ben-1.map
new file mode 100644
index 00000000000..182183ad089
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ben-1.map
@@ -0,0 +1,3 @@
+$root .
+module:import partitions/module:import.mod
+module module.mod
diff --git c/gcc/testsuite/g++.dg/modules/ben-1_a.C w/gcc/testsuite/g++.dg/modules/ben-1_a.C
new file mode 100644
index 00000000000..7e9b5661026
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/ben-1_b.C w/gcc/testsuite/g++.dg/modules/ben-1_b.C
new file mode 100644
index 00000000000..e16fa2fc857
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bfield-1_a.C w/gcc/testsuite/g++.dg/modules/bfield-1_a.C
new file mode 100644
index 00000000000..15b8cb6c54a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bfield-1_b.C w/gcc/testsuite/g++.dg/modules/bfield-1_b.C
new file mode 100644
index 00000000000..6c8dae6e29e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bfield-2_a.C w/gcc/testsuite/g++.dg/modules/bfield-2_a.C
new file mode 100644
index 00000000000..5329e62da3d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bfield-2_b.C w/gcc/testsuite/g++.dg/modules/bfield-2_b.C
new file mode 100644
index 00000000000..737173697c7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bool-1.h w/gcc/testsuite/g++.dg/modules/bool-1.h
new file mode 100644
index 00000000000..80f0ec161cc
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bool-1_a.H w/gcc/testsuite/g++.dg/modules/bool-1_a.H
new file mode 100644
index 00000000000..3b4232c1d08
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bool-1_b.H w/gcc/testsuite/g++.dg/modules/bool-1_b.H
new file mode 100644
index 00000000000..d22e1d93286
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bool-1_c.C w/gcc/testsuite/g++.dg/modules/bool-1_c.C
new file mode 100644
index 00000000000..01b08775191
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bug-1_a.C w/gcc/testsuite/g++.dg/modules/bug-1_a.C
new file mode 100644
index 00000000000..b828b7b8bc6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/bug-1_b.C w/gcc/testsuite/g++.dg/modules/bug-1_b.C
new file mode 100644
index 00000000000..7b5baeb9276
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-1_a.C w/gcc/testsuite/g++.dg/modules/builtin-1_a.C
new file mode 100644
index 00000000000..6d0731a727d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-1_b.C w/gcc/testsuite/g++.dg/modules/builtin-1_b.C
new file mode 100644
index 00000000000..e9f73485661
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-2.C w/gcc/testsuite/g++.dg/modules/builtin-2.C
new file mode 100644
index 00000000000..f9de98fda9b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-3_b.C w/gcc/testsuite/g++.dg/modules/builtin-3_b.C
new file mode 100644
index 00000000000..93489bddba4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-4_a.H w/gcc/testsuite/g++.dg/modules/builtin-4_a.H
new file mode 100644
index 00000000000..f7bc6aff639
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-4_b.C w/gcc/testsuite/g++.dg/modules/builtin-4_b.C
new file mode 100644
index 00000000000..1d780e6a80f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-5_a.H w/gcc/testsuite/g++.dg/modules/builtin-5_a.H
new file mode 100644
index 00000000000..735d32388d2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-5_b.C w/gcc/testsuite/g++.dg/modules/builtin-5_b.C
new file mode 100644
index 00000000000..bfaa64f9b55
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-6_a.H w/gcc/testsuite/g++.dg/modules/builtin-6_a.H
new file mode 100644
index 00000000000..b3263bc9ba7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-6_b.C w/gcc/testsuite/g++.dg/modules/builtin-6_b.C
new file mode 100644
index 00000000000..80f8dc64a20
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-7_a.H w/gcc/testsuite/g++.dg/modules/builtin-7_a.H
new file mode 100644
index 00000000000..a98a7b71092
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/builtin-7_b.C w/gcc/testsuite/g++.dg/modules/builtin-7_b.C
new file mode 100644
index 00000000000..28514571ce6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/by-name-1.C w/gcc/testsuite/g++.dg/modules/by-name-1.C
new file mode 100644
index 00000000000..44eb4478d13
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cexpr-1_a.C w/gcc/testsuite/g++.dg/modules/cexpr-1_a.C
new file mode 100644
index 00000000000..b9c4b1692f0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cexpr-1_b.C w/gcc/testsuite/g++.dg/modules/cexpr-1_b.C
new file mode 100644
index 00000000000..30566110e02
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cexpr-2_a.C w/gcc/testsuite/g++.dg/modules/cexpr-2_a.C
new file mode 100644
index 00000000000..632a4e3a485
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cexpr-2_b.C w/gcc/testsuite/g++.dg/modules/cexpr-2_b.C
new file mode 100644
index 00000000000..6a589aeb235
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/circ-1_a.C w/gcc/testsuite/g++.dg/modules/circ-1_a.C
new file mode 100644
index 00000000000..fa56c78b703
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/circ-1_b.C w/gcc/testsuite/g++.dg/modules/circ-1_b.C
new file mode 100644
index 00000000000..9174c1553ab
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/circ-1_c.C w/gcc/testsuite/g++.dg/modules/circ-1_c.C
new file mode 100644
index 00000000000..cea17d7a2e0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/circ-1_d.C w/gcc/testsuite/g++.dg/modules/circ-1_d.C
new file mode 100644
index 00000000000..b6f6b7ddd32
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-1_a.C w/gcc/testsuite/g++.dg/modules/class-1_a.C
new file mode 100644
index 00000000000..6463719cae2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-1_b.C w/gcc/testsuite/g++.dg/modules/class-1_b.C
new file mode 100644
index 00000000000..5eac51da073
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-1_c.C w/gcc/testsuite/g++.dg/modules/class-1_c.C
new file mode 100644
index 00000000000..8e23c4f2db6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-2_a.C w/gcc/testsuite/g++.dg/modules/class-2_a.C
new file mode 100644
index 00000000000..04f11cd8c8f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-2_b.C w/gcc/testsuite/g++.dg/modules/class-2_b.C
new file mode 100644
index 00000000000..0f8edb87095
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-3_a.C w/gcc/testsuite/g++.dg/modules/class-3_a.C
new file mode 100644
index 00000000000..c775f7b589c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-3_b.C w/gcc/testsuite/g++.dg/modules/class-3_b.C
new file mode 100644
index 00000000000..0e07e888753
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-3_c.C w/gcc/testsuite/g++.dg/modules/class-3_c.C
new file mode 100644
index 00000000000..6b82d1e7ffb
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-3_d.C w/gcc/testsuite/g++.dg/modules/class-3_d.C
new file mode 100644
index 00000000000..0710941d5ed
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-4_a.C w/gcc/testsuite/g++.dg/modules/class-4_a.C
new file mode 100644
index 00000000000..a9810ab3360
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-4_b.C w/gcc/testsuite/g++.dg/modules/class-4_b.C
new file mode 100644
index 00000000000..1cd39984052
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-5_a.C w/gcc/testsuite/g++.dg/modules/class-5_a.C
new file mode 100644
index 00000000000..417cb6b115c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-5_b.C w/gcc/testsuite/g++.dg/modules/class-5_b.C
new file mode 100644
index 00000000000..89db01c3be7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-5_c.C w/gcc/testsuite/g++.dg/modules/class-5_c.C
new file mode 100644
index 00000000000..ee3250d7bed
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-6_a.C w/gcc/testsuite/g++.dg/modules/class-6_a.C
new file mode 100644
index 00000000000..9c117c944b8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-6_b.C w/gcc/testsuite/g++.dg/modules/class-6_b.C
new file mode 100644
index 00000000000..1a49ced4b1c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-6_c.C w/gcc/testsuite/g++.dg/modules/class-6_c.C
new file mode 100644
index 00000000000..4d3abf92697
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-7_a.C w/gcc/testsuite/g++.dg/modules/class-7_a.C
new file mode 100644
index 00000000000..20fd54bb8d5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-7_b.C w/gcc/testsuite/g++.dg/modules/class-7_b.C
new file mode 100644
index 00000000000..3ed936f0a49
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-7_c.C w/gcc/testsuite/g++.dg/modules/class-7_c.C
new file mode 100644
index 00000000000..d1f2f56cb93
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-8_a.C w/gcc/testsuite/g++.dg/modules/class-8_a.C
new file mode 100644
index 00000000000..53caa5c780d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/class-8_b.C w/gcc/testsuite/g++.dg/modules/class-8_b.C
new file mode 100644
index 00000000000..0bb01ac6a33
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/clone-1_a.C w/gcc/testsuite/g++.dg/modules/clone-1_a.C
new file mode 100644
index 00000000000..43c4bbd8d31
--- /dev/null
+++ w/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<typename _CharT >
+struct basic_string
+{
+  template<typename = unsigned> basic_string();
+};
+
+inline basic_string<char>
+to_string ()
+{
+  basic_string<char> __str;
+
+  return __str;
+}
diff --git c/gcc/testsuite/g++.dg/modules/clone-1_b.C w/gcc/testsuite/g++.dg/modules/clone-1_b.C
new file mode 100644
index 00000000000..a013b9bdf28
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/concept-1_a.C w/gcc/testsuite/g++.dg/modules/concept-1_a.C
new file mode 100644
index 00000000000..1b4d83108cd
--- /dev/null
+++ w/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<typename T>
+requires (!!sizeof (bool (T{})))
+T f1 (T x)
+{ return x; }
+
diff --git c/gcc/testsuite/g++.dg/modules/concept-1_b.C w/gcc/testsuite/g++.dg/modules/concept-1_b.C
new file mode 100644
index 00000000000..d6542e6dc73
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/concept-2_a.C w/gcc/testsuite/g++.dg/modules/concept-2_a.C
new file mode 100644
index 00000000000..b1d477def38
--- /dev/null
+++ w/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<typename T>
+requires (sizeof (T) == 1)
+  char f1 (T x) { return 0; }
+
+export template<typename T>
+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 c/gcc/testsuite/g++.dg/modules/concept-2_b.C w/gcc/testsuite/g++.dg/modules/concept-2_b.C
new file mode 100644
index 00000000000..af0ab3ad88e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/concept-3_a.C w/gcc/testsuite/g++.dg/modules/concept-3_a.C
new file mode 100644
index 00000000000..36fc0861428
--- /dev/null
+++ w/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<typename _Tp>
+concept Addable = requires(_Tp& __t)
+  {
+    __t + __t;
+  };
+}
diff --git c/gcc/testsuite/g++.dg/modules/concept-3_b.C w/gcc/testsuite/g++.dg/modules/concept-3_b.C
new file mode 100644
index 00000000000..46bfe039956
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/concept-3_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -std=c++2a" }
+
+import foo;
+
+template <foo::Addable T> 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 c/gcc/testsuite/g++.dg/modules/concept-4.H w/gcc/testsuite/g++.dg/modules/concept-4.H
new file mode 100644
index 00000000000..66d12017a7c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/concept-4.H
@@ -0,0 +1,18 @@
+// { dg-additional-options "-std=c++2a -fmodule-header" }
+// { dg-module-cmi {} }
+
+template<typename T>
+inline constexpr bool disable = false;
+
+template<typename U>
+concept sized = true;
+
+template<typename V>
+class TPL
+{
+};
+
+template<typename W>
+requires (!sized<W>)
+inline constexpr bool disable<TPL<W>>
+= true;
diff --git c/gcc/testsuite/g++.dg/modules/concept-5.h w/gcc/testsuite/g++.dg/modules/concept-5.h
new file mode 100644
index 00000000000..1b049f5f1be
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/concept-5.h
@@ -0,0 +1,7 @@
+template<typename T>
+requires (sizeof (T) == 1)
+constexpr int f1 (T x) { return 1; }
+
+template<typename T>
+requires (sizeof (T) != 1)
+constexpr int f1 (T x) { return 0; }
diff --git c/gcc/testsuite/g++.dg/modules/concept-5_a.H w/gcc/testsuite/g++.dg/modules/concept-5_a.H
new file mode 100644
index 00000000000..f38febea861
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/concept-5_b.C w/gcc/testsuite/g++.dg/modules/concept-5_b.C
new file mode 100644
index 00000000000..6a196d8088d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/concept-6.h w/gcc/testsuite/g++.dg/modules/concept-6.h
new file mode 100644
index 00000000000..0e98c98727a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/concept-6.h
@@ -0,0 +1,19 @@
+
+template<typename _Callable>
+struct Base
+{
+  Base (const _Callable &)
+    requires true
+  {}
+};
+
+template<typename _Callable>
+struct Derived :  Base<_Callable>
+{
+  using Base<_Callable>::Base;
+};
+
+template<typename _Callable>
+Derived (_Callable) -> Derived<_Callable>;
+
+inline Derived all = [] (auto&& __r) {};
diff --git c/gcc/testsuite/g++.dg/modules/concept-6_a.H w/gcc/testsuite/g++.dg/modules/concept-6_a.H
new file mode 100644
index 00000000000..e677531c5f0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/concept-6_b.C w/gcc/testsuite/g++.dg/modules/concept-6_b.C
new file mode 100644
index 00000000000..4c2058d8993
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/constrained-partial-1_a.C w/gcc/testsuite/g++.dg/modules/constrained-partial-1_a.C
new file mode 100644
index 00000000000..5a5482efc45
--- /dev/null
+++ w/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 <typename T0>
+struct traits
+{
+  static constexpr int variant = 0;
+};
+
+// #2
+template <typename T2>
+requires requires { typename T2::element_type; }
+struct traits<T2 *>
+{
+  using type = typename T2::element_type;
+  static constexpr int variant = 2;
+};
+
+
+// #1
+template <typename T1>
+struct traits<T1 *>
+{
+  using type = T1;
+  static constexpr int variant = 1;
+};
+
+
+// #3
+template <typename T3>
+requires requires { typename T3::value_type; }
+struct traits<T3 *>
+{
+  using type = typename T3::value_type;
+  static constexpr int variant = 3;
+};
diff --git c/gcc/testsuite/g++.dg/modules/constrained-partial-1_b.C w/gcc/testsuite/g++.dg/modules/constrained-partial-1_b.C
new file mode 100644
index 00000000000..bbbbab54c0e
--- /dev/null
+++ w/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<Variant0>;
+  using v1 = traits<Variant0 *>;
+  using v2 = traits<Variant2 *>;
+  using v3 = traits<Variant3 *>;
+
+  static_assert (v0::variant == 0);
+  static_assert (v1::variant == 1);
+  static_assert (v2::variant == 2);
+  static_assert (v3::variant == 3);
+}
diff --git c/gcc/testsuite/g++.dg/modules/convop-1_a.C w/gcc/testsuite/g++.dg/modules/convop-1_a.C
new file mode 100644
index 00000000000..d0edec85c28
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/convop-1_b.C w/gcc/testsuite/g++.dg/modules/convop-1_b.C
new file mode 100644
index 00000000000..65350eee208
--- /dev/null
+++ w/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<int> (a))
+    return 1;
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/cpp-1.C w/gcc/testsuite/g++.dg/modules/cpp-1.C
new file mode 100644
index 00000000000..2ad9637c8fb
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-2_a.H w/gcc/testsuite/g++.dg/modules/cpp-2_a.H
new file mode 100644
index 00000000000..391843fb654
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-2_b.H w/gcc/testsuite/g++.dg/modules/cpp-2_b.H
new file mode 100644
index 00000000000..34c138d407f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-2_c.C w/gcc/testsuite/g++.dg/modules/cpp-2_c.C
new file mode 100644
index 00000000000..c6e02b7800a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-3.C w/gcc/testsuite/g++.dg/modules/cpp-3.C
new file mode 100644
index 00000000000..3aa0c6ec5f6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-4.C w/gcc/testsuite/g++.dg/modules/cpp-4.C
new file mode 100644
index 00000000000..6c194312311
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-4.h w/gcc/testsuite/g++.dg/modules/cpp-4.h
new file mode 100644
index 00000000000..aec9547ed46
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-5_a.H w/gcc/testsuite/g++.dg/modules/cpp-5_a.H
new file mode 100644
index 00000000000..3941ee817c1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-5_b.C w/gcc/testsuite/g++.dg/modules/cpp-5_b.C
new file mode 100644
index 00000000000..504e792b9b2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-5_c.C w/gcc/testsuite/g++.dg/modules/cpp-5_c.C
new file mode 100644
index 00000000000..e0a78a516ae
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-6_a.H w/gcc/testsuite/g++.dg/modules/cpp-6_a.H
new file mode 100644
index 00000000000..0bb1f41629f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-6_b.H w/gcc/testsuite/g++.dg/modules/cpp-6_b.H
new file mode 100644
index 00000000000..2d5bcccffb0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/cpp-6_c.C w/gcc/testsuite/g++.dg/modules/cpp-6_c.C
new file mode 100644
index 00000000000..f9b1e2d68b7
--- /dev/null
+++ w/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 <cpp-6_a.H>;
+TWO bibity bobity
+import empty nop(<bibity>);
+THREE bibity bobity
+import empty <bobity.H>;
+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 c/gcc/testsuite/g++.dg/modules/debug-1_a.C w/gcc/testsuite/g++.dg/modules/debug-1_a.C
new file mode 100644
index 00000000000..b0f1763bb98
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/debug-1_b.C w/gcc/testsuite/g++.dg/modules/debug-1_b.C
new file mode 100644
index 00000000000..7fca87b6aeb
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/decomp-1_a.C w/gcc/testsuite/g++.dg/modules/decomp-1_a.C
new file mode 100644
index 00000000000..07506c9956f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/decomp-1_b.C w/gcc/testsuite/g++.dg/modules/decomp-1_b.C
new file mode 100644
index 00000000000..709c333fd58
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/deferred-1.h w/gcc/testsuite/g++.dg/modules/deferred-1.h
new file mode 100644
index 00000000000..dc0fd782a80
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/deferred-1.h
@@ -0,0 +1,12 @@
+template<bool _Const>
+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 c/gcc/testsuite/g++.dg/modules/deferred-1_a.H w/gcc/testsuite/g++.dg/modules/deferred-1_a.H
new file mode 100644
index 00000000000..88e6fab6a3a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/deferred-1_b.C w/gcc/testsuite/g++.dg/modules/deferred-1_b.C
new file mode 100644
index 00000000000..5f75aec0a24
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/dep-1_a.C w/gcc/testsuite/g++.dg/modules/dep-1_a.C
new file mode 100644
index 00000000000..766f4368ee6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/dep-1_b.C w/gcc/testsuite/g++.dg/modules/dep-1_b.C
new file mode 100644
index 00000000000..138832f709e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/dep-2.C w/gcc/testsuite/g++.dg/modules/dep-2.C
new file mode 100644
index 00000000000..5e112c62350
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/dep-3.C w/gcc/testsuite/g++.dg/modules/dep-3.C
new file mode 100644
index 00000000000..f0f883e86e3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/dir-only-1.C w/gcc/testsuite/g++.dg/modules/dir-only-1.C
new file mode 100644
index 00000000000..d035b5f3def
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/dir-only-2_a.H w/gcc/testsuite/g++.dg/modules/dir-only-2_a.H
new file mode 100644
index 00000000000..3ed0de5d7b1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/dir-only-2_b.C w/gcc/testsuite/g++.dg/modules/dir-only-2_b.C
new file mode 100644
index 00000000000..0691f76ae36
--- /dev/null
+++ w/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 <dir-only-2_a.H>;
+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 c/gcc/testsuite/g++.dg/modules/dir-only-3.C w/gcc/testsuite/g++.dg/modules/dir-only-3.C
new file mode 100644
index 00000000000..6e3af8da45d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/dir-only-3.C
@@ -0,0 +1,18 @@
+# 0 "dir-only-3.C"
+# 1 "<built-in>"
+# 1 "<command-line>"
+# 31 "<command-line>"
+# 1 "/usr/include/stdc-predef.h" 1 3 4
+
+# 32 "<command-line>" 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 c/gcc/testsuite/g++.dg/modules/dir-only-4.C w/gcc/testsuite/g++.dg/modules/dir-only-4.C
new file mode 100644
index 00000000000..80d6461e81f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/dir-recovery.C w/gcc/testsuite/g++.dg/modules/dir-recovery.C
new file mode 100644
index 00000000000..90794b96882
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-1_a.C w/gcc/testsuite/g++.dg/modules/enum-1_a.C
new file mode 100644
index 00000000000..53e2ac88f20
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-1_b.C w/gcc/testsuite/g++.dg/modules/enum-1_b.C
new file mode 100644
index 00000000000..4b8c647e1b6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-2_a.C w/gcc/testsuite/g++.dg/modules/enum-2_a.C
new file mode 100644
index 00000000000..9e5e42a3b2e
--- /dev/null
+++ w/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 <int I> struct TPL
+{
+  enum p
+  {
+    u,
+    v = I
+  };
+};
diff --git c/gcc/testsuite/g++.dg/modules/enum-2_b.C w/gcc/testsuite/g++.dg/modules/enum-2_b.C
new file mode 100644
index 00000000000..4e0aed48806
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-3_a.C w/gcc/testsuite/g++.dg/modules/enum-3_a.C
new file mode 100644
index 00000000000..514bdd012ae
--- /dev/null
+++ w/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 <typename T> struct s0 {
+  enum t { a };
+};
+}
diff --git c/gcc/testsuite/g++.dg/modules/enum-3_b.C w/gcc/testsuite/g++.dg/modules/enum-3_b.C
new file mode 100644
index 00000000000..073611ca559
--- /dev/null
+++ w/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<int>::a);
diff --git c/gcc/testsuite/g++.dg/modules/enum-4_a.C w/gcc/testsuite/g++.dg/modules/enum-4_a.C
new file mode 100644
index 00000000000..96880b469cd
--- /dev/null
+++ w/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 <typename T, typename U>
+struct same
+{
+  enum { value = 0 };
+};
+
+template<typename T>
+struct same <T, T>
+{
+  enum { value = 1 };
+};
+
diff --git c/gcc/testsuite/g++.dg/modules/enum-4_b.C w/gcc/testsuite/g++.dg/modules/enum-4_b.C
new file mode 100644
index 00000000000..0f88fa1ddd2
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/enum-4_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+import bob;
+
+static_assert (same<int, float>::value == 0);
+static_assert (same<int *, int *>::value == 1);
diff --git c/gcc/testsuite/g++.dg/modules/enum-5_a.H w/gcc/testsuite/g++.dg/modules/enum-5_a.H
new file mode 100644
index 00000000000..1f2e84faad1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-5_b.C w/gcc/testsuite/g++.dg/modules/enum-5_b.C
new file mode 100644
index 00000000000..385c1d35c85
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-6_a.H w/gcc/testsuite/g++.dg/modules/enum-6_a.H
new file mode 100644
index 00000000000..066904686bf
--- /dev/null
+++ w/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<typename T> T getter ()
+{
+  return _S_chunk_size;
+}
diff --git c/gcc/testsuite/g++.dg/modules/enum-6_b.C w/gcc/testsuite/g++.dg/modules/enum-6_b.C
new file mode 100644
index 00000000000..04c1ee28b5f
--- /dev/null
+++ w/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<int> () == 7);
+}
diff --git c/gcc/testsuite/g++.dg/modules/enum-7.C w/gcc/testsuite/g++.dg/modules/enum-7.C
new file mode 100644
index 00000000000..8cf31a9f804
--- /dev/null
+++ w/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 <typename T> void adl (T) {}
+
+template <typename T>
+void frob (T arg)
+{
+  enum class case_conv {none};
+
+  case_conv x = case_conv::none;
+
+  adl (x);
+}
+
+void foo ()
+{
+  frob (1);
+}
diff --git c/gcc/testsuite/g++.dg/modules/enum-8_a.H w/gcc/testsuite/g++.dg/modules/enum-8_a.H
new file mode 100644
index 00000000000..90ccb914341
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/enum-8_a.H
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodule-header }
+
+enum : char
+{
+  Foo = 1,
+};
diff --git c/gcc/testsuite/g++.dg/modules/enum-8_b.H w/gcc/testsuite/g++.dg/modules/enum-8_b.H
new file mode 100644
index 00000000000..021ad173fbd
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/enum-8_b.H
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodule-header }
+
+enum : int
+{
+  Foo = 2,
+};
diff --git c/gcc/testsuite/g++.dg/modules/enum-8_c.C w/gcc/testsuite/g++.dg/modules/enum-8_c.C
new file mode 100644
index 00000000000..d14469b533a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-8_d.C w/gcc/testsuite/g++.dg/modules/enum-8_d.C
new file mode 100644
index 00000000000..665077325de
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-bad-1_a.H w/gcc/testsuite/g++.dg/modules/enum-bad-1_a.H
new file mode 100644
index 00000000000..2d8a7baf451
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C w/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C
new file mode 100644
index 00000000000..b01cd66a14d
--- /dev/null
+++ w/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<unnamed>' does not match\n[^\n]*enum-bad-1_b.C:4:6: note: existing definition 'enum<unnamed>'\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 c/gcc/testsuite/g++.dg/modules/err-1_a.C w/gcc/testsuite/g++.dg/modules/err-1_a.C
new file mode 100644
index 00000000000..1f7ddecc6ad
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/err-1_b.C w/gcc/testsuite/g++.dg/modules/err-1_b.C
new file mode 100644
index 00000000000..6d5609c11d6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/err-1_c.C w/gcc/testsuite/g++.dg/modules/err-1_c.C
new file mode 100644
index 00000000000..3a93cc6d18b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/err-1_d.C w/gcc/testsuite/g++.dg/modules/err-1_d.C
new file mode 100644
index 00000000000..eb6b4ba7c99
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/except-1.C w/gcc/testsuite/g++.dg/modules/except-1.C
new file mode 100644
index 00000000000..6135c8feb7a
--- /dev/null
+++ w/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<typename T>
+class bob 
+{
+  void frob () noexcept(T::frob ());
+  template<typename U> void frobber (int) noexcept (T::frob ());
+};
+
+
+class bill 
+{
+  template<typename U> void frobbest (int) noexcept (U::frob ());
+};
diff --git c/gcc/testsuite/g++.dg/modules/except-2.h w/gcc/testsuite/g++.dg/modules/except-2.h
new file mode 100644
index 00000000000..38355ec8b47
--- /dev/null
+++ w/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<typename _Tp, _Tp __v>
+struct integral_constant
+{
+  static constexpr _Tp value = __v;
+  typedef integral_constant<_Tp, __v> type;
+};
+template<typename _Tp, _Tp __v>
+constexpr _Tp integral_constant<_Tp, __v>::value;
+
+template<typename _Head>
+struct _Tuple_impl : _Head
+{
+  _Tuple_impl(_Tuple_impl&& __in)
+    noexcept (integral_constant<bool,
+	      noexcept(_Head(static_cast<_Head &&>(*(_Head *) (0))))>::type::value);
+};
+
+template <typename _Dp>
+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 <up &&>  (p));
+}
diff --git c/gcc/testsuite/g++.dg/modules/except-2_a.H w/gcc/testsuite/g++.dg/modules/except-2_a.H
new file mode 100644
index 00000000000..966169ceae0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/except-2_b.C w/gcc/testsuite/g++.dg/modules/except-2_b.C
new file mode 100644
index 00000000000..78ed8f8be9d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/except-3.h w/gcc/testsuite/g++.dg/modules/except-3.h
new file mode 100644
index 00000000000..8bf0f84d590
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/except-3.h
@@ -0,0 +1,24 @@
+
+template<typename _Tp>
+struct is_nothrow_move_constructible
+{
+  static constexpr bool value = false;
+};
+
+template<typename _Head>
+struct _Tuple_impl
+{
+  _Tuple_impl () noexcept(is_nothrow_move_constructible<_Head>::value)
+ { }
+};
+
+template<typename T>
+void TPL (_Tuple_impl<T> &) noexcept
+{
+  _Tuple_impl<T> m;
+}
+
+inline void foo (_Tuple_impl<int> &p)
+{
+  TPL<int> (p);
+}
diff --git c/gcc/testsuite/g++.dg/modules/except-3_a.H w/gcc/testsuite/g++.dg/modules/except-3_a.H
new file mode 100644
index 00000000000..2f9f00e6222
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/except-3_b.C w/gcc/testsuite/g++.dg/modules/except-3_b.C
new file mode 100644
index 00000000000..0cb84725b5a
--- /dev/null
+++ w/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<int>::__[cd]t '} 3 module } }
+// { dg-final { scan-lang-dump-times {Propagating instantiated noexcept to '::_Tuple_impl<int>::__ct <int>'} 1 module } }
diff --git c/gcc/testsuite/g++.dg/modules/exp-xlate-1_a.H w/gcc/testsuite/g++.dg/modules/exp-xlate-1_a.H
new file mode 100644
index 00000000000..2079f90c5b4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C w/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
new file mode 100644
index 00000000000..3295a6af050
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/export-1.C w/gcc/testsuite/g++.dg/modules/export-1.C
new file mode 100644
index 00000000000..8ca696ebee0
--- /dev/null
+++ w/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 <typename T> int f (T);
+export template <typename T> 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 c/gcc/testsuite/g++.dg/modules/extern-tpl-1_a.H w/gcc/testsuite/g++.dg/modules/extern-tpl-1_a.H
new file mode 100644
index 00000000000..93afc4eecfe
--- /dev/null
+++ w/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 <unsigned I> struct TPL
+{
+  int Source () 
+  {
+    return I;
+  }
+};
+
+extern template class TPL<1>;
+
+struct Foo 
+{
+  TPL<1> m;
+
+  Foo () {m.Source ();};
+  
+};
+
+static Foo __ioinit;
diff --git c/gcc/testsuite/g++.dg/modules/extern-tpl-1_b.C w/gcc/testsuite/g++.dg/modules/extern-tpl-1_b.C
new file mode 100644
index 00000000000..f3c0dc483c3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/extern-tpl-1_c.C w/gcc/testsuite/g++.dg/modules/extern-tpl-1_c.C
new file mode 100644
index 00000000000..d1b6cb6562f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/extern-tpl-2_a.H w/gcc/testsuite/g++.dg/modules/extern-tpl-2_a.H
new file mode 100644
index 00000000000..a90d50ec6f8
--- /dev/null
+++ w/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 <unsigned I> struct TPL
+{
+  int Source () 
+  {
+    return I;
+  }
+};
+
+extern template class TPL<1>;
diff --git c/gcc/testsuite/g++.dg/modules/extern-tpl-2_b.H w/gcc/testsuite/g++.dg/modules/extern-tpl-2_b.H
new file mode 100644
index 00000000000..5f9875c814a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/extern-tpl-2_c.C w/gcc/testsuite/g++.dg/modules/extern-tpl-2_c.C
new file mode 100644
index 00000000000..b73ec6e8cfc
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/extern-tpl-2_d.C w/gcc/testsuite/g++.dg/modules/extern-tpl-2_d.C
new file mode 100644
index 00000000000..25a977fb0ca
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/flag-1_a.C w/gcc/testsuite/g++.dg/modules/flag-1_a.C
new file mode 100644
index 00000000000..9f733203067
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/flag-1_b.C w/gcc/testsuite/g++.dg/modules/flag-1_b.C
new file mode 100644
index 00000000000..32bfd82f1a1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/fn-inline-1_a.C w/gcc/testsuite/g++.dg/modules/fn-inline-1_a.C
new file mode 100644
index 00000000000..13e717bb394
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/fn-inline-1_b.C w/gcc/testsuite/g++.dg/modules/fn-inline-1_b.C
new file mode 100644
index 00000000000..72de1a9a514
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C w/gcc/testsuite/g++.dg/modules/fn-inline-1_c.C
new file mode 100644
index 00000000000..55a7aaa26b4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/freeze-1_a.C w/gcc/testsuite/g++.dg/modules/freeze-1_a.C
new file mode 100644
index 00000000000..f05dd3da163
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/freeze-1_b.C w/gcc/testsuite/g++.dg/modules/freeze-1_b.C
new file mode 100644
index 00000000000..36d1323c2f3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/freeze-1_c.C w/gcc/testsuite/g++.dg/modules/freeze-1_c.C
new file mode 100644
index 00000000000..3941d30bb33
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/freeze-1_d.C w/gcc/testsuite/g++.dg/modules/freeze-1_d.C
new file mode 100644
index 00000000000..faeae148567
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-1_a.C w/gcc/testsuite/g++.dg/modules/friend-1_a.C
new file mode 100644
index 00000000000..2cfab400be7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-1_b.C w/gcc/testsuite/g++.dg/modules/friend-1_b.C
new file mode 100644
index 00000000000..380bbc54b91
--- /dev/null
+++ w/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 <secret *> (data)->key;
+}
+
+// { dg-final { scan-lang-dump {Class '::hidey@bob:.' befriending record_type:'::peeker@bob:.'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/friend-1_c.C w/gcc/testsuite/g++.dg/modules/friend-1_c.C
new file mode 100644
index 00000000000..2fb2988aa7f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-2_a.C w/gcc/testsuite/g++.dg/modules/friend-2_a.C
new file mode 100644
index 00000000000..ed329d42bb3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-2_b.C w/gcc/testsuite/g++.dg/modules/friend-2_b.C
new file mode 100644
index 00000000000..27034c709d5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-3.C w/gcc/testsuite/g++.dg/modules/friend-3.C
new file mode 100644
index 00000000000..48320eba46a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-4_a.C w/gcc/testsuite/g++.dg/modules/friend-4_a.C
new file mode 100644
index 00000000000..d9559c6577e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-4_b.C w/gcc/testsuite/g++.dg/modules/friend-4_b.C
new file mode 100644
index 00000000000..759dbb5c73b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-5_a.C w/gcc/testsuite/g++.dg/modules/friend-5_a.C
new file mode 100644
index 00000000000..4d005a876ec
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/friend-5_b.C w/gcc/testsuite/g++.dg/modules/friend-5_b.C
new file mode 100644
index 00000000000..f043d7a340d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gc-1_a.C w/gcc/testsuite/g++.dg/modules/gc-1_a.C
new file mode 100644
index 00000000000..5ee20c9e063
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gc-1_b.C w/gcc/testsuite/g++.dg/modules/gc-1_b.C
new file mode 100644
index 00000000000..d6ff09caaae
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gc-1_c.C w/gcc/testsuite/g++.dg/modules/gc-1_c.C
new file mode 100644
index 00000000000..289a9995e65
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gc-1_d.C w/gcc/testsuite/g++.dg/modules/gc-1_d.C
new file mode 100644
index 00000000000..a27e5d46603
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gc-2.map w/gcc/testsuite/g++.dg/modules/gc-2.map
new file mode 100644
index 00000000000..58963bdb32d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/gc-2.map
@@ -0,0 +1,2 @@
+$root .
+frob map-1_a.nms
diff --git c/gcc/testsuite/g++.dg/modules/gc-2_a.C w/gcc/testsuite/g++.dg/modules/gc-2_a.C
new file mode 100644
index 00000000000..a006fb394cb
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/global-1_a.C w/gcc/testsuite/g++.dg/modules/global-1_a.C
new file mode 100644
index 00000000000..68e18e35342
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/global-1_b.C w/gcc/testsuite/g++.dg/modules/global-1_b.C
new file mode 100644
index 00000000000..9a67fb17f20
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gmf-1_a.C w/gcc/testsuite/g++.dg/modules/gmf-1_a.C
new file mode 100644
index 00000000000..a340e3fd716
--- /dev/null
+++ w/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<typename T>
+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<char> const &name)
+{
+
+}
diff --git c/gcc/testsuite/g++.dg/modules/gmf-1_b.C w/gcc/testsuite/g++.dg/modules/gmf-1_b.C
new file mode 100644
index 00000000000..7162d2d1f11
--- /dev/null
+++ w/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<char>'} module } }
+// { dg-final { scan-lang-dump {Read declaration of '::greeter@hello:1'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/gmf-2_a.H w/gcc/testsuite/g++.dg/modules/gmf-2_a.H
new file mode 100644
index 00000000000..4318b166557
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gmf-2_b.C w/gcc/testsuite/g++.dg/modules/gmf-2_b.C
new file mode 100644
index 00000000000..15fafd6f78b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gmf-2_c.C w/gcc/testsuite/g++.dg/modules/gmf-2_c.C
new file mode 100644
index 00000000000..4b4acc650ea
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gmf-2_d.C w/gcc/testsuite/g++.dg/modules/gmf-2_d.C
new file mode 100644
index 00000000000..357c8e81404
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gvar_a.C w/gcc/testsuite/g++.dg/modules/gvar_a.C
new file mode 100644
index 00000000000..2855b33e250
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/gvar_b.C w/gcc/testsuite/g++.dg/modules/gvar_b.C
new file mode 100644
index 00000000000..e53e3f2d5c4
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/gvar_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+import b;
+
+int main ()
+{
+  get ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/hdr-1_a.H w/gcc/testsuite/g++.dg/modules/hdr-1_a.H
new file mode 100644
index 00000000000..4ce045b7153
--- /dev/null
+++ w/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<int I> 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 c/gcc/testsuite/g++.dg/modules/hdr-1_b.H w/gcc/testsuite/g++.dg/modules/hdr-1_b.H
new file mode 100644
index 00000000000..6817f938e1c
--- /dev/null
+++ w/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<int J>
+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 c/gcc/testsuite/g++.dg/modules/hdr-1_c.C w/gcc/testsuite/g++.dg/modules/hdr-1_c.C
new file mode 100644
index 00000000000..f8fa0934a58
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/hdr-init-1_a.H w/gcc/testsuite/g++.dg/modules/hdr-init-1_a.H
new file mode 100644
index 00000000000..25cbf3fc616
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/hdr-init-1_b.H w/gcc/testsuite/g++.dg/modules/hdr-init-1_b.H
new file mode 100644
index 00000000000..25cbf3fc616
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/hdr-init-1_c.C w/gcc/testsuite/g++.dg/modules/hdr-init-1_c.C
new file mode 100644
index 00000000000..efcc4854314
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/horcrux-1_a.C w/gcc/testsuite/g++.dg/modules/horcrux-1_a.C
new file mode 100644
index 00000000000..ff548d039ea
--- /dev/null
+++ w/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<typename _Tp, _Tp __v>
+struct integral_constant
+{};
+
+template<bool __v>
+using __bool_constant = integral_constant<bool, __v>;
+
+template<typename _Tp, typename... _Args>
+struct __is_constructible_impl
+  : public __bool_constant<__is_constructible(_Tp, _Args...)>
+{ };
+
diff --git c/gcc/testsuite/g++.dg/modules/horcrux-1_b.C w/gcc/testsuite/g++.dg/modules/horcrux-1_b.C
new file mode 100644
index 00000000000..842bf413585
--- /dev/null
+++ w/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<bool> x;
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/ice-1.C w/gcc/testsuite/g++.dg/modules/ice-1.C
new file mode 100644
index 00000000000..128734d31e6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-inline-1_a.C w/gcc/testsuite/g++.dg/modules/imp-inline-1_a.C
new file mode 100644
index 00000000000..56bbbdd0456
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-inline-1_b.C w/gcc/testsuite/g++.dg/modules/imp-inline-1_b.C
new file mode 100644
index 00000000000..c127f7005a3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-member-1_a.C w/gcc/testsuite/g++.dg/modules/imp-member-1_a.C
new file mode 100644
index 00000000000..4798ce5fb56
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-member-1_b.C w/gcc/testsuite/g++.dg/modules/imp-member-1_b.C
new file mode 100644
index 00000000000..849cf3c5be4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-member-1_c.C w/gcc/testsuite/g++.dg/modules/imp-member-1_c.C
new file mode 100644
index 00000000000..b354ca8cf98
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-member-1_d.C w/gcc/testsuite/g++.dg/modules/imp-member-1_d.C
new file mode 100644
index 00000000000..c7f3158c80d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-member-1_e.C w/gcc/testsuite/g++.dg/modules/imp-member-1_e.C
new file mode 100644
index 00000000000..b771850583f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-member-2_a.C w/gcc/testsuite/g++.dg/modules/imp-member-2_a.C
new file mode 100644
index 00000000000..8d4d8396975
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-member-2_b.C w/gcc/testsuite/g++.dg/modules/imp-member-2_b.C
new file mode 100644
index 00000000000..09795af0093
--- /dev/null
+++ w/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<C &&> (v.c)) {}
+  inline ~D () {}
+  inline D &operator= (D const &v) { c = v.c; return *this;}
+  inline D &operator= (D &&v) { c =static_cast<C &&> (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 c/gcc/testsuite/g++.dg/modules/imp-member-2_c.C w/gcc/testsuite/g++.dg/modules/imp-member-2_c.C
new file mode 100644
index 00000000000..bb6b5dee5d9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/imp-member-3.H w/gcc/testsuite/g++.dg/modules/imp-member-3.H
new file mode 100644
index 00000000000..d26b13ce0e2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/import-1_a.C w/gcc/testsuite/g++.dg/modules/import-1_a.C
new file mode 100644
index 00000000000..b42153cd08d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/import-1_b.C w/gcc/testsuite/g++.dg/modules/import-1_b.C
new file mode 100644
index 00000000000..ec15856805e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/import-1_c.C w/gcc/testsuite/g++.dg/modules/import-1_c.C
new file mode 100644
index 00000000000..b01aa5e9d2b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/import-1_d.C w/gcc/testsuite/g++.dg/modules/import-1_d.C
new file mode 100644
index 00000000000..45e63401f4a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/import-1_e.C w/gcc/testsuite/g++.dg/modules/import-1_e.C
new file mode 100644
index 00000000000..ae7cce2e4b9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/import-1_f.C w/gcc/testsuite/g++.dg/modules/import-1_f.C
new file mode 100644
index 00000000000..8dbe9c02dfb
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/import-1_g.C w/gcc/testsuite/g++.dg/modules/import-1_g.C
new file mode 100644
index 00000000000..556ba80c2c3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/import-2.C w/gcc/testsuite/g++.dg/modules/import-2.C
new file mode 100644
index 00000000000..86a14941a44
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/inc-xlate-1.map w/gcc/testsuite/g++.dg/modules/inc-xlate-1.map
new file mode 100644
index 00000000000..f2429bf3386
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/inc-xlate-1.map
@@ -0,0 +1,2 @@
+<stdarg.h>
+<stdio.h>
diff --git c/gcc/testsuite/g++.dg/modules/inc-xlate-1_a.H w/gcc/testsuite/g++.dg/modules/inc-xlate-1_a.H
new file mode 100644
index 00000000000..cd906a5b40c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/inc-xlate-1_b.H w/gcc/testsuite/g++.dg/modules/inc-xlate-1_b.H
new file mode 100644
index 00000000000..50b27efa7ef
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/inc-xlate-1_c.C w/gcc/testsuite/g++.dg/modules/inc-xlate-1_c.C
new file mode 100644
index 00000000000..e1247e645d0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C w/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C
new file mode 100644
index 00000000000..f33c464bee9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-1_a.C w/gcc/testsuite/g++.dg/modules/indirect-1_a.C
new file mode 100644
index 00000000000..f2417172fdc
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-1_b.C w/gcc/testsuite/g++.dg/modules/indirect-1_b.C
new file mode 100644
index 00000000000..c450fa9481c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-1_c.C w/gcc/testsuite/g++.dg/modules/indirect-1_c.C
new file mode 100644
index 00000000000..73d5974c846
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-2_a.C w/gcc/testsuite/g++.dg/modules/indirect-2_a.C
new file mode 100644
index 00000000000..20febb935b1
--- /dev/null
+++ w/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 I> int frob ()
+  {
+    return I;
+  }
+
+  export template<int I> class X
+  {
+    int i = I;
+
+  public:
+    operator int () const { return i; }
+  };
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/indirect-2_b.C w/gcc/testsuite/g++.dg/modules/indirect-2_b.C
new file mode 100644
index 00000000000..16e060a2210
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-2_c.C w/gcc/testsuite/g++.dg/modules/indirect-2_c.C
new file mode 100644
index 00000000000..a5cf44ba785
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-3_a.C w/gcc/testsuite/g++.dg/modules/indirect-3_a.C
new file mode 100644
index 00000000000..fad9ecf1548
--- /dev/null
+++ w/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 I> int frob () const { return I; }
+  };
+
+  export template<int I> class TPL
+  {
+  public:
+    int frob () const { return I; }
+  };
+}
diff --git c/gcc/testsuite/g++.dg/modules/indirect-3_b.C w/gcc/testsuite/g++.dg/modules/indirect-3_b.C
new file mode 100644
index 00000000000..5bdfc1d36a8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-3_c.C w/gcc/testsuite/g++.dg/modules/indirect-3_c.C
new file mode 100644
index 00000000000..9c5cb230ad2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-4_a.C w/gcc/testsuite/g++.dg/modules/indirect-4_a.C
new file mode 100644
index 00000000000..44f4b660a6e
--- /dev/null
+++ w/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<int I> class TPL
+  {
+  public:
+    template <int J> int frob () const 
+    {
+      return I + J;
+    }
+  };
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/indirect-4_b.C w/gcc/testsuite/g++.dg/modules/indirect-4_b.C
new file mode 100644
index 00000000000..8c51ce8097b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/indirect-4_c.C w/gcc/testsuite/g++.dg/modules/indirect-4_c.C
new file mode 100644
index 00000000000..7efcc115e71
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/inext-1.H w/gcc/testsuite/g++.dg/modules/inext-1.H
new file mode 100644
index 00000000000..7708c391618
--- /dev/null
+++ w/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 <inext-1.H>
+
+#endif
+
diff --git c/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1.h w/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1.h
new file mode 100644
index 00000000000..13f769f12d9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1.h
@@ -0,0 +1,35 @@
+
+template <typename _Tp>
+struct Base
+{
+  // template constructor
+  template<typename _Del> Base(_Tp *__p, _Del __d);
+};
+
+template <typename _Tp, typename _Dp>
+struct Derived : Base<_Tp>
+{
+  // Inheriting the template constructor
+  using Base<_Tp>::Base;
+};
+
+template <typename _Tp>
+class unique_ptr
+{
+  Derived<_Tp, int> _M_t;
+
+public:
+  // Instantiates Derived<ResultDerived,int>::Derived
+  template<typename _Up> unique_ptr(unique_ptr<_Up>&& __u) noexcept
+    : _M_t ((_Tp *)0, 1) { }
+};
+
+struct ResultBase { };
+struct ResultDerived : ResultBase { };
+
+void Frob (unique_ptr<ResultBase> &&__res) ;
+
+inline void X (unique_ptr<ResultDerived> &parm)
+{
+  Frob (static_cast <unique_ptr<ResultDerived> &&> (parm));
+}
diff --git c/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_a.H w/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_a.H
new file mode 100644
index 00000000000..822221229c1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_b.C w/gcc/testsuite/g++.dg/modules/inh-tmpl-ctor-1_b.C
new file mode 100644
index 00000000000..ae1612c1475
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/init-1_a.C w/gcc/testsuite/g++.dg/modules/init-1_a.C
new file mode 100644
index 00000000000..b5727d7e3b7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/init-1_b.C w/gcc/testsuite/g++.dg/modules/init-1_b.C
new file mode 100644
index 00000000000..3d2239f9982
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/init-2_a.C w/gcc/testsuite/g++.dg/modules/init-2_a.C
new file mode 100644
index 00000000000..1e9093ef13d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/init-2_b.C w/gcc/testsuite/g++.dg/modules/init-2_b.C
new file mode 100644
index 00000000000..b9692ca862c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/init-2_c.C w/gcc/testsuite/g++.dg/modules/init-2_c.C
new file mode 100644
index 00000000000..c1fa5d80cd4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/inst-1_a.C w/gcc/testsuite/g++.dg/modules/inst-1_a.C
new file mode 100644
index 00000000000..e1d438b5c19
--- /dev/null
+++ w/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 <typename T>
+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<float>'} module } }
+// { dg-final { scan-lang-dump {Depending definition function_decl:'::foo<int>'} module } }
+// { dg-final { scan-lang-dump {\[0\]=specialization definition '::foo<float>'} module } }
+// { dg-final { scan-lang-dump {\[0\]=specialization definition '::foo<int>'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/inst-1_b.C w/gcc/testsuite/g++.dg/modules/inst-1_b.C
new file mode 100644
index 00000000000..08a92aef63a
--- /dev/null
+++ w/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:.<int>'} module } }
+// { dg-final { scan-lang-dump {Reading definition function_decl '::foo@foo:.<float>'} 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 c/gcc/testsuite/g++.dg/modules/inst-2_a.C w/gcc/testsuite/g++.dg/modules/inst-2_a.C
new file mode 100644
index 00000000000..40d6229d4b3
--- /dev/null
+++ w/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 <typename T>
+inline int foo (T t)
+{
+  return baz (t);
+}
+
+export inline void user ()
+{
+  foo (1);
+}
+
+// { dg-final { scan-lang-dump {\[0\]=specialization definition '::foo<int>'} 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<int>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) function_decl:'::foo<int>'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/inst-2_b.C w/gcc/testsuite/g++.dg/modules/inst-2_b.C
new file mode 100644
index 00000000000..3e918bcfb31
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/inst-3_a.C w/gcc/testsuite/g++.dg/modules/inst-3_a.C
new file mode 100644
index 00000000000..3305805b5b7
--- /dev/null
+++ w/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<typename T> struct TPL
+{
+  T m;
+};
+
+export inline int user (int i)
+{
+  TPL<int> x;
+  x.m = i;
+  return x.m;
+}
+
+// { dg-final { scan-lang-dump {Cluster members:\n(  \[.\]=[^\n]*'\n)*  \[.\]=specialization definition '::TPL<int>'\n  \[.\]=specialization declaration '::TPL<int>::TPL<int>'\n} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s type spec merge key \(specialization\) type_decl:'::TPL<int>'} module } }
+// { dg-final { scan-lang-dump {Depset:. specialization entity:. type_decl:'::TPL<int>'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/inst-3_b.C w/gcc/testsuite/g++.dg/modules/inst-3_b.C
new file mode 100644
index 00000000000..80a9946587c
--- /dev/null
+++ w/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<int> x;
+  TPL<float> 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:.<T>::TPL'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/inst-4_a.C w/gcc/testsuite/g++.dg/modules/inst-4_a.C
new file mode 100644
index 00000000000..e7435ec2ee1
--- /dev/null
+++ w/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<typename T> struct TPL
+{
+  T m;
+};
+
+export inline int user (int i)
+{
+  TPL<int> x;
+  x.m = i;
+  return x.m;
+}
+
+// { dg-final { scan-lang-dump {Specialization '::TPL<int>' entity:. keyed to foo\[.\] '::template TPL'} module } }
+// { dg-final { scan-lang-dump {Specialization '::TPL<int>::TPL<int>' entity:. keyed to foo\[.\] '::template TPL<T>::template TPL'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/inst-4_b.C w/gcc/testsuite/g++.dg/modules/inst-4_b.C
new file mode 100644
index 00000000000..c83e1c1437c
--- /dev/null
+++ w/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<int> 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 c/gcc/testsuite/g++.dg/modules/inst-5_a.H w/gcc/testsuite/g++.dg/modules/inst-5_a.H
new file mode 100644
index 00000000000..46d9432fe7c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/inst-5_a.H
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template <int I> int fn () 
+{
+  return I;
+}
+
+inline void g ()
+{
+  fn<1> (); // instantiation gets emitted
+}
diff --git c/gcc/testsuite/g++.dg/modules/inst-5_b.C w/gcc/testsuite/g++.dg/modules/inst-5_b.C
new file mode 100644
index 00000000000..7cc94c83be3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/inst-5_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+template <int I> int fn () 
+{
+  return I;
+}
+
+void f ()
+{
+  fn<1> ();
+}
+
+import "inst-5_a.H";
+// no longer need to instantate
diff --git c/gcc/testsuite/g++.dg/modules/internal-1.C w/gcc/testsuite/g++.dg/modules/internal-1.C
new file mode 100644
index 00000000000..45d3bf06f28
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/internal-2_a.H w/gcc/testsuite/g++.dg/modules/internal-2_a.H
new file mode 100644
index 00000000000..4b530bdc72c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/internal-2_b.H w/gcc/testsuite/g++.dg/modules/internal-2_b.H
new file mode 100644
index 00000000000..cdcbe77e0d1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/internal-2_c.C w/gcc/testsuite/g++.dg/modules/internal-2_c.C
new file mode 100644
index 00000000000..c0bc46dd8a0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/isalnum.H w/gcc/testsuite/g++.dg/modules/isalnum.H
new file mode 100644
index 00000000000..2fac358d7fd
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/keyword-1_a.C w/gcc/testsuite/g++.dg/modules/keyword-1_a.C
new file mode 100644
index 00000000000..190f5739072
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/keyword-1_b.C w/gcc/testsuite/g++.dg/modules/keyword-1_b.C
new file mode 100644
index 00000000000..24a5b5b448c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-1_a.C w/gcc/testsuite/g++.dg/modules/lambda-1_a.C
new file mode 100644
index 00000000000..1b97187da96
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-1_b.C w/gcc/testsuite/g++.dg/modules/lambda-1_b.C
new file mode 100644
index 00000000000..af213492153
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-2.h w/gcc/testsuite/g++.dg/modules/lambda-2.h
new file mode 100644
index 00000000000..3433686b36d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-2_a.H w/gcc/testsuite/g++.dg/modules/lambda-2_a.H
new file mode 100644
index 00000000000..79401209049
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-2_b.C w/gcc/testsuite/g++.dg/modules/lambda-2_b.C
new file mode 100644
index 00000000000..56ec9e3aa30
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-2_c.C w/gcc/testsuite/g++.dg/modules/lambda-2_c.C
new file mode 100644
index 00000000000..c626b9dd850
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-3.h w/gcc/testsuite/g++.dg/modules/lambda-3.h
new file mode 100644
index 00000000000..8f60a824ab4
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/lambda-3.h
@@ -0,0 +1,5 @@
+
+template<int I> inline constexpr auto tmpl = [] {return I;};
+
+inline const auto tpl_1 = tmpl<1>;
+inline const auto tpl_2 = tmpl<2>;
diff --git c/gcc/testsuite/g++.dg/modules/lambda-3_a.H w/gcc/testsuite/g++.dg/modules/lambda-3_a.H
new file mode 100644
index 00000000000..171a2637969
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-3_b.C w/gcc/testsuite/g++.dg/modules/lambda-3_b.C
new file mode 100644
index 00000000000..25a418bb44a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-3_c.C w/gcc/testsuite/g++.dg/modules/lambda-3_c.C
new file mode 100644
index 00000000000..69efa50be0a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-4.h w/gcc/testsuite/g++.dg/modules/lambda-4.h
new file mode 100644
index 00000000000..fe9a06bbd0a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/lambda-4.h
@@ -0,0 +1,2 @@
+
+inline void (*all) (int) = [] (auto) {};
diff --git c/gcc/testsuite/g++.dg/modules/lambda-4_a.H w/gcc/testsuite/g++.dg/modules/lambda-4_a.H
new file mode 100644
index 00000000000..738ea8b4e36
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lambda-4_b.C w/gcc/testsuite/g++.dg/modules/lambda-4_b.C
new file mode 100644
index 00000000000..772045d9efb
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lang-1_a.H w/gcc/testsuite/g++.dg/modules/lang-1_a.H
new file mode 100644
index 00000000000..8131d3ffe79
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lang-1_b.C w/gcc/testsuite/g++.dg/modules/lang-1_b.C
new file mode 100644
index 00000000000..0db144c8ff3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lang-1_c.C w/gcc/testsuite/g++.dg/modules/lang-1_c.C
new file mode 100644
index 00000000000..e3b939df373
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lang-2_a.C w/gcc/testsuite/g++.dg/modules/lang-2_a.C
new file mode 100644
index 00000000000..a3bbe727168
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lang-2_b.C w/gcc/testsuite/g++.dg/modules/lang-2_b.C
new file mode 100644
index 00000000000..0a7a0d2f8e5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/late-ret-1.H w/gcc/testsuite/g++.dg/modules/late-ret-1.H
new file mode 100644
index 00000000000..fb73e51c0ee
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/late-ret-1.H
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename _Iterator>
+struct reverse_iterator
+{
+  _Iterator base() const;
+};
+
+template<typename _Iterator>
+reverse_iterator<_Iterator> __make_reverse_iterator (_Iterator __i);
+
+template<typename _Iterator>
+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 c/gcc/testsuite/g++.dg/modules/late-ret-2_a.H w/gcc/testsuite/g++.dg/modules/late-ret-2_a.H
new file mode 100644
index 00000000000..0ff435ff0fa
--- /dev/null
+++ w/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<typename T> struct TPL {operator T () const {return 0;}};
+
+template<typename T>
+auto Foo (T *arg)
+  -> TPL<decltype (+*arg)> {return TPL<int> ();}
+
+template<typename T>
+auto Bar (T *arg)
+  -> TPL<decltype (arg)> ;
+
+// { 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 c/gcc/testsuite/g++.dg/modules/late-ret-2_b.H w/gcc/testsuite/g++.dg/modules/late-ret-2_b.H
new file mode 100644
index 00000000000..80b83f40e3c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/late-ret-2_b.H
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename T> struct TPL {operator T () const {return 0;}};
+
+template<typename T>
+auto Foo (T *arg)
+  -> TPL<decltype (+*arg)> {return TPL<int> ();}
+
+// Deliberately different to 2_a's Bar
+template<typename T>
+auto Bar (T *arg)
+  -> TPL<decltype (*arg)> ;
diff --git c/gcc/testsuite/g++.dg/modules/late-ret-2_c.C w/gcc/testsuite/g++.dg/modules/late-ret-2_c.C
new file mode 100644
index 00000000000..c5898fb236e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/late-ret-3_a.H w/gcc/testsuite/g++.dg/modules/late-ret-3_a.H
new file mode 100644
index 00000000000..54f95db0456
--- /dev/null
+++ w/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<typename T> struct TPL_1 { using type = T;};
+
+template<typename U> struct TPL_2 { using type = int;};
+
+template<typename V> using TPL_3 = typename TPL_2<V>::type;
+
+template<typename A>
+auto Foo (const A& arg)
+  -> TPL_3<typename TPL_1<decltype(arg)>::type>
+  {return 3;}
+
+template<typename A>
+auto Bar (const A& arg)
+  -> TPL_3<typename TPL_1<decltype(arg)>::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 c/gcc/testsuite/g++.dg/modules/late-ret-3_b.H w/gcc/testsuite/g++.dg/modules/late-ret-3_b.H
new file mode 100644
index 00000000000..2ec63ac65f0
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/late-ret-3_b.H
@@ -0,0 +1,20 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename T> struct TPL_1 { using type = T;};
+
+template<typename U> struct TPL_2 { using type = int;};
+
+template<typename V> using TPL_3 = typename TPL_2<V>::type;
+
+template<typename A>
+auto Foo (const A& arg)
+  -> TPL_3<typename TPL_1<decltype(arg)>::type>
+  {return 3;}
+
+// Deliberately different to 3_a's Bar
+template<typename A>
+auto Bar (const A& arg)
+  -> TPL_3<typename TPL_1<int>::type>
+  {return 3;}
+
diff --git c/gcc/testsuite/g++.dg/modules/late-ret-3_c.C w/gcc/testsuite/g++.dg/modules/late-ret-3_c.C
new file mode 100644
index 00000000000..fae956542f9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lazy-1_a.C w/gcc/testsuite/g++.dg/modules/lazy-1_a.C
new file mode 100644
index 00000000000..0f7c7c9173c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/lazy-1_b.C w/gcc/testsuite/g++.dg/modules/lazy-1_b.C
new file mode 100644
index 00000000000..af213d59a3d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-1_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-1_a.H
new file mode 100644
index 00000000000..e7506b50874
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-1_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-1_b.H
new file mode 100644
index 00000000000..07ae824d358
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-1_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-1_c.C
new file mode 100644
index 00000000000..b204d54ccc5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-1_d.C w/gcc/testsuite/g++.dg/modules/leg-merge-1_d.C
new file mode 100644
index 00000000000..f7854524d45
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/leg-merge-1_d.C
@@ -0,0 +1,4 @@
+int bob (int i)
+{
+  return i;
+}
diff --git c/gcc/testsuite/g++.dg/modules/leg-merge-2_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-2_a.H
new file mode 100644
index 00000000000..d891c8966ce
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-2_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-2_b.H
new file mode 100644
index 00000000000..b9be14d83d5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-2_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-2_c.C
new file mode 100644
index 00000000000..d5a4da9bd63
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-3_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-3_a.H
new file mode 100644
index 00000000000..9142340bc84
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-3_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-3_b.H
new file mode 100644
index 00000000000..2ba847b6601
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-3_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-3_c.C
new file mode 100644
index 00000000000..c6b71b57c22
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-3_d.C w/gcc/testsuite/g++.dg/modules/leg-merge-3_d.C
new file mode 100644
index 00000000000..36f028c4f04
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/leg-merge-3_d.C
@@ -0,0 +1 @@
+int bob = 17;
diff --git c/gcc/testsuite/g++.dg/modules/leg-merge-4_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-4_a.H
new file mode 100644
index 00000000000..9c61ea2356f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-4_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-4_b.H
new file mode 100644
index 00000000000..09c895fdcd4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C
new file mode 100644
index 00000000000..f1b1aeb5b37
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-5_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-5_a.H
new file mode 100644
index 00000000000..ba92696ed1f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-5_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-5_b.H
new file mode 100644
index 00000000000..b77efb3f85e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-5_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-5_c.C
new file mode 100644
index 00000000000..cd1e757b340
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-6_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-6_a.H
new file mode 100644
index 00000000000..64e8d2861be
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-6_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-6_b.H
new file mode 100644
index 00000000000..2179d9002b1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-6_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-6_c.C
new file mode 100644
index 00000000000..dddd88cb0ff
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-7_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-7_a.H
new file mode 100644
index 00000000000..d8ea85943f0
--- /dev/null
+++ w/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 I> int foo (int i) 
+{
+  return I == i;
+}
diff --git c/gcc/testsuite/g++.dg/modules/leg-merge-7_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-7_b.H
new file mode 100644
index 00000000000..9ec045be468
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/leg-merge-7_b.H
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template<int I> int foo (int i) 
+{
+  return I == i;
+}
diff --git c/gcc/testsuite/g++.dg/modules/leg-merge-7_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-7_c.C
new file mode 100644
index 00000000000..0efdc0af1f4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-8_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-8_a.H
new file mode 100644
index 00000000000..ad9a2f9e543
--- /dev/null
+++ w/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<int I> struct Tpl
+{
+  int i;
+  Tpl () : i (I){}
+  operator int () const 
+  {
+    return i;
+  }
+};
diff --git c/gcc/testsuite/g++.dg/modules/leg-merge-8_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-8_b.H
new file mode 100644
index 00000000000..845984c480c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/leg-merge-8_b.H
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template<int I> struct Tpl
+{
+  int i;
+  Tpl () : i (I){}
+  operator int () const 
+  {
+    return i;
+  }
+};
diff --git c/gcc/testsuite/g++.dg/modules/leg-merge-8_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-8_c.C
new file mode 100644
index 00000000000..fa67db99a80
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-9_a.H w/gcc/testsuite/g++.dg/modules/leg-merge-9_a.H
new file mode 100644
index 00000000000..518ecbd11f7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-9_b.H w/gcc/testsuite/g++.dg/modules/leg-merge-9_b.H
new file mode 100644
index 00000000000..518ecbd11f7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/leg-merge-9_c.C w/gcc/testsuite/g++.dg/modules/leg-merge-9_c.C
new file mode 100644
index 00000000000..3c75dc8162c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-1_a.H w/gcc/testsuite/g++.dg/modules/legacy-1_a.H
new file mode 100644
index 00000000000..3ab0856bcbc
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-1_b.C w/gcc/testsuite/g++.dg/modules/legacy-1_b.C
new file mode 100644
index 00000000000..f758e3a3f8b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-1_c.C w/gcc/testsuite/g++.dg/modules/legacy-1_c.C
new file mode 100644
index 00000000000..277231c87ab
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-2.h w/gcc/testsuite/g++.dg/modules/legacy-2.h
new file mode 100644
index 00000000000..2bac5c74b84
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/legacy-2.h
@@ -0,0 +1 @@
+#define FROB frob
diff --git c/gcc/testsuite/g++.dg/modules/legacy-2.map w/gcc/testsuite/g++.dg/modules/legacy-2.map
new file mode 100644
index 00000000000..9de5392f593
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/legacy-2.map
@@ -0,0 +1 @@
+"legacy-2_a.H"
diff --git c/gcc/testsuite/g++.dg/modules/legacy-2_a.H w/gcc/testsuite/g++.dg/modules/legacy-2_a.H
new file mode 100644
index 00000000000..076bdbe4689
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-2_b.H w/gcc/testsuite/g++.dg/modules/legacy-2_b.H
new file mode 100644
index 00000000000..0d4ae071158
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-2_c.C w/gcc/testsuite/g++.dg/modules/legacy-2_c.C
new file mode 100644
index 00000000000..ff31bd41297
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-2_d.C w/gcc/testsuite/g++.dg/modules/legacy-2_d.C
new file mode 100644
index 00000000000..5384d321128
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-3.h w/gcc/testsuite/g++.dg/modules/legacy-3.h
new file mode 100644
index 00000000000..2bac5c74b84
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/legacy-3.h
@@ -0,0 +1 @@
+#define FROB frob
diff --git c/gcc/testsuite/g++.dg/modules/legacy-3_a.H w/gcc/testsuite/g++.dg/modules/legacy-3_a.H
new file mode 100644
index 00000000000..74d275536f9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-3_b.H w/gcc/testsuite/g++.dg/modules/legacy-3_b.H
new file mode 100644
index 00000000000..3bf819db661
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-3_c.H w/gcc/testsuite/g++.dg/modules/legacy-3_c.H
new file mode 100644
index 00000000000..56b81722997
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-6.map w/gcc/testsuite/g++.dg/modules/legacy-6.map
new file mode 100644
index 00000000000..8199bf9e190
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/legacy-6.map
@@ -0,0 +1,2 @@
+./legacy-6_a.H
+./legacy-6_b.H
diff --git c/gcc/testsuite/g++.dg/modules/legacy-6_a.H w/gcc/testsuite/g++.dg/modules/legacy-6_a.H
new file mode 100644
index 00000000000..7d7e970cdff
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-6_b.H w/gcc/testsuite/g++.dg/modules/legacy-6_b.H
new file mode 100644
index 00000000000..1a52d42f613
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-6_c.C w/gcc/testsuite/g++.dg/modules/legacy-6_c.C
new file mode 100644
index 00000000000..0b5bd7f2eb2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-6_d.C w/gcc/testsuite/g++.dg/modules/legacy-6_d.C
new file mode 100644
index 00000000000..58ca21dbccf
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-6_e.C w/gcc/testsuite/g++.dg/modules/legacy-6_e.C
new file mode 100644
index 00000000000..9d4dd9218dd
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-6_f.C w/gcc/testsuite/g++.dg/modules/legacy-6_f.C
new file mode 100644
index 00000000000..c15eadec6da
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-7_a.H w/gcc/testsuite/g++.dg/modules/legacy-7_a.H
new file mode 100644
index 00000000000..49578a929e8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-7_b.C w/gcc/testsuite/g++.dg/modules/legacy-7_b.C
new file mode 100644
index 00000000000..d78f45c2128
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-8_a.H w/gcc/testsuite/g++.dg/modules/legacy-8_a.H
new file mode 100644
index 00000000000..a30cd880d9f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-8_b.H w/gcc/testsuite/g++.dg/modules/legacy-8_b.H
new file mode 100644
index 00000000000..62366e11a0f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-8_c.C w/gcc/testsuite/g++.dg/modules/legacy-8_c.C
new file mode 100644
index 00000000000..88300b28582
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-8_d.C w/gcc/testsuite/g++.dg/modules/legacy-8_d.C
new file mode 100644
index 00000000000..85377d9f7d5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/legacy-8_e.C w/gcc/testsuite/g++.dg/modules/legacy-8_e.C
new file mode 100644
index 00000000000..afeb19a94c7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/libfn-1_a.C w/gcc/testsuite/g++.dg/modules/libfn-1_a.C
new file mode 100644
index 00000000000..a8a8ee8ea71
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/libfn-1_b.C w/gcc/testsuite/g++.dg/modules/libfn-1_b.C
new file mode 100644
index 00000000000..0e8346b5b71
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/literals-1_a.C w/gcc/testsuite/g++.dg/modules/literals-1_a.C
new file mode 100644
index 00000000000..9fb2aea5c82
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/literals-1_b.C w/gcc/testsuite/g++.dg/modules/literals-1_b.C
new file mode 100644
index 00000000000..5468944fad3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-1_a.C w/gcc/testsuite/g++.dg/modules/loc-1_a.C
new file mode 100644
index 00000000000..8155181b009
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-1_b.C w/gcc/testsuite/g++.dg/modules/loc-1_b.C
new file mode 100644
index 00000000000..0a0b85ed78c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-1_c.C w/gcc/testsuite/g++.dg/modules/loc-1_c.C
new file mode 100644
index 00000000000..f9522597e9e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-2_a.C w/gcc/testsuite/g++.dg/modules/loc-2_a.C
new file mode 100644
index 00000000000..a4bbce36a2a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-2_b.C w/gcc/testsuite/g++.dg/modules/loc-2_b.C
new file mode 100644
index 00000000000..42640098d8e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-2_c.C w/gcc/testsuite/g++.dg/modules/loc-2_c.C
new file mode 100644
index 00000000000..e731d50933b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-2_d.C w/gcc/testsuite/g++.dg/modules/loc-2_d.C
new file mode 100644
index 00000000000..4ae8a690c9e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-2_e.C w/gcc/testsuite/g++.dg/modules/loc-2_e.C
new file mode 100644
index 00000000000..c4d0acb7db8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-2_f.C w/gcc/testsuite/g++.dg/modules/loc-2_f.C
new file mode 100644
index 00000000000..2888d048861
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-wrapper-1.h w/gcc/testsuite/g++.dg/modules/loc-wrapper-1.h
new file mode 100644
index 00000000000..04e62d46f8f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/loc-wrapper-1.h
@@ -0,0 +1,14 @@
+template<typename _Tp>
+struct __is_integer
+{
+  enum { __value = 0 };
+};
+
+template<typename _Tp>
+struct __is_integer_nonstrict
+
+{
+  using __is_integer<_Tp>::__value;
+
+  enum { __width = __value ? sizeof(_Tp) * 8 : 0 };
+};
diff --git c/gcc/testsuite/g++.dg/modules/loc-wrapper-1_a.H w/gcc/testsuite/g++.dg/modules/loc-wrapper-1_a.H
new file mode 100644
index 00000000000..cddb46f5fab
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/loc-wrapper-1_b.C w/gcc/testsuite/g++.dg/modules/loc-wrapper-1_b.C
new file mode 100644
index 00000000000..6d0229a8193
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/local-1_a.C w/gcc/testsuite/g++.dg/modules/local-1_a.C
new file mode 100644
index 00000000000..c1a3343478b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/local-1_b.C w/gcc/testsuite/g++.dg/modules/local-1_b.C
new file mode 100644
index 00000000000..37a9461706d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/local-extern-1.C w/gcc/testsuite/g++.dg/modules/local-extern-1.C
new file mode 100644
index 00000000000..7b016053d36
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/local-extern-2.H w/gcc/testsuite/g++.dg/modules/local-extern-2.H
new file mode 100644
index 00000000000..dab5ee4fb84
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/local-struct-1_a.C w/gcc/testsuite/g++.dg/modules/local-struct-1_a.C
new file mode 100644
index 00000000000..b4323b63e67
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/local-struct-1_b.C w/gcc/testsuite/g++.dg/modules/local-struct-1_b.C
new file mode 100644
index 00000000000..96968e254ac
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macloc-1_a.C w/gcc/testsuite/g++.dg/modules/macloc-1_a.C
new file mode 100644
index 00000000000..a152b5191d8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macloc-1_b.C w/gcc/testsuite/g++.dg/modules/macloc-1_b.C
new file mode 100644
index 00000000000..8f8f1f55464
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macloc-1_c.C w/gcc/testsuite/g++.dg/modules/macloc-1_c.C
new file mode 100644
index 00000000000..9b8f7fb9d59
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macloc-1_d.C w/gcc/testsuite/g++.dg/modules/macloc-1_d.C
new file mode 100644
index 00000000000..5b2b7ba3034
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macloc-2_a.H w/gcc/testsuite/g++.dg/modules/macloc-2_a.H
new file mode 100644
index 00000000000..99f08840280
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macloc-2_b.C w/gcc/testsuite/g++.dg/modules/macloc-2_b.C
new file mode 100644
index 00000000000..601a4779c28
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-1_a.H w/gcc/testsuite/g++.dg/modules/macro-1_a.H
new file mode 100644
index 00000000000..5b212a6d487
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-1_b.C w/gcc/testsuite/g++.dg/modules/macro-1_b.C
new file mode 100644
index 00000000000..afbcab281d7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-2_a.H w/gcc/testsuite/g++.dg/modules/macro-2_a.H
new file mode 100644
index 00000000000..89d66a5f405
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-2_b.H w/gcc/testsuite/g++.dg/modules/macro-2_b.H
new file mode 100644
index 00000000000..5690712607b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-2_c.H w/gcc/testsuite/g++.dg/modules/macro-2_c.H
new file mode 100644
index 00000000000..ed053236a5b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-2_d.C w/gcc/testsuite/g++.dg/modules/macro-2_d.C
new file mode 100644
index 00000000000..04b80fb3058
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-3_a.H w/gcc/testsuite/g++.dg/modules/macro-3_a.H
new file mode 100644
index 00000000000..6582e3cb26c
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-3_b.H w/gcc/testsuite/g++.dg/modules/macro-3_b.H
new file mode 100644
index 00000000000..2af92ac51e9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-3_c.C w/gcc/testsuite/g++.dg/modules/macro-3_c.C
new file mode 100644
index 00000000000..f0795807878
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-4_a.H w/gcc/testsuite/g++.dg/modules/macro-4_a.H
new file mode 100644
index 00000000000..c04854ea594
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-4_b.H w/gcc/testsuite/g++.dg/modules/macro-4_b.H
new file mode 100644
index 00000000000..04039389045
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-4_c.H w/gcc/testsuite/g++.dg/modules/macro-4_c.H
new file mode 100644
index 00000000000..ec2bed91ccd
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-4_d.C w/gcc/testsuite/g++.dg/modules/macro-4_d.C
new file mode 100644
index 00000000000..bff9494281b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-4_e.C w/gcc/testsuite/g++.dg/modules/macro-4_e.C
new file mode 100644
index 00000000000..38fa6c7feeb
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-4_f.C w/gcc/testsuite/g++.dg/modules/macro-4_f.C
new file mode 100644
index 00000000000..1279de271c0
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-4_g.C w/gcc/testsuite/g++.dg/modules/macro-4_g.C
new file mode 100644
index 00000000000..f3ff0e49f06
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-5_a.H w/gcc/testsuite/g++.dg/modules/macro-5_a.H
new file mode 100644
index 00000000000..d0913d1c53e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-5_b.H w/gcc/testsuite/g++.dg/modules/macro-5_b.H
new file mode 100644
index 00000000000..656d51143a1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-5_c.C w/gcc/testsuite/g++.dg/modules/macro-5_c.C
new file mode 100644
index 00000000000..17f6fe29913
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-6_a.H w/gcc/testsuite/g++.dg/modules/macro-6_a.H
new file mode 100644
index 00000000000..4947e2ee76f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-6_b.C w/gcc/testsuite/g++.dg/modules/macro-6_b.C
new file mode 100644
index 00000000000..cbc3b2a68e5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-6_c.C w/gcc/testsuite/g++.dg/modules/macro-6_c.C
new file mode 100644
index 00000000000..a9a6f4f5db7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-7_a.C w/gcc/testsuite/g++.dg/modules/macro-7_a.C
new file mode 100644
index 00000000000..f336f006d5f
--- /dev/null
+++ w/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 I> int Factory ()
+{
+  // this macro expansion location ends up in the instantiation
+  // emitted by an importer
+  return MACRO(I);
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/macro-7_b.C w/gcc/testsuite/g++.dg/modules/macro-7_b.C
new file mode 100644
index 00000000000..025f5ebd29a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/macro-7_c.C w/gcc/testsuite/g++.dg/modules/macro-7_c.C
new file mode 100644
index 00000000000..902f1a8a803
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/map-1.map w/gcc/testsuite/g++.dg/modules/map-1.map
new file mode 100644
index 00000000000..58963bdb32d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/map-1.map
@@ -0,0 +1,2 @@
+$root .
+frob map-1_a.nms
diff --git c/gcc/testsuite/g++.dg/modules/map-1_a.C w/gcc/testsuite/g++.dg/modules/map-1_a.C
new file mode 100644
index 00000000000..f714672d05e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/map-1_b.C w/gcc/testsuite/g++.dg/modules/map-1_b.C
new file mode 100644
index 00000000000..0e306d8ba1f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/map-1_b.map w/gcc/testsuite/g++.dg/modules/map-1_b.map
new file mode 100644
index 00000000000..f125dc8bda1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/map-2.C w/gcc/testsuite/g++.dg/modules/map-2.C
new file mode 100644
index 00000000000..dceb1834196
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/map-2.map w/gcc/testsuite/g++.dg/modules/map-2.map
new file mode 100644
index 00000000000..43aecde4b7f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/map-2.map
@@ -0,0 +1 @@
+$bad .
diff --git c/gcc/testsuite/g++.dg/modules/member-def-1_a.C w/gcc/testsuite/g++.dg/modules/member-def-1_a.C
new file mode 100644
index 00000000000..f7a508cbea9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/member-def-1_b.C w/gcc/testsuite/g++.dg/modules/member-def-1_b.C
new file mode 100644
index 00000000000..fbe1ac44cf2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/member-def-1_c.C w/gcc/testsuite/g++.dg/modules/member-def-1_c.C
new file mode 100644
index 00000000000..c7c3f6eb194
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/member-def-1_d.C w/gcc/testsuite/g++.dg/modules/member-def-1_d.C
new file mode 100644
index 00000000000..5609d47b075
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/member-def-2_a.C w/gcc/testsuite/g++.dg/modules/member-def-2_a.C
new file mode 100644
index 00000000000..b4904dabbec
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/member-def-2_b.C w/gcc/testsuite/g++.dg/modules/member-def-2_b.C
new file mode 100644
index 00000000000..dedcbe70fcd
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/member-def-2_c.C w/gcc/testsuite/g++.dg/modules/member-def-2_c.C
new file mode 100644
index 00000000000..f0a193f34ce
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/member-def-2_d.C w/gcc/testsuite/g++.dg/modules/member-def-2_d.C
new file mode 100644
index 00000000000..c2b9c3e655b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/memref-1_a.C w/gcc/testsuite/g++.dg/modules/memref-1_a.C
new file mode 100644
index 00000000000..e780999778d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/memref-1_b.C w/gcc/testsuite/g++.dg/modules/memref-1_b.C
new file mode 100644
index 00000000000..82c52faed7a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-10.h w/gcc/testsuite/g++.dg/modules/merge-10.h
new file mode 100644
index 00000000000..9df9d2cb75b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-10.h
@@ -0,0 +1,8 @@
+
+struct timex
+{
+  unsigned modes;
+  int :32;
+  int :32;
+};
+
diff --git c/gcc/testsuite/g++.dg/modules/merge-10_a.H w/gcc/testsuite/g++.dg/modules/merge-10_a.H
new file mode 100644
index 00000000000..dc4be18f076
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-10_b.C w/gcc/testsuite/g++.dg/modules/merge-10_b.C
new file mode 100644
index 00000000000..9df07ee962a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-11.h w/gcc/testsuite/g++.dg/modules/merge-11.h
new file mode 100644
index 00000000000..87342e18880
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-11.h
@@ -0,0 +1,15 @@
+
+
+
+template<typename _From, bool>
+struct __is_nt_convertible_helper;
+
+template<typename _From>
+class __is_nt_convertible_helper<_From, false>
+{
+  template<typename> static int __test (int);
+  template<typename> static void __test(...);
+  
+public:
+  using type = decltype(__test<_From>(0));
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-11_a.H w/gcc/testsuite/g++.dg/modules/merge-11_a.H
new file mode 100644
index 00000000000..6de063d1a7f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-11_b.C w/gcc/testsuite/g++.dg/modules/merge-11_b.C
new file mode 100644
index 00000000000..2c30e341f53
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-12.h w/gcc/testsuite/g++.dg/modules/merge-12.h
new file mode 100644
index 00000000000..96b2ba30265
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-12.h
@@ -0,0 +1,23 @@
+
+template<typename _Functor, typename _ArgTypes>
+struct invoke_result;
+
+template<typename _Fn, typename _ArgTypes>
+struct is_invocable;
+
+template<typename _Fn, typename... _Args>
+concept invocable = is_invocable<_Fn, _Args...>::value;
+
+template<typename _Fn, typename _Is>
+requires invocable<_Fn, _Is>
+  using indirect_result_t = typename invoke_result<_Fn, _Is>::type;
+
+template<typename _Tp>
+struct remove_cv;
+
+template<typename _Iter, typename _Proj>
+struct projected
+{
+  using value_type = remove_cv<indirect_result_t<_Proj&, _Iter>>;
+};
+
diff --git c/gcc/testsuite/g++.dg/modules/merge-12_a.H w/gcc/testsuite/g++.dg/modules/merge-12_a.H
new file mode 100644
index 00000000000..4ee061f590e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-12_b.C w/gcc/testsuite/g++.dg/modules/merge-12_b.C
new file mode 100644
index 00000000000..4bafbddb816
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-13.h w/gcc/testsuite/g++.dg/modules/merge-13.h
new file mode 100644
index 00000000000..ad282a0ed62
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-13.h
@@ -0,0 +1,10 @@
+template<typename T> class Base;
+
+template<typename U> class Derived : Base<U>
+{
+  using Base_ = Base<U>;
+  using typename Base_::base_member;
+
+public:
+  base_member Func ();
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-13_a.H w/gcc/testsuite/g++.dg/modules/merge-13_a.H
new file mode 100644
index 00000000000..ecf0c319e49
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-13_b.C w/gcc/testsuite/g++.dg/modules/merge-13_b.C
new file mode 100644
index 00000000000..b62101fefb1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-14.h w/gcc/testsuite/g++.dg/modules/merge-14.h
new file mode 100644
index 00000000000..0b867b68826
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-14.h
@@ -0,0 +1,7 @@
+template<typename T>
+struct TPL
+{
+  T val = 0;
+};
+
+inline TPL<int> x;
diff --git c/gcc/testsuite/g++.dg/modules/merge-14_a.H w/gcc/testsuite/g++.dg/modules/merge-14_a.H
new file mode 100644
index 00000000000..c197ec85e2d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-14_b.C w/gcc/testsuite/g++.dg/modules/merge-14_b.C
new file mode 100644
index 00000000000..4d92b084b95
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-15.h w/gcc/testsuite/g++.dg/modules/merge-15.h
new file mode 100644
index 00000000000..ccf3b844d69
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-15.h
@@ -0,0 +1,5 @@
+struct optional
+{
+  int &get () &;
+  int &&get () &&;
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-15_a.H w/gcc/testsuite/g++.dg/modules/merge-15_a.H
new file mode 100644
index 00000000000..afef95dbcbf
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-15_b.C w/gcc/testsuite/g++.dg/modules/merge-15_b.C
new file mode 100644
index 00000000000..07378d65368
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-1_a.C w/gcc/testsuite/g++.dg/modules/merge-1_a.C
new file mode 100644
index 00000000000..966fd4bc4df
--- /dev/null
+++ w/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<typename _Tp, _Tp __v>
+struct integral_constant
+{
+};
+
+typedef integral_constant<bool, true> true_type;
+
+void __throw_with_nested_impl (true_type);
diff --git c/gcc/testsuite/g++.dg/modules/merge-1_b.C w/gcc/testsuite/g++.dg/modules/merge-1_b.C
new file mode 100644
index 00000000000..c7f533ff1ba
--- /dev/null
+++ w/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<bool, true> ());
+}
diff --git c/gcc/testsuite/g++.dg/modules/merge-2_a.H w/gcc/testsuite/g++.dg/modules/merge-2_a.H
new file mode 100644
index 00000000000..ac6d06a1d8f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-2_a.H
@@ -0,0 +1,29 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename _CharT> class istreambuf_iterator;
+
+void move(char __t);
+void move(istreambuf_iterator<char> &__u);
+
+template<typename _Tp> struct allocator {};
+
+template<typename _Alloc> struct __alloc_traits
+{
+  static void _S_on_swap(_Alloc& __b)
+  {
+    move (__b);
+  }
+
+  typedef allocator<char> other;
+};
+
+template<typename _CharT> class basic_string
+{
+  typedef __alloc_traits<char>::other _Char_alloc_type;
+};
+
+template<typename _CharT> class istreambuf_iterator
+{
+  void frob (const basic_string<char>& __s);
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-2_b.C w/gcc/testsuite/g++.dg/modules/merge-2_b.C
new file mode 100644
index 00000000000..21bbd048f2d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-3_a.H w/gcc/testsuite/g++.dg/modules/merge-3_a.H
new file mode 100644
index 00000000000..80dfd9cc9a1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-3_b.C w/gcc/testsuite/g++.dg/modules/merge-3_b.C
new file mode 100644
index 00000000000..1e863f8c1e5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-4.h w/gcc/testsuite/g++.dg/modules/merge-4.h
new file mode 100644
index 00000000000..842fedc5718
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-4.h
@@ -0,0 +1,7 @@
+template<typename T> struct Bob 
+{
+  struct M 
+  {
+    int m;
+  };
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-4_a.H w/gcc/testsuite/g++.dg/modules/merge-4_a.H
new file mode 100644
index 00000000000..78b0ec74edd
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-4_b.C w/gcc/testsuite/g++.dg/modules/merge-4_b.C
new file mode 100644
index 00000000000..89b69619ee2
--- /dev/null
+++ w/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<T>::template M'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/merge-5.h w/gcc/testsuite/g++.dg/modules/merge-5.h
new file mode 100644
index 00000000000..5db1b0a8115
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-5.h
@@ -0,0 +1,8 @@
+
+template<bool> struct __truth_type;
+
+template<typename T> struct __traitor
+{
+  enum X { __value = true };
+  typedef typename __truth_type<__value>::__type __type;
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-5_a.H w/gcc/testsuite/g++.dg/modules/merge-5_a.H
new file mode 100644
index 00000000000..e3d8c690921
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-5_b.C w/gcc/testsuite/g++.dg/modules/merge-5_b.C
new file mode 100644
index 00000000000..58c2a348c0a
--- /dev/null
+++ w/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<T>::template X<T>::__value'} module } }
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
+// { dg-final { scan-lang-dump-not {merge key \(unique\)} module } }
diff --git c/gcc/testsuite/g++.dg/modules/merge-6.h w/gcc/testsuite/g++.dg/modules/merge-6.h
new file mode 100644
index 00000000000..6a1d6542c51
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-6.h
@@ -0,0 +1,10 @@
+
+template<bool>
+struct __truth_type;
+
+template<typename T>
+struct __traitor
+{
+  enum { __value = true }; // Oh, an anonymous templatey thing!
+  typedef typename __truth_type<__value>::__type __type;
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-6_a.H w/gcc/testsuite/g++.dg/modules/merge-6_a.H
new file mode 100644
index 00000000000..4e0b81c5a4a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-6_b.C w/gcc/testsuite/g++.dg/modules/merge-6_b.C
new file mode 100644
index 00000000000..11fe63153d5
--- /dev/null
+++ w/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<T>::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 c/gcc/testsuite/g++.dg/modules/merge-7.h w/gcc/testsuite/g++.dg/modules/merge-7.h
new file mode 100644
index 00000000000..6350e743f72
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-7.h
@@ -0,0 +1,5 @@
+template<typename _Tp2, typename _Up2>
+struct __promote_2
+{
+  typedef __typeof__(_Tp2() + _Up2()) __type;
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-7_a.H w/gcc/testsuite/g++.dg/modules/merge-7_a.H
new file mode 100644
index 00000000000..3c32b33ada8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-7_b.C w/gcc/testsuite/g++.dg/modules/merge-7_b.C
new file mode 100644
index 00000000000..da9632d71bf
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-8.h w/gcc/testsuite/g++.dg/modules/merge-8.h
new file mode 100644
index 00000000000..d2539021ce3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/merge-8.h
@@ -0,0 +1,17 @@
+
+struct __do_is_destructible_impl
+{
+  template<typename _Tp, typename = decltype(_Tp().~_Tp())>
+  static bool __test(int);
+
+  template<typename>
+  static float __test(...);
+};
+
+template<typename _Tp>
+struct __is_destructible_impl
+  : public __do_is_destructible_impl
+{
+  // Requires BINFO merging
+  typedef decltype(__test<_Tp>(0)) type;
+};
diff --git c/gcc/testsuite/g++.dg/modules/merge-8_a.H w/gcc/testsuite/g++.dg/modules/merge-8_a.H
new file mode 100644
index 00000000000..d2add6bfdd8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-8_b.C w/gcc/testsuite/g++.dg/modules/merge-8_b.C
new file mode 100644
index 00000000000..c489e30a8ec
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-9.h w/gcc/testsuite/g++.dg/modules/merge-9.h
new file mode 100644
index 00000000000..19447799fea
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-9_a.H w/gcc/testsuite/g++.dg/modules/merge-9_a.H
new file mode 100644
index 00000000000..69f32cb3671
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/merge-9_b.C w/gcc/testsuite/g++.dg/modules/merge-9_b.C
new file mode 100644
index 00000000000..0a92cf344df
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-exp-1_a.C w/gcc/testsuite/g++.dg/modules/mod-exp-1_a.C
new file mode 100644
index 00000000000..800752dc871
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-exp-1_b.C w/gcc/testsuite/g++.dg/modules/mod-exp-1_b.C
new file mode 100644
index 00000000000..efea205a50d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-imp-1_a.C w/gcc/testsuite/g++.dg/modules/mod-imp-1_a.C
new file mode 100644
index 00000000000..cf9e1d7a2cc
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-imp-1_b.C w/gcc/testsuite/g++.dg/modules/mod-imp-1_b.C
new file mode 100644
index 00000000000..0dc4bdb58a3
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-imp-1_c.C w/gcc/testsuite/g++.dg/modules/mod-imp-1_c.C
new file mode 100644
index 00000000000..e32aaaf7461
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-imp-1_d.C w/gcc/testsuite/g++.dg/modules/mod-imp-1_d.C
new file mode 100644
index 00000000000..ca6f64914c2
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-impl-1_a.C w/gcc/testsuite/g++.dg/modules/mod-impl-1_a.C
new file mode 100644
index 00000000000..9f9dfd42806
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-impl-1_b.C w/gcc/testsuite/g++.dg/modules/mod-impl-1_b.C
new file mode 100644
index 00000000000..c1f9a5c9233
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-impl-1_c.C w/gcc/testsuite/g++.dg/modules/mod-impl-1_c.C
new file mode 100644
index 00000000000..c50aade4212
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-impl-1_d.C w/gcc/testsuite/g++.dg/modules/mod-impl-1_d.C
new file mode 100644
index 00000000000..4f05a76159b
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-indirect-1_a.C w/gcc/testsuite/g++.dg/modules/mod-indirect-1_a.C
new file mode 100644
index 00000000000..a27153cb9ab
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-indirect-1_b.C w/gcc/testsuite/g++.dg/modules/mod-indirect-1_b.C
new file mode 100644
index 00000000000..7e466f1d897
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-indirect-1_c.C w/gcc/testsuite/g++.dg/modules/mod-indirect-1_c.C
new file mode 100644
index 00000000000..e19f41d4601
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-indirect-1_d.C w/gcc/testsuite/g++.dg/modules/mod-indirect-1_d.C
new file mode 100644
index 00000000000..304be95561e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-indirect-1_e.C w/gcc/testsuite/g++.dg/modules/mod-indirect-1_e.C
new file mode 100644
index 00000000000..23241b1601f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-stamp-1_a.C w/gcc/testsuite/g++.dg/modules/mod-stamp-1_a.C
new file mode 100644
index 00000000000..cf8e73f85d7
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-stamp-1_b.C w/gcc/testsuite/g++.dg/modules/mod-stamp-1_b.C
new file mode 100644
index 00000000000..3a5e8e20ba5
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-stamp-1_c.C w/gcc/testsuite/g++.dg/modules/mod-stamp-1_c.C
new file mode 100644
index 00000000000..554ba3f26eb
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-stamp-1_d.C w/gcc/testsuite/g++.dg/modules/mod-stamp-1_d.C
new file mode 100644
index 00000000000..f16833ed5c9
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-sym-1.C w/gcc/testsuite/g++.dg/modules/mod-sym-1.C
new file mode 100644
index 00000000000..b20710189d1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-sym-2.C w/gcc/testsuite/g++.dg/modules/mod-sym-2.C
new file mode 100644
index 00000000000..ef0c3f03317
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-sym-3.C w/gcc/testsuite/g++.dg/modules/mod-sym-3.C
new file mode 100644
index 00000000000..9481ad1e719
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-tpl-1_a.C w/gcc/testsuite/g++.dg/modules/mod-tpl-1_a.C
new file mode 100644
index 00000000000..f48e1237d01
--- /dev/null
+++ w/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 <typename T>
+T twice (T x)
+{
+  return x * 2;
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/mod-tpl-1_b.C w/gcc/testsuite/g++.dg/modules/mod-tpl-1_b.C
new file mode 100644
index 00000000000..669f2c68881
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/mod-tpl-2_a.C w/gcc/testsuite/g++.dg/modules/mod-tpl-2_a.C
new file mode 100644
index 00000000000..86281bb97a6
--- /dev/null
+++ w/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 <typename T>
+class X
+{
+  T m;
+
+public:
+  void frob (T v) { m = v; }
+
+  T frobber (T v) { return v + m; }
+};
diff --git c/gcc/testsuite/g++.dg/modules/mod-tpl-2_b.C w/gcc/testsuite/g++.dg/modules/mod-tpl-2_b.C
new file mode 100644
index 00000000000..8452c7d7875
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/mod-tpl-2_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import frob;
+
+int main ()
+{
+  X<int> x;
+
+  x.frob (3);
+
+  return ! (x.frobber (-3) == 0);
+}
diff --git c/gcc/testsuite/g++.dg/modules/mutual-friend.ii w/gcc/testsuite/g++.dg/modules/mutual-friend.ii
new file mode 100644
index 00000000000..b42b9798998
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-1_a.C w/gcc/testsuite/g++.dg/modules/namespace-1_a.C
new file mode 100644
index 00000000000..1929acc167a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-1_b.C w/gcc/testsuite/g++.dg/modules/namespace-1_b.C
new file mode 100644
index 00000000000..096e6ce41ae
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-1_c.C w/gcc/testsuite/g++.dg/modules/namespace-1_c.C
new file mode 100644
index 00000000000..748ef5d79a4
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-2_a.C w/gcc/testsuite/g++.dg/modules/namespace-2_a.C
new file mode 100644
index 00000000000..18327e205ee
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-2_b.C w/gcc/testsuite/g++.dg/modules/namespace-2_b.C
new file mode 100644
index 00000000000..6ab5113c23a
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-3_a.C w/gcc/testsuite/g++.dg/modules/namespace-3_a.C
new file mode 100644
index 00000000000..8e9508d7ff8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-3_b.C w/gcc/testsuite/g++.dg/modules/namespace-3_b.C
new file mode 100644
index 00000000000..f779ffe8c8f
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-4_a.C w/gcc/testsuite/g++.dg/modules/namespace-4_a.C
new file mode 100644
index 00000000000..b49e0ea7ce6
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/namespace-4_b.C w/gcc/testsuite/g++.dg/modules/namespace-4_b.C
new file mode 100644
index 00000000000..3530bcd9def
--- /dev/null
+++ w/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 <int *> (nope));
+  return nope; // Ok sees above nope
+}
diff --git c/gcc/testsuite/g++.dg/modules/namespace-4_c.C w/gcc/testsuite/g++.dg/modules/namespace-4_c.C
new file mode 100644
index 00000000000..2526289ec3e
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nest-1_a.C w/gcc/testsuite/g++.dg/modules/nest-1_a.C
new file mode 100644
index 00000000000..4788d5da601
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nest-1_b.C w/gcc/testsuite/g++.dg/modules/nest-1_b.C
new file mode 100644
index 00000000000..cc302781248
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nest-1_c.C w/gcc/testsuite/g++.dg/modules/nest-1_c.C
new file mode 100644
index 00000000000..05ca02ffc61
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nested-1_a.C w/gcc/testsuite/g++.dg/modules/nested-1_a.C
new file mode 100644
index 00000000000..31726571ae8
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nested-1_b.C w/gcc/testsuite/g++.dg/modules/nested-1_b.C
new file mode 100644
index 00000000000..9f775b16c17
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nested-1_c.C w/gcc/testsuite/g++.dg/modules/nested-1_c.C
new file mode 100644
index 00000000000..f46e6dfde3d
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nested-2_a.C w/gcc/testsuite/g++.dg/modules/nested-2_a.C
new file mode 100644
index 00000000000..e21973593d1
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nested-2_b.C w/gcc/testsuite/g++.dg/modules/nested-2_b.C
new file mode 100644
index 00000000000..1ca02bdc2fe
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nested-constr-1.h w/gcc/testsuite/g++.dg/modules/nested-constr-1.h
new file mode 100644
index 00000000000..6962ccad850
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/nested-constr-1.h
@@ -0,0 +1,15 @@
+
+template<typename T>
+struct traits
+{
+  template<typename U>
+    struct nested
+    { using type = void; };
+
+  template<typename U> requires requires { typename U::type; }
+    struct nested<U>
+    { using type = typename U::type; };
+};
+
+using V = traits<char>::nested<int>::type;
+
diff --git c/gcc/testsuite/g++.dg/modules/nested-constr-1_a.H w/gcc/testsuite/g++.dg/modules/nested-constr-1_a.H
new file mode 100644
index 00000000000..9398986dd42
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nested-constr-1_b.C w/gcc/testsuite/g++.dg/modules/nested-constr-1_b.C
new file mode 100644
index 00000000000..7043ffa8554
--- /dev/null
+++ w/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<char>::nested<X>::type b;
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git c/gcc/testsuite/g++.dg/modules/nested-constr-2_a.C w/gcc/testsuite/g++.dg/modules/nested-constr-2_a.C
new file mode 100644
index 00000000000..b29d670a570
--- /dev/null
+++ w/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<typename T>
+struct traits
+{
+  template<typename U>
+    struct nested
+    { using type = void; };
+
+  template<typename U> requires requires { typename U::type; }
+    struct nested<U>
+    { using type = typename U::type; };
+};
+
+export using V = traits<char>::nested<int>::type;
+
diff --git c/gcc/testsuite/g++.dg/modules/nested-constr-2_b.C w/gcc/testsuite/g++.dg/modules/nested-constr-2_b.C
new file mode 100644
index 00000000000..a34ef523f90
--- /dev/null
+++ w/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<char>::nested<X>::type b;
diff --git c/gcc/testsuite/g++.dg/modules/nested-constr-2_c.C w/gcc/testsuite/g++.dg/modules/nested-constr-2_c.C
new file mode 100644
index 00000000000..5c81b3b6c09
--- /dev/null
+++ w/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 c/gcc/testsuite/g++.dg/modules/nodes-1_a.C w/gcc/testsuite/g++.dg/modules/nodes-1_a.C
new file mode 100644
index 00000000000..446461c8a6b
--- /dev/null
+++ w/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 <typename T> void assert (T t)
+{
+  static_assert (sizeof (T) == sizeof (int), "whoops");
+}
+
+export class other 
+{
+public:
+  other () :f (5) {}
+  void o () { }
+  int f;
+};
+
+export template<typename T> class baselink : T, other
+{
+public:
+  int Frob ()
+  {
+    o ();
+    return this->T::frob ();
+  }
+};
+
+export template <typename T> bool trait ()
+{
+  return __has_nothrow_assign(T);
+}
+
+export inline bool ptrmemdata (other const &obj)
+{
+  int other::*ptr = &other::f;
+
+  return (obj.*ptr) == 5;
+}
+
+export template<typename T> int ptrmemfn (T const &obj)
+{
+  int (T::*ptr) () const = &T::frob;
+  return (obj.*ptr) ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/nodes-1_b.C w/gcc/testsuite/g++.dg/modules/nodes-1_b.C
new file mode 100644
index 00000000000..1567e90c1a5
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/nodes-1_b.C
@@ -0,0 +1,27 @@
+// { dg-additional-options -fmodules-ts }
+import node;
+
+struct b
+{
+  int frob () const
+  {
+    return 0;
+  }
+};
+
+int main ()
+{
+  assert (0);
+  baselink<b> thing;
+  thing.Frob ();
+  if (!trait<b> ())
+    return 1;
+
+  if (!ptrmemdata (other ()))
+    return 2;
+
+  if (ptrmemfn (b ()))
+    return 2;
+
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/noexcept-1.h w/gcc/testsuite/g++.dg/modules/noexcept-1.h
new file mode 100644
index 00000000000..a4a0de5dd7f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/noexcept-1.h
@@ -0,0 +1,78 @@
+template<typename _Tp, _Tp __v>
+struct integral_constant
+{
+  static constexpr _Tp value = __v;
+  typedef _Tp value_type;
+  typedef integral_constant<_Tp, __v> type;
+};
+
+template<typename _Tp, _Tp __v>
+constexpr _Tp integral_constant<_Tp, __v>::value;
+
+typedef integral_constant<bool, false> false_type;
+
+
+template<typename _T1>
+struct Alien
+{
+};
+
+template<typename _T1>
+bool operator==(const Alien<_T1>& __x, const Alien<_T1>& __y);
+
+template<typename _Rep>
+struct duration;
+
+template<bool _DenIsOne>
+struct __duration_cast_impl
+{
+};
+
+template<typename _ToDur, typename _Rep>
+long Frob (const duration<_Rep>& __d)
+{
+  typedef __duration_cast_impl<// finds ::operator==
+			       _ToDur::num == 1> __dc;
+
+  return 0;
+}
+
+template<typename _Rep>
+struct duration
+{
+public:
+  constexpr duration() = default;
+
+  duration (const duration& __d)
+  {
+    Frob <duration> (__d);
+  }
+};
+
+template<typename _Tp>
+struct __atomic_semaphore
+{
+  template<typename _Rep>
+  bool _M_try_acquire_for (const duration<_Rep>& __rtime) noexcept;
+
+  void _M_release() noexcept;
+};
+
+template<long __least_max_value>
+class counting_semaphore
+{
+  __atomic_semaphore<unsigned> _M_sem;
+
+public:
+  explicit counting_semaphore() noexcept;
+
+  void release() noexcept (noexcept (_M_sem._M_release ()));
+};
+
+class stop_token
+{
+public:
+  counting_semaphore<1> _M_done;
+};
+
+bool operator==(const stop_token& __a, const stop_token& __b);
diff --git c/gcc/testsuite/g++.dg/modules/noexcept-1_a.H w/gcc/testsuite/g++.dg/modules/noexcept-1_a.H
new file mode 100644
index 00000000000..00949cf5a3c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/noexcept-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options {-std=c++20 -fmodule-header} }
+// { dg-module-cmi {} }
+
+#include "noexcept-1.h"
diff --git c/gcc/testsuite/g++.dg/modules/noexcept-1_b.C w/gcc/testsuite/g++.dg/modules/noexcept-1_b.C
new file mode 100644
index 00000000000..62a13fcf6a7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/noexcept-1_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options {-std=c++20 -fmodules-ts -fno-module-lazy} }
+
+#include "noexcept-1.h"
+import "noexcept-1_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/ns-alias-1_a.C w/gcc/testsuite/g++.dg/modules/ns-alias-1_a.C
new file mode 100644
index 00000000000..9f501eee166
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-alias-1_a.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export namespace detail {
+  using bob = int;
+}
+
+namespace elsewhere {
+export namespace det = ::detail;
+namespace ail = ::detail;
+
+void frob (det::bob);
+
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-alias-1_b.C w/gcc/testsuite/g++.dg/modules/ns-alias-1_b.C
new file mode 100644
index 00000000000..55fd9268b44
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-alias-1_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module foo;
+
+elsewhere::det::bob j;
+elsewhere::ail::bob k;
diff --git c/gcc/testsuite/g++.dg/modules/ns-alias-1_c.C w/gcc/testsuite/g++.dg/modules/ns-alias-1_c.C
new file mode 100644
index 00000000000..9e4a81dce82
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-alias-1_c.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import foo;
+
+elsewhere::det::bob j;
+elsewhere::ail::bob k; // { dg-error "does not name a type" }
diff --git c/gcc/testsuite/g++.dg/modules/ns-dir-1_a.C w/gcc/testsuite/g++.dg/modules/ns-dir-1_a.C
new file mode 100644
index 00000000000..d63f9fd8aaa
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-dir-1_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+
+export module bob;
+// { dg-module-cmi bob }
+
+namespace detail {
+int i;
+}
+
+namespace elsewhere {
+
+export inline void frob ()
+{
+  using namespace detail;
+  i = 5;
+}
+
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-dir-1_b.C w/gcc/testsuite/g++.dg/modules/ns-dir-1_b.C
new file mode 100644
index 00000000000..b26e7875a6e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-dir-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import bob;
+
+void foo ()
+{
+  elsewhere::frob ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-dup-1_a.C w/gcc/testsuite/g++.dg/modules/ns-dup-1_a.C
new file mode 100644
index 00000000000..600f518207a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-dup-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export namespace std 
+{
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-dup-1_b.C w/gcc/testsuite/g++.dg/modules/ns-dup-1_b.C
new file mode 100644
index 00000000000..23190db013e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-dup-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options {-fmodules-ts -Wno-pedantic} }
+
+module;
+# 5 __FILE__ 1
+namespace std {}
+# 7 "" 2
+export module bob;
+// { dg-module-cmi bob }
+
+import foo;
+namespace std {}
diff --git c/gcc/testsuite/g++.dg/modules/ns-imp-1_a.C w/gcc/testsuite/g++.dg/modules/ns-imp-1_a.C
new file mode 100644
index 00000000000..9a91a1e1970
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-imp-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Foo;
+// { dg-module-cmi {Foo} }
+
+namespace Bob
+{
+export int Random ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-imp-1_b.C w/gcc/testsuite/g++.dg/modules/ns-imp-1_b.C
new file mode 100644
index 00000000000..449c70513c5
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-imp-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Bar;
+// { dg-module-cmi {Bar} }
+
+export import Foo;
+
+namespace Bob
+{
+export int Quux ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-imp-1_c.C w/gcc/testsuite/g++.dg/modules/ns-imp-1_c.C
new file mode 100644
index 00000000000..2a58a919661
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-imp-1_c.C
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodules-ts }
+
+export import Foo;
+export import Bar;
+
+namespace Bob
+{
+void Widget ()
+{
+  Random ();
+  Quux ();
+}
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-part-1_a.C w/gcc/testsuite/g++.dg/modules/ns-part-1_a.C
new file mode 100644
index 00000000000..5b761dfb11e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-part-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Foo:A;
+// { dg-module-cmi {Foo:A} }
+
+namespace Bob
+{
+export int Random ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-part-1_b.C w/gcc/testsuite/g++.dg/modules/ns-part-1_b.C
new file mode 100644
index 00000000000..d5b49b88ea9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-part-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Foo:B;
+// { dg-module-cmi {Foo:B} }
+
+export import :A;
+
+namespace Bob
+{
+export int Quux ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/ns-part-1_c.C w/gcc/testsuite/g++.dg/modules/ns-part-1_c.C
new file mode 100644
index 00000000000..ee0ec4018d7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ns-part-1_c.C
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodules-ts }
+
+export module Foo;
+// { dg-module-cmi {Foo} }
+
+export import :A;
+export import :B;
+
+namespace Bob
+{
+export void Widget ()
+{
+  Random ();
+  Quux ();
+}
+}
diff --git c/gcc/testsuite/g++.dg/modules/nsdmi-1_a.C w/gcc/testsuite/g++.dg/modules/nsdmi-1_a.C
new file mode 100644
index 00000000000..8e26d3cf832
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/nsdmi-1_a.C
@@ -0,0 +1,9 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodules-ts }
+export module nsdmi;
+// { dg-module-cmi nsdmi }
+
+export struct Bob
+{
+  int m = 42;
+};
diff --git c/gcc/testsuite/g++.dg/modules/nsdmi-1_b.C w/gcc/testsuite/g++.dg/modules/nsdmi-1_b.C
new file mode 100644
index 00000000000..032cf5be986
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/nsdmi-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+import nsdmi;
+
+int main ()
+{
+  Bob b;
+
+  return b.m != 42;
+}
diff --git c/gcc/testsuite/g++.dg/modules/nsdmi-2.C w/gcc/testsuite/g++.dg/modules/nsdmi-2.C
new file mode 100644
index 00000000000..081c1a154fe
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/nsdmi-2.C
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+export module foo;
+// { dg-module-cmi foo }
+
+
+export enum class file_type : signed char { none = 0 };
+
+export class directory_entry
+{
+public:
+  directory_entry(int);
+    
+  int _M_path;
+
+  // ICE from deferred_parse NSDMI in as_base class
+  file_type _M_type = file_type::none;
+};
+
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl definition '::directory_entry'\n  \[1\]=decl definition '::directory_entry::__as_base '\n  \[2\]=decl declaration '::directory_entry::__ct '\n} module } }
diff --git c/gcc/testsuite/g++.dg/modules/omp-1_a.C w/gcc/testsuite/g++.dg/modules/omp-1_a.C
new file mode 100644
index 00000000000..722720a0e93
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/omp-1_a.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts -fopenmp" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export inline void frob (unsigned (&ary)[64])
+{
+  int sum = 0;
+
+#pragma omp for
+  for (unsigned ix = 0; ix < 64; ix++)
+    sum += ary[ix];
+
+#pragma omp simd safelen(16) aligned (ary : 16)
+  for (unsigned ix = 0; ix < 64; ix++)
+    ary[ix] *= 2;
+}
diff --git c/gcc/testsuite/g++.dg/modules/omp-1_b.C w/gcc/testsuite/g++.dg/modules/omp-1_b.C
new file mode 100644
index 00000000000..f3f5d92e517
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/omp-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fopenmp" }
+
+import foo;
+
+unsigned ary[64];
+
+int main ()
+{
+  frob (ary);
+}
diff --git c/gcc/testsuite/g++.dg/modules/omp-1_c.C w/gcc/testsuite/g++.dg/modules/omp-1_c.C
new file mode 100644
index 00000000000..f30f6115277
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/omp-1_c.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import foo;
+
+// { dg-regexp "In module imported at \[^\n]*omp-1_c.C:3:1:\nfoo: error: module contains OpenMP, use '-fopenmp' to enable\n" }
+// { dg-prune-output "failed to read" }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "compilation terminated" }
diff --git c/gcc/testsuite/g++.dg/modules/omp-2_a.C w/gcc/testsuite/g++.dg/modules/omp-2_a.C
new file mode 100644
index 00000000000..d2291b6bbe0
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/omp-2_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts -fopenmp" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+// The OpenMPness doesn't escape to the interface.
+export void frob (unsigned (&ary)[64])
+{
+  int sum = 0;
+
+#pragma omp for
+  for (unsigned ix = 0; ix < 64; ix++)
+    sum += ary[ix];
+
+#pragma omp simd safelen(16) aligned (ary : 16)
+  for (unsigned ix = 0; ix < 64; ix++)
+    ary[ix] *= 2;
+}
diff --git c/gcc/testsuite/g++.dg/modules/omp-2_b.C w/gcc/testsuite/g++.dg/modules/omp-2_b.C
new file mode 100644
index 00000000000..39f34c70275
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/omp-2_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import foo;
+
+unsigned ary[64];
+
+int main ()
+{
+  frob (ary);
+}
diff --git c/gcc/testsuite/g++.dg/modules/only-1.C w/gcc/testsuite/g++.dg/modules/only-1.C
new file mode 100644
index 00000000000..97dcb1d0cf1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/only-1.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fmodule-only" }
+
+export module bob;
+// { dg-module-cmi bob }
diff --git c/gcc/testsuite/g++.dg/modules/only-2.C w/gcc/testsuite/g++.dg/modules/only-2.C
new file mode 100644
index 00000000000..6be8c767d3e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/only-2.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodule-only" }
+
+
+int i;
+// { dg-warning "for non-interface" "" { target *-*-* } 0 }
diff --git c/gcc/testsuite/g++.dg/modules/only-3.C w/gcc/testsuite/g++.dg/modules/only-3.C
new file mode 100644
index 00000000000..a3c61c4bf64
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/only-3.C
@@ -0,0 +1,5 @@
+// { dg-options "-fmodule-only" }
+
+
+int i;
+// { dg-warning "for non-interface" "" { target *-*-* } 0 }
diff --git c/gcc/testsuite/g++.dg/modules/operator-1_a.C w/gcc/testsuite/g++.dg/modules/operator-1_a.C
new file mode 100644
index 00000000000..d7a7176eb99
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/operator-1_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options {-fmodules-ts -Wno-pedantic} }
+
+module;
+# 5 __FILE__ 1
+
+struct Type {};
+bool operator==(Type const &, Type const &);
+
+# 10 "" 2
+export module Foo;
+// { dg-module-cmi Foo }
+
+export template<typename T>
+bool equal (T const &x, T const &y)
+{
+  return x == y;
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/operator-1_b.C w/gcc/testsuite/g++.dg/modules/operator-1_b.C
new file mode 100644
index 00000000000..dab8d1093b9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/operator-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options {-fmodules-ts -Wno-pedantic} }
+
+struct Type {};
+
+import Foo;
+
+bool foo (Type const &t)
+{
+  return equal (t, t);
+}
diff --git c/gcc/testsuite/g++.dg/modules/p0713-1.C w/gcc/testsuite/g++.dg/modules/p0713-1.C
new file mode 100644
index 00000000000..f7d8006cd58
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/p0713-1.C
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodules-ts" }
+module;
+module; // { dg-error "expected" }
diff --git c/gcc/testsuite/g++.dg/modules/p0713-2.C w/gcc/testsuite/g++.dg/modules/p0713-2.C
new file mode 100644
index 00000000000..c7846e450a9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/p0713-2.C
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodules-ts" }
+int j;
+module; // { dg-error "not permitted" }
diff --git c/gcc/testsuite/g++.dg/modules/p0713-3.C w/gcc/testsuite/g++.dg/modules/p0713-3.C
new file mode 100644
index 00000000000..3c539ebab3e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/p0713-3.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+int k;
+module frob; // { dg-error "not permitted" }
+// { dg-prune-output "failed to read" }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "compilation terminated" }
diff --git c/gcc/testsuite/g++.dg/modules/part-1_a.C w/gcc/testsuite/g++.dg/modules/part-1_a.C
new file mode 100644
index 00000000000..de58a20fab4
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+// { dg-module-cmi foo:baz }
+
+export module foo:baz;
+
+export int baz ()
+{
+  return -1;
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-1_b.C w/gcc/testsuite/g++.dg/modules/part-1_b.C
new file mode 100644
index 00000000000..c908c22e395
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-1_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export import :baz;
+
+export int foo (int a)
+{
+  return a;
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-1_c.C w/gcc/testsuite/g++.dg/modules/part-1_c.C
new file mode 100644
index 00000000000..88b033036dc
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-1_c.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+int main ()
+{
+  if (baz () != -1)
+    return 1;
+
+  if (foo (42) != 42)
+    return 2;
+
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-2_a.C w/gcc/testsuite/g++.dg/modules/part-2_a.C
new file mode 100644
index 00000000000..60fbe9942e5
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-2_a.C
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo:inter;
+// { dg-module-cmi foo:inter }
diff --git c/gcc/testsuite/g++.dg/modules/part-2_b.C w/gcc/testsuite/g++.dg/modules/part-2_b.C
new file mode 100644
index 00000000000..c9bbac8e5e1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-2_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo:imp;
+// { dg-module-cmi foo:imp }
+
+import :inter; // ok
diff --git c/gcc/testsuite/g++.dg/modules/part-2_c.C w/gcc/testsuite/g++.dg/modules/part-2_c.C
new file mode 100644
index 00000000000..759f1c9260c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-2_c.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo:inter2;
+// { dg-module-cmi foo:inter2 }
+
+import :imp; // ok
+
+import :inter; // ok at this point
diff --git c/gcc/testsuite/g++.dg/modules/part-2_d.C w/gcc/testsuite/g++.dg/modules/part-2_d.C
new file mode 100644
index 00000000000..b2e72891bc4
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-2_d.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi !foo }
+
+import :imp; // ok
+
+export import :inter2; // ok
+
+// { dg-regexp "In module imported at \[^\n]*part-2_b.C:6:.,\nof module foo:imp, imported at \[^\n]*part-2_d.C:6:\nfoo:inter: error: interface partition is not exported\n" }
diff --git c/gcc/testsuite/g++.dg/modules/part-2_e.C w/gcc/testsuite/g++.dg/modules/part-2_e.C
new file mode 100644
index 00000000000..677c066ad6b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-2_e.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+import :imp; // ok
+
+export import :inter2; // ok
+
+export import :inter; // ok now
+
diff --git c/gcc/testsuite/g++.dg/modules/part-3_a.C w/gcc/testsuite/g++.dg/modules/part-3_a.C
new file mode 100644
index 00000000000..85100d27123
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-3_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+export module foo:bar;
+// { dg-module-cmi foo:bar }
+
+int foo (int x)
+{
+  return -x;
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-3_b.C w/gcc/testsuite/g++.dg/modules/part-3_b.C
new file mode 100644
index 00000000000..a60ad3ee997
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-3_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo:baz;
+// { dg-module-cmi foo:baz }
+
+int foo (int);
diff --git c/gcc/testsuite/g++.dg/modules/part-3_c.C w/gcc/testsuite/g++.dg/modules/part-3_c.C
new file mode 100644
index 00000000000..aff74766436
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-3_c.C
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export import :bar;
+export import :baz;
+
+export inline int frob (int x)
+{
+  return foo (x);
+}
+
+// { dg-final { scan-lang-dump {Read:-[0-9]'s named merge key \(new\) function_decl:'::foo'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]'s named merge key \(matched\) function_decl:'::foo'} module } }
+// { dg-final { scan-lang-dump {Cluster sections are \[1,3\)} module } }
diff --git c/gcc/testsuite/g++.dg/modules/part-3_d.C w/gcc/testsuite/g++.dg/modules/part-3_d.C
new file mode 100644
index 00000000000..d07274a3fa7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-3_d.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" }
+import foo;
+
+int main ()
+{
+  int r = frob (75);
+  return !(r == -75);
+}
+
+// { dg-final { scan-lang-dump { Read:-[0-9]'s named merge key \(unique\) function_decl:'::frob'} module } }
+// { dg-final { scan-lang-dump {>  Read:-[0-9]'s named merge key \(unique\) function_decl:'::foo'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/part-4_a.C w/gcc/testsuite/g++.dg/modules/part-4_a.C
new file mode 100644
index 00000000000..edd606bbcdc
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-4_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 c/gcc/testsuite/g++.dg/modules/part-4_b.C w/gcc/testsuite/g++.dg/modules/part-4_b.C
new file mode 100644
index 00000000000..a200ecac3d6
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-4_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+// detecting an ICE in dumping machinery
+
+export module foo;
+// { dg-module-cmi foo }
+
+export import :part1;
+
+export frob foo ()
+{
+  return frob ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-4_c.C w/gcc/testsuite/g++.dg/modules/part-4_c.C
new file mode 100644
index 00000000000..1f319cccf20
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-4_c.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+import foo;
+
+void f ()
+{
+  auto f = foo ();
+
+  decltype (f)::inner x;
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-6_a.C w/gcc/testsuite/g++.dg/modules/part-6_a.C
new file mode 100644
index 00000000000..8fece83349e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-6_a.C
@@ -0,0 +1,15 @@
+// { dg-module-do link }
+// { dg-additional-options -fmodules-ts }
+
+export module foo:exp;
+// { dg-module-cmi foo:exp }
+
+export class Foo
+{
+  Foo ();
+
+public:
+  void Func ();
+
+  static Foo *Factory ();
+};
diff --git c/gcc/testsuite/g++.dg/modules/part-6_b.C w/gcc/testsuite/g++.dg/modules/part-6_b.C
new file mode 100644
index 00000000000..0bad008db9e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-6_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export import :exp;
diff --git c/gcc/testsuite/g++.dg/modules/part-6_c.C w/gcc/testsuite/g++.dg/modules/part-6_c.C
new file mode 100644
index 00000000000..395e7096683
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-6_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+module foo:bits;
+import :exp;
+
+void Foo::Func () 
+{
+}
+
+inline Foo::Foo ()
+{
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-6_d.C w/gcc/testsuite/g++.dg/modules/part-6_d.C
new file mode 100644
index 00000000000..71783a6a360
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-6_d.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+module foo;
+import :bits;
+
+Foo *Foo::Factory ()
+{
+  return new Foo ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-6_e.C w/gcc/testsuite/g++.dg/modules/part-6_e.C
new file mode 100644
index 00000000000..6c1ba4c0995
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-6_e.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+int main ()
+{
+  Foo::Factory ()->Func ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/part-7_a.C w/gcc/testsuite/g++.dg/modules/part-7_a.C
new file mode 100644
index 00000000000..32b10f4b6be
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-7_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo:bill;
+// { dg-module-cmi foo:bill }
+
+export class frob;
+
+export template<int I> class FROB;
diff --git c/gcc/testsuite/g++.dg/modules/part-7_b.C w/gcc/testsuite/g++.dg/modules/part-7_b.C
new file mode 100644
index 00000000000..9a7eb134b1a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-7_b.C
@@ -0,0 +1,20 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-blocks} }
+
+module foo:bob;
+// { dg-module-cmi foo:bob }
+
+class frob
+{
+public:
+  int field;
+};
+
+template<int J>
+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 c/gcc/testsuite/g++.dg/modules/part-7_c.C w/gcc/testsuite/g++.dg/modules/part-7_c.C
new file mode 100644
index 00000000000..4e1df2af020
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-7_c.C
@@ -0,0 +1,19 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-blocks} }
+
+export module foo;
+// { dg-module-cmi foo }
+import :bob;
+export import :bill;
+
+int foo (frob *p)
+{
+  return p->field;
+}
+
+int foo (FROB<2> *p)
+{
+  return p->val;
+}
+
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl definition '::frob@foo:bob:1'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl definition '::template FROB@foo:bob:1'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/part-hdr-1_a.H w/gcc/testsuite/g++.dg/modules/part-hdr-1_a.H
new file mode 100644
index 00000000000..62f3b7d4e69
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-hdr-1_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
diff --git c/gcc/testsuite/g++.dg/modules/part-hdr-1_b.C w/gcc/testsuite/g++.dg/modules/part-hdr-1_b.C
new file mode 100644
index 00000000000..93759097f24
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-hdr-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+// { dg-module-cmi {mod:impl} }
+
+module;
+# 6 "inner" 1
+import "part-hdr-1_a.H";
+# 8 "" 2
+module mod:impl;
+
diff --git c/gcc/testsuite/g++.dg/modules/part-hdr-1_c.C w/gcc/testsuite/g++.dg/modules/part-hdr-1_c.C
new file mode 100644
index 00000000000..78a53d2fda3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-hdr-1_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi {mod} }
+
+export module mod;
+import mod:impl;
diff --git c/gcc/testsuite/g++.dg/modules/part-mac-1_a.H w/gcc/testsuite/g++.dg/modules/part-mac-1_a.H
new file mode 100644
index 00000000000..191525dc44d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-mac-1_a.H
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#define FOO(X) int X
+
diff --git c/gcc/testsuite/g++.dg/modules/part-mac-1_b.C w/gcc/testsuite/g++.dg/modules/part-mac-1_b.C
new file mode 100644
index 00000000000..2adc3b08c0c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-mac-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+// { dg-module-cmi {mod:impl} }
+
+module;
+# 6 "inner" 1
+import "part-mac-1_a.H";
+# 8 "" 2
+module mod:impl;
+
+FOO(k);
diff --git c/gcc/testsuite/g++.dg/modules/part-mac-1_c.C w/gcc/testsuite/g++.dg/modules/part-mac-1_c.C
new file mode 100644
index 00000000000..78a53d2fda3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/part-mac-1_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi {mod} }
+
+export module mod;
+import mod:impl;
diff --git c/gcc/testsuite/g++.dg/modules/partial-1.h w/gcc/testsuite/g++.dg/modules/partial-1.h
new file mode 100644
index 00000000000..0f911076762
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/partial-1.h
@@ -0,0 +1,30 @@
+
+template<typename _Tp>
+class allocator {};
+
+template<typename _Alloc> struct allocator_traits;
+
+template<typename _Tp>
+struct allocator_traits <allocator<_Tp>>
+{
+  using pointer = _Tp*;
+};
+
+struct mutex {};
+
+template<typename _Tp, typename _Alloc>
+class Inplace
+{
+public:
+  virtual void _M_dispose() noexcept
+  {
+    // bogus error ambiguous partial specializations
+    typename allocator_traits<_Alloc>::pointer v;
+  }
+};
+
+inline void *
+allocate_shared()
+{
+  return new Inplace<mutex, allocator<mutex>> ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/partial-1_a.H w/gcc/testsuite/g++.dg/modules/partial-1_a.H
new file mode 100644
index 00000000000..164a54c8c9e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/partial-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "partial-1.h"
diff --git c/gcc/testsuite/g++.dg/modules/partial-1_b.C w/gcc/testsuite/g++.dg/modules/partial-1_b.C
new file mode 100644
index 00000000000..7e981eb0be4
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/partial-1_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+#include "partial-1.h"
+import "partial-1_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/pmf-1.h w/gcc/testsuite/g++.dg/modules/pmf-1.h
new file mode 100644
index 00000000000..e4c99f5e6f1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmf-1.h
@@ -0,0 +1,10 @@
+
+struct X 
+{
+  int mfn ();
+};
+
+inline void bob (X &)
+{
+  int (X::*pmf) () = &X::mfn;
+}
diff --git c/gcc/testsuite/g++.dg/modules/pmf-1_a.H w/gcc/testsuite/g++.dg/modules/pmf-1_a.H
new file mode 100644
index 00000000000..c597db1fe8a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmf-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "pmf-1.h"
diff --git c/gcc/testsuite/g++.dg/modules/pmf-1_b.C w/gcc/testsuite/g++.dg/modules/pmf-1_b.C
new file mode 100644
index 00000000000..0b086107045
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmf-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "pmf-1.h"
+import "pmf-1_a.H";
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
+// The function-scope var is unique
+// { dg-final { scan-lang-dump-times {merge key \(unique\)} 1 module } }
diff --git c/gcc/testsuite/g++.dg/modules/pmf-2.h w/gcc/testsuite/g++.dg/modules/pmf-2.h
new file mode 100644
index 00000000000..890b9856c43
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmf-2.h
@@ -0,0 +1,26 @@
+template<typename _Tp>
+struct remove_reference
+{ typedef _Tp FOO; };
+
+template<typename _Tp>
+void forward (typename remove_reference<_Tp>::FOO const& __t)
+{
+}
+
+template<typename _Callable>
+void __invoke(_Callable const & __fn)
+{
+  forward<_Callable const>(__fn);
+}
+
+class _State_baseV2
+{
+public:
+  void _M_set_result()
+  {
+    __invoke (&_State_baseV2::_M_do_set);
+  }
+
+  void _M_do_set();
+};
+
diff --git c/gcc/testsuite/g++.dg/modules/pmf-2_a.H w/gcc/testsuite/g++.dg/modules/pmf-2_a.H
new file mode 100644
index 00000000000..b6bd763b745
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmf-2_a.H
@@ -0,0 +1,6 @@
+// { dg-additional-options {-fmodule-header -fdump-lang-module-uid} }
+// { dg-module-cmi {} }
+
+#include "pmf-2.h"
+
+// { dg-final { scan-lang-dump-times {Written:-[0-9]* ptrmem type} 1 module } }
diff --git c/gcc/testsuite/g++.dg/modules/pmf-2_b.C w/gcc/testsuite/g++.dg/modules/pmf-2_b.C
new file mode 100644
index 00000000000..b76f090ff7b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmf-2_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-uid" }
+
+#include "pmf-2.h"
+import "pmf-2_a.H";
+
+// { dg-final { scan-lang-dump {Cloned:-[0-9]* typedef template_type_parm:'::template remove_reference<_Tp>::template FOO<_Tp>'} module } }
+// { dg-final { scan-lang-dump {Created:-[0-9]* ptrmem type} module } }
diff --git c/gcc/testsuite/g++.dg/modules/pmp-1_a.C w/gcc/testsuite/g++.dg/modules/pmp-1_a.C
new file mode 100644
index 00000000000..2832692faa6
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmp-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+export module bob;
+// { dg-module-cmi bob }
+int k;
+
+module :private; // { dg-message "sorry, unimplemented: private module fragment" }
+int i;
diff --git c/gcc/testsuite/g++.dg/modules/pmp-1_b.C w/gcc/testsuite/g++.dg/modules/pmp-1_b.C
new file mode 100644
index 00000000000..40cb0fa5278
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmp-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+
+module bob;
+int k;
+
+module :private; // { dg-error "private module fragment" }
+int i;
diff --git c/gcc/testsuite/g++.dg/modules/pmp-2.C w/gcc/testsuite/g++.dg/modules/pmp-2.C
new file mode 100644
index 00000000000..56ce48f9a7f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmp-2.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+
+export module bob;
+// { dg-module-cmi bob }
+
+module :private; // { dg-message "sorry, unimplemented: private module fragment" }
+int i;
diff --git c/gcc/testsuite/g++.dg/modules/pmp-3.C w/gcc/testsuite/g++.dg/modules/pmp-3.C
new file mode 100644
index 00000000000..8c68bbe89a3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pmp-3.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+int k;
+
+module :private; // { dg-error "private module fragment" }
+int i;
diff --git c/gcc/testsuite/g++.dg/modules/pragma-1_a.H w/gcc/testsuite/g++.dg/modules/pragma-1_a.H
new file mode 100644
index 00000000000..6eb0a5900a7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pragma-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+
+// { dg-module-cmi {} }
+int i;
diff --git c/gcc/testsuite/g++.dg/modules/pragma-1_b.C w/gcc/testsuite/g++.dg/modules/pragma-1_b.C
new file mode 100644
index 00000000000..55d5de3d537
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pragma-1_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+#pragma GCC visibility push (default)
+#pragma GCC visibility pop
+
+import "pragma-1_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/predef-1.C w/gcc/testsuite/g++.dg/modules/predef-1.C
new file mode 100644
index 00000000000..07a85b0e6b1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/predef-1.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts -nostdinc -include [srcdir]/predef-1.h" }
+// { dg-additional-files predef-1.C }
+
+// test macro expansion inside forced header
+
+export module bob;
diff --git c/gcc/testsuite/g++.dg/modules/predef-1.h w/gcc/testsuite/g++.dg/modules/predef-1.h
new file mode 100644
index 00000000000..ab366d59a5a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/predef-1.h
@@ -0,0 +1,10 @@
+
+// expands a macro (inside #if conditional) inside forced header.
+// modelled on glibc's stdc_predef.h
+
+#define GCC_IEC_559 1
+
+# if GCC_IEC_559 > 0
+#  define STDC_IEC_559__		1
+# endif
+
diff --git c/gcc/testsuite/g++.dg/modules/predef-2.h w/gcc/testsuite/g++.dg/modules/predef-2.h
new file mode 100644
index 00000000000..79486f1a253
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/predef-2.h
@@ -0,0 +1,7 @@
+
+// expands a macro (inside #if conditional) inside forced header.
+// modelled on glibc's stdc_predef.h
+
+// some builtin macro
+# if __GNUC__ > 0
+# endif
diff --git c/gcc/testsuite/g++.dg/modules/predef-2_a.C w/gcc/testsuite/g++.dg/modules/predef-2_a.C
new file mode 100644
index 00000000000..bbf83440cce
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/predef-2_a.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -nostdinc -include [srcdir]/predef-2.h" }
+// { dg-additional-files predef-2.h }
+
+// test macro expansion inside forced header
+
+export module bob:part;
+// { dg-module-cmi bob:part }
diff --git c/gcc/testsuite/g++.dg/modules/predef-2_b.C w/gcc/testsuite/g++.dg/modules/predef-2_b.C
new file mode 100644
index 00000000000..d0dfb885933
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/predef-2_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -nostdinc -include [srcdir]/predef-2.h" }
+// { dg-additional-files predef-2.h }
+
+// test macro expansion inside forced header
+
+export module bob;
+// { dg-module-cmi bob }
+
+export import :part;
diff --git c/gcc/testsuite/g++.dg/modules/preproc-1.C w/gcc/testsuite/g++.dg/modules/preproc-1.C
new file mode 100644
index 00000000000..e7ba6d6f02b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/preproc-1.C
@@ -0,0 +1,3 @@
+# 0 "preproc-1.C"
+// { dg-additional-options "-fmodule-header -fpreprocessed" }
+// { dg-module-cmi {=gcm.cache/,/preproc-1.C.gcm} }
diff --git c/gcc/testsuite/g++.dg/modules/preproc-2_a.H w/gcc/testsuite/g++.dg/modules/preproc-2_a.H
new file mode 100644
index 00000000000..8e81fb51a83
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/preproc-2_a.H
@@ -0,0 +1,11 @@
+# 0 "preproc-2_a.H"
+# 0 "<built-in>"
+#define __STDC__ 1
+# 0 "<command-line>"
+#define NAME bob
+# 1 "preproc-2_a.H"
+# 8 "preproc-2_a.H"
+void NAME ();
+
+// { dg-additional-options "-fmodules-ts -fpreprocessed -fdirectives-only" }
+// { dg-module-cmi {,/preproc-2_a.H} }
diff --git c/gcc/testsuite/g++.dg/modules/preproc-2_b.C w/gcc/testsuite/g++.dg/modules/preproc-2_b.C
new file mode 100644
index 00000000000..8ce21fdcdba
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/preproc-2_b.C
@@ -0,0 +1,21 @@
+# 0 "preproc-2_b.C"
+# 0 "<built-in>"
+#define __STDC__ 1
+# 0 "<command-line>"
+# 1 "preproc-2_b.C"
+# 7 "preproc-2_b.C"
+import "./preproc-2_a.H";
+
+#define NAME bill
+
+int NAME = 4;
+
+int bob; // error with header
+
+float NAME; // error with self
+
+// { dg-additional-options "-fmodules-ts -fpreprocessed -fdirectives-only" }
+
+// { dg-regexp {preproc-2_b.C:13:5: error: 'int bob' redeclared as different kind of entity\nIn module ./preproc-2_a.H, imported at preproc-2_b.C:7:\n<command-line>: note: previous declaration 'void bob\(\)'\npreproc-2_a.H:8:6: note: in expansion of macro 'NAME'} }
+
+// { dg-regexp {preproc-2_b.C:9:14: error: conflicting declaration 'float bill'\npreproc-2_b.C:15:7: note: in expansion of macro 'NAME'\npreproc-2_b.C:9:14: note: previous declaration as 'int bill'\npreproc-2_b.C:11:5: note: in expansion of macro 'NAME'} }
diff --git c/gcc/testsuite/g++.dg/modules/printf-1_a.H w/gcc/testsuite/g++.dg/modules/printf-1_a.H
new file mode 100644
index 00000000000..900c0631515
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/printf-1_a.H
@@ -0,0 +1,9 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+extern "C" 
+{
+  // this matches an anticipated fn
+  extern int printf (const char *__restrict, ...);
+}
diff --git c/gcc/testsuite/g++.dg/modules/printf-1_b.C w/gcc/testsuite/g++.dg/modules/printf-1_b.C
new file mode 100644
index 00000000000..a434e762833
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/printf-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+import "printf-1_a.H";
+
+int main ()
+{
+  printf ("hello world!\n");
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/reparent-1_a.C w/gcc/testsuite/g++.dg/modules/reparent-1_a.C
new file mode 100644
index 00000000000..c5450985ecc
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/reparent-1_a.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+// { dg-module-cmi foo }
+
+
+export module foo;
+export void v ();
diff --git c/gcc/testsuite/g++.dg/modules/reparent-1_b.C w/gcc/testsuite/g++.dg/modules/reparent-1_b.C
new file mode 100644
index 00000000000..b44ae1cafb3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/reparent-1_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options {-fmodules-ts -Wno-pedantic} }
+// { dg-module-cmi bar }
+
+
+module;
+# 7 "gmf1" 1
+# 8 "gmf2" 1
+# 9 "gmf3" 1
+import foo;
+# 11 "" 2
+# 12 "" 2
+# 13 "" 2
+export module bar;
+export import foo;
diff --git c/gcc/testsuite/g++.dg/modules/reparent-1_c.C w/gcc/testsuite/g++.dg/modules/reparent-1_c.C
new file mode 100644
index 00000000000..e4e984c87a9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/reparent-1_c.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+import bar;
+
+int main ()
+{
+  v (0); // { dg-error "too many arguments" }
+}
+
+// { dg -regexp {In module foo, imported at [^\n]*/reparent-1_b.C:14,\nof module bar, imported at [^\n]*/reparent-1_c.C:2:\n[^\n]*/reparent-1_a.C:6:13: note: declared here\n} }
diff --git c/gcc/testsuite/g++.dg/modules/scc-1.C w/gcc/testsuite/g++.dg/modules/scc-1.C
new file mode 100644
index 00000000000..a5d71f358c3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/scc-1.C
@@ -0,0 +1,16 @@
+// Check SCC regions are atomic
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export int bar (int);
+export int baz (int = bar (1));
+export int bar (int = baz (1));
+
+// The ordering depends on hash table iteration, which is address-dependent
+
+// { dg-final { scan-lang-dump { Writing named:-[0-9]* function_decl:'::bar'} "module" } }
+// { dg-final { scan-lang-dump { Writing named:-[0-9]* function_decl:'::baz'} "module" } }
+// { dg-final { scan-lang-dump {  \.[0-9]*\.  Wrote backref:-[0-9]* function_decl:'::ba[rz]'} "module" } }
+// { dg-final { scan-lang-dump { Wrote backref:-[0-9]* function_decl:'::ba[rz]'} "module" } }
diff --git c/gcc/testsuite/g++.dg/modules/scc-2.C w/gcc/testsuite/g++.dg/modules/scc-2.C
new file mode 100644
index 00000000000..385f27c45dd
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/scc-2.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+export module frob;
+// { dg-module-cmi frob }
+
+export enum X 
+{
+  One, Two, Three
+};
diff --git c/gcc/testsuite/g++.dg/modules/shadow-1_a.C w/gcc/testsuite/g++.dg/modules/shadow-1_a.C
new file mode 100644
index 00000000000..e4641aa529d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/shadow-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+export module shadow;
+// { dg-module-cmi shadow }
+
+export struct stat
+{
+};
+
+export void stat ();
diff --git c/gcc/testsuite/g++.dg/modules/shadow-1_b.C w/gcc/testsuite/g++.dg/modules/shadow-1_b.C
new file mode 100644
index 00000000000..646381237ac
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/shadow-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+import shadow;
+
+// unfortunately not the exact same diagnostic in both cases :(
+
+void stat (); // { dg-error "conflicts with import" }
+
+struct stat {}; // { dg-error "in a different module" }
diff --git c/gcc/testsuite/g++.dg/modules/stat-tpl-1_a.H w/gcc/testsuite/g++.dg/modules/stat-tpl-1_a.H
new file mode 100644
index 00000000000..fa4991f264d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/stat-tpl-1_a.H
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename _CharT>
+static inline __attribute__((__always_inline__)) constexpr void
+__constant_char_array_p ()
+{
+}
+
+inline void foo ()
+{
+  __constant_char_array_p<char> ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/static-1_a.C w/gcc/testsuite/g++.dg/modules/static-1_a.C
new file mode 100644
index 00000000000..6bfced5ec04
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/static-1_a.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+
+module;
+# 5 "gmf" 1
+static void Bar () {}
+# 7 "" 2
+export module Foo;
+// { dg-module-cmi Foo }
+
+static void Baz () {}
+
diff --git c/gcc/testsuite/g++.dg/modules/static-1_b.C w/gcc/testsuite/g++.dg/modules/static-1_b.C
new file mode 100644
index 00000000000..f2f170d49f0
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/static-1_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module Foo;
+
+void Frob ()
+{
+  Bar (); // { dg-error "not declared" }
+  Baz (); // { dg-error "not declared"  }
+}
+
+static void Baz () {}
+static void Bar () {}
+
+void Quux ()
+{
+  Bar ();
+  Baz ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/static-1_c.C w/gcc/testsuite/g++.dg/modules/static-1_c.C
new file mode 100644
index 00000000000..a7ab89aaea7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/static-1_c.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import Foo;
+
+void Frob ()
+{
+  Bar (); // { dg-error "not declared" }
+  Baz (); // { dg-error "not declared" }
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/std-1_a.C w/gcc/testsuite/g++.dg/modules/std-1_a.C
new file mode 100644
index 00000000000..53bdc7a1cd2
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/std-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+
+namespace std
+{
+int bob;
+}
diff --git c/gcc/testsuite/g++.dg/modules/std-1_b.C w/gcc/testsuite/g++.dg/modules/std-1_b.C
new file mode 100644
index 00000000000..3fa4f40d576
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/std-1_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+int *i = &std::bob;
diff --git c/gcc/testsuite/g++.dg/modules/stdns_a.C w/gcc/testsuite/g++.dg/modules/stdns_a.C
new file mode 100644
index 00000000000..2d2cdbbc139
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/stdns_a.C
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodules-ts }
+
+export module std;
+// { dg-module-cmi std }
+
+namespace std
+{
+export int frob () 
+{
+  return 1;
+}
+
+}
diff --git c/gcc/testsuite/g++.dg/modules/stdns_b.C w/gcc/testsuite/g++.dg/modules/stdns_b.C
new file mode 100644
index 00000000000..c00e120b837
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/stdns_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import std;
+
+int main ()
+{
+  return !std::frob ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/sv-1.h w/gcc/testsuite/g++.dg/modules/sv-1.h
new file mode 100644
index 00000000000..113ae1bb15a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sv-1.h
@@ -0,0 +1,75 @@
+template<bool __v>
+struct integral_constant {};
+
+typedef integral_constant<true> true_type;
+typedef integral_constant<false> false_type;
+
+template<typename>
+struct __is_not_void_helper
+  : public true_type { };
+
+template<> struct __is_not_void_helper<void>
+  : public false_type { };
+
+template<typename _Tp, typename _Up>
+struct is_same
+  : public integral_constant<__is_same_as(_Tp, _Up)> {};
+
+template<typename _Iterator>
+struct iterator_traits;
+
+template<typename _Tp> requires __is_not_void_helper<_Tp>::value
+struct iterator_traits<_Tp*>;
+
+template<typename _Tp>
+struct iterator {};
+
+template<typename _Iterator>
+class reverse_iterator
+  : public iterator<typename iterator_traits<_Iterator>::value_type>
+{
+};
+
+template<typename _Tp> struct _Deque_iterator;
+
+template<typename _Tp> void __copy_move_a1(_Deque_iterator<_Tp>);
+
+template<typename _Iterator>
+decltype (NOPE (_Iterator{})) __niter_base (reverse_iterator<_Iterator> __it);
+
+
+template<typename _II>
+inline void __copy_move_a (_II __first)
+{
+  __copy_move_a1 (__niter_base (__first));
+}
+
+template<typename _CharT>
+struct __gnu_char_traits
+{
+  static void move (const char* __s2)
+  {
+    __copy_move_a (__s2);
+  }
+};
+
+class string_view
+{
+  using t = __gnu_char_traits<char>;
+
+public:
+    string_view (const char* __str) noexcept;
+};
+
+template<typename _Ret>
+void __stoa ()
+{
+  struct _Range_chk {
+    static bool _S_chk (false_type) { return false; }
+    static bool _S_chk (true_type) { return true; }
+  };
+
+  _Range_chk::_S_chk (is_same<_Ret, long>{});
+}
+
+inline void stoi () { __stoa<long> (); }
diff --git c/gcc/testsuite/g++.dg/modules/sv-1_a.C w/gcc/testsuite/g++.dg/modules/sv-1_a.C
new file mode 100644
index 00000000000..8d866fde0b0
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sv-1_a.C
@@ -0,0 +1,7 @@
+// { dg-additional-options {-fmodules-ts -std=c++2a} }
+module;
+#include "sv-1.h"
+export module Hello;
+// { dg-module-cmi Hello }
+
+export void SayHello (string_view const &name);
diff --git c/gcc/testsuite/g++.dg/modules/sv-1_b.C w/gcc/testsuite/g++.dg/modules/sv-1_b.C
new file mode 100644
index 00000000000..72dbe593825
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sv-1_b.C
@@ -0,0 +1,15 @@
+// { dg-additional-options {-std=c++2a -fmodules-ts -fno-module-lazy} }
+#include "sv-1.h"
+import Hello;
+
+#if 0
+int main ()
+{
+  SayHello ("World");
+}
+#endif
+
+void foo ()
+{
+  is_same<long, int> q;
+}
diff --git c/gcc/testsuite/g++.dg/modules/sym-subst-1.C w/gcc/testsuite/g++.dg/modules/sym-subst-1.C
new file mode 100644
index 00000000000..96ee25c65b5
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sym-subst-1.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+export module bob.stuart.kevin;
+// { dg-module-cmi bob.stuart.kevin }
+
+class mytype 
+{
+};
+
+void frob (mytype &)
+{
+}
+
+// { dg-final { scan-assembler {_ZW3bob6stuart5kevinE4frobRW_2E6mytype:} } }
diff --git c/gcc/testsuite/g++.dg/modules/sym-subst-2_a.C w/gcc/testsuite/g++.dg/modules/sym-subst-2_a.C
new file mode 100644
index 00000000000..cd0a79dc729
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sym-subst-2_a.C
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module bob.stuart;
+// { dg-module-cmi bob.stuart }
+
+template <typename T> void inner (T &)
+{
+}
+
+export template <typename T> void foo (T &x)
+{
+  inner (x);
+}
+
+// { dg-final { scan-assembler-not {all must have scan-assembler} } }
diff --git c/gcc/testsuite/g++.dg/modules/sym-subst-2_b.C w/gcc/testsuite/g++.dg/modules/sym-subst-2_b.C
new file mode 100644
index 00000000000..fc3db0ac5f8
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sym-subst-2_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module bob.kevin;
+// { dg-module-cmi bob.kevin }
+
+import bob.stuart;
+
+class mytype 
+{
+};
+
+void bar (mytype &m)
+{
+  foo (m);
+}
+
+// { dg-final { scan-assembler {_ZW3bob5kevinE3barRW_1E6mytype:} } }
+// { dg-final { scan-assembler {_ZW3bob6stuartE5innerIW_05kevinE6mytypeEvRT_:} } }
diff --git c/gcc/testsuite/g++.dg/modules/sym-subst-3_a.C w/gcc/testsuite/g++.dg/modules/sym-subst-3_a.C
new file mode 100644
index 00000000000..bd958dc0dc3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sym-subst-3_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -std=c++17" }
+export module t.s;
+// { dg-module-cmi t.s }
+
+struct s;
+
+export s *S;
+
+// { dg-final { scan-assembler {.globa?l[ \t]*_?S\n} } }
diff --git c/gcc/testsuite/g++.dg/modules/sym-subst-3_b.C w/gcc/testsuite/g++.dg/modules/sym-subst-3_b.C
new file mode 100644
index 00000000000..9ae3f8f7816
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sym-subst-3_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -std=c++17" }
+export module t;
+// { dg-module-cmi t }
+import t.s;
+struct t;
+export void f (t*, decltype (S)){}
+// { dg-final { scan-assembler {_Z1fPW1tE1tPW_01sE1s:} } }
diff --git c/gcc/testsuite/g++.dg/modules/sym-subst-4.C w/gcc/testsuite/g++.dg/modules/sym-subst-4.C
new file mode 100644
index 00000000000..d2266c407f4
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sym-subst-4.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+export module zero.eins.zwei.drei.vier.funf.sechs.sieben.acht.neun;
+// We're in cologne!
+// { dg-module-cmi zero.eins.zwei.drei.vier.funf.sechs.sieben.acht.neun }
+
+class mytype 
+{
+};
+
+void frob (mytype &)
+{
+}
+
+// { dg-final { scan-assembler {_ZW4zero4eins4zwei4drei4vier4funf5sechs6sieben4acht4neunE4frobRW_9E6mytype:} } }
diff --git c/gcc/testsuite/g++.dg/modules/sym-subst-5.C w/gcc/testsuite/g++.dg/modules/sym-subst-5.C
new file mode 100644
index 00000000000..1e26e7594ef
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sym-subst-5.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+export module zero.eins.zwei.drei.vier.funf.sechs.sieben.acht.neun.zehn;
+// We're in cologne!
+// { dg-module-cmi zero.eins.zwei.drei.vier.funf.sechs.sieben.acht.neun.zehn }
+
+class mytype 
+{
+};
+
+void frob (mytype &)
+{
+}
+
+// { dg-final { scan-assembler {_ZW4zero4eins4zwei4drei4vier4funf5sechs6sieben4acht4neun4zehnE4frobRWW0_E6mytype:} } }
diff --git c/gcc/testsuite/g++.dg/modules/sym-subst-6.C w/gcc/testsuite/g++.dg/modules/sym-subst-6.C
new file mode 100644
index 00000000000..0a9ac6d8f38
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sym-subst-6.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+export module zero.eins.zwei.drei.vier.funf.sechs.sieben.acht.neun.zehn.elf;
+// We're in cologne!
+// { dg-module-cmi zero.eins.zwei.drei.vier.funf.sechs.sieben.acht.neun.zehn.elf }
+
+class mytype 
+{
+};
+
+void frob (mytype &)
+{
+}
+
+// { dg-final { scan-assembler {_ZW4zero4eins4zwei4drei4vier4funf5sechs6sieben4acht4neun4zehn3elfE4frobRWW1_E6mytype:} } }
diff --git c/gcc/testsuite/g++.dg/modules/sys/alias-2_a.H w/gcc/testsuite/g++.dg/modules/sys/alias-2_a.H
new file mode 100644
index 00000000000..5a058089725
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sys/alias-2_a.H
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodule-header -isystem [srcdir]/sys" }
+// { dg-module-cmi {} }
+
+#ifndef ALIAS_2_A_SYS
+#define ALIAS_2_A_SYS
+
+int frob (int);
+
+#endif
diff --git c/gcc/testsuite/g++.dg/modules/sys/inext-1.H w/gcc/testsuite/g++.dg/modules/sys/inext-1.H
new file mode 100644
index 00000000000..1ecfe80a39b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/sys/inext-1.H
@@ -0,0 +1,2 @@
+#define NEXT bob
+int foo ();
diff --git c/gcc/testsuite/g++.dg/modules/tdef-1_a.C w/gcc/testsuite/g++.dg/modules/tdef-1_a.C
new file mode 100644
index 00000000000..6bec2023f4e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module tdef;
+// { dg-module-cmi tdef }
+
+export struct A
+{
+  typedef int I;
+};
diff --git c/gcc/testsuite/g++.dg/modules/tdef-1_b.C w/gcc/testsuite/g++.dg/modules/tdef-1_b.C
new file mode 100644
index 00000000000..627d67215ec
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import tdef;
+
+A::I main ()
+{
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tdef-2_a.C w/gcc/testsuite/g++.dg/modules/tdef-2_a.C
new file mode 100644
index 00000000000..f7abf3064e3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-2_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module tdef;
+// { dg-module-cmi tdef }
+
+export typedef int I;
+typedef int J;
+
diff --git c/gcc/testsuite/g++.dg/modules/tdef-2_b.C w/gcc/testsuite/g++.dg/modules/tdef-2_b.C
new file mode 100644
index 00000000000..128e95ec8b5
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-2_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module tdef;
+
+I yup;
+J yupper;
diff --git c/gcc/testsuite/g++.dg/modules/tdef-2_c.C w/gcc/testsuite/g++.dg/modules/tdef-2_c.C
new file mode 100644
index 00000000000..387a41d8075
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-2_c.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import tdef;
+
+I main ()
+{
+  return 0;
+}
+
+J nope; // { dg-error "does not name a type" }
+
+typedef char J;
+
+static J ok;
diff --git c/gcc/testsuite/g++.dg/modules/tdef-3_a.C w/gcc/testsuite/g++.dg/modules/tdef-3_a.C
new file mode 100644
index 00000000000..8cc2276ce8f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-3_a.C
@@ -0,0 +1,7 @@
+// { dg-module-do run }
+
+// { dg-additional-options -fmodules-ts }
+export module frob;
+// { dg-module-cmi frob }
+
+export typedef struct { int m; } frob;
diff --git c/gcc/testsuite/g++.dg/modules/tdef-3_b.C w/gcc/testsuite/g++.dg/modules/tdef-3_b.C
new file mode 100644
index 00000000000..9980acf06e7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-3_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+export module quux;
+// { dg-module-cmi quux }
+import frob;
+
+export int foo (frob *p)
+{
+  return p->m;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tdef-3_c.C w/gcc/testsuite/g++.dg/modules/tdef-3_c.C
new file mode 100644
index 00000000000..378415d5daf
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-3_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+
+import frob;
+import quux;
+
+int main ()
+{
+  frob f {2};
+
+  return !(foo (&f) == 2);
+}
diff --git c/gcc/testsuite/g++.dg/modules/tdef-4_a.C w/gcc/testsuite/g++.dg/modules/tdef-4_a.C
new file mode 100644
index 00000000000..6136b383f77
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-4_a.C
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export struct pthread_attr_t
+// guess where this came from?
+{
+  int m;
+};
+typedef struct pthread_attr_t pthread_attr_t;
+
+struct bob 
+{
+};
+export typedef struct bob bob;
diff --git c/gcc/testsuite/g++.dg/modules/tdef-4_b.C w/gcc/testsuite/g++.dg/modules/tdef-4_b.C
new file mode 100644
index 00000000000..af488e90feb
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-4_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+module foo;
+
+pthread_attr_t obj1;
+struct pthread_attr_t obj2;
+
+bob obj3;
+struct bob obj4; // OK -- we see the implicit typedef
diff --git c/gcc/testsuite/g++.dg/modules/tdef-4_c.C w/gcc/testsuite/g++.dg/modules/tdef-4_c.C
new file mode 100644
index 00000000000..a85a4d04823
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-4_c.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+struct pthread_attr_t obj2;
+pthread_attr_t obj1; // OK -- we see the implicit typedef
+
+bob obj4;
+// the structure tag is not exported.  We find the typedef-name, which
+// is ill-formed
+struct bob obj5;  // { dg-error "using typedef-name" }
diff --git c/gcc/testsuite/g++.dg/modules/tdef-5_a.C w/gcc/testsuite/g++.dg/modules/tdef-5_a.C
new file mode 100644
index 00000000000..4d23ae14baa
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-5_a.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+typedef float _IO_lock_t;
+
+_IO_lock_t _lock;
diff --git c/gcc/testsuite/g++.dg/modules/tdef-5_b.C w/gcc/testsuite/g++.dg/modules/tdef-5_b.C
new file mode 100644
index 00000000000..d37b7e28420
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-5_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+module foo;
+
+_IO_lock_t bob ()
+{
+  return _lock;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tdef-6_a.H w/gcc/testsuite/g++.dg/modules/tdef-6_a.H
new file mode 100644
index 00000000000..aff599476b1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-6_a.H
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+typedef struct x
+{
+  int __count;
+} X;
+
+typedef struct
+{
+  int __count;
+} __mbstate_t;
diff --git c/gcc/testsuite/g++.dg/modules/tdef-6_b.C w/gcc/testsuite/g++.dg/modules/tdef-6_b.C
new file mode 100644
index 00000000000..2d12a2c9a2e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-6_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" }
+
+typedef struct
+{
+  int __count;
+} __mbstate_t;
+
+typedef struct x
+{
+  int __count;
+} X;
+
+import "tdef-6_a.H";
+
+X y;
+__mbstate_t x;
+
+// { dg-final { scan-lang-dump {Read:-[0-9]'s named merge key \(matched\) type_decl:'::__mbstate_t'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tdef-7.h w/gcc/testsuite/g++.dg/modules/tdef-7.h
new file mode 100644
index 00000000000..5bc21e176cb
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-7.h
@@ -0,0 +1,7 @@
+
+constexpr void duration_cast ()
+{
+  // the constexpr's body's clone merely duplicates the TYPE_DECL, it
+  // doesn't create a kosher typedef
+  typedef int __to_rep;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tdef-7_a.H w/gcc/testsuite/g++.dg/modules/tdef-7_a.H
new file mode 100644
index 00000000000..9c6db65ba55
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-7_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "tdef-7.h"
diff --git c/gcc/testsuite/g++.dg/modules/tdef-7_b.C w/gcc/testsuite/g++.dg/modules/tdef-7_b.C
new file mode 100644
index 00000000000..c526ca8dd4f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-7_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias-uid" }
+
+#include "tdef-7.h"
+import "tdef-7_a.H";
+
+// { dg-final { scan-lang-dump-times {merge key \(matched\) function_decl:'::duration_cast} 1 module } }
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
+// { dg-final { scan-lang-dump-times {merge key \(unique\) type_decl:'#null#'} 2 module } }
+// { dg-final { scan-lang-dump-times {Cloned:-[0-9]* typedef integer_type:'::duration_cast::__to_rep'} 1 module } }
diff --git c/gcc/testsuite/g++.dg/modules/tdef-8_a.C w/gcc/testsuite/g++.dg/modules/tdef-8_a.C
new file mode 100644
index 00000000000..3ad20948ad1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-8_a.C
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodules-ts }
+
+export module bob;
+// { dg-module-cmi bob }
+
+// from tr1/type_traits
+export struct __sfinae_types
+{
+  // anon struct with tdef name
+  typedef struct  { int i; } __two;
+};
+
diff --git c/gcc/testsuite/g++.dg/modules/tdef-8_b.C w/gcc/testsuite/g++.dg/modules/tdef-8_b.C
new file mode 100644
index 00000000000..2cf59d78fde
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-8_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import bob;
+
+int frob (__sfinae_types::__two *p)
+{
+  return p->i;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tdef-inst-1.h w/gcc/testsuite/g++.dg/modules/tdef-inst-1.h
new file mode 100644
index 00000000000..757113c0283
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-inst-1.h
@@ -0,0 +1,14 @@
+
+template <typename T>
+class basic_string;
+
+typedef basic_string<char> string;
+
+template <typename T>
+class basic_string
+{
+ public:
+  string Frob ();
+
+  basic_string (int);
+};
diff --git c/gcc/testsuite/g++.dg/modules/tdef-inst-1_a.C w/gcc/testsuite/g++.dg/modules/tdef-inst-1_a.C
new file mode 100644
index 00000000000..ab302bc1b6b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-inst-1_a.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+
+// The instantiation of the *definition* of basic_string is used in
+// importers, *after* they have instantiated a declaration of it *and*
+// created type variants.
+
+module;
+
+#include "tdef-inst-1.h"
+
+export module foo;
+// { dg-module-cmi foo }
+
+export inline int greeter (string const &bob)
+{
+  return sizeof (bob); // instantiates string
+}
diff --git c/gcc/testsuite/g++.dg/modules/tdef-inst-1_b.C w/gcc/testsuite/g++.dg/modules/tdef-inst-1_b.C
new file mode 100644
index 00000000000..ccf70520464
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tdef-inst-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+#include "tdef-inst-1.h"
+import foo;
+
+string Quux ()
+{
+  return 1; // failed to find converting ctor of string
+}
diff --git c/gcc/testsuite/g++.dg/modules/thunk-1_a.C w/gcc/testsuite/g++.dg/modules/thunk-1_a.C
new file mode 100644
index 00000000000..7652400fd13
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/thunk-1_a.C
@@ -0,0 +1,23 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export struct Base
+{
+  virtual ~Base () {}
+  int m;
+};
+
+// Force the creation of implicit members, because we get that wrong
+// in the importer and think its imported (as of 2018-11-27 this
+// causes an ICE, previously it happened to work in this particular
+// testcase.  
+Base x;
+
+export struct Derived : virtual Base 
+{
+  ~Derived () {}  
+};
+
+Derived y;
diff --git c/gcc/testsuite/g++.dg/modules/thunk-1_b.C w/gcc/testsuite/g++.dg/modules/thunk-1_b.C
new file mode 100644
index 00000000000..99eb029d513
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/thunk-1_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+export module baz;
+// { dg-module-cmi baz }
+
+import foo;
+
+export struct Container  : virtual Derived
+{
+  Container () {}
+  ~Container () {}
+};
+  
+  
+  
diff --git c/gcc/testsuite/g++.dg/modules/tmpl-part-req-1.h w/gcc/testsuite/g++.dg/modules/tmpl-part-req-1.h
new file mode 100644
index 00000000000..09de42923da
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tmpl-part-req-1.h
@@ -0,0 +1,15 @@
+
+template<typename _Iterator, typename>
+struct Trait;
+
+template<typename _Iterator>
+struct Trait<_Iterator, void> {};
+
+template<typename _Iterator>
+requires  true
+struct Trait<_Iterator, void>
+{
+  template<typename _Iter> struct __diff {};
+  
+  template<typename _Iter> requires true struct __diff<_Iter> {};
+};
diff --git c/gcc/testsuite/g++.dg/modules/tmpl-part-req-1_a.H w/gcc/testsuite/g++.dg/modules/tmpl-part-req-1_a.H
new file mode 100644
index 00000000000..20804d73620
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tmpl-part-req-1_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header -std=c++2a" }
+// { dg-module-cmi {} }
+#include "tmpl-part-req-1.h"
diff --git c/gcc/testsuite/g++.dg/modules/tmpl-part-req-1_b.C w/gcc/testsuite/g++.dg/modules/tmpl-part-req-1_b.C
new file mode 100644
index 00000000000..4c00d54aee9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tmpl-part-req-1_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-std=c++2a -fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "tmpl-part-req-1.h"
+import "tmpl-part-req-1_a.H";
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tmpl-part-req-2.h w/gcc/testsuite/g++.dg/modules/tmpl-part-req-2.h
new file mode 100644
index 00000000000..0ca05933b11
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tmpl-part-req-2.h
@@ -0,0 +1,24 @@
+
+template<typename _Iterator, typename>
+struct Trait;
+
+template<typename _Iterator>
+struct Trait<_Iterator, void> {};
+
+template<typename _Iterator>
+requires  true && true
+struct Trait<_Iterator, void>
+{
+  template<typename _Iter> struct __cat {};
+  
+  template<typename _Iter> requires true struct __cat<_Iter> {};
+};
+
+template<typename _Iterator>
+requires  true
+struct Trait<_Iterator, void>
+{
+  template<typename _Iter> struct __diff {};
+  
+  template<typename _Iter> requires true struct __diff<_Iter> {};
+};
diff --git c/gcc/testsuite/g++.dg/modules/tmpl-part-req-2_a.H w/gcc/testsuite/g++.dg/modules/tmpl-part-req-2_a.H
new file mode 100644
index 00000000000..66b97ea372b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tmpl-part-req-2_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header -std=c++2a" }
+// { dg-module-cmi {} }
+#include "tmpl-part-req-2.h"
diff --git c/gcc/testsuite/g++.dg/modules/tmpl-part-req-2_b.C w/gcc/testsuite/g++.dg/modules/tmpl-part-req-2_b.C
new file mode 100644
index 00000000000..1176f6012c7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tmpl-part-req-2_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-std=c++2a -fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "tmpl-part-req-2.h"
+import "tmpl-part-req-2_a.H";
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git c/gcc/testsuite/g++.dg/modules/token-1.C w/gcc/testsuite/g++.dg/modules/token-1.C
new file mode 100644
index 00000000000..50eee4c7ea1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/token-1.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+# 3 __FILE__ 1
+module ; // { dg-error "cannot be in included file" }
+export module bob; // { dg-error "cannot be in included file" }
+# 6 "" 2
+// { dg-module-cmi !bob }
+// { dg-prune-output "not writing module" }
diff --git c/gcc/testsuite/g++.dg/modules/token-2_a.C w/gcc/testsuite/g++.dg/modules/token-2_a.C
new file mode 100644
index 00000000000..a1dfbf77367
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/token-2_a.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+# 1 "other_name"
+module ;
+export module bob;
+// { dg-module-cmi bob }
diff --git c/gcc/testsuite/g++.dg/modules/token-2_b.C w/gcc/testsuite/g++.dg/modules/token-2_b.C
new file mode 100644
index 00000000000..52b7498a26b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/token-2_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodules-ts }
+#define SEMI ; // this is ok since p1857
+import bob SEMI
+#define IMPORT import // { dg-error "does not name a type" }
+IMPORT bob ;
diff --git c/gcc/testsuite/g++.dg/modules/token-3.C w/gcc/testsuite/g++.dg/modules/token-3.C
new file mode 100644
index 00000000000..5bab426e2a6
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/token-3.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+# 3 __FILE__ 1
+export module bob; // { dg-error "in included file" }
+# 6 "" 2
+// { dg-module-cmi !bob }
+// { dg-prune-output "not writing module" }
diff --git c/gcc/testsuite/g++.dg/modules/token-4.C w/gcc/testsuite/g++.dg/modules/token-4.C
new file mode 100644
index 00000000000..5a852370d66
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/token-4.C
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodules-ts }
+#define MODULE module   // { dg-error "does not name a type" }
+export MODULE bob; // { dg-error "may only occur after" }
+// { dg-module-cmi !bob }
+// { dg-prune-output "not writing module" }
diff --git c/gcc/testsuite/g++.dg/modules/token-5.C w/gcc/testsuite/g++.dg/modules/token-5.C
new file mode 100644
index 00000000000..29d3ec8fd70
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/token-5.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+module;
+
+class X; // { dg-error "global module fragment contents" }
+
+class Y;
+
+export module frob;
+// { dg-module-cmi !frob }
+// { dg-prune-output "not writing module" }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-alias-1.h w/gcc/testsuite/g++.dg/modules/tpl-alias-1.h
new file mode 100644
index 00000000000..00f2d9b5b2b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-alias-1.h
@@ -0,0 +1,70 @@
+template<typename _Ptr> struct pointer_traits;
+
+template<typename _Tp>
+struct pointer_traits<_Tp*>
+{
+  template<typename _Up> using rebind = _Up*;
+};
+
+template<typename _Ptr, typename _Tp>
+using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>;
+
+template<typename _Tp>
+struct allocator
+{
+  typedef _Tp value_type;
+  typedef _Tp* pointer;
+};
+
+template<typename _Alloc> struct allocator_traits;
+
+template<typename _Tp>
+struct allocator_traits<allocator<_Tp>>
+{
+  using pointer = _Tp*;
+  template<typename _Up>
+  using rebind_alloc = allocator<_Up>;
+};
+
+template<typename _Alloc, typename = typename _Alloc::value_type>
+struct __alloc_traits
+  : allocator_traits<_Alloc>
+{
+  typedef _Alloc allocator_type;
+  typedef allocator_traits<_Alloc> _Base_type;
+  template<typename _Tp>
+  struct rebind
+  {
+    typedef typename _Base_type::template rebind_alloc<_Tp> other;
+  };
+};
+
+template<typename _Ref, typename _Ptr>
+struct _Deque_iterator
+{
+  template<typename _CvTp>
+  using __iter = _Deque_iterator<_CvTp&, __ptr_rebind<_Ptr, _CvTp>>;
+  
+  typedef __ptr_rebind<_Ptr, long> _Elt_pointer;
+  typedef __ptr_rebind<_Ptr, _Elt_pointer> _Map_pointer;
+};
+
+template<typename _Alloc>
+struct _Deque_base
+{
+  typedef typename __alloc_traits<_Alloc>::template rebind<long>::other _Tp_alloc_type;
+
+  typedef __alloc_traits<_Tp_alloc_type> _Alloc_traits;
+
+  typedef typename _Alloc_traits::pointer _Ptr;
+
+  typedef _Deque_iterator<long&, _Ptr> iterator;
+  
+  typedef typename iterator::_Map_pointer _Map_pointer;
+};
+
+
+inline void stack ()
+{
+  _Deque_base<allocator<long>> c;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H w/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
new file mode 100644
index 00000000000..502a649c74d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodule-header -fdump-lang-module-alias-uid" }
+// { dg-module-cmi {} }
+
+#include "tpl-alias-1.h"
+
+// { dg-final { scan-lang-dump {Writing named:-[0-9]* template_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc<_Up>'} module } }
+// { dg-final { scan-lang-dump {Writing decl spec:-[0-9]* type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<_Up>'} module } }
+// { dg-final { scan-lang-dump {Writing:-[0-9]*'s decl spec merge key \(specialization\) type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<_Up>'} module } }
+// { dg-final { scan-lang-dump {Wrote\(-[0-9]*\) alias template type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<_Up>'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-alias-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-alias-1_b.C
new file mode 100644
index 00000000000..59fd09c0454
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-alias-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-uid-alias" }
+
+#include "tpl-alias-1.h"
+import "tpl-alias-1_a.H";
+
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) template_decl:'::allocator_traits<::allocator<long int>>::template rebind_alloc'} module } }
+// { dg-final { scan-lang-dump {Read:-[0-9]*'s decl spec merge key \(matched\) type_decl:'::allocator_traits<::allocator<_Tp>>::rebind_alloc'} module } }
+// { dg-final { scan-lang-dump {Read alias template type_decl:'::allocator_traits<::allocator<long int>>::rebind_alloc<_Up>'} module } }
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-ary-1.h w/gcc/testsuite/g++.dg/modules/tpl-ary-1.h
new file mode 100644
index 00000000000..2f745afba36
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-ary-1.h
@@ -0,0 +1,15 @@
+
+int ary[4];
+extern int unb[];
+typedef int z[0];
+
+
+template<typename _Tp>
+struct __aligned_membuf
+{
+  unsigned char _M_storage[sizeof(_Tp)];
+  _Tp bob[5];
+
+  typedef _Tp ary[5];
+  typedef const ary c_ary;
+};
diff --git c/gcc/testsuite/g++.dg/modules/tpl-ary-1_a.H w/gcc/testsuite/g++.dg/modules/tpl-ary-1_a.H
new file mode 100644
index 00000000000..0534e9349d1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-ary-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodule-header -Wno-pedantic" }
+// { dg-module-cmi {} }
+
+#include "tpl-ary-1.h"
diff --git c/gcc/testsuite/g++.dg/modules/tpl-ary-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-ary-1_b.C
new file mode 100644
index 00000000000..c64758085d1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-ary-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "tpl-ary-1.h"
+import "tpl-ary-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 c/gcc/testsuite/g++.dg/modules/tpl-extern-fn-1_a.H w/gcc/testsuite/g++.dg/modules/tpl-extern-fn-1_a.H
new file mode 100644
index 00000000000..f0aba549dfd
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-extern-fn-1_a.H
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename T>
+inline void Foo ()
+{
+  {
+    void Frob ();
+  }
+  {
+    void Frob ();
+  }
+  {
+    void Frob ();
+  }
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-extern-fn-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-extern-fn-1_b.C
new file mode 100644
index 00000000000..8b093d4e15a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-extern-fn-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import "tpl-extern-fn-1_a.H";
+
+int main ()
+{
+  Foo<int> ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-extern-var-1_a.H w/gcc/testsuite/g++.dg/modules/tpl-extern-var-1_a.H
new file mode 100644
index 00000000000..4a6437a85e3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-extern-var-1_a.H
@@ -0,0 +1,19 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename T>
+inline void Foo ()
+{
+  {
+    extern int EXTERN_;
+    EXTERN_++;
+  }
+  {
+    extern int EXTERN_;
+    EXTERN_++;
+  }
+  {
+    extern int EXTERN_;
+    EXTERN_++;
+  }
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-extern-var-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-extern-var-1_b.C
new file mode 100644
index 00000000000..222418128be
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-extern-var-1_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+
+import "tpl-extern-var-1_a.H";
+
+int main ()
+{
+  Foo<int> ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-1_a.C w/gcc/testsuite/g++.dg/modules/tpl-friend-1_a.C
new file mode 100644
index 00000000000..88bb6e61f0c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-1_a.C
@@ -0,0 +1,40 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-graph-blocks" }
+// declarations followed by friend injection
+
+export module foo;
+// { dg-module-cmi foo }
+
+void foo (int, void *);
+void foo (float, void *);
+
+template <typename T> class TPL
+{
+  friend void foo (T, void *); // { dg-warning "non-template function" }
+
+  T member;
+};
+
+template class TPL<float>;  // instantiate
+
+// binding->465500
+// FUNCTION_DECL->465500
+//   DECL_TEMPLATE_INFO->NULL
+//   DECL_USE_TEMPLATE->0
+
+// specialization 465500
+// tmpl->333580 template_decl
+//  the friend decl implicit template
+
+// args->46b640 tree_vec
+//   length:1
+//   elt:0 real_type
+
+// do not add this (non-)specialization to the depset table
+// the ::foo fns and TPL should be in different depsets
+// the friend decl should be streamed as part of TPL's definition
+
+// { dg-final { scan-lang-dump-not {Connecting declaration decl template_decl:'::foo'} module } }
+
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl declaration '::foo'\n  \[1\]=decl declaration '::foo'\n  \[2\]=binding '::foo'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl definition '::template TPL'\n(  \[.\]=[^\n]*'\n)*  \[.\]=binding '::TPL'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=specialization definition '::TPL<float>'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-friend-1_b.C
new file mode 100644
index 00000000000..e4c42d18663
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-1_b.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+void foo (int x, void *p)
+{
+  auto *obj = reinterpret_cast<TPL<int> *> (p);
+
+  obj->member = x;
+}
+
+void foo (float x, void *p)
+{
+  auto *obj = reinterpret_cast<TPL<float> *> (p);
+
+  obj->member = x;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C w/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C
new file mode 100644
index 00000000000..3acacf8ee34
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C
@@ -0,0 +1,20 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-graph-blocks" }
+// injection followed by declaration
+
+export module foo;
+// { dg-module-cmi foo }
+
+template <typename T> class TPL
+{
+  friend void foo (T, void *); // { dg-warning "non-template function" }
+
+  T member;
+};
+
+template class TPL<int>;  // instantiate
+
+void foo (int, void *);
+
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl definition '::template TPL'\n(  \[.\]=[^\n]*'\n)*  \[.\]=decl declaration '::template foo'\n(  \[.\]=[^\n]*'\n)*  \[.\]=binding '::TPL'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl declaration '::foo<int>'\n  \[.\]=binding '::foo'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=specialization definition '::TPL<int>'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-2_b.C w/gcc/testsuite/g++.dg/modules/tpl-friend-2_b.C
new file mode 100644
index 00000000000..38d89f06b1a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-2_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+module foo;
+
+void foo (int x, void *p)
+{
+  auto *obj = reinterpret_cast<TPL<int> *> (p);
+
+  obj->member = x;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-3_a.C w/gcc/testsuite/g++.dg/modules/tpl-friend-3_a.C
new file mode 100644
index 00000000000..e71a2588e75
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-3_a.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-fmodules-ts" }
+// declarations followed by friend definition injection
+
+export module foo;
+// { dg-module-cmi foo }
+
+void foo (int, void *);
+void foo (float, void *);
+
+template <typename T> class TPL
+{
+  friend void foo (T x, void *p)
+  {
+    auto *obj = reinterpret_cast<TPL<T> *> (p);
+
+    obj->member = x;
+  }
+
+  T member;
+};
+
+template class TPL<float>;  // instantiate
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-3_b.C w/gcc/testsuite/g++.dg/modules/tpl-friend-3_b.C
new file mode 100644
index 00000000000..accf5d5353c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-3_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+template class TPL<int>;
+// (instantiated in interface) template class TPL<float>;
+
+void m ()
+{
+  // friend definitions instantiated on-demand here
+  foo (1, 0);
+  foo (1.0f, 0);
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-4_a.C w/gcc/testsuite/g++.dg/modules/tpl-friend-4_a.C
new file mode 100644
index 00000000000..8acf5b91bf8
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-4_a.C
@@ -0,0 +1,25 @@
+// { dg-additional-options "-fmodules-ts" }
+// friend injection then definition injection
+
+export module foo;
+// { dg-module-cmi foo }
+
+template <typename T> class TPL
+{
+  friend void foo (T, void *); // { dg-warning "non-template function" }
+
+  T member;
+};
+
+template <typename U> class DEF
+{
+  friend void foo (U x, void *p)
+  {
+    auto *obj = reinterpret_cast<TPL<U> *> (p);
+
+    obj->member = x;
+  }
+};
+
+template class TPL<float>;  // instantiate
+template class DEF<float>;  // instantiate
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-4_b.C w/gcc/testsuite/g++.dg/modules/tpl-friend-4_b.C
new file mode 100644
index 00000000000..3dd8741e42e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-4_b.C
@@ -0,0 +1,21 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+template class TPL<int>;
+template class DEF<int>;
+
+void m ()
+{
+  // ADL to find hidden functions
+  foo (1, (TPL<int> *)0);
+  foo (1.0f, (TPL<int> *)0);
+
+  // no ADL, no find
+  {
+    foo (1, 0);  // { dg-error "not declared" }
+  }
+  {
+    foo (1.0f, 0); // { dg-error "not declared" }
+  }
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-5_a.C w/gcc/testsuite/g++.dg/modules/tpl-friend-5_a.C
new file mode 100644
index 00000000000..e894c734efa
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-5_a.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template<typename _CharT> class basic_ios;
+
+template<typename _CharT>
+class basic_streambuf
+{
+  friend class basic_ios<_CharT>;
+
+  _CharT member;
+};
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-5_b.C w/gcc/testsuite/g++.dg/modules/tpl-friend-5_b.C
new file mode 100644
index 00000000000..adbe85d47fd
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-5_b.C
@@ -0,0 +1,23 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+module foo;
+
+template class basic_streambuf<char>;
+
+template<typename _CharT> class basic_ios
+{
+public:
+  static void frob (basic_streambuf<_CharT> *p, _CharT val)
+  {
+    p->member = val;
+  }
+};
+
+void bill (basic_streambuf<char> *p)
+{
+  basic_ios<char>::frob (p, 5);
+}
+
+// { dg-final { scan-lang-dump {Lazily binding '::basic_streambuf'@'foo' section:} module } }
+// { dg-final { scan-lang-dump {Loading entity foo\[0\] section:1} module } }
+// { dg-final { scan-lang-dump {Loading entity foo\[1\] section:2} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-6_a.C w/gcc/testsuite/g++.dg/modules/tpl-friend-6_a.C
new file mode 100644
index 00000000000..cc07c60a512
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-6_a.C
@@ -0,0 +1,26 @@
+// { dg-additional-options -fmodules-ts }
+// befriending a specialization
+
+export module foo;
+// { dg-module-cmi foo }
+
+namespace not_std {
+
+template<typename T>
+class basic_streambuf;
+
+template<typename T>
+void __copy_streambufs_eof(basic_streambuf<T>*);
+
+template<typename T>
+class basic_streambuf
+{
+  friend void __copy_streambufs_eof<>(basic_streambuf*);
+
+  T member;
+};
+
+template<>
+void
+__copy_streambufs_eof(basic_streambuf<char>* __sbin);
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-6_b.C w/gcc/testsuite/g++.dg/modules/tpl-friend-6_b.C
new file mode 100644
index 00000000000..942fe7045bb
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-6_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodules-ts }
+module foo;
+
+namespace not_std {
+
+template<>
+void
+__copy_streambufs_eof(basic_streambuf<char>* __sbin)
+{
+  __sbin->member = 0;
+}
+
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-7_a.C w/gcc/testsuite/g++.dg/modules/tpl-friend-7_a.C
new file mode 100644
index 00000000000..bf13cf79ff9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-7_a.C
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template<typename _Tp>
+class new_allocator
+{
+  template<typename _Up>
+  friend bool
+  operator!=(const new_allocator&, const new_allocator<_Up>&)
+    noexcept
+  { return false; }
+};
+
+new_allocator<char> x;
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-7_b.C w/gcc/testsuite/g++.dg/modules/tpl-friend-7_b.C
new file mode 100644
index 00000000000..e6e4461541a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-7_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+new_allocator<char> y;
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1.cc w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1.cc
new file mode 100644
index 00000000000..a4a1d211e3a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1.cc
@@ -0,0 +1,6 @@
+void __istream_extract (int)
+{
+  (void)basic_streambuf<char>::field;
+  (void)basic_streambuf<int>::field;
+  (void)basic_streambuf<long>::field;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1.h w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1.h
new file mode 100644
index 00000000000..fd455363d9f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1.h
@@ -0,0 +1,9 @@
+
+template<typename T>
+class basic_streambuf
+{
+  friend void __istream_extract (int);
+
+  // something private
+  static constexpr int field = 5;
+};
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_a.H w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_a.H
new file mode 100644
index 00000000000..566b8604929
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_a.H
@@ -0,0 +1,6 @@
+// { dg-additional-options {-fmodule-header -W} }
+
+// { dg-module-cmi {} }
+
+#include "tpl-friend-merge-1.h"
+extern template class basic_streambuf<char>;
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_b.H w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_b.H
new file mode 100644
index 00000000000..b35d8e1f211
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_b.H
@@ -0,0 +1,6 @@
+// { dg-additional-options {-fmodule-header -W} }
+
+// { dg-module-cmi {} }
+
+#include "tpl-friend-merge-1.h"
+extern template class basic_streambuf<int>;
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_c.H w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_c.H
new file mode 100644
index 00000000000..197b8313bb1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_c.H
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodule-header }
+
+// { dg-module-cmi {} }
+
+void __istream_extract (int);
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_d.C w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_d.C
new file mode 100644
index 00000000000..e6f46ef7ef7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_d.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+import "tpl-friend-merge-1_a.H";
+import "tpl-friend-merge-1_b.H";
+import "tpl-friend-merge-1_c.H";
+
+#include "tpl-friend-merge-1.cc"
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_e.C w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_e.C
new file mode 100644
index 00000000000..185242bdb0c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_e.C
@@ -0,0 +1,7 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy -fdump-lang-module-alias} }
+
+import "tpl-friend-merge-1_a.H";
+import "tpl-friend-merge-1_c.H";
+import "tpl-friend-merge-1_b.H";
+
+#include "tpl-friend-merge-1.cc"
diff --git c/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_f.C w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_f.C
new file mode 100644
index 00000000000..4ec7cde3699
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-friend-merge-1_f.C
@@ -0,0 +1,7 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy -fdump-lang-module-alias} }
+
+import "tpl-friend-merge-1_c.H";
+import "tpl-friend-merge-1_a.H";
+import "tpl-friend-merge-1_b.H";
+
+#include "tpl-friend-merge-1.cc"
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-1_a.C w/gcc/testsuite/g++.dg/modules/tpl-spec-1_a.C
new file mode 100644
index 00000000000..26350f09856
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-1_a.C
@@ -0,0 +1,22 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks} }
+
+export module TPL;
+// { dg-module-cmi TPL }
+
+export template <typename T> int foo (T x) 
+{
+  return int (x);
+}
+
+// Body is emitted in module-unit itself
+template <> int foo<int> (int y)
+{
+  return 0;
+}
+
+// { dg-final { scan-lang-dump {Dependencies of specialization function_decl:'::foo<int>'} module } }
+// { dg-final { scan-lang-dump-not {Depending definition function_decl:'::foo<int>'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=specialization declaration '::foo<int>'} module } }
+// { dg-final { scan-lang-dump {Specialization '::foo<int>' entity:[0-9]* keyed to TPL\[0\] '::template foo'} module } }
+
+// { dg-final { scan-assembler {_Z3fooIiEiT_:} } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-spec-1_b.C
new file mode 100644
index 00000000000..1f64fbbbcb8
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-1_b.C
@@ -0,0 +1,20 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module} }
+
+import TPL;
+
+int main ()
+{
+  if (foo (1.0f) != 1)
+    return 1;
+
+  if (foo (1) != 0)
+    return 2;
+
+  return 0;
+}
+
+// { dg-final { scan-lang-dump-not {Reading definition function_decl '::foo@TPL:.<int>'} module } }
+// { dg-final { scan-lang-dump {Specialization keyed to TPL\[0\] entity:1} module } }
+// { dg-final { scan-lang-dump {Reading 1 pending specializations keyed to TPL\[0\] '::template foo@TPL:1'} module } }
+
+// { dg-final { scan-assembler-not {_Z3fooIiEiT_:} } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-2_a.C w/gcc/testsuite/g++.dg/modules/tpl-spec-2_a.C
new file mode 100644
index 00000000000..bb136d9c8f6
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-2_a.C
@@ -0,0 +1,11 @@
+// { dg-additional-options {-fmodules-ts} }
+
+export module TPL;
+// { dg-module-cmi TPL }
+
+export template <typename T> int foo (T x) 
+{
+  return int (x);
+}
+
+// { dg-final { scan-assembler-not {^[a-zA-Z0-9_]*:} } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-2_b.C w/gcc/testsuite/g++.dg/modules/tpl-spec-2_b.C
new file mode 100644
index 00000000000..d1374819261
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-2_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks} }
+
+export module SPEC;
+
+export import TPL;
+
+// Body is emitted in module-unit itself
+template <> int foo<int> (int y)
+{
+  return 0;
+}
+
+// { dg-final { scan-lang-dump {Dependencies of specialization function_decl:'::foo<int>'} module } }
+// { dg-final { scan-lang-dump-not {Depending definition function_decl:'::foo<int>'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=specialization declaration '::foo<int>'} module } }
+// { dg-final { scan-lang-dump {Specialization '::foo<int>' entity:[0-9]* keyed to TPL\[.\] '::template foo@TPL:.'} module } }
+
+// { dg-final { scan-assembler {_Z3fooIiEiT_:} } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-2_c.C w/gcc/testsuite/g++.dg/modules/tpl-spec-2_c.C
new file mode 100644
index 00000000000..3b0a7c733e7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-2_c.C
@@ -0,0 +1,19 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module} }
+
+import SPEC;
+
+int main ()
+{
+  if (foo (1.0f) != 1)
+    return 1;
+
+  if (foo (1) != 0)
+    return 2;
+
+  return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading 1 pending specializations keyed to TPL\[0\] '::template foo@TPL:.'} module } }
+// { dg-final { scan-lang-dump-not {Reading definition function_decl '::foo@TPL:.<int>'} module } }
+
+// { dg-final { scan-assembler-not {_Z3fooIiEiT_:} } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-2_d.C w/gcc/testsuite/g++.dg/modules/tpl-spec-2_d.C
new file mode 100644
index 00000000000..4095dea021a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-2_d.C
@@ -0,0 +1,27 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module} }
+
+import TPL;
+
+int one ()
+{
+  if (foo (1.0f) != 1)
+    return 1;
+  return 0;
+}
+
+
+import SPEC;
+
+int two ()
+{
+  if (foo (1) != 0)
+    return 2;
+
+  return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading 1 pending specializations keyed to TPL\[0\] '::template foo@TPL:.'} module } }
+// { dg-final { scan-lang-dump-not {Reading definition function_decl '::foo@TPL:.<int>'} module } }
+
+// { dg-final { scan-assembler-not {_Z3fooIiEiT_:} } }
+// { dg-final { scan-assembler {_Z3fooIfEiT_:} } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-3_a.C w/gcc/testsuite/g++.dg/modules/tpl-spec-3_a.C
new file mode 100644
index 00000000000..1f3fb4023c8
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-3_a.C
@@ -0,0 +1,27 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks} }
+
+export module TPL;
+// { dg-module-cmi TPL }
+
+export struct frob 
+{
+  int i;
+
+  template<typename T> void store (T i_)
+  {
+    i = int (i_);
+  }
+};
+
+// Not inline!
+template <> void frob::store (int i_)
+{
+  i = -i_;
+}
+
+// { dg-final { scan-lang-dump {Dependencies of specialization function_decl:'::frob::store<int>'} module } }
+// { dg-final { scan-lang-dump-not {Depending definition function_decl:'::frob::store<int>'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=specialization declaration '::frob::store<int>'} module } }
+// { dg-final { scan-lang-dump {Specialization '::frob::store<int>' entity:[0-9]* keyed to TPL\[1\] '::frob::template store'} module } }
+
+// { dg-final { scan-assembler {_ZN4frob5storeIiEEvT_:} } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-3_b.C w/gcc/testsuite/g++.dg/modules/tpl-spec-3_b.C
new file mode 100644
index 00000000000..a9cd8d72308
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-3_b.C
@@ -0,0 +1,24 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module} }
+
+import TPL;
+
+int main ()
+{
+  frob f;
+
+  f.store (1);
+  if (f.i != -1)
+    return 1;
+
+  f.store (1.0f);
+  if (f.i != 1)
+    return 2;
+
+  return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading 1 pending specializations keyed to TPL\[1\] '::frob@TPL:.::template store@TPL:.'} module } }
+// { dg-final { scan-lang-dump-not {Reading definition function_decl '::frob@TPL:.::store@TPL:.<int>'} module } }
+
+// { dg-final { scan-assembler-not {_ZN4frob5storeIiEEvT_:} } }
+
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-4_a.C w/gcc/testsuite/g++.dg/modules/tpl-spec-4_a.C
new file mode 100644
index 00000000000..29e09deebd9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-4_a.C
@@ -0,0 +1,19 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks} }
+
+export module TPL;
+// { dg-module-cmi TPL }
+
+export template <typename T>
+struct X
+{
+  T f;
+};
+
+template<> struct X<int>
+{
+  int m;
+};
+
+// { dg-final { scan-lang-dump {Dependencies of specialization type_decl:'::X<int>'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n(  \[.\]=[^\n]*'\n)*  \[.\]=specialization definition '::X<int>'} module } }
+// { dg-final { scan-lang-dump {Specialization '::X<int>' entity:[0-9]* keyed to TPL\[0\] '::template X'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-4_b.C w/gcc/testsuite/g++.dg/modules/tpl-spec-4_b.C
new file mode 100644
index 00000000000..94ced9bed38
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-4_b.C
@@ -0,0 +1,17 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks} }
+
+import TPL;
+
+int main ()
+{
+  X<int> q;
+
+  q.m = 5;
+
+  X<float> p;
+  p.f = 4.0f;
+
+  return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading 1 pending specializations keyed to TPL\[0\] '::template X@TPL:.'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-5_a.C w/gcc/testsuite/g++.dg/modules/tpl-spec-5_a.C
new file mode 100644
index 00000000000..08bcac2e078
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-5_a.C
@@ -0,0 +1,19 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-graph-blocks} }
+
+export module TPL;
+// { dg-module-cmi TPL }
+
+export template <typename T, int I>
+struct X
+{
+  T ary[I];
+};
+
+template<typename T> struct X<T,1>
+{
+  T scalar;
+};
+
+// { dg-final { scan-lang-dump {Dependency on partial template_decl:'::template X<T,0x1>' found} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n(  \[.\][^\n]*'\n)*  \[.\]=partial definition '::template X<T,0x1>'} module } }
+// { dg-final { scan-lang-dump {Specialization '::template X<T,0x1>' entity:[0-9]* keyed to TPL\[0\] '::template X'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-5_b.C w/gcc/testsuite/g++.dg/modules/tpl-spec-5_b.C
new file mode 100644
index 00000000000..8a1a5575f45
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-5_b.C
@@ -0,0 +1,17 @@
+// { dg-additional-options {-fmodules-ts -fdump-lang-module-alias} }
+
+import TPL;
+
+int main ()
+{
+  X<int,2> q;
+
+  q.ary[0] = 5;
+
+  X<float,1> p;
+  p.scalar = 4.0f;
+
+  return 0;
+}
+
+// { dg-final { scan-lang-dump {Reading 1 pending specializations keyed to TPL\[0\] '::template X@TPL:.'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-6_a.C w/gcc/testsuite/g++.dg/modules/tpl-spec-6_a.C
new file mode 100644
index 00000000000..111c718b10b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-6_a.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template<typename _Tp, _Tp __v>
+struct integral_constant;
+
+template<typename _From, typename _To, bool>
+struct __is_nt_convertible_helper;
+
+template<typename _From, typename _To>
+class __is_nt_convertible_helper<_From, _To, false>
+{
+  template<typename _To1>
+  static void __test_aux(_To1) noexcept;
+  
+  template<typename _From1, typename _To1>
+  static
+  integral_constant<bool, noexcept(__test_aux<_To1> (_From1 ()))>
+  __test(int);
+};
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-6_b.C w/gcc/testsuite/g++.dg/modules/tpl-spec-6_b.C
new file mode 100644
index 00000000000..3a1142823bb
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-6_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module foo;
+
+__is_nt_convertible_helper<int, int, false> ok;
+__is_nt_convertible_helper<int, int, true> not_ok; // { dg-error "incomplete" }
diff --git c/gcc/testsuite/g++.dg/modules/tpl-spec-7.C w/gcc/testsuite/g++.dg/modules/tpl-spec-7.C
new file mode 100644
index 00000000000..71f821df0c4
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-spec-7.C
@@ -0,0 +1,38 @@
+// { dg-additional-options "-fmodules-ts" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+typedef unsigned long size_t;
+
+template<typename _Tp, bool _IsInt, bool _IsEnum>
+class __make_unsigned_selector;
+
+class __make_unsigned_selector_base
+{
+protected:
+  template<typename...> struct _List { };
+
+  template<typename _Tp, typename... _Up>
+  struct _List<_Tp, _Up...> : _List<_Up...>
+  { static constexpr size_t __size = sizeof(_Tp); };
+
+  template<size_t _Sz, typename _Tp, bool = (_Sz <= _Tp::__size)>
+  struct __select;
+};
+
+template<typename _Tp>
+class __make_unsigned_selector<_Tp, false, true>
+  : __make_unsigned_selector_base
+{
+  using _UInts = _List<unsigned char, unsigned short, unsigned int,
+		       unsigned long, unsigned long long>;
+
+  using __unsigned_type = typename __select<sizeof(_Tp), _UInts>::__type;
+};
+
+
+
+
+
+
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-friend-1_a.C w/gcc/testsuite/g++.dg/modules/tpl-tpl-friend-1_a.C
new file mode 100644
index 00000000000..23ebfde701c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-friend-1_a.C
@@ -0,0 +1,15 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template <typename T> class TPL
+{
+  template <typename U> friend void foo (U);
+};
+
+template class TPL<char>;
+
+template <typename V> void foo (V x)
+{
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-friend-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-tpl-friend-1_b.C
new file mode 100644
index 00000000000..276a7d2a2a0
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-friend-1_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+void m ()
+{
+  foo ('a');
+  foo (0);
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-mem-1_a.C w/gcc/testsuite/g++.dg/modules/tpl-tpl-mem-1_a.C
new file mode 100644
index 00000000000..2d58465df33
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-mem-1_a.C
@@ -0,0 +1,19 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template <typename T>
+class outer 
+{
+public:
+  template <typename U>
+  struct inner 
+  {
+    typedef outer<U> other;
+  };
+
+  using type = T;
+};
+
+template class outer<int>;
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-mem-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-tpl-mem-1_b.C
new file mode 100644
index 00000000000..3e90ac8633d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-mem-1_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+static_assert (sizeof (outer<int>::inner<char>::other::type) == 1);
+static_assert (sizeof (outer<char>::inner<int>::other::type) == sizeof (int));
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1.h w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1.h
new file mode 100644
index 00000000000..71ee1929a01
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1.h
@@ -0,0 +1,22 @@
+typedef long unsigned int size_t;
+
+template<typename _Tp, typename _Up>
+struct Replace;
+
+template<template<typename> class _Template>
+struct Replace<_Template<char>, char>
+{
+  using type = _Template<char>;
+};
+
+template<typename _Tp>
+struct TPL;
+
+template<typename _Alloc>
+struct Traits
+{
+  template<typename _Tp>
+  using Rebind = typename Replace<_Alloc, _Tp>::type;
+};
+
+using tdef = Traits<TPL<char>>::template Rebind<char>;
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1_a.H w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1_a.H
new file mode 100644
index 00000000000..ccd450838bc
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "tpl-tpl-merge-1.h"
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1_b.C
new file mode 100644
index 00000000000..d953ec3a5b0
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-1_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+#include "tpl-tpl-merge-1.h"
+import "tpl-tpl-merge-1_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2.h w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2.h
new file mode 100644
index 00000000000..005523ee9a8
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2.h
@@ -0,0 +1,65 @@
+typedef long unsigned int size_t;
+
+template<typename> class allocator;
+
+template<typename _Tp, typename _Up>
+struct __replace_first_arg
+{ };
+
+template<template<typename, typename...> class _Template, typename _Up,
+	 typename _Tp, typename... _Types>
+struct __replace_first_arg<_Template<_Tp, _Types...>, _Up>
+{
+  using type = _Template<_Up, _Types...>;
+};
+
+template<typename _Tp, typename _Up>
+using __replace_first_arg_t = typename __replace_first_arg<_Tp, _Up>::type;
+
+template<typename _Tp>
+class new_allocator
+{
+public:
+  typedef _Tp value_type;
+};
+
+template<typename _Tp>
+using __allocator_base = new_allocator<_Tp>;
+
+template<typename _Tp>
+class allocator : public __allocator_base<_Tp>
+{
+public:
+};
+
+struct __allocator_traits_base
+{
+  template<typename _Tp, typename _Up, typename = void>
+  struct __rebind : __replace_first_arg<_Tp, _Up> { };
+};
+
+template<typename _Alloc, typename _Up>
+using __alloc_rebind
+= typename __allocator_traits_base::template __rebind<_Alloc, _Up>::type;
+
+template<typename _Alloc>
+struct allocator_traits : __allocator_traits_base
+{
+public:
+  template<typename _Tp>
+  using rebind_alloc = __alloc_rebind<_Alloc, _Tp>;
+};
+
+template<typename _Alloc, typename = typename _Alloc::value_type>
+struct __alloc_traits
+
+{
+  template<typename _Tp>
+  struct rebind
+  {
+    typedef typename allocator_traits<_Alloc>::template rebind_alloc<_Tp> other;
+  };
+};
+
+typedef typename __alloc_traits<allocator<char>>::template
+rebind<char>::other _Char_alloc_type;
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2_a.H w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2_a.H
new file mode 100644
index 00000000000..051c19bf175
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "tpl-tpl-merge-2.h"
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2_b.C w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2_b.C
new file mode 100644
index 00000000000..54da419b12b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-merge-2_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+#include "tpl-tpl-merge-2.h"
+import "tpl-tpl-merge-2_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-1_a.H w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-1_a.H
new file mode 100644
index 00000000000..159efc35786
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-1_a.H
@@ -0,0 +1,12 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<template<typename> class _TQual>
+struct basic_common_reference;
+
+template<typename _Tp>
+struct __xref;
+
+template<typename _Tp1>
+using __basic_common_ref
+= typename basic_common_reference<__xref<_Tp1>::template __type>::type;
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-1_b.C w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-1_b.C
new file mode 100644
index 00000000000..c8918d6466d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-1_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+
+import "tpl-tpl-parm-1_a.H";
+
+template<> struct __xref<int> 
+{
+  template <typename T> struct __type;
+};
+
+template<> struct basic_common_reference<__xref<int>::__type>
+{
+  typedef int type;
+};
+
+__basic_common_ref<int> main ()
+{
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2.h w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2.h
new file mode 100644
index 00000000000..16832bf8e7f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2.h
@@ -0,0 +1,16 @@
+
+
+
+template<typename _Alloc>
+struct allocator_traits
+{
+  template<template<typename> class _Func>
+  struct _Ptr {};
+
+  using rebind_alloc = int;
+};
+
+inline void frob ()
+{
+  allocator_traits<int> _M_unpooled;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2_a.H w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2_a.H
new file mode 100644
index 00000000000..cec1a67454f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "tpl-tpl-parm-2.h"
diff --git c/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2_b.C w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2_b.C
new file mode 100644
index 00000000000..3504e502c56
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-2_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+#include "tpl-tpl-parm-2.h"
+import "tpl-tpl-parm-2_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/tplmem-1_a.C w/gcc/testsuite/g++.dg/modules/tplmem-1_a.C
new file mode 100644
index 00000000000..97e228a8385
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tplmem-1_a.C
@@ -0,0 +1,32 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module frob;
+// { dg-module-cmi "frob" }
+
+export struct A
+{
+  A ()
+  {
+  }
+
+  template<typename T> operator T () const
+  {
+    return T(99);
+  }
+};
+
+export template<typename T> struct B
+{
+  T m;
+
+  B(T t) : m(t) 
+  {
+  }
+
+  template<typename S> operator S () const
+  {
+    return S (m);
+  }
+};
+
diff --git c/gcc/testsuite/g++.dg/modules/tplmem-1_b.C w/gcc/testsuite/g++.dg/modules/tplmem-1_b.C
new file mode 100644
index 00000000000..352ad0c813a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tplmem-1_b.C
@@ -0,0 +1,28 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import frob;
+
+int main ()
+{
+  A a;
+
+  if (int (a) != 99)
+    return 1;
+  if (float (a) != 99)
+    return 2;
+  if (static_cast <void *> (a) != (void *)99)
+    return 3;
+
+  B<int> bi(1);
+  B<float> bf(1.25f);
+  if (int (bi) != 1)
+    return 4;
+  if (int (bf) != 1)
+    return 5;
+
+  // 1.25 is exactly representable
+  if (float (bf) != 1.25f)
+    return 6;
+
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/tplmem-3_a.C w/gcc/testsuite/g++.dg/modules/tplmem-3_a.C
new file mode 100644
index 00000000000..9d9cc0af5cd
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tplmem-3_a.C
@@ -0,0 +1,17 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module billy.bob.thornton;
+// { dg-module-cmi "billy.bob.thornton" }
+
+export template<unsigned I> struct Outer
+{
+  template<unsigned J> struct Inner
+  {
+    static unsigned m () 
+    {
+      return I * J;
+    }
+  };
+};
+
diff --git c/gcc/testsuite/g++.dg/modules/tplmem-3_b.C w/gcc/testsuite/g++.dg/modules/tplmem-3_b.C
new file mode 100644
index 00000000000..c5225cac089
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/tplmem-3_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import billy.bob.thornton;
+
+int main ()
+{
+  Outer<4>::Inner<16> v;
+
+  if (v.m () != 64)
+    return 1;
+  return 0;
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/ttp-1_a.C w/gcc/testsuite/g++.dg/modules/ttp-1_a.C
new file mode 100644
index 00000000000..eb2d939d2ae
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ttp-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+export module bob;
+
+export template<template<typename> class TPL, typename T>
+struct Wrapper
+{
+  using type = TPL<T>;
+};
diff --git c/gcc/testsuite/g++.dg/modules/ttp-1_b.C w/gcc/testsuite/g++.dg/modules/ttp-1_b.C
new file mode 100644
index 00000000000..30a73c0a8cc
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ttp-1_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+
+import bob;
+
+template<typename T> struct X
+{
+  using type = T;
+};
+
+template<typename X, typename Y> struct same;
+template<typename X> struct same<X, X> {};
+
+void frob ()
+{
+  using type = Wrapper<X, int>::type::type;
+
+  same<type, int> v;
+}
diff --git c/gcc/testsuite/g++.dg/modules/ttp-2_a.C w/gcc/testsuite/g++.dg/modules/ttp-2_a.C
new file mode 100644
index 00000000000..c14aeea3a1b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ttp-2_a.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template<template<typename...> class Arg1>
+struct TPL1;
+
+template<template<typename...> class Arg2>
+struct TPL2;
diff --git c/gcc/testsuite/g++.dg/modules/ttp-2_b.C w/gcc/testsuite/g++.dg/modules/ttp-2_b.C
new file mode 100644
index 00000000000..bf0242ac800
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ttp-2_b.C
@@ -0,0 +1,18 @@
+// { dg-additional-options -fmodules-ts }
+
+module foo;
+
+template <template<typename ...> class Arg4>
+struct TPL1
+{
+};
+
+template <template<typename ...> class Arg4>
+struct TPL2
+{
+};
+
+template <typename> class Arg;
+
+
+template struct TPL1<Arg>;
diff --git c/gcc/testsuite/g++.dg/modules/ttp-3_a.C w/gcc/testsuite/g++.dg/modules/ttp-3_a.C
new file mode 100644
index 00000000000..d1f5857cfd6
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ttp-3_a.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+template<typename Arg1, template<typename> typename Arg2>
+struct TPL
+{
+  using type = char;
+};
+
+/// Implementation of the detection idiom (positive case).
+template<template<typename> typename Op>
+struct TPL <Op<int>, Op>
+{
+  using type = int;
+};
diff --git c/gcc/testsuite/g++.dg/modules/ttp-3_b.C w/gcc/testsuite/g++.dg/modules/ttp-3_b.C
new file mode 100644
index 00000000000..7f61b7c437a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/ttp-3_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options -fmodules-ts }
+module foo;
+
+
+template <typename> class Y;
+
+static_assert (sizeof (TPL<Y<char>, Y>::type) == 1);
+static_assert (sizeof (TPL<Y<int>, Y>::type) != 1, "where's my specialization?");
diff --git c/gcc/testsuite/g++.dg/modules/typename-1_a.C w/gcc/testsuite/g++.dg/modules/typename-1_a.C
new file mode 100644
index 00000000000..e8b5599f81c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/typename-1_a.C
@@ -0,0 +1,13 @@
+// { dg-additional-options -fmodules-ts }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export template <typename T>
+struct TPL 
+{
+  typename T::type m;
+  using type = typename T::type;
+  const type cm;
+};
+
diff --git c/gcc/testsuite/g++.dg/modules/typename-1_b.C w/gcc/testsuite/g++.dg/modules/typename-1_b.C
new file mode 100644
index 00000000000..ba7aecf7a56
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/typename-1_b.C
@@ -0,0 +1,15 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+struct X
+{
+  using type = int;
+};
+
+int main ()
+{
+  TPL<X> x {0,1};
+
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/unnamed-1_a.C w/gcc/testsuite/g++.dg/modules/unnamed-1_a.C
new file mode 100644
index 00000000000..8c5674a171a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/unnamed-1_a.C
@@ -0,0 +1,20 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+export module PiL;
+// { dg-module-cmi PiL }
+
+int counter = 0;
+
+export inline int get ()
+{
+  return counter++;
+}
+
+export inline int hwm ()
+{
+  return counter;
+}
+
+// { dg-final { scan-lang-dump {Bindings '::counter' section:1} module } }
+// { dg-final { scan-lang-dump-not {horcrux} module } }
+// { dg-final { scan-lang-dump-not {Unnamed . '::counter'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/unnamed-1_b.C w/gcc/testsuite/g++.dg/modules/unnamed-1_b.C
new file mode 100644
index 00000000000..847ced6bcf9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/unnamed-1_b.C
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+
+import PiL;
+
+// Until the linkage is promoted, this won't link.
+
+int main ()
+{
+  int i = get ();
+  if (i)
+    return 1;
+  int h = hwm ();
+  if (h != 1)
+    return 2;
+  return 0;
+}
+
+// { dg-final { scan-lang-dump {Bindings '::counter'} module } }
+// { dg-final { scan-lang-dump {>Loading entity PiL\[0\] section:1} module } }
diff --git c/gcc/testsuite/g++.dg/modules/unnamed-2.C w/gcc/testsuite/g++.dg/modules/unnamed-2.C
new file mode 100644
index 00000000000..2b589302e5b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/unnamed-2.C
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module" }
+export module PiL;
+// { dg-module-cmi PiL }
+
+static int counter = 0;
+
+// These are not inlined, so their bodies don't get into the BMI
+export int get ()
+{
+  return counter++;
+}
+
+export int hwm ()
+{
+  return counter;
+}
+
+// { dg-final { scan-lang-dump-not {Bindings '::counter' section:} module } }
+// { dg-final { scan-lang-dump-not {Unnamed . '::counter'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/used-1_a.H w/gcc/testsuite/g++.dg/modules/used-1_a.H
new file mode 100644
index 00000000000..39aacf504a3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/used-1_a.H
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+inline int frob (int x)
+{
+  return x;
+}
diff --git c/gcc/testsuite/g++.dg/modules/used-1_b.H w/gcc/testsuite/g++.dg/modules/used-1_b.H
new file mode 100644
index 00000000000..05f29dbdf36
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/used-1_b.H
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+import "used-1_a.H";
+
+inline int wrapper (int x)
+{
+  return frob (x);
+}
diff --git c/gcc/testsuite/g++.dg/modules/used-1_c.C w/gcc/testsuite/g++.dg/modules/used-1_c.C
new file mode 100644
index 00000000000..0d1514e031c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/used-1_c.C
@@ -0,0 +1,10 @@
+// { dg-additional-options -fmodules-ts }
+
+import "used-1_b.H";
+
+int main ()
+{
+  return wrapper (0);
+}
+
+// { dg-final { scan-assembler {_Z4frobi:} } }
diff --git c/gcc/testsuite/g++.dg/modules/using-1_a.C w/gcc/testsuite/g++.dg/modules/using-1_a.C
new file mode 100644
index 00000000000..010c7fa00f9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-1_a.C
@@ -0,0 +1,19 @@
+// { dg-module-do link }
+// { dg-additional-options "-fmodules-ts" }
+export module frob;
+// { dg-module-cmi frob }
+
+namespace details
+{
+void foo ()
+{
+}
+}
+
+using details::foo;
+void footle ();
+export void bink ()
+{
+  foo ();
+  footle ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/using-1_b.C w/gcc/testsuite/g++.dg/modules/using-1_b.C
new file mode 100644
index 00000000000..e36caaf1cc1
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-1_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options -fmodules-ts }
+module frob;
+
+void footle ()
+{
+  foo ();
+}
diff --git c/gcc/testsuite/g++.dg/modules/using-1_c.C w/gcc/testsuite/g++.dg/modules/using-1_c.C
new file mode 100644
index 00000000000..d9835bc781d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-1_c.C
@@ -0,0 +1,9 @@
+// { dg-additional-options -fmodules-ts }
+
+import frob;
+
+int main ()
+{
+  bink ();
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/using-2_a.C w/gcc/testsuite/g++.dg/modules/using-2_a.C
new file mode 100644
index 00000000000..ef6f5e5ff4a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-2_a.C
@@ -0,0 +1,19 @@
+// { dg-additional-options -fmodules-ts }
+
+export module bob;
+// { dg-module-cmi bob }
+
+namespace N {
+export int foo (int a)
+{
+  return -a;
+}
+int bar (int a)
+{
+  return -a;
+}
+}
+
+export using N::foo;
+using N::bar;
+
diff --git c/gcc/testsuite/g++.dg/modules/using-2_b.C w/gcc/testsuite/g++.dg/modules/using-2_b.C
new file mode 100644
index 00000000000..6181073a1b4
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-2_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options -fmodules-ts }
+
+module bob;
+
+int a = foo (1);
+int b = bar (2);
diff --git c/gcc/testsuite/g++.dg/modules/using-2_c.C w/gcc/testsuite/g++.dg/modules/using-2_c.C
new file mode 100644
index 00000000000..c3c06703509
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-2_c.C
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodules-ts }
+import bob;
+
+int a = foo (1);
diff --git c/gcc/testsuite/g++.dg/modules/using-3.C w/gcc/testsuite/g++.dg/modules/using-3.C
new file mode 100644
index 00000000000..d21512fb20a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-3.C
@@ -0,0 +1,17 @@
+// { dg-additional-options -fmodules-ts }
+export module bad;
+// { dg-module-cmi !bad }
+
+namespace N
+{
+static int foo ();
+int bar ();
+}
+
+using N::foo;
+using N::bar;
+
+export using N::foo; // { dg-error "does not have external linkage" }
+export using N::bar; // { dg-error "does not have external linkage" }
+
+// { dg-prune-output "not writing module" }
diff --git c/gcc/testsuite/g++.dg/modules/using-4_a.C w/gcc/testsuite/g++.dg/modules/using-4_a.C
new file mode 100644
index 00000000000..1eba527f1a0
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-4_a.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+
+export module bob;
+// { dg-module-cmi bob }
+
+namespace N {
+export int foo ();
+}
+
+// Only one using decl exported!
+using N::foo;
+export using N::foo;
+
+// { dg-final { scan-lang-dump {Writing section:2 2 depsets} module } }
+// { dg-final { scan-lang-dump {Depset:0 using overload:'::N::foo'} module } }
+// { dg-final { scan-lang-dump {Depset:1 binding namespace_decl:'::foo'} module } }
+
diff --git c/gcc/testsuite/g++.dg/modules/using-4_b.C w/gcc/testsuite/g++.dg/modules/using-4_b.C
new file mode 100644
index 00000000000..f899f505340
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-4_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+
+import bob;
+
+int a = foo ();
+
+// { dg-final { scan-lang-dump {Binding of '::foo'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/using-5_a.C w/gcc/testsuite/g++.dg/modules/using-5_a.C
new file mode 100644
index 00000000000..88cbaf9d89c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-5_a.C
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+export module foo;
+// { dg-module-cmi foo }
+
+namespace One {
+class X;
+}
+
+namespace Two {
+using One::X;
+}
+
+
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl declaration '::One::X'\n  \[1\]=binding '::One::X'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=using declaration '::One::X'\n  \[1\]=binding '::Two::X'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/using-5_b.C w/gcc/testsuite/g++.dg/modules/using-5_b.C
new file mode 100644
index 00000000000..9fbe14e5937
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-5_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+module foo;
+
+Two::X *p;
diff --git c/gcc/testsuite/g++.dg/modules/using-6_a.C w/gcc/testsuite/g++.dg/modules/using-6_a.C
new file mode 100644
index 00000000000..40c32b380ae
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-6_a.C
@@ -0,0 +1,20 @@
+// { dg-additional-options -fmodules-ts }
+
+export module bob;
+// { dg-module-cmi bob }
+
+namespace A
+{
+export void swap (int &, int &);
+void copy (int &);
+}
+
+export template <typename T>
+void Foo (T & a, T &b)
+{
+  using A::swap;
+  swap (a, b);
+
+  using A::copy;
+  copy (b);
+}
diff --git c/gcc/testsuite/g++.dg/modules/using-6_b.C w/gcc/testsuite/g++.dg/modules/using-6_b.C
new file mode 100644
index 00000000000..feac0cab6b7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-6_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+import bob;
+
+int main ()
+{
+  int a = 0, b = 1;
+  Foo (a, b);
+
+  return 0;
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/using-7.C w/gcc/testsuite/g++.dg/modules/using-7.C
new file mode 100644
index 00000000000..01a5ad31984
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-7.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-blocks" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export namespace __gnu_cxx
+{
+enum _Lock_policy { _S_single};
+}
+
+export namespace std
+{
+  using __gnu_cxx::_S_single;
+}
+
+// { dg-final { scan-lang-dump {Writing section:1 4 depsets\n Cluster members:\n  \[0\]=decl definition '::__gnu_cxx::_Lock_policy'\n  \[1\]=using declaration '::__gnu_cxx::_Lock_policy::_S_single'\n  \[2\]=binding '::__gnu_cxx::_[A-Za-z_]*'\n  \[3\]=binding '::__gnu_cxx::_[A-Za-z_]*'\n} module } }
+// { dg-final { scan-lang-dump {Writing section:2 2 depsets\n Cluster members:\n  \[0\]=using declaration '::__gnu_cxx::_Lock_policy::_S_single'\n  \[1\]=binding '::std::_S_single'\n} module } }
diff --git c/gcc/testsuite/g++.dg/modules/using-8_a.C w/gcc/testsuite/g++.dg/modules/using-8_a.C
new file mode 100644
index 00000000000..1e71d2d8ccc
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-8_a.C
@@ -0,0 +1,21 @@
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+module;
+# 4 __FILE__ 1
+namespace A
+{
+void swap (int &, int &);
+void copy (int &);
+}
+# 10 "" 2
+export module bob;
+// { dg-module-cmi bob }
+
+export template <typename T>
+void Foo (T & a, T &b)
+{
+  using A::swap;
+  swap (a, b);
+
+  using A::copy;
+  copy (b);
+}
diff --git c/gcc/testsuite/g++.dg/modules/using-8_b.C w/gcc/testsuite/g++.dg/modules/using-8_b.C
new file mode 100644
index 00000000000..feac0cab6b7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-8_b.C
@@ -0,0 +1,11 @@
+// { dg-additional-options -fmodules-ts }
+import bob;
+
+int main ()
+{
+  int a = 0, b = 1;
+  Foo (a, b);
+
+  return 0;
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/using-enum-1_a.H w/gcc/testsuite/g++.dg/modules/using-enum-1_a.H
new file mode 100644
index 00000000000..a4204b4f6be
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-enum-1_a.H
@@ -0,0 +1,16 @@
+// { dg-additional-options {-fmodule-header -std=c++2a} }
+// { dg-module-cmi {} }
+
+enum class E {a, b, c};
+struct C
+{
+  using enum E;
+};
+
+struct D: C 
+{
+  int foo ()
+  {
+    return int (a);
+  }
+};
diff --git c/gcc/testsuite/g++.dg/modules/using-enum-1_b.C w/gcc/testsuite/g++.dg/modules/using-enum-1_b.C
new file mode 100644
index 00000000000..af0610ab97b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/using-enum-1_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy -std=c++2a } }
+
+#include "using-enum-1_a.H"
+import "using-enum-1_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/var-1_a.C w/gcc/testsuite/g++.dg/modules/var-1_a.C
new file mode 100644
index 00000000000..2a5d6bd0a6c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/var-1_a.C
@@ -0,0 +1,9 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module Var;
+// { dg-module-cmi Var }
+
+export int counter = 2;
+export extern const int limit = 5;
+
diff --git c/gcc/testsuite/g++.dg/modules/var-1_b.C w/gcc/testsuite/g++.dg/modules/var-1_b.C
new file mode 100644
index 00000000000..9a57f6166f5
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/var-1_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import Var;
+
+int main ()
+{
+  if (counter != 2)
+    return 1;
+  if (limit != 5)
+    return 2;
+  static_assert (limit == 5, "huh?");
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/var-tpl-1_a.C w/gcc/testsuite/g++.dg/modules/var-tpl-1_a.C
new file mode 100644
index 00000000000..f538304f4a3
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/var-tpl-1_a.C
@@ -0,0 +1,21 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodules-ts }
+
+export module frob;
+// { dg-module-cmi frob }
+
+export template<typename T> T sum (T a)
+{
+  return a;
+}
+
+export template<typename T, typename... R>
+inline T sum (T a, R... b)
+{
+  return a + static_cast<T> (sum (b...));
+}
+
+export inline int add (int a, int b, int c)
+{
+  return sum (a, b, c);
+}
diff --git c/gcc/testsuite/g++.dg/modules/var-tpl-1_b.C w/gcc/testsuite/g++.dg/modules/var-tpl-1_b.C
new file mode 100644
index 00000000000..a8c85247d7d
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/var-tpl-1_b.C
@@ -0,0 +1,14 @@
+// { dg-additional-options -fmodules-ts }
+
+import frob;
+
+int main ()
+{
+  if (6 != add (1, 2, 3))
+    return 1;
+
+  if (10 != sum (1, unsigned (2), 3.0f, 4.0))
+    return 2;
+
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/var-tpl-concept-1.h w/gcc/testsuite/g++.dg/modules/var-tpl-concept-1.h
new file mode 100644
index 00000000000..1dbd07fbd8e
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/var-tpl-concept-1.h
@@ -0,0 +1,70 @@
+
+template<class _CharT> struct char_traits;
+
+template<typename _CharT, typename _Traits = char_traits<_CharT>>
+class basic_string;
+
+typedef basic_string<char> string;
+
+template<typename> struct iterator_traits;
+
+template<bool _Cond> struct conditional;
+
+template<typename _Iter>
+inline constexpr bool disable_sized_sentinel_for = false;
+
+template<typename _Iter>
+concept sized_sentinel_for = !disable_sized_sentinel_for<_Iter>;
+
+template<typename _Iterator>
+class __normal_iterator
+{
+  typedef iterator_traits<_Iterator> __traits_type;
+};
+
+template<typename _Iterator>
+class reverse_iterator
+{
+public:
+  using iterator_concept
+    = typename conditional<sized_sentinel_for<_Iterator>>::type;
+};
+
+
+template<typename _Iterator>
+requires (!sized_sentinel_for<_Iterator>)
+bool disable_sized_sentinel_for<reverse_iterator<_Iterator>> = true;
+
+
+template<typename _Iterator>
+bool operator==(const reverse_iterator<_Iterator>& __x,
+		const reverse_iterator<_Iterator>& __y);
+template<typename _Iterator>
+bool operator==(const __normal_iterator<_Iterator>& __lhs,
+		const __normal_iterator<_Iterator>& __rhs);
+
+template<typename _It >
+class common_iterator
+{
+public:
+  friend bool operator==(const common_iterator& __x,
+			 const common_iterator& __y)
+  {
+    return __x._M_it == __y._M_it;
+  }
+
+private:
+  _It _M_it;
+};
+
+template<typename _It>
+struct iterator_traits<common_iterator<_It>>
+{
+};
+
+template<typename _CharT>
+struct char_traits
+{
+  static bool eq(const _CharT& __c1, const _CharT& __c2)
+  { return __c1 == __c2; }
+};
diff --git c/gcc/testsuite/g++.dg/modules/var-tpl-concept-1_a.C w/gcc/testsuite/g++.dg/modules/var-tpl-concept-1_a.C
new file mode 100644
index 00000000000..4655e396118
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/var-tpl-concept-1_a.C
@@ -0,0 +1,8 @@
+// { dg-additional-options {-fmodules-ts -fconcepts} }
+module;
+#include "var-tpl-concept-1.h"
+
+export module foo:part1;
+// { dg-module-cmi {foo:part1} }
+
+export void bar (string &);
diff --git c/gcc/testsuite/g++.dg/modules/var-tpl-concept-1_b.C w/gcc/testsuite/g++.dg/modules/var-tpl-concept-1_b.C
new file mode 100644
index 00000000000..2c44edeba29
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/var-tpl-concept-1_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options {-fmodules-ts -fconcepts} }
+module;
+#include "var-tpl-concept-1.h"
+
+export module foo;
+// { dg-module-cmi {foo} }
+
+export import :part1;
+
+export void baz (string &);
diff --git c/gcc/testsuite/g++.dg/modules/virt-1_a.C w/gcc/testsuite/g++.dg/modules/virt-1_a.C
new file mode 100644
index 00000000000..7719a287709
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/virt-1_a.C
@@ -0,0 +1,25 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export struct Visitor
+{
+  virtual int Visit ();
+};
+
+// Key function explicitly not in line (regardless of p1779's state)
+// We emit vtables & rtti only in this TU
+int Visitor::Visit ()
+{
+  return 0;
+}
+
+export int Visit (Visitor *v)
+{
+  return v->Visit ();
+}
+
+// { dg-final { scan-assembler {_ZTV7Visitor:} } }
+// { dg-final { scan-assembler {_ZTI7Visitor:} } }
+// { dg-final { scan-assembler {_ZTS7Visitor:} } }
diff --git c/gcc/testsuite/g++.dg/modules/virt-1_b.C w/gcc/testsuite/g++.dg/modules/virt-1_b.C
new file mode 100644
index 00000000000..b4372e19f0f
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/virt-1_b.C
@@ -0,0 +1,23 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+struct Mine : Visitor 
+{
+  int Visit () override
+  {
+    return 1;
+  }
+};
+
+int main ()
+{
+  Mine me;
+
+  return !(Visit (&me) == 1);
+}
+
+// We do not emit Visitor vtable or rtti here
+// { dg-final { scan-assembler-not {_ZTV7Visitor:} } }
+// { dg-final { scan-assembler-not {_ZTI7Visitor:} } }
+// { dg-final { scan-assembler-not {_ZTS7Visitor:} } }
diff --git c/gcc/testsuite/g++.dg/modules/virt-2_a.C w/gcc/testsuite/g++.dg/modules/virt-2_a.C
new file mode 100644
index 00000000000..9115cc19cc2
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/virt-2_a.C
@@ -0,0 +1,27 @@
+// { dg-module-do run }
+// { dg-additional-options -fmodules-ts }
+export module foo;
+// { dg-module-cmi foo }
+
+export struct Visitor
+{
+  virtual int Visit ();
+};
+
+// Key function explicitly inline (regardless of p1779's state)
+// We emit vtables & rtti only in this TU
+inline // Yoink!
+  int Visitor::Visit ()
+{
+  return 0;
+}
+
+export int Visit (Visitor *v)
+{
+  return v->Visit ();
+}
+
+// Emit here
+// { dg-final { scan-assembler {_ZTV7Visitor:} } }
+// { dg-final { scan-assembler {_ZTI7Visitor:} } }
+// { dg-final { scan-assembler {_ZTS7Visitor:} } }
diff --git c/gcc/testsuite/g++.dg/modules/virt-2_b.C w/gcc/testsuite/g++.dg/modules/virt-2_b.C
new file mode 100644
index 00000000000..543218956e9
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/virt-2_b.C
@@ -0,0 +1,28 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+struct Mine : Visitor 
+{
+  int Visit () override
+  {
+    return 1;
+  }
+};
+
+extern int Foo ();
+
+int main ()
+{
+  Mine me;
+
+  if (auto b = Foo ())
+    return b;
+  return !(Visit (&me) == 1);
+}
+
+// We do not emit Visitor vtable
+// but we do emit rtti here
+// { dg-final { scan-assembler-not {_ZTV7Visitor:} } }
+// { dg-final { scan-assembler {_ZTI7Visitor:} } }
+// { dg-final { scan-assembler {_ZTS7Visitor:} } }
diff --git c/gcc/testsuite/g++.dg/modules/virt-2_c.C w/gcc/testsuite/g++.dg/modules/virt-2_c.C
new file mode 100644
index 00000000000..1ac7f994792
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/virt-2_c.C
@@ -0,0 +1,16 @@
+// { dg-additional-options -fmodules-ts }
+
+import foo;
+
+int Foo ()
+{
+  Visitor v;
+
+  return !(Visit (&v) == 0);
+}
+
+// We do emit Visitor vtable
+// andl also we do emit rtti here
+// { dg-final { scan-assembler {_ZTV7Visitor:} } }
+// { dg-final { scan-assembler {_ZTI7Visitor:} } }
+// { dg-final { scan-assembler {_ZTS7Visitor:} } }
diff --git c/gcc/testsuite/g++.dg/modules/vmort-1_a.C w/gcc/testsuite/g++.dg/modules/vmort-1_a.C
new file mode 100644
index 00000000000..aa404dda11a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vmort-1_a.C
@@ -0,0 +1,34 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+export module tom.riddle;
+// { dg-module-cmi tom.riddle }
+
+export inline auto One (int a)
+{
+  struct X {
+    int x;
+    // p1779 makes these things not-inline, which is a surprise.
+    // Asking CWG
+    inline X(int a) :x(a){}
+    inline operator int () const {return x;}
+  };
+
+  return X(a);
+}
+
+// Look Ma! this isn't inline!
+export auto Two (int a)
+{
+  struct Y {
+    int x;
+    // In this case we do manage to emit these fns (if not marked as
+    // inline), but we give them internal linkage, so they are not
+    // nameable from elsewhere.  Workaround for now.
+    inline Y(int a) :x(a){}
+    inline operator int () const {return x;}
+  };
+
+  return Y(a);
+}
+
diff --git c/gcc/testsuite/g++.dg/modules/vmort-1_b.C w/gcc/testsuite/g++.dg/modules/vmort-1_b.C
new file mode 100644
index 00000000000..9ba49f130cc
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vmort-1_b.C
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import tom.riddle;
+
+int main ()
+{
+  auto one = One (2);
+
+  if (int (one) != 2)
+    return 1;
+
+  int two = Two (3);
+  if (two != 3)
+    return 2;
+
+  return 0;
+}
diff --git c/gcc/testsuite/g++.dg/modules/vmort-2_a.C w/gcc/testsuite/g++.dg/modules/vmort-2_a.C
new file mode 100644
index 00000000000..27d114d86d0
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vmort-2_a.C
@@ -0,0 +1,15 @@
+// { dg-module-do run }
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-graph-blocks" }
+
+export module voldy;
+// { dg-module-cmi voldy }
+
+export auto frobber (int i)
+{
+  return [=] (int j) { return i + j; };
+}
+
+// { dg-final { scan-lang-dump {Connecting definition decl type_decl:'::frobber::._anon_0'} module } }
+// { dg-final { scan-lang-dump {Entities 5} module } }
+
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl declaration '::frobber'\n  \[1\]=decl definition '::frobber::._anon_0'\n(  \[.\]=decl [^\n]*'\n)*  \[.\]=binding '::frobber'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/vmort-2_b.C w/gcc/testsuite/g++.dg/modules/vmort-2_b.C
new file mode 100644
index 00000000000..e7376cc4fd7
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vmort-2_b.C
@@ -0,0 +1,20 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-graph-blocks" }
+
+export module malfoy;
+// { dg-module-cmi malfoy }
+
+import voldy;
+
+void interpose ()
+{
+  // Force renumber of anon vars
+  auto lambda = [] () {};
+}
+
+export auto conduit (int i)
+{
+  return frobber (i);
+}
+
+// { dg-final { scan-lang-dump-not {Cluster import } module } }
+// { dg-final { scan-lang-dump-not {onnecting definition decl type_decl:'::frobber@voldy:.::._anon_1@voldy:.'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/vmort-2_c.C w/gcc/testsuite/g++.dg/modules/vmort-2_c.C
new file mode 100644
index 00000000000..f50c40732fe
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vmort-2_c.C
@@ -0,0 +1,21 @@
+// { dg-additional-options "-fmodules-ts -fdump-lang-module-uid" }
+
+import malfoy;
+
+void interpose ()
+{
+  // Force renumber of anon vars
+  auto lambda0 = [] () {};
+  auto lambda1 = [] () {};
+  auto lambda2 = [] () {};
+}
+
+int main ()
+{
+  auto widget = conduit (2);
+
+  return !(widget (8) == 10);
+}
+
+// { dg-final { scan-lang-dump {Loading entity voldy\[1\] section:1} module } }
+// { dg-final { scan-lang-dump {Indirect:-[0-9]* decl's type record_type:'::frobber@voldy:.::._anon_3@voldy:.'} module } }
diff --git c/gcc/testsuite/g++.dg/modules/vtt-1_a.C w/gcc/testsuite/g++.dg/modules/vtt-1_a.C
new file mode 100644
index 00000000000..11a1f6fb161
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vtt-1_a.C
@@ -0,0 +1,36 @@
+// { dg-additional-options "-fmodules-ts -O2 -fno-inline" }
+
+export module foo;
+// { dg-module-cmi foo }
+
+export struct base 
+{
+  base () {}
+  virtual ~base ();
+  int m;
+};
+
+base::~base ()
+{
+}
+
+export struct derived : virtual base 
+{
+  derived () {}
+  virtual ~derived ();
+  int m2;
+};
+
+derived::~derived ()
+{
+}
+
+export void make_foo ()
+{
+  base b;
+  derived d;
+}
+
+// { dg-final {scan-assembler "_ZTV4base:" } }
+// { dg-final {scan-assembler "_ZTV7derived:" } }
+// { dg-final {scan-assembler "_ZTT7derived:" } }
diff --git c/gcc/testsuite/g++.dg/modules/vtt-1_b.C w/gcc/testsuite/g++.dg/modules/vtt-1_b.C
new file mode 100644
index 00000000000..2f1b9659a56
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vtt-1_b.C
@@ -0,0 +1,28 @@
+// { dg-additional-options "-fmodules-ts -O2 -fno-inline" }
+
+export module bar;
+// { dg-module-cmi bar }
+
+export import foo;
+
+export struct mine : derived
+{
+  mine () {}
+  ~mine ();
+  int mm;
+};
+
+mine::~mine ()
+{
+}
+
+export inline void make_bar ()
+{
+  mine m;
+}
+
+// { dg-final {scan-assembler-not "_ZTV4base:" } }
+// { dg-final {scan-assembler-not "_ZTV7derived:" } }
+// { dg-final {scan-assembler-not "_ZTT7derived:" } }
+// { dg-final {scan-assembler "_ZTV4mine:" } }
+// { dg-final {scan-assembler "_ZTT4mine:" } }
diff --git c/gcc/testsuite/g++.dg/modules/vtt-1_c.C w/gcc/testsuite/g++.dg/modules/vtt-1_c.C
new file mode 100644
index 00000000000..9acdd32f03b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vtt-1_c.C
@@ -0,0 +1,19 @@
+// { dg-additional-options "-fmodules-ts -O2 -fno-inline" }
+
+import bar;
+
+int main ()
+{
+  make_foo ();
+  make_bar ();
+
+  mine m0;
+
+  return 0;
+}
+
+// { dg-final {scan-assembler-not "_ZTV4base:" } }
+// { dg-final {scan-assembler-not "_ZTV7derived:" } }
+// { dg-final {scan-assembler-not "_ZTT7derived:" } }
+// { dg-final {scan-assembler-not "_ZTV4mine:" } }
+// { dg-final {scan-assembler-not "_ZTT4mine:" } }
diff --git c/gcc/testsuite/g++.dg/modules/vtt-2.h w/gcc/testsuite/g++.dg/modules/vtt-2.h
new file mode 100644
index 00000000000..5ae0db0cb7b
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vtt-2.h
@@ -0,0 +1,14 @@
+
+class basic_ios
+{
+public:
+  virtual ~basic_ios();
+  basic_ios();
+};
+
+class basic_ostream : virtual public basic_ios
+{
+public:
+  basic_ostream();
+  virtual ~basic_ostream();
+};
diff --git c/gcc/testsuite/g++.dg/modules/vtt-2_a.H w/gcc/testsuite/g++.dg/modules/vtt-2_a.H
new file mode 100644
index 00000000000..0e018726fa6
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vtt-2_a.H
@@ -0,0 +1,4 @@
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+#include "vtt-2.h"
diff --git c/gcc/testsuite/g++.dg/modules/vtt-2_b.C w/gcc/testsuite/g++.dg/modules/vtt-2_b.C
new file mode 100644
index 00000000000..c1ed3d53741
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/vtt-2_b.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fdump-lang-module-alias" }
+
+#include "vtt-2.h"
+import "vtt-2_a.H";
+
+// { dg-final { scan-lang-dump-not {merge key \(new\)} module } }
+// { dg-final { scan-lang-dump-times {merge key \(unique\)} 2 module } }
