From 58e3e393dc57b93624920e295fdbe1d2bf25ba57 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 17 Jul 2025 12:09:25 -0400
Subject: [PATCH 29/41] {needs ChangeLog} move option_classifier to its own
 files

---
 gcc/Makefile.in                      |   1 +
 gcc/diagnostic.cc                    | 193 -----------------------
 gcc/diagnostics/context.h            |  82 +---------
 gcc/diagnostics/option-classifier.cc | 222 +++++++++++++++++++++++++++
 gcc/diagnostics/option-classifier.h  | 110 +++++++++++++
 5 files changed, 335 insertions(+), 273 deletions(-)
 create mode 100644 gcc/diagnostics/option-classifier.cc
 create mode 100644 gcc/diagnostics/option-classifier.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index fa68c6d1480f..cef28379ed95 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1860,6 +1860,7 @@ OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \
 	diagnostics/sarif-sink.o \
 	diagnostics/text-sink.o \
 	diagnostics/macro-unwinding.o \
+	diagnostics/option-classifier.o \
 	diagnostics/paths.o \
 	diagnostics/paths-output.o \
 	diagnostics/source-printing.o \
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 847464d1e5f0..9aecd0653cc9 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -126,95 +126,6 @@ diagnostic_set_caret_max_width (diagnostics::context *context, int value)
   context->m_source_printing.max_width = value;
 }
 
-void
-diagnostics::option_classifier::init (int n_opts)
-{
-  m_n_opts = n_opts;
-  m_classify_diagnostic = XNEWVEC (diagnostic_t, n_opts);
-  for (int i = 0; i < n_opts; i++)
-    m_classify_diagnostic[i] = DK_UNSPECIFIED;
-  m_push_list = vNULL;
-  m_classification_history = vNULL;
-}
-
-void
-diagnostics::option_classifier::fini ()
-{
-  XDELETEVEC (m_classify_diagnostic);
-  m_classify_diagnostic = nullptr;
-  m_classification_history.release ();
-  m_push_list.release ();
-}
-
-/* Save the diagnostics::option_classifier state to F for PCH
-   output.  Returns 0 on success, -1 on error.  */
-
-int
-diagnostics::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
-      || (lengths[0]
-	  && fwrite (m_classification_history.address (),
-		     sizeof (classification_change_t),
-		     lengths[0], f) != lengths[0])
-      || (lengths[1]
-	  && fwrite (m_push_list.address (), sizeof (int),
-		     lengths[1], f) != lengths[1]))
-    return -1;
-  return 0;
-}
-
-/* Read the diagnostics::option_classifier state from F for PCH
-   read.  Returns 0 on success, -1 on error.  */
-
-int
-diagnostics::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 ((lengths[0]
-       && fread (m_classification_history.address (),
-		 sizeof (classification_change_t),
-		 lengths[0], f) != lengths[0])
-      || (lengths[1]
-	  && fread (m_push_list.address (), sizeof (int),
-		    lengths[1], f) != lengths[1]))
-    return -1;
-  return 0;
-}
-
-/* Save all diagnostic classifications in a stack.  */
-
-void
-diagnostics::option_classifier::push ()
-{
-  m_push_list.safe_push (m_classification_history.length ());
-}
-
-/* Restore the topmost classification set off the stack.  If the stack
-   is empty, revert to the state based on command line parameters.  */
-
-void
-diagnostics::option_classifier::pop (location_t where)
-{
-  int jump_to;
-
-  if (!m_push_list.is_empty ())
-    jump_to = m_push_list.pop ();
-  else
-    jump_to = 0;
-
-  classification_change_t v = { where, jump_to, DK_POP };
-  m_classification_history.safe_push (v);
-}
-
 /* Initialize the diagnostic message outputting machinery.  */
 
 void
@@ -1078,58 +989,6 @@ diagnostics::logical_locations::manager::function_p (key k) const
     }
 }
 
-/* Interface to specify diagnostic kind overrides.  Returns the
-   previous setting, or DK_UNSPECIFIED if the parameters are out of
-   range.  If OPTION_ID is zero, the new setting is for all the
-   diagnostics.  */
-diagnostic_t
-diagnostics::option_classifier::
-classify_diagnostic (const diagnostics::context *context,
-		     diagnostic_option_id option_id,
-		     diagnostic_t new_kind,
-		     location_t where)
-{
-  diagnostic_t old_kind;
-
-  if (option_id.m_idx < 0
-      || option_id.m_idx >= m_n_opts
-      || new_kind >= DK_LAST_DIAGNOSTIC_KIND)
-    return DK_UNSPECIFIED;
-
-  old_kind = m_classify_diagnostic[option_id.m_idx];
-
-  /* Handle pragmas separately, since we need to keep track of *where*
-     the pragmas were.  */
-  if (where != UNKNOWN_LOCATION)
-    {
-      unsigned i;
-
-      /* Record the command-line status, so we can reset it back on DK_POP. */
-      if (old_kind == DK_UNSPECIFIED)
-	{
-	  old_kind = (!context->option_enabled_p (option_id)
-		      ? DK_IGNORED : DK_ANY);
-	  m_classify_diagnostic[option_id.m_idx] = old_kind;
-	}
-
-      classification_change_t *p;
-      FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
-	if (p->option == option_id.m_idx)
-	  {
-	    old_kind = p->kind;
-	    break;
-	  }
-
-      classification_change_t v
-	= { where, option_id.m_idx, new_kind };
-      m_classification_history.safe_push (v);
-    }
-  else
-    m_classify_diagnostic[option_id.m_idx] = new_kind;
-
-  return old_kind;
-}
-
 /* Helper function for print_parseable_fixits.  Print TEXT to PP, obeying the
    escaping rules for -fdiagnostics-parseable-fixits.  */
 
@@ -1239,58 +1098,6 @@ diagnostics::context::get_any_inlining_info (diagnostic_info *diagnostic)
     }
 }
 
-/* Update the kind of DIAGNOSTIC based on its location(s), including
-   any of those in its inlining stack, relative to any
-     #pragma GCC diagnostic
-   directives recorded within this object.
-
-   Return the new kind of DIAGNOSTIC if it was updated, or DK_UNSPECIFIED
-   otherwise.  */
-
-diagnostic_t
-diagnostics::option_classifier::
-update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
-{
-  if (m_classification_history.is_empty ())
-    return DK_UNSPECIFIED;
-
-  /* Iterate over the locations, checking the diagnostic disposition
-     for the diagnostic at each.  If it's explicitly set as opposed
-     to unspecified, update the disposition for this instance of
-     the diagnostic and return it.  */
-  for (location_t loc: diagnostic->m_iinfo.m_ilocs)
-    {
-      /* FIXME: Stupid search.  Optimize later. */
-      unsigned int i;
-      classification_change_t *p;
-      FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
-	{
-	  location_t pragloc = p->location;
-	  if (!linemap_location_before_p (line_table, pragloc, loc))
-	    continue;
-
-	  if (p->kind == (int) DK_POP)
-	    {
-	      /* Move on to the next region.  */
-	      i = p->option;
-	      continue;
-	    }
-
-	  diagnostic_option_id option = p->option;
-	  /* The option 0 is for all the diagnostics.  */
-	  if (option == 0 || option == diagnostic->m_option_id)
-	    {
-	      diagnostic_t kind = p->kind;
-	      if (kind != DK_UNSPECIFIED)
-		diagnostic->m_kind = kind;
-	      return kind;
-	    }
-	}
-    }
-
-  return DK_UNSPECIFIED;
-}
-
 /* Generate a URL string describing CWE.  The caller is responsible for
    freeing the string.  */
 
diff --git a/gcc/diagnostics/context.h b/gcc/diagnostics/context.h
index 21688439aaa5..9dee03342b2a 100644
--- a/gcc/diagnostics/context.h
+++ b/gcc/diagnostics/context.h
@@ -20,6 +20,8 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_DIAGNOSTICS_CONTEXT_H
 #define GCC_DIAGNOSTICS_CONTEXT_H
 
+#include "diagnostics/option-classifier.h"
+
 namespace diagnostics {
 
 /*  Forward declarations.  */
@@ -73,86 +75,6 @@ public:
   virtual char *make_option_url (diagnostic_option_id option_id) const = 0;
 };
 
-/* A stack of sets of classifications: each entry in the stack is
-   a mapping from option index to diagnostic severity that can be changed
-   via pragmas.  The stack can be pushed and popped.  */
-
-class option_classifier
-{
-public:
-  void init (int n_opts);
-  void fini ();
-
-  /* Save all diagnostic classifications in a stack.  */
-  void push ();
-
-  /* Restore the topmost classification set off the stack.  If the stack
-     is empty, revert to the state based on command line parameters.  */
-  void pop (location_t where);
-
-  bool option_unspecified_p (diagnostic_option_id option_id) const
-  {
-    return get_current_override (option_id) == DK_UNSPECIFIED;
-  }
-
-  diagnostic_t get_current_override (diagnostic_option_id option_id) const
-  {
-    gcc_assert (option_id.m_idx < m_n_opts);
-    return m_classify_diagnostic[option_id.m_idx];
-  }
-
-  diagnostic_t
-  classify_diagnostic (const context *context,
-		       diagnostic_option_id option_id,
-		       diagnostic_t new_kind,
-		       location_t where);
-
-  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
-     these structs.  */
-  struct classification_change_t
-  {
-    location_t location;
-
-    /* For DK_POP, this is the index of the corresponding push (as stored
-       in m_push_list).
-       Otherwise, this is an option index.  */
-    int option;
-
-    diagnostic_t kind;
-  };
-
-  int m_n_opts;
-
-  /* For each option index that can be passed to warning() et al
-     (OPT_* from options.h when using this code with the core GCC
-     options), this array may contain a new kind that the diagnostic
-     should be changed to before reporting, or DK_UNSPECIFIED to leave
-     it as the reported kind, or DK_IGNORED to not report it at
-     all.  */
-  diagnostic_t *m_classify_diagnostic;
-
-  /* History of all changes to the classifications above.  This list
-     is stored in location-order, so we can search it, either
-     binary-wise or end-to-front, to find the most recent
-     classification for a given diagnostic, given the location of the
-     diagnostic.  */
-  vec<classification_change_t> m_classification_history;
-
-  /* For context::get_classification_history, declared later.  */
-  friend class context;
-
-  /* For pragma push/pop.  */
-  vec<int> m_push_list;
-};
-
 /* A bundle of options relating to printing the user's source code
    (potentially with a margin, underlining, labels, etc).  */
 
diff --git a/gcc/diagnostics/option-classifier.cc b/gcc/diagnostics/option-classifier.cc
new file mode 100644
index 000000000000..77bce36a7302
--- /dev/null
+++ b/gcc/diagnostics/option-classifier.cc
@@ -0,0 +1,222 @@
+/* Stacks of set of classifications of diagnostics.
+   Copyright (C) 1999-2025 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "version.h"
+#include "diagnostic.h"
+
+namespace diagnostics {
+
+void
+option_classifier::init (int n_opts)
+{
+  m_n_opts = n_opts;
+  m_classify_diagnostic = XNEWVEC (diagnostic_t, n_opts);
+  for (int i = 0; i < n_opts; i++)
+    m_classify_diagnostic[i] = DK_UNSPECIFIED;
+  m_push_list = vNULL;
+  m_classification_history = vNULL;
+}
+
+void
+option_classifier::fini ()
+{
+  XDELETEVEC (m_classify_diagnostic);
+  m_classify_diagnostic = nullptr;
+  m_classification_history.release ();
+  m_push_list.release ();
+}
+
+/* Save the diagnostics::option_classifier state to F for PCH
+   output.  Returns 0 on success, -1 on error.  */
+
+int
+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
+      || (lengths[0]
+	  && fwrite (m_classification_history.address (),
+		     sizeof (classification_change_t),
+		     lengths[0], f) != lengths[0])
+      || (lengths[1]
+	  && fwrite (m_push_list.address (), sizeof (int),
+		     lengths[1], f) != lengths[1]))
+    return -1;
+  return 0;
+}
+
+/* Read the diagnostics::option_classifier state from F for PCH
+   read.  Returns 0 on success, -1 on error.  */
+
+int
+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 ((lengths[0]
+       && fread (m_classification_history.address (),
+		 sizeof (classification_change_t),
+		 lengths[0], f) != lengths[0])
+      || (lengths[1]
+	  && fread (m_push_list.address (), sizeof (int),
+		    lengths[1], f) != lengths[1]))
+    return -1;
+  return 0;
+}
+
+/* Save all diagnostic classifications in a stack.  */
+
+void
+option_classifier::push ()
+{
+  m_push_list.safe_push (m_classification_history.length ());
+}
+
+/* Restore the topmost classification set off the stack.  If the stack
+   is empty, revert to the state based on command line parameters.  */
+
+void
+option_classifier::pop (location_t where)
+{
+  int jump_to;
+
+  if (!m_push_list.is_empty ())
+    jump_to = m_push_list.pop ();
+  else
+    jump_to = 0;
+
+  classification_change_t v = { where, jump_to, DK_POP };
+  m_classification_history.safe_push (v);
+}
+
+/* Interface to specify diagnostic kind overrides.  Returns the
+   previous setting, or DK_UNSPECIFIED if the parameters are out of
+   range.  If OPTION_ID is zero, the new setting is for all the
+   diagnostics.  */
+
+diagnostic_t
+option_classifier::classify_diagnostic (const context *dc,
+					diagnostic_option_id option_id,
+					diagnostic_t new_kind,
+					location_t where)
+{
+  diagnostic_t old_kind;
+
+  if (option_id.m_idx < 0
+      || option_id.m_idx >= m_n_opts
+      || new_kind >= DK_LAST_DIAGNOSTIC_KIND)
+    return DK_UNSPECIFIED;
+
+  old_kind = m_classify_diagnostic[option_id.m_idx];
+
+  /* Handle pragmas separately, since we need to keep track of *where*
+     the pragmas were.  */
+  if (where != UNKNOWN_LOCATION)
+    {
+      unsigned i;
+
+      /* Record the command-line status, so we can reset it back on DK_POP. */
+      if (old_kind == DK_UNSPECIFIED)
+	{
+	  old_kind = (!dc->option_enabled_p (option_id)
+		      ? DK_IGNORED : DK_ANY);
+	  m_classify_diagnostic[option_id.m_idx] = old_kind;
+	}
+
+      classification_change_t *p;
+      FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
+	if (p->option == option_id.m_idx)
+	  {
+	    old_kind = p->kind;
+	    break;
+	  }
+
+      classification_change_t v
+	= { where, option_id.m_idx, new_kind };
+      m_classification_history.safe_push (v);
+    }
+  else
+    m_classify_diagnostic[option_id.m_idx] = new_kind;
+
+  return old_kind;
+}
+
+/* Update the kind of DIAGNOSTIC based on its location(s), including
+   any of those in its inlining stack, relative to any
+     #pragma GCC diagnostic
+   directives recorded within this object.
+
+   Return the new kind of DIAGNOSTIC if it was updated, or DK_UNSPECIFIED
+   otherwise.  */
+
+diagnostic_t
+option_classifier::
+update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
+{
+  if (m_classification_history.is_empty ())
+    return DK_UNSPECIFIED;
+
+  /* Iterate over the locations, checking the diagnostic disposition
+     for the diagnostic at each.  If it's explicitly set as opposed
+     to unspecified, update the disposition for this instance of
+     the diagnostic and return it.  */
+  for (location_t loc: diagnostic->m_iinfo.m_ilocs)
+    {
+      /* FIXME: Stupid search.  Optimize later. */
+      unsigned int i;
+      classification_change_t *p;
+      FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
+	{
+	  location_t pragloc = p->location;
+	  if (!linemap_location_before_p (line_table, pragloc, loc))
+	    continue;
+
+	  if (p->kind == (int) DK_POP)
+	    {
+	      /* Move on to the next region.  */
+	      i = p->option;
+	      continue;
+	    }
+
+	  diagnostic_option_id option = p->option;
+	  /* The option 0 is for all the diagnostics.  */
+	  if (option == 0 || option == diagnostic->m_option_id)
+	    {
+	      diagnostic_t kind = p->kind;
+	      if (kind != DK_UNSPECIFIED)
+		diagnostic->m_kind = kind;
+	      return kind;
+	    }
+	}
+    }
+
+  return DK_UNSPECIFIED;
+}
+
+} // namespace diagnostics
diff --git a/gcc/diagnostics/option-classifier.h b/gcc/diagnostics/option-classifier.h
new file mode 100644
index 000000000000..246b56c7b4ab
--- /dev/null
+++ b/gcc/diagnostics/option-classifier.h
@@ -0,0 +1,110 @@
+/* Stacks of set of classifications of diagnostics.
+   Copyright (C) 2000-2025 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_DIAGNOSTICS_OPTIONS_CLASSIFIER_H
+#define GCC_DIAGNOSTICS_OPTIONS_CLASSIFIER_H
+
+namespace diagnostics {
+
+/*  Forward declarations.  */
+class context;
+
+/* A stack of sets of classifications: each entry in the stack is
+   a mapping from option index to diagnostic severity that can be changed
+   via pragmas.  The stack can be pushed and popped.  */
+
+class option_classifier
+{
+public:
+  void init (int n_opts);
+  void fini ();
+
+  /* Save all diagnostic classifications in a stack.  */
+  void push ();
+
+  /* Restore the topmost classification set off the stack.  If the stack
+     is empty, revert to the state based on command line parameters.  */
+  void pop (location_t where);
+
+  bool option_unspecified_p (diagnostic_option_id option_id) const
+  {
+    return get_current_override (option_id) == DK_UNSPECIFIED;
+  }
+
+  diagnostic_t get_current_override (diagnostic_option_id option_id) const
+  {
+    gcc_assert (option_id.m_idx < m_n_opts);
+    return m_classify_diagnostic[option_id.m_idx];
+  }
+
+  diagnostic_t
+  classify_diagnostic (const context *context,
+		       diagnostic_option_id option_id,
+		       diagnostic_t new_kind,
+		       location_t where);
+
+  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
+     these structs.  */
+  struct classification_change_t
+  {
+    location_t location;
+
+    /* For DK_POP, this is the index of the corresponding push (as stored
+       in m_push_list).
+       Otherwise, this is an option index.  */
+    int option;
+
+    diagnostic_t kind;
+  };
+
+  int m_n_opts;
+
+  /* For each option index that can be passed to warning() et al
+     (OPT_* from options.h when using this code with the core GCC
+     options), this array may contain a new kind that the diagnostic
+     should be changed to before reporting, or DK_UNSPECIFIED to leave
+     it as the reported kind, or DK_IGNORED to not report it at
+     all.  */
+  diagnostic_t *m_classify_diagnostic;
+
+  /* History of all changes to the classifications above.  This list
+     is stored in location-order, so we can search it, either
+     binary-wise or end-to-front, to find the most recent
+     classification for a given diagnostic, given the location of the
+     diagnostic.  */
+  vec<classification_change_t> m_classification_history;
+
+  /* For context::get_classification_history, declared later.  */
+  friend class context;
+
+  /* For pragma push/pop.  */
+  vec<int> m_push_list;
+};
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_OPTIONS_CLASSIFIER_H */
-- 
2.26.3

