--- gcc/diagnostic.h.jj	2024-09-26 15:42:05.696731787 +0200
+++ gcc/diagnostic.h	2024-09-26 17:32:16.419161700 +0200
@@ -256,6 +256,9 @@ public:
   diagnostic_t
   update_effective_level_from_pragmas (diagnostic_info *diagnostic) const;
 
+  int pch_save (FILE *);
+  int pch_restore (FILE *);
+
 private:
   /* Each time a diagnostic's classification is changed with a pragma,
      we record the change and the location of the change in an array of
@@ -551,6 +554,18 @@ public:
 			  const char *, const char *, va_list *,
 			  diagnostic_t) ATTRIBUTE_GCC_DIAG(7,0);
 
+  int
+  pch_save (FILE *f)
+  {
+    return m_option_classifier.pch_save (f);
+  }
+
+  int
+  pch_restore (FILE *f)
+  {
+    return m_option_classifier.pch_restore (f);
+  }
+
 private:
   void error_recursion () ATTRIBUTE_NORETURN;
 
--- gcc/diagnostic.cc.jj	2024-09-26 16:11:51.664502977 +0200
+++ gcc/diagnostic.cc	2024-09-26 22:59:05.204135316 +0200
@@ -156,6 +156,46 @@ diagnostic_option_classifier::fini ()
   m_push_list.release ();
 }
 
+/* Save the diagnostic_option_classifier state to F for PCH
+   output.  Returns 0 on success, -1 on error.  */
+
+int
+diagnostic_option_classifier::pch_save (FILE *f)
+{
+  unsigned int lengths[2] = { m_classification_history.length (),
+			      m_push_list.length () };
+  if (fwrite (lengths, sizeof (lengths), 1, f) != 1
+      || fwrite (m_classification_history.address (),
+		 sizeof (diagnostic_classification_change_t),
+		 lengths[0], f) != lengths[0]
+      || fwrite (m_push_list.address (), sizeof (int),
+		 lengths[1], f) != lengths[1])
+    return -1;
+  return 0;
+}
+
+/* Read the diagnostic_option_classifier state from F for PCH
+   read.  Returns 0 on success, -1 on error.  */
+
+int
+diagnostic_option_classifier::pch_restore (FILE *f)
+{
+  unsigned int lengths[2];
+  if (fread (lengths, sizeof (lengths), 1, f) != 1)
+    return -1;
+  gcc_checking_assert (m_classification_history.is_empty ());
+  gcc_checking_assert (m_push_list.is_empty ());
+  m_classification_history.safe_grow (lengths[0]);
+  m_push_list.safe_grow (lengths[1]);
+  if (fread (m_classification_history.address (),
+	     sizeof (diagnostic_classification_change_t),
+	     lengths[0], f) != lengths[0]
+      || fread (m_push_list.address (), sizeof (int),
+		lengths[1], f) != lengths[1])
+    return -1;
+  return 0;
+}
+
 /* Save all diagnostic classifications in a stack.  */
 
 void
--- gcc/c-family/c-pch.cc.jj	2024-02-01 16:00:37.149739756 +0100
+++ gcc/c-family/c-pch.cc	2024-09-26 18:12:31.097700113 +0200
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.
 #include "c-pragma.h"
 #include "langhooks.h"
 #include "hosthooks.h"
+#include "diagnostic.h"
 
 /* This is a list of flag variables that must match exactly, and their
    names for the error message.  The possible values for *flag_var must
@@ -178,7 +179,8 @@ c_common_write_pch (void)
   cpp_write_pch_state (parse_in, pch_outfile);
   timevar_pop (TV_PCH_CPP_SAVE);
 
-  if (fseek (pch_outfile, 0, SEEK_SET) != 0
+  if (global_dc->pch_save (pch_outfile) < 0
+      || fseek (pch_outfile, 0, SEEK_SET) != 0
       || fwrite (get_ident (), IDENT_LENGTH, 1, pch_outfile) != 1)
     fatal_error (input_location, "cannot write %s: %m", pch_file);
 
@@ -359,6 +361,10 @@ c_common_read_pch (cpp_reader *pfile, co
   linemap_line_start (line_table, saved_loc.line, 0);
 
   timevar_pop (TV_PCH_CPP_RESTORE);
+
+  if (global_dc->pch_restore (f) < 0)
+    fatal_error (input_location, "cannot read %s: %m", name);
+
   fclose (f);
 
   if (cpp_result != 0)
--- gcc/testsuite/g++.dg/pch/pr116847.C.jj	2024-09-26 18:29:02.679292807 +0200
+++ gcc/testsuite/g++.dg/pch/pr116847.C	2024-09-26 18:27:42.679374530 +0200
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++11 } }
+
+#include "pr116847.H"
+
+int a = S<0>::bar ();
+
+int
+main ()
+{
+}
--- gcc/testsuite/g++.dg/pch/pr116847.Hs.jj	2024-09-26 18:28:58.866344362 +0200
+++ gcc/testsuite/g++.dg/pch/pr116847.Hs	2024-09-26 18:27:35.579470530 +0200
@@ -0,0 +1,8 @@
+[[deprecated]] int foo () { return 42; }
+template <int N>
+struct S {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+static int bar () { return foo (); }
+#pragma GCC diagnostic pop
+};
