diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 4a9fb1c3c00..712fdc45d40 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2480,6 +2480,9 @@ vague_linkage_p (tree decl)
   /* Unfortunately, import_export_decl has not always been called
      before the function is processed, so we cannot simply check
      DECL_COMDAT.  */
+  if (DECL_LANG_SPECIFIC (decl)
+      && DECL_EXPLICIT_INSTANTIATION (decl))
+    return false;
   if (DECL_COMDAT (decl)
       || (TREE_CODE (decl) == FUNCTION_DECL
 	  && DECL_DECLARED_INLINE_P (decl)
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-3_a.C b/gcc/testsuite/g++.dg/modules/extern-tpl-3_a.C
new file mode 100644
index 00000000000..def3cd1413d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-3_a.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules -Wno-global-module" }
+// { dg-module-cmi M }
+
+module;
+template <typename>
+struct S {
+  S() {}
+};
+export module M;
+extern template class S<int>;
+S<int> s;
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-3_b.C b/gcc/testsuite/g++.dg/modules/extern-tpl-3_b.C
new file mode 100644
index 00000000000..5d96937ce02
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-3_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules" }
+
+template <typename>
+struct S {
+  S() {}
+};
+
+void foo() { S<double> x;}
+
+import M;
+
+// Lazy loading of extern S<int> at EOF should not ICE
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-4_a.C b/gcc/testsuite/g++.dg/modules/extern-tpl-4_a.C
new file mode 100644
index 00000000000..16f1b041307
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-4_a.C
@@ -0,0 +1,24 @@
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi M }
+
+export module M;
+
+export template <typename T> inline void a() {}
+extern template void a<int>();
+extern template void a<bool>();
+template void a<char>();
+
+export template <typename T> void b() {}
+extern template void b<int>();
+extern template void b<bool>();
+template void b<char>();
+
+export template <typename T> inline int c = 123;
+extern template int c<int>;
+extern template int c<bool>;
+template int c<char>;
+
+export template <typename T> int d = 123;
+extern template int d<int>;
+extern template int d<bool>;
+template int d<char>;
diff --git a/gcc/testsuite/g++.dg/modules/extern-tpl-4_b.C b/gcc/testsuite/g++.dg/modules/extern-tpl-4_b.C
new file mode 100644
index 00000000000..1dd4afe9f6b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/extern-tpl-4_b.C
@@ -0,0 +1,46 @@
+// { dg-additional-options "-fmodules" }
+
+import M;
+
+int main() {
+  a<int>();
+  a<char>();
+  a<double>();
+
+  b<int>();
+  b<char>();
+  b<double>();
+
+  int x = c<int> + c<char> + c<double>;
+  int y = d<int> + d<char> + d<double>;
+  return x + y;
+}
+
+// 'int': imported explicit instantiation decls should not be emitted here:
+// { dg-final { scan-assembler-not "_ZW1M1aIiEvv:" } }
+// { dg-final { scan-assembler-not "_ZW1M1bIiEvv:" } }
+// { dg-final { scan-assembler-not "_ZW1M1cIiE:" } }
+// { dg-final { scan-assembler-not "_ZW1M1dIiE:" } }
+
+// 'char': explicit instantiation definitions don't need to be emitted here:
+// { dg-final { scan-assembler-not "_ZW1M1aIcEvv:" } }
+// { dg-final { scan-assembler-not "_ZW1M1bIcEvv:" } }
+// { dg-final { scan-assembler-not "_ZW1M1cIcE:" } }
+// { dg-final { scan-assembler-not "_ZW1M1dIcE:" } }
+
+// 'double': these are not explicitly instantiated and should be emitted here:
+// { dg-final { scan-assembler "_ZW1M1aIdEvv:" } }
+// { dg-final { scan-assembler "_ZW1M1bIdEvv:" } }
+// { dg-final { scan-assembler "_ZW1M1cIdE:" } }
+// { dg-final { scan-assembler "_ZW1M1dIdE:" } }
+
+template void a<bool>();
+template void b<bool>();
+template int c<bool>;
+template int d<bool>;
+
+// 'bool': instantiated in this file, and so must be emitted here:
+// { dg-final { scan-assembler "_ZW1M1aIbEvv:" } }
+// { dg-final { scan-assembler "_ZW1M1bIbEvv:" } }
+// { dg-final { scan-assembler "_ZW1M1cIbE:" } }
+// { dg-final { scan-assembler "_ZW1M1dIbE:" } }
