Branch data Line data Source code
1 : : /* Stacks of set of classifications of diagnostics.
2 : : Copyright (C) 1999-2025 Free Software Foundation, Inc.
3 : :
4 : : This file is part of GCC.
5 : :
6 : : GCC is free software; you can redistribute it and/or modify it under
7 : : the terms of the GNU General Public License as published by the Free
8 : : Software Foundation; either version 3, or (at your option) any later
9 : : version.
10 : :
11 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : : for more details.
15 : :
16 : : You should have received a copy of the GNU General Public License
17 : : along with GCC; see the file COPYING3. If not see
18 : : <http://www.gnu.org/licenses/>. */
19 : :
20 : :
21 : : #include "config.h"
22 : : #include "system.h"
23 : : #include "coretypes.h"
24 : : #include "version.h"
25 : : #include "diagnostic.h"
26 : :
27 : : namespace diagnostics {
28 : :
29 : : void
30 : 709618 : option_classifier::init (int n_opts)
31 : : {
32 : 709618 : m_n_opts = n_opts;
33 : 709618 : m_classify_diagnostic = XNEWVEC (enum kind, n_opts);
34 : 703218869 : for (int i = 0; i < n_opts; i++)
35 : 702509251 : m_classify_diagnostic[i] = kind::unspecified;
36 : 709618 : m_push_list = vNULL;
37 : 709618 : m_classification_history = vNULL;
38 : 709618 : }
39 : :
40 : : void
41 : 304801 : option_classifier::fini ()
42 : : {
43 : 304801 : XDELETEVEC (m_classify_diagnostic);
44 : 304801 : m_classify_diagnostic = nullptr;
45 : 304801 : m_classification_history.release ();
46 : 304801 : m_push_list.release ();
47 : 304801 : }
48 : :
49 : : /* Save the diagnostics::option_classifier state to F for PCH
50 : : output. Returns 0 on success, -1 on error. */
51 : :
52 : : int
53 : 435 : option_classifier::pch_save (FILE *f)
54 : : {
55 : 435 : unsigned int lengths[2] = { m_classification_history.length (),
56 : 435 : m_push_list.length () };
57 : 435 : if (fwrite (lengths, sizeof (lengths), 1, f) != 1
58 : 435 : || (lengths[0]
59 : 64 : && fwrite (m_classification_history.address (),
60 : : sizeof (classification_change_t),
61 : 32 : lengths[0], f) != lengths[0])
62 : 870 : || (lengths[1]
63 : 0 : && fwrite (m_push_list.address (), sizeof (int),
64 : 0 : lengths[1], f) != lengths[1]))
65 : 0 : return -1;
66 : : return 0;
67 : : }
68 : :
69 : : /* Read the diagnostics::option_classifier state from F for PCH
70 : : read. Returns 0 on success, -1 on error. */
71 : :
72 : : int
73 : 347 : option_classifier::pch_restore (FILE *f)
74 : : {
75 : 347 : unsigned int lengths[2];
76 : 347 : if (fread (lengths, sizeof (lengths), 1, f) != 1)
77 : : return -1;
78 : 347 : gcc_checking_assert (m_classification_history.is_empty ());
79 : 347 : gcc_checking_assert (m_push_list.is_empty ());
80 : 347 : m_classification_history.safe_grow (lengths[0]);
81 : 347 : m_push_list.safe_grow (lengths[1]);
82 : 347 : if ((lengths[0]
83 : 48 : && fread (m_classification_history.address (),
84 : : sizeof (classification_change_t),
85 : 24 : lengths[0], f) != lengths[0])
86 : 371 : || (lengths[1]
87 : 0 : && fread (m_push_list.address (), sizeof (int),
88 : 0 : lengths[1], f) != lengths[1]))
89 : 0 : return -1;
90 : : return 0;
91 : : }
92 : :
93 : : /* Save all diagnostic classifications in a stack. */
94 : :
95 : : void
96 : 3976735 : option_classifier::push ()
97 : : {
98 : 7914874 : m_push_list.safe_push (m_classification_history.length ());
99 : 3976735 : }
100 : :
101 : : /* Restore the topmost classification set off the stack. If the stack
102 : : is empty, revert to the state based on command line parameters. */
103 : :
104 : : void
105 : 3976064 : option_classifier::pop (location_t where)
106 : : {
107 : 3976064 : int jump_to;
108 : :
109 : 3976064 : if (!m_push_list.is_empty ())
110 : 3976051 : jump_to = m_push_list.pop ();
111 : : else
112 : : jump_to = 0;
113 : :
114 : 3976064 : classification_change_t v = { where, jump_to, kind::pop };
115 : 3976064 : m_classification_history.safe_push (v);
116 : 3976064 : }
117 : :
118 : : /* Interface to specify diagnostic kind overrides. Returns the
119 : : previous setting, or kind::unspecified if the parameters are out of
120 : : range. If OPTION_ID is zero, the new setting is for all the
121 : : diagnostics. */
122 : :
123 : : enum kind
124 : 4645984 : option_classifier::classify_diagnostic (const context *dc,
125 : : option_id opt_id,
126 : : enum kind new_kind,
127 : : location_t where)
128 : : {
129 : 4645984 : enum kind old_kind;
130 : :
131 : 4645984 : if (opt_id.m_idx < 0
132 : 4645984 : || opt_id.m_idx >= m_n_opts
133 : 4645984 : || new_kind >= kind::last_diagnostic_kind)
134 : : return kind::unspecified;
135 : :
136 : 4645984 : old_kind = m_classify_diagnostic[opt_id.m_idx];
137 : :
138 : : /* Handle pragmas separately, since we need to keep track of *where*
139 : : the pragmas were. */
140 : 4645984 : if (where != UNKNOWN_LOCATION)
141 : : {
142 : 3587079 : unsigned i;
143 : :
144 : : /* Record the command-line status, so we can reset it back on kind::pop. */
145 : 3587079 : if (old_kind == kind::unspecified)
146 : : {
147 : 482830 : old_kind = (!dc->option_enabled_p (opt_id)
148 : 320834 : ? kind::ignored : kind::any);
149 : 320834 : m_classify_diagnostic[opt_id.m_idx] = old_kind;
150 : : }
151 : :
152 : 3587079 : classification_change_t *p;
153 : 115252154 : FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
154 : 111376941 : if (p->option == opt_id.m_idx)
155 : : {
156 : 3260244 : old_kind = p->kind;
157 : 3260244 : break;
158 : : }
159 : :
160 : 3587079 : classification_change_t v
161 : 3587079 : = { where, opt_id.m_idx, new_kind };
162 : 3587079 : m_classification_history.safe_push (v);
163 : : }
164 : : else
165 : 1058905 : m_classify_diagnostic[opt_id.m_idx] = new_kind;
166 : :
167 : : return old_kind;
168 : : }
169 : :
170 : : /* Update the kind of DIAGNOSTIC based on its location(s), including
171 : : any of those in its inlining stack, relative to any
172 : : #pragma GCC diagnostic
173 : : directives recorded within this object.
174 : :
175 : : Return the new kind of DIAGNOSTIC if it was updated, or kind::unspecified
176 : : otherwise. */
177 : :
178 : : enum kind
179 : 2043427 : option_classifier::
180 : : update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
181 : : {
182 : 2429425 : if (m_classification_history.is_empty ())
183 : : return kind::unspecified;
184 : :
185 : : /* Iterate over the locations, checking the diagnostic disposition
186 : : for the diagnostic at each. If it's explicitly set as opposed
187 : : to unspecified, update the disposition for this instance of
188 : : the diagnostic and return it. */
189 : 6219408 : for (location_t loc: diagnostic->m_iinfo.m_ilocs)
190 : : {
191 : : /* FIXME: Stupid search. Optimize later. */
192 : 1944596 : unsigned int i;
193 : 1944596 : classification_change_t *p;
194 : 54462002 : FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
195 : : {
196 : 51745080 : location_t pragloc = p->location;
197 : 51745080 : if (!linemap_location_before_p (line_table, pragloc, loc))
198 : 50186647 : continue;
199 : :
200 : 34395854 : if (p->kind == kind::pop)
201 : : {
202 : : /* Move on to the next region. */
203 : 32754890 : i = p->option;
204 : 32754890 : continue;
205 : : }
206 : :
207 : 1640964 : option_id opt_id = p->option;
208 : : /* The option 0 is for all the diagnostics. */
209 : 1640964 : if (opt_id == 0 || opt_id == diagnostic->m_option_id)
210 : : {
211 : 1558433 : enum kind kind = p->kind;
212 : 1558433 : if (kind != diagnostics::kind::unspecified)
213 : 1558433 : diagnostic->m_kind = kind;
214 : 1558433 : return kind;
215 : : }
216 : : }
217 : : }
218 : :
219 : : return kind::unspecified;
220 : : }
221 : :
222 : : } // namespace diagnostics
|