c++: Tweaks for -Wredundant-move [PR107363]
[official-gcc.git] / gcc / analyzer / pending-diagnostic.h
blob6ca8ab9f4aad73b2759bfc5b654a113bfd716fe5
1 /* Classes for analyzer diagnostics.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
21 #ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H
22 #define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
24 #include "diagnostic-path.h"
25 #include "analyzer/sm.h"
27 namespace ana {
29 /* A bundle of information about things that are of interest to a
30 pending_diagnostic.
32 For now, merely the set of regions that are pertinent to the
33 diagnostic, so that we can notify the user about when they
34 were created. */
36 struct interesting_t
38 void add_region_creation (const region *reg);
40 void dump_to_pp (pretty_printer *pp, bool simple) const;
42 auto_vec<const region *> m_region_creation;
45 /* Various bundles of information used for generating more precise
46 messages for events within a diagnostic_path, for passing to the
47 various "describe_*" vfuncs of pending_diagnostic. See those
48 for more information. */
50 namespace evdesc {
52 struct event_desc
54 event_desc (bool colorize) : m_colorize (colorize) {}
56 label_text formatted_print (const char *fmt, ...) const
57 ATTRIBUTE_GCC_DIAG(2,3);
59 bool m_colorize;
62 /* For use by pending_diagnostic::describe_region_creation. */
64 struct region_creation : public event_desc
66 region_creation (bool colorize, const region *reg)
67 : event_desc (colorize), m_reg (reg)
70 const region *m_reg;
73 /* For use by pending_diagnostic::describe_state_change. */
75 struct state_change : public event_desc
77 state_change (bool colorize,
78 tree expr,
79 tree origin,
80 state_machine::state_t old_state,
81 state_machine::state_t new_state,
82 diagnostic_event_id_t event_id,
83 const state_change_event &event)
84 : event_desc (colorize),
85 m_expr (expr), m_origin (origin),
86 m_old_state (old_state), m_new_state (new_state),
87 m_event_id (event_id), m_event (event)
90 bool is_global_p () const { return m_expr == NULL_TREE; }
92 tree m_expr;
93 tree m_origin;
94 state_machine::state_t m_old_state;
95 state_machine::state_t m_new_state;
96 diagnostic_event_id_t m_event_id;
97 const state_change_event &m_event;
100 /* For use by pending_diagnostic::describe_call_with_state. */
102 struct call_with_state : public event_desc
104 call_with_state (bool colorize,
105 tree caller_fndecl, tree callee_fndecl,
106 tree expr, state_machine::state_t state)
107 : event_desc (colorize),
108 m_caller_fndecl (caller_fndecl),
109 m_callee_fndecl (callee_fndecl),
110 m_expr (expr),
111 m_state (state)
115 tree m_caller_fndecl;
116 tree m_callee_fndecl;
117 tree m_expr;
118 state_machine::state_t m_state;
121 /* For use by pending_diagnostic::describe_return_of_state. */
123 struct return_of_state : public event_desc
125 return_of_state (bool colorize,
126 tree caller_fndecl, tree callee_fndecl,
127 state_machine::state_t state)
128 : event_desc (colorize),
129 m_caller_fndecl (caller_fndecl),
130 m_callee_fndecl (callee_fndecl),
131 m_state (state)
135 tree m_caller_fndecl;
136 tree m_callee_fndecl;
137 state_machine::state_t m_state;
140 /* For use by pending_diagnostic::describe_final_event. */
142 struct final_event : public event_desc
144 final_event (bool colorize,
145 tree expr, state_machine::state_t state)
146 : event_desc (colorize),
147 m_expr (expr), m_state (state)
150 tree m_expr;
151 state_machine::state_t m_state;
154 } /* end of namespace evdesc */
156 /* An abstract base class for capturing information about a diagnostic in
157 a form that is ready to emit at a later point (or be rejected).
158 Each kind of diagnostic will have a concrete subclass of
159 pending_diagnostic.
161 Normally, gcc diagnostics are emitted using va_list, which can't be
162 portably stored for later use, so we have to use an "emit" virtual
163 function.
165 This class also supports comparison, so that multiple pending_diagnostic
166 instances can be de-duplicated.
168 As well as emitting a diagnostic, the class has various "precision of
169 wording" virtual functions, for generating descriptions for events
170 within a diagnostic_path. These are optional, but implementing these
171 allows for more precise wordings than the more generic
172 implementation. */
174 class pending_diagnostic
176 public:
177 virtual ~pending_diagnostic () {}
179 /* Vfunc to get the command-line option used when emitting the diagnostic,
180 or zero if there is none.
181 Used by diagnostic_manager for early rejection of diagnostics (to avoid
182 having to generate feasible execution paths for them). */
183 virtual int get_controlling_option () const = 0;
185 /* Vfunc for emitting the diagnostic. The rich_location will have been
186 populated with a diagnostic_path.
187 Return true if a diagnostic is actually emitted. */
188 virtual bool emit (rich_location *) = 0;
190 /* Hand-coded RTTI: get an ID for the subclass. */
191 virtual const char *get_kind () const = 0;
193 /* A vfunc for identifying "use of uninitialized value". */
194 virtual bool use_of_uninit_p () const { return false; }
196 /* Compare for equality with OTHER, which might be of a different
197 subclass. */
199 bool equal_p (const pending_diagnostic &other) const
201 /* Check for pointer equality on the IDs from get_kind. */
202 if (get_kind () != other.get_kind ())
203 return false;
204 /* Call vfunc now we know they have the same ID: */
205 return subclass_equal_p (other);
208 /* A vfunc for testing for equality, where we've already
209 checked they have the same ID. See pending_diagnostic_subclass
210 below for a convenience subclass for implementing this. */
211 virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
213 /* Return true if T1 and T2 are "the same" for the purposes of
214 diagnostic deduplication. */
215 static bool same_tree_p (tree t1, tree t2);
217 /* A vfunc for fixing up locations (both the primary location for the
218 diagnostic, and for events in their paths), e.g. to avoid unwinding
219 inside specific macros. */
220 virtual location_t fixup_location (location_t loc) const;
222 /* For greatest precision-of-wording, the various following "describe_*"
223 virtual functions give the pending diagnostic a way to describe events
224 in a diagnostic_path in terms that make sense for that diagnostic.
226 In each case, return a non-NULL label_text to give the event a custom
227 description; NULL otherwise (falling back on a more generic
228 description). */
230 /* Precision-of-wording vfunc for describing a region creation event
231 triggered by the mark_interesting_stuff vfunc. */
232 virtual label_text
233 describe_region_creation_event (const evdesc::region_creation &)
235 /* Default no-op implementation. */
236 return label_text ();
239 /* Precision-of-wording vfunc for describing a critical state change
240 within the diagnostic_path.
242 For example, a double-free diagnostic might use the descriptions:
243 - "first 'free' happens here"
244 - "second 'free' happens here"
245 for the pertinent events, whereas a use-after-free might use the
246 descriptions:
247 - "freed here"
248 - "use after free here"
249 Note how in both cases the first event is a "free": the best
250 description to use depends on the diagnostic. */
252 virtual label_text describe_state_change (const evdesc::state_change &)
254 /* Default no-op implementation. */
255 return label_text ();
258 /* Vfunc for implementing diagnostic_event::get_meaning for
259 state_change_event. */
260 virtual diagnostic_event::meaning
261 get_meaning_for_state_change (const evdesc::state_change &) const
263 /* Default no-op implementation. */
264 return diagnostic_event::meaning ();
267 /* Precision-of-wording vfunc for describing an interprocedural call
268 carrying critial state for the diagnostic, from caller to callee.
270 For example a double-free diagnostic might use:
271 - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
272 to make it clearer how the freed value moves from caller to
273 callee. */
275 virtual label_text describe_call_with_state (const evdesc::call_with_state &)
277 /* Default no-op implementation. */
278 return label_text ();
281 /* Precision-of-wording vfunc for describing an interprocedural return
282 within the diagnostic_path that carries critial state for the
283 diagnostic, from callee back to caller.
285 For example, a deref-of-unchecked-malloc diagnostic might use:
286 - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
287 to make it clearer how the unchecked value moves from callee
288 back to caller. */
290 virtual label_text describe_return_of_state (const evdesc::return_of_state &)
292 /* Default no-op implementation. */
293 return label_text ();
296 /* Precision-of-wording vfunc for describing the final event within a
297 diagnostic_path.
299 For example a double-free diagnostic might use:
300 - "second 'free' here; first 'free' was at (3)"
301 and a use-after-free might use
302 - "use after 'free' here; memory was freed at (2)". */
304 virtual label_text describe_final_event (const evdesc::final_event &)
306 /* Default no-op implementation. */
307 return label_text ();
310 /* End of precision-of-wording vfuncs. */
312 /* Vfunc for extending/overriding creation of the events for an
313 exploded_edge that corresponds to a superedge, allowing for custom
314 events to be created that are pertinent to a particular
315 pending_diagnostic subclass.
317 For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
318 custom event showing when the pertinent stack frame is popped
319 (and thus the point at which the jmp_buf becomes invalid). */
321 virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &,
322 checker_path *)
324 return false;
327 /* Vfunc for adding a call_event to a checker_path, so that e.g.
328 the varargs diagnostics can add a custom event subclass that annotates
329 the variadic arguments. */
330 virtual void add_call_event (const exploded_edge &,
331 checker_path *);
333 /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
334 and that OTHER should therefore not be emitted.
335 They have already been tested for being at the same stmt. */
337 virtual bool
338 supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
340 return false;
343 /* Vfunc for registering additional information of interest to this
344 diagnostic. */
346 virtual void mark_interesting_stuff (interesting_t *)
348 /* Default no-op implementation. */
352 /* A template to make it easier to make subclasses of pending_diagnostic.
354 This uses the curiously-recurring template pattern, to implement
355 pending_diagnostic::subclass_equal_p by casting and calling
356 the operator==
358 This assumes that BASE_OTHER has already been checked to have
359 been of the same subclass (which pending_diagnostic::equal_p does). */
361 template <class Subclass>
362 class pending_diagnostic_subclass : public pending_diagnostic
364 public:
365 bool subclass_equal_p (const pending_diagnostic &base_other) const
366 final override
368 const Subclass &other = (const Subclass &)base_other;
369 return *(const Subclass*)this == other;
373 /* An abstract base class for capturing additional notes that are to be
374 emitted with a diagnostic. */
376 class pending_note
378 public:
379 virtual ~pending_note () {}
381 /* Hand-coded RTTI: get an ID for the subclass. */
382 virtual const char *get_kind () const = 0;
384 /* Vfunc for emitting the note. */
385 virtual void emit () const = 0;
387 bool equal_p (const pending_note &other) const
389 /* Check for pointer equality on the IDs from get_kind. */
390 if (get_kind () != other.get_kind ())
391 return false;
392 /* Call vfunc now we know they have the same ID: */
393 return subclass_equal_p (other);
396 /* A vfunc for testing for equality, where we've already
397 checked they have the same ID. See pending_note_subclass
398 below for a convenience subclass for implementing this. */
399 virtual bool subclass_equal_p (const pending_note &other) const = 0;
402 /* Analogous to pending_diagnostic_subclass, but for pending_note. */
404 template <class Subclass>
405 class pending_note_subclass : public pending_note
407 public:
408 bool subclass_equal_p (const pending_note &base_other) const
409 final override
411 const Subclass &other = (const Subclass &)base_other;
412 return *(const Subclass*)this == other;
416 } // namespace ana
418 #endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */