Line data Source code
1 : /* Stacks of set of classifications of diagnostics.
2 : Copyright (C) 1999-2026 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 735313 : option_classifier::init (int n_opts)
31 : {
32 735313 : m_n_opts = n_opts;
33 735313 : m_classify_diagnostic = XNEWVEC (enum kind, n_opts);
34 759399209 : for (int i = 0; i < n_opts; i++)
35 758663896 : m_classify_diagnostic[i] = kind::unspecified;
36 735313 : m_push_list = vNULL;
37 735313 : m_classification_history = vNULL;
38 735313 : }
39 :
40 : void
41 313212 : option_classifier::fini ()
42 : {
43 313212 : XDELETEVEC (m_classify_diagnostic);
44 313212 : m_classify_diagnostic = nullptr;
45 313212 : m_classification_history.release ();
46 313212 : m_push_list.release ();
47 313212 : }
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 470 : option_classifier::pch_save (FILE *f)
54 : {
55 470 : unsigned int lengths[2] = { m_classification_history.length (),
56 470 : m_push_list.length () };
57 470 : if (fwrite (lengths, sizeof (lengths), 1, f) != 1
58 470 : || (lengths[0]
59 64 : && fwrite (m_classification_history.address (),
60 : sizeof (classification_change_t),
61 32 : lengths[0], f) != lengths[0])
62 940 : || (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 350 : option_classifier::pch_restore (FILE *f)
74 : {
75 350 : unsigned int lengths[2];
76 350 : if (fread (lengths, sizeof (lengths), 1, f) != 1)
77 : return -1;
78 350 : gcc_checking_assert (m_classification_history.is_empty ());
79 350 : gcc_checking_assert (m_push_list.is_empty ());
80 350 : m_classification_history.safe_grow (lengths[0]);
81 350 : m_push_list.safe_grow (lengths[1]);
82 350 : if ((lengths[0]
83 48 : && fread (m_classification_history.address (),
84 : sizeof (classification_change_t),
85 24 : lengths[0], f) != lengths[0])
86 374 : || (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 4877556 : option_classifier::push ()
97 : {
98 9715289 : m_push_list.safe_push (m_classification_history.length ());
99 4877556 : }
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 4876951 : option_classifier::pop (location_t where)
106 : {
107 4876951 : int jump_to;
108 :
109 4876951 : if (!m_push_list.is_empty ())
110 4876944 : jump_to = m_push_list.pop ();
111 : else
112 : jump_to = 0;
113 :
114 4876951 : classification_change_t v = { where, jump_to, kind::pop };
115 4876951 : m_classification_history.safe_push (v);
116 4876951 : }
117 :
118 : /* Interface to specify diagnostic kind overrides. If OPTION_ID is zero, the
119 : new setting is for all the diagnostics. */
120 :
121 : void
122 5630908 : option_classifier::classify_diagnostic (const context *dc,
123 : option_id opt_id,
124 : enum kind new_kind,
125 : location_t where)
126 : {
127 5630908 : if (opt_id.m_idx < 0
128 5630908 : || opt_id.m_idx >= m_n_opts
129 5630908 : || new_kind >= kind::last_diagnostic_kind)
130 : return;
131 :
132 5630908 : auto &base_kind = m_classify_diagnostic[opt_id.m_idx];
133 :
134 : /* Handle pragmas separately, since we need to keep track of *where*
135 : the pragmas were. */
136 5630908 : if (where != UNKNOWN_LOCATION)
137 : {
138 : /* Record the command-line status, so we can reset it back on kind::pop. */
139 4527306 : if (base_kind == kind::unspecified)
140 776374 : base_kind = (!dc->option_enabled_p (opt_id)
141 388187 : ? kind::ignored : kind::any);
142 :
143 4527306 : classification_change_t v
144 4527306 : = { where, opt_id.m_idx, new_kind };
145 4527306 : m_classification_history.safe_push (v);
146 : }
147 : else
148 1103602 : base_kind = new_kind;
149 : }
150 :
151 : /* Update the kind of DIAGNOSTIC based on its location(s), including
152 : any of those in its inlining stack, relative to any
153 : #pragma GCC diagnostic
154 : directives recorded within this object.
155 :
156 : Return the new kind of DIAGNOSTIC if it was updated, or kind::unspecified
157 : otherwise. */
158 :
159 : enum kind
160 3786284 : option_classifier::
161 : update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
162 : {
163 5590476 : if (m_classification_history.is_empty ())
164 : return kind::unspecified;
165 :
166 : /* Iterate over the locations, checking the diagnostic disposition
167 : for the diagnostic at each. If it's explicitly set as opposed
168 : to unspecified, update the disposition for this instance of
169 : the diagnostic and return it. */
170 12850692 : for (location_t loc: diagnostic->m_iinfo.m_ilocs)
171 : {
172 : /* FIXME: Stupid search. Optimize later. */
173 3682679 : unsigned int i;
174 3682679 : classification_change_t *p;
175 870490331 : FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
176 : {
177 863200254 : location_t pragloc = p->location;
178 863200254 : if (!linemap_location_before_p (line_table, pragloc, loc))
179 861321274 : continue;
180 :
181 208744547 : if (p->kind == kind::pop)
182 : {
183 : /* Move on to the next region. */
184 205101907 : i = p->option;
185 205101907 : continue;
186 : }
187 :
188 3642640 : option_id opt_id = p->option;
189 : /* The option 0 is for all the diagnostics. */
190 3642640 : if (opt_id == 0 || opt_id == diagnostic->m_option_id)
191 : {
192 1878980 : enum kind kind = p->kind;
193 1878980 : if (kind != diagnostics::kind::unspecified)
194 1878980 : diagnostic->m_kind = kind;
195 1878980 : return kind;
196 : }
197 : }
198 : }
199 :
200 : return kind::unspecified;
201 : }
202 :
203 : } // namespace diagnostics
|