aboutsummaryrefslogtreecommitdiff
path: root/gcc/diagnostics/option-classifier.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/diagnostics/option-classifier.cc')
-rw-r--r--gcc/diagnostics/option-classifier.cc222
1 files changed, 222 insertions, 0 deletions
diff --git a/gcc/diagnostics/option-classifier.cc b/gcc/diagnostics/option-classifier.cc
new file mode 100644
index 0000000..f98fd55
--- /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 (enum kind, n_opts);
+ for (int i = 0; i < n_opts; i++)
+ m_classify_diagnostic[i] = kind::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, kind::pop };
+ m_classification_history.safe_push (v);
+}
+
+/* Interface to specify diagnostic kind overrides. Returns the
+ previous setting, or kind::unspecified if the parameters are out of
+ range. If OPTION_ID is zero, the new setting is for all the
+ diagnostics. */
+
+enum kind
+option_classifier::classify_diagnostic (const context *dc,
+ option_id opt_id,
+ enum kind new_kind,
+ location_t where)
+{
+ enum kind old_kind;
+
+ if (opt_id.m_idx < 0
+ || opt_id.m_idx >= m_n_opts
+ || new_kind >= kind::last_diagnostic_kind)
+ return kind::unspecified;
+
+ old_kind = m_classify_diagnostic[opt_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 kind::pop. */
+ if (old_kind == kind::unspecified)
+ {
+ old_kind = (!dc->option_enabled_p (opt_id)
+ ? kind::ignored : kind::any);
+ m_classify_diagnostic[opt_id.m_idx] = old_kind;
+ }
+
+ classification_change_t *p;
+ FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
+ if (p->option == opt_id.m_idx)
+ {
+ old_kind = p->kind;
+ break;
+ }
+
+ classification_change_t v
+ = { where, opt_id.m_idx, new_kind };
+ m_classification_history.safe_push (v);
+ }
+ else
+ m_classify_diagnostic[opt_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 kind::unspecified
+ otherwise. */
+
+enum kind
+option_classifier::
+update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
+{
+ if (m_classification_history.is_empty ())
+ return kind::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 == kind::pop)
+ {
+ /* Move on to the next region. */
+ i = p->option;
+ continue;
+ }
+
+ option_id opt_id = p->option;
+ /* The option 0 is for all the diagnostics. */
+ if (opt_id == 0 || opt_id == diagnostic->m_option_id)
+ {
+ enum kind kind = p->kind;
+ if (kind != diagnostics::kind::unspecified)
+ diagnostic->m_kind = kind;
+ return kind;
+ }
+ }
+ }
+
+ return kind::unspecified;
+}
+
+} // namespace diagnostics