vect: Ensure both NITERSM1 and NITERS are INTEGER_CSTs or neither of them [PR113210]
[official-gcc.git] / gcc / analyzer / pending-diagnostic.h
blob288410af71a3330b78faf1be79f9970601e005ec
1 /* Classes for analyzer diagnostics.
2 Copyright (C) 2019-2024 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-metadata.h"
25 #include "diagnostic-path.h"
26 #include "analyzer/sm.h"
28 namespace ana {
30 /* A bundle of information about things that are of interest to a
31 pending_diagnostic.
33 For now, merely the set of regions that are pertinent to the
34 diagnostic, so that we can notify the user about when they
35 were created. */
37 struct interesting_t
39 void add_region_creation (const region *reg);
41 void dump_to_pp (pretty_printer *pp, bool simple) const;
43 auto_vec<const region *> m_region_creation;
46 /* Various bundles of information used for generating more precise
47 messages for events within a diagnostic_path, for passing to the
48 various "describe_*" vfuncs of pending_diagnostic. See those
49 for more information. */
51 namespace evdesc {
53 struct event_desc
55 event_desc (bool colorize) : m_colorize (colorize) {}
57 label_text formatted_print (const char *fmt, ...) const
58 ATTRIBUTE_GCC_DIAG(2,3);
60 bool m_colorize;
63 /* For use by pending_diagnostic::describe_state_change. */
65 struct state_change : public event_desc
67 state_change (bool colorize,
68 tree expr,
69 tree origin,
70 state_machine::state_t old_state,
71 state_machine::state_t new_state,
72 diagnostic_event_id_t event_id,
73 const state_change_event &event)
74 : event_desc (colorize),
75 m_expr (expr), m_origin (origin),
76 m_old_state (old_state), m_new_state (new_state),
77 m_event_id (event_id), m_event (event)
80 bool is_global_p () const { return m_expr == NULL_TREE; }
82 tree m_expr;
83 tree m_origin;
84 state_machine::state_t m_old_state;
85 state_machine::state_t m_new_state;
86 diagnostic_event_id_t m_event_id;
87 const state_change_event &m_event;
90 /* For use by pending_diagnostic::describe_call_with_state. */
92 struct call_with_state : public event_desc
94 call_with_state (bool colorize,
95 tree caller_fndecl, tree callee_fndecl,
96 tree expr, state_machine::state_t state)
97 : event_desc (colorize),
98 m_caller_fndecl (caller_fndecl),
99 m_callee_fndecl (callee_fndecl),
100 m_expr (expr),
101 m_state (state)
105 tree m_caller_fndecl;
106 tree m_callee_fndecl;
107 tree m_expr;
108 state_machine::state_t m_state;
111 /* For use by pending_diagnostic::describe_return_of_state. */
113 struct return_of_state : public event_desc
115 return_of_state (bool colorize,
116 tree caller_fndecl, tree callee_fndecl,
117 state_machine::state_t state)
118 : event_desc (colorize),
119 m_caller_fndecl (caller_fndecl),
120 m_callee_fndecl (callee_fndecl),
121 m_state (state)
125 tree m_caller_fndecl;
126 tree m_callee_fndecl;
127 state_machine::state_t m_state;
130 /* For use by pending_diagnostic::describe_final_event. */
132 struct final_event : public event_desc
134 final_event (bool colorize,
135 tree expr, state_machine::state_t state,
136 const warning_event &event)
137 : event_desc (colorize),
138 m_expr (expr), m_state (state), m_event (event)
141 tree m_expr;
142 state_machine::state_t m_state;
143 const warning_event &m_event;
146 } /* end of namespace evdesc */
148 /* A bundle of information for use by implementations of the
149 pending_diagnostic::emit vfunc.
151 The rich_location will have already been populated with a
152 diagnostic_path. */
154 class diagnostic_emission_context
156 public:
157 diagnostic_emission_context (const saved_diagnostic &sd,
158 rich_location &rich_loc,
159 diagnostic_metadata &metadata,
160 logger *logger)
161 : m_sd (sd),
162 m_rich_loc (rich_loc),
163 m_metadata (metadata),
164 m_logger (logger)
168 const pending_diagnostic &get_pending_diagnostic () const;
170 bool warn (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
171 void inform (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
173 location_t get_location () const { return m_rich_loc.get_loc (); }
174 logger *get_logger () const { return m_logger; }
176 void add_cwe (int cwe) { m_metadata.add_cwe (cwe); }
177 void add_rule (const diagnostic_metadata::rule &r)
179 m_metadata.add_rule (r);
182 private:
183 const saved_diagnostic &m_sd;
184 rich_location &m_rich_loc;
185 diagnostic_metadata &m_metadata;
186 logger *m_logger;
189 /* An abstract base class for capturing information about a diagnostic in
190 a form that is ready to emit at a later point (or be rejected).
191 Each kind of diagnostic will have a concrete subclass of
192 pending_diagnostic.
194 Normally, gcc diagnostics are emitted using va_list, which can't be
195 portably stored for later use, so we have to use an "emit" virtual
196 function.
198 This class also supports comparison, so that multiple pending_diagnostic
199 instances can be de-duplicated.
201 As well as emitting a diagnostic, the class has various "precision of
202 wording" virtual functions, for generating descriptions for events
203 within a diagnostic_path. These are optional, but implementing these
204 allows for more precise wordings than the more generic
205 implementation. */
207 class pending_diagnostic
209 public:
210 virtual ~pending_diagnostic () {}
212 /* Vfunc to get the command-line option used when emitting the diagnostic,
213 or zero if there is none.
214 Used by diagnostic_manager for early rejection of diagnostics (to avoid
215 having to generate feasible execution paths for them). */
216 virtual int get_controlling_option () const = 0;
218 /* Vfunc to give the diagnostic the chance to terminate the execution
219 path being explored. By default, don't terminate the path. */
220 virtual bool terminate_path_p () const { return false; }
222 /* Vfunc for emitting the diagnostic.
223 Return true if a diagnostic is actually emitted. */
224 virtual bool emit (diagnostic_emission_context &) = 0;
226 /* Hand-coded RTTI: get an ID for the subclass. */
227 virtual const char *get_kind () const = 0;
229 /* A vfunc for identifying "use of uninitialized value". */
230 virtual bool use_of_uninit_p () const { return false; }
232 /* Compare for equality with OTHER, which might be of a different
233 subclass. */
235 bool equal_p (const pending_diagnostic &other) const
237 /* Check for pointer equality on the IDs from get_kind. */
238 if (get_kind () != other.get_kind ())
239 return false;
240 /* Call vfunc now we know they have the same ID: */
241 return subclass_equal_p (other);
244 /* A vfunc for testing for equality, where we've already
245 checked they have the same ID. See pending_diagnostic_subclass
246 below for a convenience subclass for implementing this. */
247 virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
249 /* Return true if T1 and T2 are "the same" for the purposes of
250 diagnostic deduplication. */
251 static bool same_tree_p (tree t1, tree t2);
253 /* Vfunc for fixing up locations, e.g. to avoid unwinding
254 inside specific macros. PRIMARY is true for the primary location
255 for the diagnostic, and FALSE for events in their paths. */
256 virtual location_t fixup_location (location_t loc, bool primary) const;
258 /* Precision-of-wording vfunc for describing a critical state change
259 within the diagnostic_path.
261 For example, a double-free diagnostic might use the descriptions:
262 - "first 'free' happens here"
263 - "second 'free' happens here"
264 for the pertinent events, whereas a use-after-free might use the
265 descriptions:
266 - "freed here"
267 - "use after free here"
268 Note how in both cases the first event is a "free": the best
269 description to use depends on the diagnostic. */
271 virtual label_text describe_state_change (const evdesc::state_change &)
273 /* Default no-op implementation. */
274 return label_text ();
277 /* Vfunc for implementing diagnostic_event::get_meaning for
278 state_change_event. */
279 virtual diagnostic_event::meaning
280 get_meaning_for_state_change (const evdesc::state_change &) const
282 /* Default no-op implementation. */
283 return diagnostic_event::meaning ();
286 /* Precision-of-wording vfunc for describing an interprocedural call
287 carrying critial state for the diagnostic, from caller to callee.
289 For example a double-free diagnostic might use:
290 - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
291 to make it clearer how the freed value moves from caller to
292 callee. */
294 virtual label_text describe_call_with_state (const evdesc::call_with_state &)
296 /* Default no-op implementation. */
297 return label_text ();
300 /* Precision-of-wording vfunc for describing an interprocedural return
301 within the diagnostic_path that carries critial state for the
302 diagnostic, from callee back to caller.
304 For example, a deref-of-unchecked-malloc diagnostic might use:
305 - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
306 to make it clearer how the unchecked value moves from callee
307 back to caller. */
309 virtual label_text describe_return_of_state (const evdesc::return_of_state &)
311 /* Default no-op implementation. */
312 return label_text ();
315 /* Precision-of-wording vfunc for describing the final event within a
316 diagnostic_path.
318 For example a double-free diagnostic might use:
319 - "second 'free' here; first 'free' was at (3)"
320 and a use-after-free might use
321 - "use after 'free' here; memory was freed at (2)". */
323 virtual label_text describe_final_event (const evdesc::final_event &)
325 /* Default no-op implementation. */
326 return label_text ();
329 /* End of precision-of-wording vfuncs. */
331 /* Vfunc for adding a function_entry_event to a checker_path, so that e.g.
332 the infinite recursion diagnostic can add a custom event subclass
333 that annotates recursively entering a function. */
335 virtual void
336 add_function_entry_event (const exploded_edge &eedge,
337 checker_path *emission_path);
339 /* Vfunc for extending/overriding creation of the events for an
340 exploded_edge that corresponds to a superedge, allowing for custom
341 events to be created that are pertinent to a particular
342 pending_diagnostic subclass.
344 For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
345 custom event showing when the pertinent stack frame is popped
346 (and thus the point at which the jmp_buf becomes invalid). */
348 virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &,
349 checker_path *)
351 return false;
354 /* Vfunc for adding a call_event to a checker_path, so that e.g.
355 the varargs diagnostics can add a custom event subclass that annotates
356 the variadic arguments. */
357 virtual void add_call_event (const exploded_edge &,
358 checker_path *);
360 /* Vfunc for adding any events for the creation of regions identified
361 by the mark_interesting_stuff vfunc.
362 See the comment for class region_creation_event. */
363 virtual void add_region_creation_events (const region *reg,
364 tree capacity,
365 const event_loc_info &loc_info,
366 checker_path &emission_path);
368 /* Vfunc for adding the final warning_event to a checker_path, so that e.g.
369 the infinite recursion diagnostic can have its diagnostic appear at
370 the callsite, but the final event in the path be at the entrypoint
371 of the called function. */
372 virtual void add_final_event (const state_machine *sm,
373 const exploded_node *enode,
374 const gimple *stmt,
375 tree var, state_machine::state_t state,
376 checker_path *emission_path);
378 /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
379 and that OTHER should therefore not be emitted.
380 They have already been tested for being at the same stmt. */
382 virtual bool
383 supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
385 return false;
388 /* Vfunc for registering additional information of interest to this
389 diagnostic. */
391 virtual void mark_interesting_stuff (interesting_t *)
393 /* Default no-op implementation. */
396 /* Vfunc to give diagnostic subclasses the opportunity to reject diagnostics
397 by imposing their own additional feasibility checks on the path to a
398 given feasible_node. */
399 virtual bool check_valid_fpath_p (const feasible_node &,
400 const gimple *) const
402 /* Default implementation: accept this path. */
403 return true;
406 /* Vfunc for use in SARIF output to give pending_diagnostic subclasses
407 the opportunity to add diagnostic-specific properties to the SARIF
408 "result" object for the diagnostic.
409 This is intended for use when debugging a diagnostic. */
410 virtual void maybe_add_sarif_properties (sarif_object &/*result_obj*/) const
412 /* Default no-op implementation. */
416 /* A template to make it easier to make subclasses of pending_diagnostic.
418 This uses the curiously-recurring template pattern, to implement
419 pending_diagnostic::subclass_equal_p by casting and calling
420 the operator==
422 This assumes that BASE_OTHER has already been checked to have
423 been of the same subclass (which pending_diagnostic::equal_p does). */
425 template <class Subclass>
426 class pending_diagnostic_subclass : public pending_diagnostic
428 public:
429 bool subclass_equal_p (const pending_diagnostic &base_other) const
430 final override
432 const Subclass &other = (const Subclass &)base_other;
433 return *(const Subclass*)this == other;
437 /* An abstract base class for capturing additional notes that are to be
438 emitted with a diagnostic. */
440 class pending_note
442 public:
443 virtual ~pending_note () {}
445 /* Hand-coded RTTI: get an ID for the subclass. */
446 virtual const char *get_kind () const = 0;
448 /* Vfunc for emitting the note. */
449 virtual void emit () const = 0;
451 bool equal_p (const pending_note &other) const
453 /* Check for pointer equality on the IDs from get_kind. */
454 if (get_kind () != other.get_kind ())
455 return false;
456 /* Call vfunc now we know they have the same ID: */
457 return subclass_equal_p (other);
460 /* A vfunc for testing for equality, where we've already
461 checked they have the same ID. See pending_note_subclass
462 below for a convenience subclass for implementing this. */
463 virtual bool subclass_equal_p (const pending_note &other) const = 0;
466 /* Analogous to pending_diagnostic_subclass, but for pending_note. */
468 template <class Subclass>
469 class pending_note_subclass : public pending_note
471 public:
472 bool subclass_equal_p (const pending_note &base_other) const
473 final override
475 const Subclass &other = (const Subclass &)base_other;
476 return *(const Subclass*)this == other;
480 } // namespace ana
482 #endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */