]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/analyzer/pending-diagnostic.h
analyzer: early rejection of disabled warnings [PR104955]
[thirdparty/gcc.git] / gcc / analyzer / pending-diagnostic.h
1 /* Classes for analyzer diagnostics.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H
22 #define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
23
24 namespace ana {
25
26 /* A bundle of information about things that are of interest to a
27 pending_diagnostic.
28
29 For now, merely the set of regions that are pertinent to the
30 diagnostic, so that we can notify the user about when they
31 were created. */
32
33 struct interesting_t
34 {
35 void add_region_creation (const region *reg);
36
37 void dump_to_pp (pretty_printer *pp, bool simple) const;
38
39 auto_vec<const region *> m_region_creation;
40 };
41
42 /* Various bundles of information used for generating more precise
43 messages for events within a diagnostic_path, for passing to the
44 various "describe_*" vfuncs of pending_diagnostic. See those
45 for more information. */
46
47 namespace evdesc {
48
49 struct event_desc
50 {
51 event_desc (bool colorize) : m_colorize (colorize) {}
52
53 label_text formatted_print (const char *fmt, ...) const
54 ATTRIBUTE_GCC_DIAG(2,3);
55
56 bool m_colorize;
57 };
58
59 /* For use by pending_diagnostic::describe_state_change. */
60
61 struct state_change : public event_desc
62 {
63 state_change (bool colorize,
64 tree expr,
65 tree origin,
66 state_machine::state_t old_state,
67 state_machine::state_t new_state,
68 diagnostic_event_id_t event_id,
69 const state_change_event &event)
70 : event_desc (colorize),
71 m_expr (expr), m_origin (origin),
72 m_old_state (old_state), m_new_state (new_state),
73 m_event_id (event_id), m_event (event)
74 {}
75
76 bool is_global_p () const { return m_expr == NULL_TREE; }
77
78 tree m_expr;
79 tree m_origin;
80 state_machine::state_t m_old_state;
81 state_machine::state_t m_new_state;
82 diagnostic_event_id_t m_event_id;
83 const state_change_event &m_event;
84 };
85
86 /* For use by pending_diagnostic::describe_call_with_state. */
87
88 struct call_with_state : public event_desc
89 {
90 call_with_state (bool colorize,
91 tree caller_fndecl, tree callee_fndecl,
92 tree expr, state_machine::state_t state)
93 : event_desc (colorize),
94 m_caller_fndecl (caller_fndecl),
95 m_callee_fndecl (callee_fndecl),
96 m_expr (expr),
97 m_state (state)
98 {
99 }
100
101 tree m_caller_fndecl;
102 tree m_callee_fndecl;
103 tree m_expr;
104 state_machine::state_t m_state;
105 };
106
107 /* For use by pending_diagnostic::describe_return_of_state. */
108
109 struct return_of_state : public event_desc
110 {
111 return_of_state (bool colorize,
112 tree caller_fndecl, tree callee_fndecl,
113 state_machine::state_t state)
114 : event_desc (colorize),
115 m_caller_fndecl (caller_fndecl),
116 m_callee_fndecl (callee_fndecl),
117 m_state (state)
118 {
119 }
120
121 tree m_caller_fndecl;
122 tree m_callee_fndecl;
123 state_machine::state_t m_state;
124 };
125
126 /* For use by pending_diagnostic::describe_final_event. */
127
128 struct final_event : public event_desc
129 {
130 final_event (bool colorize,
131 tree expr, state_machine::state_t state)
132 : event_desc (colorize),
133 m_expr (expr), m_state (state)
134 {}
135
136 tree m_expr;
137 state_machine::state_t m_state;
138 };
139
140 } /* end of namespace evdesc */
141
142 /* An abstract base class for capturing information about a diagnostic in
143 a form that is ready to emit at a later point (or be rejected).
144 Each kind of diagnostic will have a concrete subclass of
145 pending_diagnostic.
146
147 Normally, gcc diagnostics are emitted using va_list, which can't be
148 portably stored for later use, so we have to use an "emit" virtual
149 function.
150
151 This class also supports comparison, so that multiple pending_diagnostic
152 instances can be de-duplicated.
153
154 As well as emitting a diagnostic, the class has various "precision of
155 wording" virtual functions, for generating descriptions for events
156 within a diagnostic_path. These are optional, but implementing these
157 allows for more precise wordings than the more generic
158 implementation. */
159
160 class pending_diagnostic
161 {
162 public:
163 virtual ~pending_diagnostic () {}
164
165 /* Vfunc to get the command-line option used when emitting the diagnostic,
166 or zero if there is none.
167 Used by diagnostic_manager for early rejection of diagnostics (to avoid
168 having to generate feasible execution paths for them). */
169 virtual int get_controlling_option () const = 0;
170
171 /* Vfunc for emitting the diagnostic. The rich_location will have been
172 populated with a diagnostic_path.
173 Return true if a diagnostic is actually emitted. */
174 virtual bool emit (rich_location *) = 0;
175
176 /* Hand-coded RTTI: get an ID for the subclass. */
177 virtual const char *get_kind () const = 0;
178
179 /* A vfunc for identifying "use of uninitialized value". */
180 virtual bool use_of_uninit_p () const { return false; }
181
182 /* Compare for equality with OTHER, which might be of a different
183 subclass. */
184
185 bool equal_p (const pending_diagnostic &other) const
186 {
187 /* Check for pointer equality on the IDs from get_kind. */
188 if (get_kind () != other.get_kind ())
189 return false;
190 /* Call vfunc now we know they have the same ID: */
191 return subclass_equal_p (other);
192 }
193
194 /* A vfunc for testing for equality, where we've already
195 checked they have the same ID. See pending_diagnostic_subclass
196 below for a convenience subclass for implementing this. */
197 virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
198
199 /* Return true if T1 and T2 are "the same" for the purposes of
200 diagnostic deduplication. */
201 static bool same_tree_p (tree t1, tree t2);
202
203 /* A vfunc for fixing up locations (both the primary location for the
204 diagnostic, and for events in their paths), e.g. to avoid unwinding
205 inside specific macros. */
206 virtual location_t fixup_location (location_t loc) const
207 {
208 return loc;
209 }
210
211 /* For greatest precision-of-wording, the various following "describe_*"
212 virtual functions give the pending diagnostic a way to describe events
213 in a diagnostic_path in terms that make sense for that diagnostic.
214
215 In each case, return a non-NULL label_text to give the event a custom
216 description; NULL otherwise (falling back on a more generic
217 description). */
218
219 /* Precision-of-wording vfunc for describing a critical state change
220 within the diagnostic_path.
221
222 For example, a double-free diagnostic might use the descriptions:
223 - "first 'free' happens here"
224 - "second 'free' happens here"
225 for the pertinent events, whereas a use-after-free might use the
226 descriptions:
227 - "freed here"
228 - "use after free here"
229 Note how in both cases the first event is a "free": the best
230 description to use depends on the diagnostic. */
231
232 virtual label_text describe_state_change (const evdesc::state_change &)
233 {
234 /* Default no-op implementation. */
235 return label_text ();
236 }
237
238 /* Precision-of-wording vfunc for describing an interprocedural call
239 carrying critial state for the diagnostic, from caller to callee.
240
241 For example a double-free diagnostic might use:
242 - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
243 to make it clearer how the freed value moves from caller to
244 callee. */
245
246 virtual label_text describe_call_with_state (const evdesc::call_with_state &)
247 {
248 /* Default no-op implementation. */
249 return label_text ();
250 }
251
252 /* Precision-of-wording vfunc for describing an interprocedural return
253 within the diagnostic_path that carries critial state for the
254 diagnostic, from callee back to caller.
255
256 For example, a deref-of-unchecked-malloc diagnostic might use:
257 - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
258 to make it clearer how the unchecked value moves from callee
259 back to caller. */
260
261 virtual label_text describe_return_of_state (const evdesc::return_of_state &)
262 {
263 /* Default no-op implementation. */
264 return label_text ();
265 }
266
267 /* Precision-of-wording vfunc for describing the final event within a
268 diagnostic_path.
269
270 For example a double-free diagnostic might use:
271 - "second 'free' here; first 'free' was at (3)"
272 and a use-after-free might use
273 - "use after 'free' here; memory was freed at (2)". */
274
275 virtual label_text describe_final_event (const evdesc::final_event &)
276 {
277 /* Default no-op implementation. */
278 return label_text ();
279 }
280
281 /* End of precision-of-wording vfuncs. */
282
283 /* Vfunc for extending/overriding creation of the events for an
284 exploded_edge that corresponds to a superedge, allowing for custom
285 events to be created that are pertinent to a particular
286 pending_diagnostic subclass.
287
288 For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
289 custom event showing when the pertinent stack frame is popped
290 (and thus the point at which the jmp_buf becomes invalid). */
291
292 virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &,
293 checker_path *)
294 {
295 return false;
296 }
297
298 /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
299 and that OTHER should therefore not be emitted.
300 They have already been tested for being at the same stmt. */
301
302 virtual bool
303 supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
304 {
305 return false;
306 }
307
308 /* Vfunc for registering additional information of interest to this
309 diagnostic. */
310
311 virtual void mark_interesting_stuff (interesting_t *)
312 {
313 /* Default no-op implementation. */
314 }
315 };
316
317 /* A template to make it easier to make subclasses of pending_diagnostic.
318
319 This uses the curiously-recurring template pattern, to implement
320 pending_diagnostic::subclass_equal_p by casting and calling
321 the operator==
322
323 This assumes that BASE_OTHER has already been checked to have
324 been of the same subclass (which pending_diagnostic::equal_p does). */
325
326 template <class Subclass>
327 class pending_diagnostic_subclass : public pending_diagnostic
328 {
329 public:
330 bool subclass_equal_p (const pending_diagnostic &base_other) const
331 FINAL OVERRIDE
332 {
333 const Subclass &other = (const Subclass &)base_other;
334 return *(const Subclass*)this == other;
335 }
336 };
337
338 /* An abstract base class for capturing additional notes that are to be
339 emitted with a diagnostic. */
340
341 class pending_note
342 {
343 public:
344 virtual ~pending_note () {}
345
346 /* Hand-coded RTTI: get an ID for the subclass. */
347 virtual const char *get_kind () const = 0;
348
349 /* Vfunc for emitting the note. */
350 virtual void emit () const = 0;
351
352 bool equal_p (const pending_note &other) const
353 {
354 /* Check for pointer equality on the IDs from get_kind. */
355 if (get_kind () != other.get_kind ())
356 return false;
357 /* Call vfunc now we know they have the same ID: */
358 return subclass_equal_p (other);
359 }
360
361 /* A vfunc for testing for equality, where we've already
362 checked they have the same ID. See pending_note_subclass
363 below for a convenience subclass for implementing this. */
364 virtual bool subclass_equal_p (const pending_note &other) const = 0;
365 };
366
367 /* Analogous to pending_diagnostic_subclass, but for pending_note. */
368
369 template <class Subclass>
370 class pending_note_subclass : public pending_note
371 {
372 public:
373 bool subclass_equal_p (const pending_note &base_other) const
374 FINAL OVERRIDE
375 {
376 const Subclass &other = (const Subclass &)base_other;
377 return *(const Subclass*)this == other;
378 }
379 };
380
381 } // namespace ana
382
383 #endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */