diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 7c42aea05ee..07477d33955 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -3681,7 +3681,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
 
  public:
   /* Read and write module.  */
-  void write_begin (elf_out *to, cpp_reader *,
+  bool write_begin (elf_out *to, cpp_reader *,
 		    module_state_config &, unsigned &crc);
   void write_end (elf_out *to, cpp_reader *,
 		  module_state_config &, unsigned &crc);
@@ -18317,7 +18317,7 @@ ool_cmp (const void *a_, const void *b_)
      MOD_SNAME_PFX.cfg      : config data
 */
 
-void
+bool
 module_state::write_begin (elf_out *to, cpp_reader *reader,
 			   module_state_config &config, unsigned &crc)
 {
@@ -18395,10 +18395,7 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
   table.find_dependencies (this);
 
   if (!table.finalize_dependencies ())
-    {
-      to->set_error ();
-      return;
-    }
+    return false;
 
 #if CHECKING_P
   /* We're done verifying at-most once reading, reset to verify
@@ -18595,6 +18592,8 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
   // so-controlled.
   if (false)
     write_env (to);
+
+  return true;
 }
 
 // Finish module writing after we've emitted all dynamic initializers. 
@@ -20847,20 +20846,29 @@ finish_module_processing (cpp_reader *reader)
 
       cookie = new module_processing_cookie (cmi_name, tmp_name, fd, e);
 
-      if (errorcount
-	  /* Don't write the module if it contains an erroneous template.  */
-	  || (erroneous_templates
-	      && !erroneous_templates->is_empty ()))
-	warning_at (state->loc, 0, "not writing module %qs due to errors",
-		    state->get_flatname ());
+      if (errorcount)
+	/* Don't write the module if we have reported errors.  */;
+      else if (erroneous_templates
+	       && !erroneous_templates->is_empty ())
+	{
+	  /* Don't write the module if it contains an erroneous template.
+	     Also emit notes about where errors occurred in case
+	     -Wno-template-body was passed.  */
+	  auto_diagnostic_group d;
+	  error_at (state->loc, "not writing module %qs due to errors "
+		    "in template bodies", state->get_flatname ());
+	  if (!warn_template_body)
+	    inform (state->loc, "enable %<-Wtemplate-body%> for more details");
+	  for (auto e : *erroneous_templates)
+	    inform (e.second, "first error in %qD appeared here", e.first);
+	}
       else if (cookie->out.begin ())
 	{
-	  cookie->began = true;
-	  auto loc = input_location;
 	  /* So crashes finger-point the module decl.  */
-	  input_location = state->loc;
-	  state->write_begin (&cookie->out, reader, cookie->config, cookie->crc);
-	  input_location = loc;
+	  iloc_sentinel ils = state->loc;
+	  if (state->write_begin (&cookie->out, reader, cookie->config,
+				  cookie->crc))
+	    cookie->began = true;
 	}
 
       dump.pop (n);
diff --git a/gcc/testsuite/g++.dg/modules/ambig-2_b.C b/gcc/testsuite/g++.dg/modules/ambig-2_b.C
index b94416aabbf..859cf14ac07 100644
--- a/gcc/testsuite/g++.dg/modules/ambig-2_b.C
+++ b/gcc/testsuite/g++.dg/modules/ambig-2_b.C
@@ -6,5 +6,3 @@ import A;
 
 extern "C++" int foo ();
 extern "C++" int bar ();  // { dg-error "ambiguating new declaration" }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/atom-decl-2.C b/gcc/testsuite/g++.dg/modules/atom-decl-2.C
index b463dc8e214..43120152b45 100644
--- a/gcc/testsuite/g++.dg/modules/atom-decl-2.C
+++ b/gcc/testsuite/g++.dg/modules/atom-decl-2.C
@@ -2,5 +2,3 @@
 export module thing;
 int i;
 import baz; // { dg-error "must be contiguous" }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/atom-pragma-3.C b/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
index b95b2c8ad75..f2cadf02f2f 100644
--- a/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
+++ b/gcc/testsuite/g++.dg/modules/atom-pragma-3.C
@@ -8,5 +8,3 @@ export module foo;
 import baz; // { dg-error "must be contiguous" }
 
 int i;
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C b/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C
index 28e54b808b2..42b84af651c 100644
--- a/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C
+++ b/gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C
@@ -7,4 +7,3 @@ import kevin; // { dg-error "not be from header" }
 # 8 "" 2
 
 import kevin; // ok
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/block-decl-2.C b/gcc/testsuite/g++.dg/modules/block-decl-2.C
index 974e26f9b7a..d491a18dfb1 100644
--- a/gcc/testsuite/g++.dg/modules/block-decl-2.C
+++ b/gcc/testsuite/g++.dg/modules/block-decl-2.C
@@ -17,5 +17,3 @@ export extern "C++" auto foo() {
   };
   return X{};
 }
-
-// { dg-prune-output "failed to write compiled module" }
diff --git a/gcc/testsuite/g++.dg/modules/dir-only-4.C b/gcc/testsuite/g++.dg/modules/dir-only-4.C
index 80d6461e81f..9cb0587c0aa 100644
--- a/gcc/testsuite/g++.dg/modules/dir-only-4.C
+++ b/gcc/testsuite/g++.dg/modules/dir-only-4.C
@@ -7,4 +7,3 @@ export module foo;
 class import {};
 
 import x; // { dg-error "post-module-declaration" }
- // { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/enum-12.C b/gcc/testsuite/g++.dg/modules/enum-12.C
index cf8f445e076..3f29c52d59d 100644
--- a/gcc/testsuite/g++.dg/modules/enum-12.C
+++ b/gcc/testsuite/g++.dg/modules/enum-12.C
@@ -6,5 +6,3 @@ export module foo;
 namespace std {
   enum class align_val_t : decltype(sizeof(int)) {};  // { dg-error "in module .foo. conflicts with builtin" }
 }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C b/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
index 3295a6af050..736e891d1c7 100644
--- a/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C
@@ -4,4 +4,3 @@ export module evil;
 
 export // { dg-error "not part of following" }
 #include "exp-xlate-1_a.H" // { dg-error "must be contiguous" }
-// { dg-prune-output {not writing module} }
diff --git a/gcc/testsuite/g++.dg/modules/export-1.C b/gcc/testsuite/g++.dg/modules/export-1.C
index 598814370ec..071f5ca2f35 100644
--- a/gcc/testsuite/g++.dg/modules/export-1.C
+++ b/gcc/testsuite/g++.dg/modules/export-1.C
@@ -24,5 +24,3 @@ export class A; // { dg-error "conflicting exporting for declaration" }
 
 template <typename T> struct B;
 export template <typename T> struct B {};  // { dg-error "conflicting exporting for declaration" }
-
-// { dg-warning "due to errors" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/modules/export-3.C b/gcc/testsuite/g++.dg/modules/export-3.C
index 76765fd2b2f..6af314b9519 100644
--- a/gcc/testsuite/g++.dg/modules/export-3.C
+++ b/gcc/testsuite/g++.dg/modules/export-3.C
@@ -26,5 +26,3 @@ namespace {
 }
 
 export namespace {}  // { dg-error "internal linkage" }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/friend-3.C b/gcc/testsuite/g++.dg/modules/friend-3.C
index 48320eba46a..cf0bbb7de5e 100644
--- a/gcc/testsuite/g++.dg/modules/friend-3.C
+++ b/gcc/testsuite/g++.dg/modules/friend-3.C
@@ -31,4 +31,3 @@ export void quux (); // { dg-error "conflicting export" }
 void toto (); // not exported
 
 }
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/friend-5_b.C b/gcc/testsuite/g++.dg/modules/friend-5_b.C
index 6b561265155..b362cf82547 100644
--- a/gcc/testsuite/g++.dg/modules/friend-5_b.C
+++ b/gcc/testsuite/g++.dg/modules/friend-5_b.C
@@ -8,4 +8,3 @@ class B { // { dg-error "conflicts with import" }
   B() { object.value = 42; }
   A object;
 };
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C b/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C
index f33c464bee9..338c017c9b9 100644
--- a/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C
@@ -1,5 +1,3 @@
 // { dg-additional-options "-fmodules-ts -fmodule-mapper=|@g++-mapper-server\\ -t\\ [srcdir]/inc-xlate-1.map" }
 export module bad;
 #include "inc-xlate-1_a.H"  // { dg-error "not be include-translated" }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/internal-1.C b/gcc/testsuite/g++.dg/modules/internal-1.C
index 45d3bf06f28..9f7299a5fc7 100644
--- a/gcc/testsuite/g++.dg/modules/internal-1.C
+++ b/gcc/testsuite/g++.dg/modules/internal-1.C
@@ -1,6 +1,6 @@
 // { dg-additional-options "-fmodules-ts" }
 
-export module frob; // { dg-error "failed to write" }
+export module frob;
 // { dg-module-cmi !frob }
 
 namespace {
diff --git a/gcc/testsuite/g++.dg/modules/linkage-2.C b/gcc/testsuite/g++.dg/modules/linkage-2.C
index d913d6a30fc..4b20411572c 100644
--- a/gcc/testsuite/g++.dg/modules/linkage-2.C
+++ b/gcc/testsuite/g++.dg/modules/linkage-2.C
@@ -28,5 +28,3 @@ export void use() {
 // here is an exposure of this type, so this should be an error; we don't yet
 // implement this checking however.
 struct {} s;  // { dg-error "TU-local" "" { xfail *-*-* } }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/local-extern-1.C b/gcc/testsuite/g++.dg/modules/local-extern-1.C
index 7b016053d36..3e10c67d132 100644
--- a/gcc/testsuite/g++.dg/modules/local-extern-1.C
+++ b/gcc/testsuite/g++.dg/modules/local-extern-1.C
@@ -15,6 +15,3 @@ inline void dob ()
 {
   extern int bob; // { dg-error "block-scope extern" }
 }
-
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/main-1.C b/gcc/testsuite/g++.dg/modules/main-1.C
index 0d79edddb75..42929778481 100644
--- a/gcc/testsuite/g++.dg/modules/main-1.C
+++ b/gcc/testsuite/g++.dg/modules/main-1.C
@@ -1,5 +1,4 @@
 // { dg-additional-options "-fmodules-ts" }
-// { dg-prune-output "not writing module" }
 
 export module M;
 int main() {}  // { dg-error "attach" }
diff --git a/gcc/testsuite/g++.dg/modules/map-2.C b/gcc/testsuite/g++.dg/modules/map-2.C
index dceb1834196..94d3f7a1a41 100644
--- a/gcc/testsuite/g++.dg/modules/map-2.C
+++ b/gcc/testsuite/g++.dg/modules/map-2.C
@@ -7,5 +7,3 @@
 export module foo;
 // { dg-error "Interface: no such module" "" { target *-*-* } .-1 }
 // { dg-error "failed reading mapper" "" { target *-*-* } 0 }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/mod-decl-1.C b/gcc/testsuite/g++.dg/modules/mod-decl-1.C
index df398b3ef50..ac7bb84699a 100644
--- a/gcc/testsuite/g++.dg/modules/mod-decl-1.C
+++ b/gcc/testsuite/g++.dg/modules/mod-decl-1.C
@@ -27,5 +27,3 @@ void Bink ()
 
 module a.; // { dg-error "only permitted as" }
 
-// { dg-prune-output "not writing module" }
-
diff --git a/gcc/testsuite/g++.dg/modules/mod-decl-3.C b/gcc/testsuite/g++.dg/modules/mod-decl-3.C
index 16fa5a85a56..23ba7f13957 100644
--- a/gcc/testsuite/g++.dg/modules/mod-decl-3.C
+++ b/gcc/testsuite/g++.dg/modules/mod-decl-3.C
@@ -22,5 +22,3 @@ namespace Bink
   import  // { dg-error "does not name" }
   ben;
 }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/permissive-error-1.C b/gcc/testsuite/g++.dg/modules/permissive-error-1.C
new file mode 100644
index 00000000000..70ae1ec2dfc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/permissive-error-1.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts -fpermissive" }
+// { dg-module-cmi !M }
+
+export module M;  // { dg-error "not writing module" }
+
+template <typename T> void f() {
+  const int n = 42;
+  ++n;  // { dg-warning "read-only" }
+	// { dg-message "appeared here" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/modules/permissive-error-2.C b/gcc/testsuite/g++.dg/modules/permissive-error-2.C
new file mode 100644
index 00000000000..1e62d45207f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/permissive-error-2.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -Wno-template-body" }
+// { dg-module-cmi !M }
+
+export module M;  // { dg-error "not writing module" }
+
+template <typename T> void f() {
+  const int n = 42;
+  ++n;  // { dg-message "appeared here" }
+}
+
+// { dg-message "enable \[^\n\r\]* for more details" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/modules/pr99174.H b/gcc/testsuite/g++.dg/modules/pr99174.H
index 62d5513b19a..60d01c59c77 100644
--- a/gcc/testsuite/g++.dg/modules/pr99174.H
+++ b/gcc/testsuite/g++.dg/modules/pr99174.H
@@ -1,5 +1,3 @@
 // { dg-additional-options -fmodule-header }
 // { dg-module-cmi !{} }
 import "pr99174.H"; // { dg-error "cannot import" }
-
-// { dg-prune-output {not writing module} }
diff --git a/gcc/testsuite/g++.dg/modules/pr99468.H b/gcc/testsuite/g++.dg/modules/pr99468.H
index b6be0c349d5..d7da3a83e1c 100644
--- a/gcc/testsuite/g++.dg/modules/pr99468.H
+++ b/gcc/testsuite/g++.dg/modules/pr99468.H
@@ -4,4 +4,3 @@
 module M; // { dg-error "module-declaration not permitted" }
 
 int i;
-// { dg-prune-output "not writing" }
diff --git a/gcc/testsuite/g++.dg/modules/token-1.C b/gcc/testsuite/g++.dg/modules/token-1.C
index 50eee4c7ea1..db9a09b415f 100644
--- a/gcc/testsuite/g++.dg/modules/token-1.C
+++ b/gcc/testsuite/g++.dg/modules/token-1.C
@@ -4,4 +4,3 @@ 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 a/gcc/testsuite/g++.dg/modules/token-3.C b/gcc/testsuite/g++.dg/modules/token-3.C
index 5bab426e2a6..1b4f66e6345 100644
--- a/gcc/testsuite/g++.dg/modules/token-3.C
+++ b/gcc/testsuite/g++.dg/modules/token-3.C
@@ -3,4 +3,3 @@
 export module bob; // { dg-error "in included file" }
 # 6 "" 2
 // { dg-module-cmi !bob }
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/token-4.C b/gcc/testsuite/g++.dg/modules/token-4.C
index 5a852370d66..388da102f5f 100644
--- a/gcc/testsuite/g++.dg/modules/token-4.C
+++ b/gcc/testsuite/g++.dg/modules/token-4.C
@@ -2,4 +2,3 @@
 #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 a/gcc/testsuite/g++.dg/modules/token-5.C b/gcc/testsuite/g++.dg/modules/token-5.C
index 29d3ec8fd70..8190f5ef6fb 100644
--- a/gcc/testsuite/g++.dg/modules/token-5.C
+++ b/gcc/testsuite/g++.dg/modules/token-5.C
@@ -7,4 +7,3 @@ class Y;
 
 export module frob;
 // { dg-module-cmi !frob }
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/using-10.C b/gcc/testsuite/g++.dg/modules/using-10.C
index 5735353ee21..d468a36f5d8 100644
--- a/gcc/testsuite/g++.dg/modules/using-10.C
+++ b/gcc/testsuite/g++.dg/modules/using-10.C
@@ -67,5 +67,3 @@ namespace t {
 export using t::a;  // { dg-error "does not have external linkage" }
 export using t::b;  // { dg-error "does not have external linkage" }
 export using t::c;  // { dg-error "does not have external linkage" }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/using-12.C b/gcc/testsuite/g++.dg/modules/using-12.C
index 54eacf7276e..52ef3c6285d 100644
--- a/gcc/testsuite/g++.dg/modules/using-12.C
+++ b/gcc/testsuite/g++.dg/modules/using-12.C
@@ -69,5 +69,3 @@ namespace t {
   export using t::b;  // { dg-error "does not have external linkage" }
   export using t::c;  // { dg-error "does not have external linkage" }
 }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/using-3.C b/gcc/testsuite/g++.dg/modules/using-3.C
index d21512fb20a..898618d6cc0 100644
--- a/gcc/testsuite/g++.dg/modules/using-3.C
+++ b/gcc/testsuite/g++.dg/modules/using-3.C
@@ -13,5 +13,3 @@ 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 a/gcc/testsuite/g++.dg/modules/using-9.C b/gcc/testsuite/g++.dg/modules/using-9.C
index 4290280d897..8fb7b5e2c85 100644
--- a/gcc/testsuite/g++.dg/modules/using-9.C
+++ b/gcc/testsuite/g++.dg/modules/using-9.C
@@ -9,5 +9,3 @@ namespace outer {
 }
 
 export using outer::any_of;  // { dg-error "does not have external linkage" }
-
-// { dg-prune-output "not writing module" }
diff --git a/gcc/testsuite/g++.dg/modules/using-enum-2.C b/gcc/testsuite/g++.dg/modules/using-enum-2.C
index 813e2f630ab..12e37758e81 100644
--- a/gcc/testsuite/g++.dg/modules/using-enum-2.C
+++ b/gcc/testsuite/g++.dg/modules/using-enum-2.C
@@ -19,5 +19,3 @@ export using enum s::e1;  // { dg-error "does not have external linkage" }
 export using enum s::e2;  // { dg-error "does not have external linkage" }
 export using enum m::e3;  // { dg-error "does not have external linkage" }
 export using enum m::e4;  // { dg-error "does not have external linkage" }
-
-// { dg-prune-output "not writing module" }
