LCOV - code coverage report
Current view: top level - gcc/analyzer - diagnostic-manager.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 83.2 % 1127 938
Test Date: 2025-12-13 14:10:19 Functions: 92.6 % 68 63
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Classes for saving, deduplicating, and emitting analyzer diagnostics.
       2                 :             :    Copyright (C) 2019-2025 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                 :             : #include "analyzer/common.h"
      22                 :             : 
      23                 :             : #include "cfg.h"
      24                 :             : #include "gimple-pretty-print.h"
      25                 :             : #include "gimple-iterator.h"
      26                 :             : #include "inlining-iterator.h"
      27                 :             : #include "cgraph.h"
      28                 :             : #include "digraph.h"
      29                 :             : #include "gcc-rich-location.h"
      30                 :             : #include "diagnostics/sarif-sink.h"
      31                 :             : 
      32                 :             : #include "analyzer/analyzer-logging.h"
      33                 :             : #include "analyzer/sm.h"
      34                 :             : #include "analyzer/pending-diagnostic.h"
      35                 :             : #include "analyzer/diagnostic-manager.h"
      36                 :             : #include "analyzer/call-string.h"
      37                 :             : #include "analyzer/program-point.h"
      38                 :             : #include "analyzer/store.h"
      39                 :             : #include "analyzer/region-model.h"
      40                 :             : #include "analyzer/constraint-manager.h"
      41                 :             : #include "analyzer/supergraph.h"
      42                 :             : #include "analyzer/program-state.h"
      43                 :             : #include "analyzer/exploded-graph.h"
      44                 :             : #include "analyzer/trimmed-graph.h"
      45                 :             : #include "analyzer/feasible-graph.h"
      46                 :             : #include "analyzer/checker-path.h"
      47                 :             : #include "analyzer/reachability.h"
      48                 :             : 
      49                 :             : #if ENABLE_ANALYZER
      50                 :             : 
      51                 :             : namespace ana {
      52                 :             : 
      53                 :             : class feasible_worklist;
      54                 :             : 
      55                 :             : // struct pending_location
      56                 :             : 
      57                 :         908 : pending_location::pending_location ()
      58                 :         908 : : m_enode (nullptr),
      59                 :         908 :   m_event_loc_info (UNKNOWN_LOCATION, NULL_TREE, 0)
      60                 :             : {
      61                 :         908 : }
      62                 :             : 
      63                 :        7078 : pending_location::pending_location (exploded_node *enode)
      64                 :        7078 : : m_enode (enode),
      65                 :        7078 :   m_event_loc_info (enode)
      66                 :             : {
      67                 :        7078 : }
      68                 :             : 
      69                 :        3545 : pending_location::pending_location (exploded_node *enode,
      70                 :        3545 :                                     location_t loc)
      71                 :        3545 : : m_enode (enode),
      72                 :        3545 :   m_event_loc_info (enode)
      73                 :             : {
      74                 :        3545 :   m_event_loc_info.m_loc = loc;
      75                 :        3545 : }
      76                 :             : 
      77                 :             : std::unique_ptr<json::object>
      78                 :          36 : pending_location::to_json () const
      79                 :             : {
      80                 :          36 :   auto ploc_obj = std::make_unique<json::object> ();
      81                 :             : 
      82                 :          36 :   if (m_enode)
      83                 :          36 :     ploc_obj->set_integer ("enode", m_enode->m_index);
      84                 :             :   // TODO: also store m_event_loc_info
      85                 :          36 :   return ploc_obj;
      86                 :             : }
      87                 :             : 
      88                 :             : /* State for finding the shortest feasible exploded_path for a
      89                 :             :    saved_diagnostic.
      90                 :             :    This is shared between all diagnostics, so that we avoid repeating work.  */
      91                 :             : 
      92                 :             : class epath_finder
      93                 :             : {
      94                 :             : public:
      95                 :        1540 :   epath_finder (const exploded_graph &eg)
      96                 :        1540 :   : m_eg (eg),
      97                 :        1540 :     m_sep (nullptr)
      98                 :             :   {
      99                 :             :     /* This is shared by all diagnostics, but only needed if
     100                 :             :        !flag_analyzer_feasibility.  */
     101                 :        1540 :     if (!flag_analyzer_feasibility)
     102                 :           4 :       m_sep = new shortest_exploded_paths (eg, eg.get_origin (),
     103                 :           4 :                                            SPS_FROM_GIVEN_ORIGIN);
     104                 :        1540 :   }
     105                 :             : 
     106                 :        1544 :   ~epath_finder () { delete m_sep; }
     107                 :             : 
     108                 :      155787 :   logger *get_logger () const { return m_eg.get_logger (); }
     109                 :             : 
     110                 :             :   std::unique_ptr<exploded_path>
     111                 :             :   get_best_epath (const exploded_node *target_enode,
     112                 :             :                   const pending_diagnostic &pd,
     113                 :             :                   const char *desc, unsigned diag_idx,
     114                 :             :                   std::unique_ptr<feasibility_problem> *out_problem);
     115                 :             : 
     116                 :             : private:
     117                 :             :   DISABLE_COPY_AND_ASSIGN(epath_finder);
     118                 :             : 
     119                 :             :   std::unique_ptr<exploded_path>
     120                 :             :   explore_feasible_paths (const exploded_node *target_enode,
     121                 :             :                           const pending_diagnostic &pd,
     122                 :             :                           const char *desc, unsigned diag_idx);
     123                 :             :   bool
     124                 :             :   process_worklist_item (feasible_worklist *worklist,
     125                 :             :                          const trimmed_graph &tg,
     126                 :             :                          feasible_graph *fg,
     127                 :             :                          const exploded_node *target_enode,
     128                 :             :                          const pending_diagnostic &pd,
     129                 :             :                          unsigned diag_idx,
     130                 :             :                          std::unique_ptr<exploded_path> *out_best_path) const;
     131                 :             :   void dump_trimmed_graph (const exploded_node *target_enode,
     132                 :             :                            const char *desc, unsigned diag_idx,
     133                 :             :                            const trimmed_graph &tg,
     134                 :             :                            const shortest_paths<eg_traits, exploded_path> &sep);
     135                 :             :   void dump_feasible_graph (const exploded_node *target_enode,
     136                 :             :                             const char *desc, unsigned diag_idx,
     137                 :             :                             const feasible_graph &fg);
     138                 :             :   void dump_feasible_path (const exploded_node *target_enode,
     139                 :             :                            unsigned diag_idx,
     140                 :             :                            const feasible_graph &fg,
     141                 :             :                            const feasible_node &fnode) const;
     142                 :             : 
     143                 :             :   const exploded_graph &m_eg;
     144                 :             :   shortest_exploded_paths *m_sep;
     145                 :             : };
     146                 :             : 
     147                 :             : /* class epath_finder.  */
     148                 :             : 
     149                 :             : /* Get the "best" exploded_path for reaching TARGET_ENODE from the origin,
     150                 :             :    returning ownership of it to the caller.
     151                 :             : 
     152                 :             :    Ideally we want to report the shortest feasible path.
     153                 :             :    Return nullptr if we could not find a feasible path
     154                 :             :    (when flag_analyzer_feasibility is true).
     155                 :             : 
     156                 :             :    If flag_analyzer_feasibility is false, then simply return the
     157                 :             :    shortest path.
     158                 :             : 
     159                 :             :    Use DESC and DIAG_IDX when logging.
     160                 :             : 
     161                 :             :    Write any feasibility_problem to *OUT_PROBLEM.  */
     162                 :             : 
     163                 :             : std::unique_ptr<exploded_path>
     164                 :        6373 : epath_finder::get_best_epath (const exploded_node *target_enode,
     165                 :             :                               const pending_diagnostic &pd,
     166                 :             :                               const char *desc, unsigned diag_idx,
     167                 :             :                               std::unique_ptr<feasibility_problem> *out_problem)
     168                 :             : {
     169                 :        6373 :   logger *logger = get_logger ();
     170                 :        6373 :   LOG_SCOPE (logger);
     171                 :             : 
     172                 :        6373 :   unsigned snode_id = target_enode->get_supernode ()->m_id;
     173                 :        6373 :   if (logger)
     174                 :           0 :     logger->log ("considering %qs at EN: %i, SN: %i (sd: %i)",
     175                 :           0 :                  desc, target_enode->m_index, snode_id, diag_idx);
     176                 :             : 
     177                 :             :   /* State-merging means that not every path in the egraph corresponds
     178                 :             :      to a feasible one w.r.t. states.
     179                 :             : 
     180                 :             :      We want to find the shortest feasible path from the origin to ENODE
     181                 :             :      in the egraph.  */
     182                 :             : 
     183                 :        6373 :   if (flag_analyzer_feasibility)
     184                 :             :     {
     185                 :             :       /* Attempt to find the shortest feasible path using feasible_graph.  */
     186                 :        6369 :       if (logger)
     187                 :           0 :         logger->log ("trying to find shortest feasible path");
     188                 :        6369 :       if (std::unique_ptr<exploded_path> epath
     189                 :        6369 :             = explore_feasible_paths (target_enode, pd, desc, diag_idx))
     190                 :             :         {
     191                 :        6090 :           if (logger)
     192                 :           0 :             logger->log ("accepting %qs at EN: %i, SN: %i (sd: %i)"
     193                 :             :                          " with feasible path (length: %i)",
     194                 :           0 :                          desc, target_enode->m_index, snode_id, diag_idx,
     195                 :             :                          epath->length ());
     196                 :        6090 :           return epath;
     197                 :             :         }
     198                 :             :       else
     199                 :             :         {
     200                 :         279 :           if (logger)
     201                 :           0 :             logger->log ("rejecting %qs at EN: %i, SN: %i (sd: %i)"
     202                 :             :                          " due to not finding feasible path",
     203                 :           0 :                          desc, target_enode->m_index, snode_id, diag_idx);
     204                 :         279 :           return nullptr;
     205                 :        6369 :         }
     206                 :             :     }
     207                 :             :   else
     208                 :             :     {
     209                 :             :       /* As a crude approximation to shortest feasible path, simply find
     210                 :             :          the shortest path, and note whether it is feasible.
     211                 :             :          There could be longer feasible paths within the egraph, so this
     212                 :             :          approach would lead to diagnostics being falsely rejected
     213                 :             :          (PR analyzer/96374).  */
     214                 :           4 :       if (logger)
     215                 :           0 :         logger->log ("trying to find shortest path ignoring feasibility");
     216                 :           4 :       gcc_assert (m_sep);
     217                 :           4 :       auto epath
     218                 :             :         = std::make_unique<exploded_path>
     219                 :           4 :             (m_sep->get_shortest_path (target_enode));
     220                 :           4 :       if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg))
     221                 :             :         {
     222                 :           0 :           if (logger)
     223                 :           0 :             logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i)"
     224                 :             :                          " with feasible path (length: %i)",
     225                 :           0 :                          desc, target_enode->m_index, snode_id, diag_idx,
     226                 :             :                          epath->length ());
     227                 :             :         }
     228                 :             :       else
     229                 :             :         {
     230                 :           4 :           if (logger)
     231                 :           0 :             logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i) (length: %i)"
     232                 :             :                          " despite infeasible path (due to %qs)",
     233                 :           0 :                          desc, target_enode->m_index, snode_id, diag_idx,
     234                 :             :                          epath->length (),
     235                 :             :                          "-fno-analyzer-feasibility");
     236                 :             :         }
     237                 :           4 :       return epath;
     238                 :           4 :     }
     239                 :        6373 : }
     240                 :             : 
     241                 :             : /* A class for managing the worklist of feasible_nodes in
     242                 :             :    epath_finder::explore_feasible_paths, prioritizing them
     243                 :             :    so that shorter paths appear earlier in the queue.  */
     244                 :             : 
     245                 :       12738 : class feasible_worklist
     246                 :             : {
     247                 :             : public:
     248                 :        6369 :   feasible_worklist (const shortest_paths<eg_traits, exploded_path> &sep)
     249                 :       12738 :   : m_queue (key_t (*this, nullptr)),
     250                 :        6369 :     m_sep (sep)
     251                 :             :   {
     252                 :        6369 :   }
     253                 :             : 
     254                 :      136672 :   feasible_node *take_next () { return m_queue.extract_min (); }
     255                 :             : 
     256                 :      140179 :   void add_node (feasible_node *fnode)
     257                 :             :   {
     258                 :      280358 :     m_queue.insert (key_t (*this, fnode), fnode);
     259                 :      133810 :   }
     260                 :             : 
     261                 :             : private:
     262                 :             :   struct key_t
     263                 :             :   {
     264                 :      146548 :     key_t (const feasible_worklist &w, feasible_node *fnode)
     265                 :        6369 :     : m_worklist (w), m_fnode (fnode)
     266                 :             :     {}
     267                 :             : 
     268                 :      153193 :     bool operator< (const key_t &other) const
     269                 :             :     {
     270                 :      153193 :       return cmp (*this, other) < 0;
     271                 :             :     }
     272                 :             : 
     273                 :       46024 :     bool operator== (const key_t &other) const
     274                 :             :     {
     275                 :       46024 :       return cmp (*this, other) == 0;
     276                 :             :     }
     277                 :             : 
     278                 :       46024 :     bool operator> (const key_t &other) const
     279                 :             :     {
     280                 :       46024 :       return !(*this == other || *this < other);
     281                 :             :     }
     282                 :             : 
     283                 :             :   private:
     284                 :      199217 :     static int cmp (const key_t &ka, const key_t &kb)
     285                 :             :     {
     286                 :             :       /* Choose the node for which if the remaining path were feasible,
     287                 :             :          it would be the shortest path (summing the length of the
     288                 :             :          known-feasible path so far with that of the remaining
     289                 :             :          possibly-feasible path).  */
     290                 :      199217 :       int ca = ka.m_worklist.get_estimated_cost (ka.m_fnode);
     291                 :      199217 :       int cb = kb.m_worklist.get_estimated_cost (kb.m_fnode);
     292                 :      199217 :       return ca - cb;
     293                 :             :     }
     294                 :             : 
     295                 :             :     const feasible_worklist &m_worklist;
     296                 :             :     feasible_node *m_fnode;
     297                 :             :   };
     298                 :             : 
     299                 :             :   /* Get the estimated length of a path involving FNODE from
     300                 :             :      the origin to the target enode.
     301                 :             :      Sum the length of the known-feasible path so far with
     302                 :             :      that of the remaining possibly-feasible path.  */
     303                 :             : 
     304                 :      398434 :   int get_estimated_cost (const feasible_node *fnode) const
     305                 :             :   {
     306                 :      398434 :     unsigned length_so_far = fnode->get_path_length ();
     307                 :      398434 :     int shortest_remaining_path
     308                 :      398434 :       = m_sep.get_shortest_distance (fnode->get_inner_node ());
     309                 :             : 
     310                 :      398434 :     gcc_assert (shortest_remaining_path >= 0);
     311                 :             :     /* This should be true since we're only exploring nodes within
     312                 :             :        the trimmed graph (and we anticipate it being much smaller
     313                 :             :        than this, and thus not overflowing the sum).  */
     314                 :      398434 :     gcc_assert (shortest_remaining_path < INT_MAX);
     315                 :             : 
     316                 :      398434 :     return length_so_far + shortest_remaining_path;
     317                 :             :   }
     318                 :             : 
     319                 :             :   /* Priority queue, backed by a fibonacci_heap.  */
     320                 :             :   typedef fibonacci_heap<key_t, feasible_node> queue_t;
     321                 :             :   queue_t m_queue;
     322                 :             :   const shortest_paths<eg_traits, exploded_path> &m_sep;
     323                 :             : };
     324                 :             : 
     325                 :             : /* When we're building the exploded graph we want to simplify
     326                 :             :    overly-complicated symbolic values down to "UNKNOWN" to try to avoid
     327                 :             :    state explosions and unbounded chains of exploration.
     328                 :             : 
     329                 :             :    However, when we're building the feasibility graph for a diagnostic
     330                 :             :    (actually a tree), we don't want UNKNOWN values, as conditions on them
     331                 :             :    are also unknown: we don't want to have a contradiction such as a path
     332                 :             :    where (VAL != 0) and then (VAL == 0) along the same path.
     333                 :             : 
     334                 :             :    Hence this is an RAII class for temporarily disabling complexity-checking
     335                 :             :    in the region_model_manager, for use within
     336                 :             :    epath_finder::explore_feasible_paths.
     337                 :             : 
     338                 :             :    We also disable the creation of unknown_svalue instances during feasibility
     339                 :             :    checking, instead creating unique svalues, to avoid paradoxes in paths.  */
     340                 :             : 
     341                 :             : class auto_checking_feasibility
     342                 :             : {
     343                 :             : public:
     344                 :        6369 :   auto_checking_feasibility (region_model_manager *mgr) : m_mgr (mgr)
     345                 :             :   {
     346                 :        6369 :     m_mgr->begin_checking_feasibility ();
     347                 :        6369 :   }
     348                 :        6369 :   ~auto_checking_feasibility ()
     349                 :             :   {
     350                 :        6369 :     m_mgr->end_checking_feasibility ();
     351                 :             :   }
     352                 :             : private:
     353                 :             :   region_model_manager *m_mgr;
     354                 :             : };
     355                 :             : 
     356                 :             : /* Attempt to find the shortest feasible path from the origin to
     357                 :             :    TARGET_ENODE by iteratively building a feasible_graph, in which
     358                 :             :    every path to a feasible_node is feasible by construction.
     359                 :             : 
     360                 :             :    We effectively explore the tree of feasible paths in order of shortest
     361                 :             :    path until we either find a feasible path to TARGET_ENODE, or hit
     362                 :             :    a limit and give up.
     363                 :             : 
     364                 :             :    Preliminaries:
     365                 :             :    - Find the shortest path from each node to the TARGET_ENODE (without
     366                 :             :    checking feasibility), so that we can prioritize our worklist.
     367                 :             :    - Construct a trimmed_graph: the subset of nodes/edges that
     368                 :             :    are on a path that eventually reaches TARGET_ENODE.  We will only need
     369                 :             :    to consider these when considering the shortest feasible path.
     370                 :             : 
     371                 :             :    Build a feasible_graph, in which every path to a feasible_node
     372                 :             :    is feasible by construction.
     373                 :             :    We use a worklist to flatten the exploration into an iteration.
     374                 :             :    Starting at the origin, find feasible out-edges within the trimmed graph.
     375                 :             :    At each stage, choose the node for which if the remaining path were feasible,
     376                 :             :    it would be the shortest path (summing the length of the known-feasible path
     377                 :             :    so far with that of the remaining possibly-feasible path).
     378                 :             :    This way, the first feasible path we find to TARGET_ENODE is the shortest.
     379                 :             :    We start by trying the shortest possible path, but if that fails,
     380                 :             :    we explore progressively longer paths, eventually trying iterations through
     381                 :             :    loops.  The exploration is captured in the feasible_graph, which can be
     382                 :             :    dumped as a .dot file to visualize the exploration.  The indices of the
     383                 :             :    feasible_nodes show the order in which they were created.
     384                 :             : 
     385                 :             :    This is something of a brute-force approach, but the trimmed_graph
     386                 :             :    hopefully keeps the complexity manageable.
     387                 :             : 
     388                 :             :    Terminate with failure when the number of infeasible edges exceeds
     389                 :             :    a threshold (--param=analyzer-max-infeasible-edges=).
     390                 :             :    This is guaranteed to eventually lead to terminatation, as
     391                 :             :    we can't keep creating feasible nodes without eventually
     392                 :             :    either reaching an infeasible edge, or reaching the
     393                 :             :    TARGET_ENODE.  Specifically, there can't be a cycle of
     394                 :             :    feasible edges that doesn't reach the target_enode without
     395                 :             :    an out-edge that either fails feasibility or gets closer
     396                 :             :    to the TARGET_ENODE: on each iteration we are either:
     397                 :             :    - effectively getting closer to the TARGET_ENODE (which can't
     398                 :             :      continue forever without reaching the target), or
     399                 :             :    - getting monotonically closer to the termination threshold.  */
     400                 :             : 
     401                 :             : std::unique_ptr<exploded_path>
     402                 :        6369 : epath_finder::explore_feasible_paths (const exploded_node *target_enode,
     403                 :             :                                       const pending_diagnostic &pd,
     404                 :             :                                       const char *desc, unsigned diag_idx)
     405                 :             : {
     406                 :        6369 :   logger *logger = get_logger ();
     407                 :        6369 :   LOG_SCOPE (logger);
     408                 :             : 
     409                 :        6369 :   region_model_manager *mgr = m_eg.get_engine ()->get_model_manager ();
     410                 :             : 
     411                 :             :   /* Determine the shortest path to TARGET_ENODE from each node in
     412                 :             :      the exploded graph.  */
     413                 :        6369 :   shortest_paths<eg_traits, exploded_path> sep
     414                 :        6369 :     (m_eg, target_enode, SPS_TO_GIVEN_TARGET);
     415                 :             : 
     416                 :             :   /* Construct a trimmed_graph: the subset of nodes/edges that
     417                 :             :      are on a path that eventually reaches TARGET_ENODE.
     418                 :             :      We only need to consider these when considering the shortest
     419                 :             :      feasible path.  */
     420                 :        6369 :   trimmed_graph tg (m_eg, target_enode);
     421                 :             : 
     422                 :        6369 :   if (flag_dump_analyzer_feasibility)
     423                 :           4 :     dump_trimmed_graph (target_enode, desc, diag_idx, tg, sep);
     424                 :             : 
     425                 :        6369 :   feasible_graph fg;
     426                 :        6369 :   feasible_worklist worklist (sep);
     427                 :             : 
     428                 :             :   /* Populate the worklist with the origin node.  */
     429                 :        6369 :   {
     430                 :        6369 :     feasibility_state init_state (mgr, m_eg.get_supergraph ());
     431                 :        6369 :     feasible_node *origin = fg.add_node (m_eg.get_origin (), init_state, 0);
     432                 :        6369 :     worklist.add_node (origin);
     433                 :        6369 :   }
     434                 :             : 
     435                 :             :   /* Iteratively explore the tree of feasible paths in order of shortest
     436                 :             :      path until we either find a feasible path to TARGET_ENODE, or hit
     437                 :             :      a limit.  */
     438                 :             : 
     439                 :             :   /* Set this if we find a feasible path to TARGET_ENODE.  */
     440                 :        6369 :   std::unique_ptr<exploded_path> best_path = nullptr;
     441                 :             : 
     442                 :        6369 :   {
     443                 :        6369 :     auto_checking_feasibility sentinel (mgr);
     444                 :             : 
     445                 :      136672 :     while (process_worklist_item (&worklist, tg, &fg, target_enode,
     446                 :             :                                   pd, diag_idx, &best_path))
     447                 :             :       {
     448                 :             :         /* Empty; the work is done within process_worklist_item.  */
     449                 :             :       }
     450                 :        6369 :   }
     451                 :             : 
     452                 :        6369 :   if (logger)
     453                 :             :     {
     454                 :           0 :       logger->log ("tg for sd: %i:", diag_idx);
     455                 :           0 :       logger->inc_indent ();
     456                 :           0 :       tg.log_stats (logger);
     457                 :           0 :       logger->dec_indent ();
     458                 :             : 
     459                 :           0 :       logger->log ("fg for sd: %i:", diag_idx);
     460                 :           0 :       logger->inc_indent ();
     461                 :           0 :       fg.log_stats (logger);
     462                 :           0 :       logger->dec_indent ();
     463                 :             :     }
     464                 :             : 
     465                 :             :   /* Dump the feasible_graph.  */
     466                 :        6369 :   if (flag_dump_analyzer_feasibility)
     467                 :           4 :     dump_feasible_graph (target_enode, desc, diag_idx, fg);
     468                 :             : 
     469                 :        6369 :   return best_path;
     470                 :       12738 : }
     471                 :             : 
     472                 :             : /* Process the next item in WORKLIST, potentially adding new items
     473                 :             :    based on feasible out-edges, and extending FG accordingly.
     474                 :             :    Use TG to ignore out-edges that don't lead to TARGET_ENODE.
     475                 :             :    Return true if the worklist processing should continue.
     476                 :             :    Return false if the processing of the worklist should stop
     477                 :             :    (either due to reaching TARGET_ENODE, or hitting a limit).
     478                 :             :    Write to *OUT_BEST_PATH if stopping due to finding a feasible path
     479                 :             :    to TARGET_ENODE.
     480                 :             :    Use PD to provide additional restrictions on feasibility of
     481                 :             :    the final path in the feasible_graph before converting to
     482                 :             :    an exploded_path.  */
     483                 :             : 
     484                 :             : bool
     485                 :      136672 : epath_finder::
     486                 :             : process_worklist_item (feasible_worklist *worklist,
     487                 :             :                        const trimmed_graph &tg,
     488                 :             :                        feasible_graph *fg,
     489                 :             :                        const exploded_node *target_enode,
     490                 :             :                        const pending_diagnostic &pd,
     491                 :             :                        unsigned diag_idx,
     492                 :             :                        std::unique_ptr<exploded_path> *out_best_path) const
     493                 :             : {
     494                 :      136672 :   logger *logger = get_logger ();
     495                 :             : 
     496                 :      136672 :   feasible_node *fnode = worklist->take_next ();
     497                 :      136672 :   if (!fnode)
     498                 :             :     {
     499                 :          52 :       if (logger)
     500                 :           0 :         logger->log ("drained worklist for sd: %i"
     501                 :             :                      " without finding feasible path",
     502                 :             :                      diag_idx);
     503                 :          52 :       return false;
     504                 :             :     }
     505                 :             : 
     506                 :      136620 :   log_scope s (logger, "fg worklist item",
     507                 :             :                "considering FN: %i (EN: %i) for sd: %i",
     508                 :      136620 :                fnode->get_index (), fnode->get_inner_node ()->m_index,
     509                 :      136620 :                diag_idx);
     510                 :             : 
     511                 :             :   /* Iterate through all out-edges from this item.  */
     512                 :      136620 :   unsigned i;
     513                 :      136620 :   exploded_edge *succ_eedge;
     514                 :      325919 :   FOR_EACH_VEC_ELT (fnode->get_inner_node ()->m_succs, i, succ_eedge)
     515                 :             :     {
     516                 :      195616 :       log_scope s (logger, "edge", "considering edge: EN:%i -> EN:%i",
     517                 :      195616 :                    succ_eedge->m_src->m_index,
     518                 :      195616 :                    succ_eedge->m_dest->m_index);
     519                 :             :       /* Reject edges that aren't in the trimmed graph.  */
     520                 :      195616 :       if (!tg.contains_p (succ_eedge))
     521                 :             :         {
     522                 :       53407 :           if (logger)
     523                 :           0 :             logger->log ("rejecting: not in trimmed graph");
     524                 :       53407 :           continue;
     525                 :             :         }
     526                 :             : 
     527                 :      142209 :       feasibility_state succ_state (fnode->get_state ());
     528                 :      142209 :       std::unique_ptr<rejected_constraint> rc;
     529                 :      142209 :       if (succ_state.maybe_update_for_edge (logger, succ_eedge, nullptr, &rc))
     530                 :             :         {
     531                 :      139961 :           gcc_assert (rc == nullptr);
     532                 :      139961 :           feasible_node *succ_fnode
     533                 :      139961 :             = fg->add_node (succ_eedge->m_dest,
     534                 :             :                             succ_state,
     535                 :      139961 :                             fnode->get_path_length () + 1);
     536                 :      139961 :           if (logger)
     537                 :           0 :             logger->log ("accepting as FN: %i", succ_fnode->get_index ());
     538                 :      139961 :           fg->add_edge (new feasible_edge (fnode, succ_fnode, succ_eedge));
     539                 :             : 
     540                 :             :           /* Have we reached TARGET_ENODE?  */
     541                 :      139961 :           if (succ_fnode->get_inner_node () == target_enode)
     542                 :             :             {
     543                 :        6151 :               if (logger)
     544                 :           0 :                 logger->log ("success: got feasible path to EN: %i (sd: %i)"
     545                 :             :                              " (length: %i)",
     546                 :           0 :                              target_enode->m_index, diag_idx,
     547                 :             :                              succ_fnode->get_path_length ());
     548                 :        6151 :               if (!pd.check_valid_fpath_p (*succ_fnode))
     549                 :             :                 {
     550                 :          61 :                   if (logger)
     551                 :           0 :                     logger->log ("rejecting feasible path due to"
     552                 :             :                                  " pending_diagnostic");
     553                 :          61 :                   return false;
     554                 :             :                 }
     555                 :        6090 :               *out_best_path = fg->make_epath (succ_fnode);
     556                 :        6090 :               if (flag_dump_analyzer_feasibility)
     557                 :           4 :                 dump_feasible_path (target_enode, diag_idx, *fg, *succ_fnode);
     558                 :             : 
     559                 :             :               /* Success: stop the worklist iteration.  */
     560                 :        6090 :               return false;
     561                 :             :             }
     562                 :             :           else
     563                 :      133810 :             worklist->add_node (succ_fnode);
     564                 :             :         }
     565                 :             :       else
     566                 :             :         {
     567                 :        2248 :           if (logger)
     568                 :           0 :             logger->log ("infeasible");
     569                 :        2248 :           gcc_assert (rc);
     570                 :        2248 :           fg->add_feasibility_problem (fnode,
     571                 :             :                                        succ_eedge,
     572                 :             :                                        std::move (rc));
     573                 :             : 
     574                 :             :           /* Give up if there have been too many infeasible edges.  */
     575                 :        2248 :           if (fg->get_num_infeasible ()
     576                 :        2248 :               > (unsigned)param_analyzer_max_infeasible_edges)
     577                 :             :             {
     578                 :         166 :               if (logger)
     579                 :           0 :                 logger->log ("too many infeasible edges (%i); giving up",
     580                 :             :                              fg->get_num_infeasible ());
     581                 :         166 :               return false;
     582                 :             :             }
     583                 :             :         }
     584                 :      195616 :     }
     585                 :             : 
     586                 :             :   /* Continue the worklist iteration.  */
     587                 :             :   return true;
     588                 :      136620 : }
     589                 :             : 
     590                 :             : /* Helper class for epath_finder::dump_trimmed_graph
     591                 :             :    to dump extra per-node information.
     592                 :             :    Use SEP to add the length of the shortest path from each
     593                 :             :    node to the target node to each node's dump.  */
     594                 :             : 
     595                 :             : class dump_eg_with_shortest_path : public eg_traits::dump_args_t
     596                 :             : {
     597                 :             : public:
     598                 :           4 :   dump_eg_with_shortest_path
     599                 :             :     (const exploded_graph &eg,
     600                 :             :      const shortest_paths<eg_traits, exploded_path> &sep)
     601                 :           4 :   : dump_args_t (eg),
     602                 :           4 :     m_sep (sep)
     603                 :             :   {
     604                 :             :   }
     605                 :             : 
     606                 :          74 :   void dump_extra_info (const exploded_node *enode,
     607                 :             :                         pretty_printer *pp) const final override
     608                 :             :   {
     609                 :         144 :     pp_printf (pp, "sp: %i", m_sep.get_shortest_path (enode).length ());
     610                 :          74 :     pp_newline (pp);
     611                 :          74 :   }
     612                 :             : 
     613                 :             : private:
     614                 :             :   const shortest_paths<eg_traits, exploded_path> &m_sep;
     615                 :             : };
     616                 :             : 
     617                 :             : /* Dump TG to "BASE_NAME.DESC.DIAG_IDX.to-enN.tg.dot",
     618                 :             :    annotating each node with the length of the shortest path
     619                 :             :    from that node to TARGET_ENODE (using SEP).  */
     620                 :             : 
     621                 :             : void
     622                 :           4 : epath_finder::
     623                 :             : dump_trimmed_graph (const exploded_node *target_enode,
     624                 :             :                     const char *desc, unsigned diag_idx,
     625                 :             :                     const trimmed_graph &tg,
     626                 :             :                     const shortest_paths<eg_traits, exploded_path> &sep)
     627                 :             : {
     628                 :           4 :   auto_timevar tv (TV_ANALYZER_DUMP);
     629                 :           4 :   dump_eg_with_shortest_path inner_args (m_eg, sep);
     630                 :           4 :   trimmed_graph::dump_args_t args (inner_args);
     631                 :           4 :   pretty_printer pp;
     632                 :           4 :   pp_printf (&pp, "%s.%s.%i.to-en%i.tg.dot",
     633                 :           4 :              dump_base_name, desc, diag_idx, target_enode->m_index);
     634                 :           4 :   char *filename = xstrdup (pp_formatted_text (&pp));
     635                 :           4 :   tg.dump_dot (filename, nullptr, args);
     636                 :           4 :   free (filename);
     637                 :           4 : }
     638                 :             : 
     639                 :             : /* Dump FG to "BASE_NAME.DESC.DIAG_IDX.to-enN.fg.dot".  */
     640                 :             : 
     641                 :             : void
     642                 :           4 : epath_finder::dump_feasible_graph (const exploded_node *target_enode,
     643                 :             :                                    const char *desc, unsigned diag_idx,
     644                 :             :                                    const feasible_graph &fg)
     645                 :             : {
     646                 :           4 :   auto_timevar tv (TV_ANALYZER_DUMP);
     647                 :           4 :   exploded_graph::dump_args_t inner_args (m_eg);
     648                 :           4 :   feasible_graph::dump_args_t args (inner_args);
     649                 :           4 :   pretty_printer pp;
     650                 :           4 :   pp_printf (&pp, "%s.%s.%i.to-en%i.fg.dot",
     651                 :           4 :              dump_base_name, desc, diag_idx, target_enode->m_index);
     652                 :           4 :   char *filename = xstrdup (pp_formatted_text (&pp));
     653                 :           4 :   fg.dump_dot (filename, nullptr, args);
     654                 :           4 :   free (filename);
     655                 :           4 : }
     656                 :             : 
     657                 :             : /* Dump the path to FNODE to "BASE_NAME.DIAG_IDX.to-enN.fpath.txt".  */
     658                 :             : 
     659                 :             : void
     660                 :           4 : epath_finder::dump_feasible_path (const exploded_node *target_enode,
     661                 :             :                                   unsigned diag_idx,
     662                 :             :                                   const feasible_graph &fg,
     663                 :             :                                   const feasible_node &fnode) const
     664                 :             : {
     665                 :           4 :   auto_timevar tv (TV_ANALYZER_DUMP);
     666                 :           4 :   pretty_printer pp;
     667                 :           4 :   pp_printf (&pp, "%s.%i.to-en%i.fpath.txt",
     668                 :           4 :              dump_base_name, diag_idx, target_enode->m_index);
     669                 :           4 :   char *filename = xstrdup (pp_formatted_text (&pp));
     670                 :           4 :   fg.dump_feasible_path (fnode, filename);
     671                 :           4 :   free (filename);
     672                 :           4 : }
     673                 :             : 
     674                 :             : /* class saved_diagnostic.  */
     675                 :             : 
     676                 :             : /* saved_diagnostic's ctor.  */
     677                 :             : 
     678                 :        6373 : saved_diagnostic::saved_diagnostic (const state_machine *sm,
     679                 :             :                                     pending_location &&ploc,
     680                 :             :                                     tree var,
     681                 :             :                                     const svalue *sval,
     682                 :             :                                     state_machine::state_t state,
     683                 :             :                                     std::unique_ptr<pending_diagnostic> d,
     684                 :        6373 :                                     unsigned idx)
     685                 :        6373 : : m_sm (sm),
     686                 :        6373 :   m_ploc (std::move (ploc)),
     687                 :        6373 :   m_var (var), m_sval (sval), m_state (state),
     688                 :        6373 :   m_d (std::move (d)), m_trailing_eedge (nullptr),
     689                 :        6373 :   m_idx (idx),
     690                 :        6373 :   m_best_epath (nullptr), m_problem (nullptr),
     691                 :        6373 :   m_notes ()
     692                 :             : {
     693                 :             :   /* We must have an enode in order to be able to look for paths
     694                 :             :      through the exploded_graph to this diagnostic.  */
     695                 :        6373 :   gcc_assert (m_ploc.m_enode);
     696                 :        6373 : }
     697                 :             : 
     698                 :             : const supernode *
     699                 :      139488 : saved_diagnostic::get_supernode () const
     700                 :             : {
     701                 :      139488 :   return m_ploc.m_enode->get_supernode ();
     702                 :             : }
     703                 :             : 
     704                 :             : bool
     705                 :       46754 : saved_diagnostic::operator== (const saved_diagnostic &other) const
     706                 :             : {
     707                 :       48898 :   if (m_notes.length () != other.m_notes.length ())
     708                 :             :     return false;
     709                 :       46301 :   for (unsigned i = 0; i < m_notes.length (); i++)
     710                 :         733 :     if (!m_notes[i]->equal_p (*other.m_notes[i]))
     711                 :             :       return false;
     712                 :             : 
     713                 :             :   // Don't deduplicate dump_path_diagnostic instances
     714                 :       45568 :   if (!strcmp (m_d->get_kind (), "dump_path_diagnostic"))
     715                 :        1980 :     return this == &other;
     716                 :             : 
     717                 :       43588 :   return (m_sm == other.m_sm
     718                 :             :           /* We don't compare m_enode.  */
     719                 :       38465 :           && get_supernode () == other.get_supernode ()
     720                 :        8775 :           && (m_ploc.m_event_loc_info.m_loc
     721                 :        8775 :               == other.m_ploc.m_event_loc_info.m_loc)
     722                 :        6751 :           && pending_diagnostic::same_tree_p (m_var, other.m_var)
     723                 :        6045 :           && m_state == other.m_state
     724                 :        5983 :           && m_d->equal_p (*other.m_d)
     725                 :       49413 :           && m_trailing_eedge == other.m_trailing_eedge);
     726                 :             : }
     727                 :             : 
     728                 :             : /* Add PN to this diagnostic, taking ownership of it.  */
     729                 :             : 
     730                 :             : void
     731                 :         193 : saved_diagnostic::add_note (std::unique_ptr<pending_note> pn)
     732                 :             : {
     733                 :         193 :   gcc_assert (pn);
     734                 :         193 :   m_notes.safe_push (pn.release ());
     735                 :         193 : }
     736                 :             : 
     737                 :             : /* Add EVENT to this diagnostic.  */
     738                 :             : 
     739                 :             : void
     740                 :         158 : saved_diagnostic::add_event (std::unique_ptr<checker_event> event)
     741                 :             : {
     742                 :         158 :   gcc_assert (event);
     743                 :         158 :   m_saved_events.safe_push (event.release ());
     744                 :         158 : }
     745                 :             : 
     746                 :             : /* Return a new json::object of the form
     747                 :             :    {"sm": optional str,
     748                 :             :     "ploc": {},
     749                 :             :     "sval": optional str,
     750                 :             :     "state": optional str,
     751                 :             :     "path_length": optional int,
     752                 :             :     "pending_diagnostic": str,
     753                 :             :     "idx": int}.  */
     754                 :             : 
     755                 :             : std::unique_ptr<json::object>
     756                 :           0 : saved_diagnostic::to_json () const
     757                 :             : {
     758                 :           0 :   auto sd_obj = std::make_unique<json::object> ();
     759                 :             : 
     760                 :           0 :   if (m_sm)
     761                 :           0 :     sd_obj->set_string ("sm", m_sm->get_name ());
     762                 :           0 :   sd_obj->set ("ploc", m_ploc.to_json ());
     763                 :           0 :   if (m_sval)
     764                 :           0 :     sd_obj->set ("sval", m_sval->to_json ());
     765                 :           0 :   if (m_state)
     766                 :           0 :     sd_obj->set ("state", m_state->to_json ());
     767                 :           0 :   if (m_best_epath)
     768                 :           0 :     sd_obj->set_integer ("path_length", get_epath_length ());
     769                 :           0 :   sd_obj->set_string ("pending_diagnostic", m_d->get_kind ());
     770                 :           0 :   sd_obj->set_integer ("idx", m_idx);
     771                 :             : 
     772                 :           0 :   return sd_obj;
     773                 :             : }
     774                 :             : 
     775                 :             : /* Dump this to PP in a form suitable for use as an id in .dot output.  */
     776                 :             : 
     777                 :             : void
     778                 :          16 : saved_diagnostic::dump_dot_id (pretty_printer *pp) const
     779                 :             : {
     780                 :          16 :   pp_printf (pp, "sd_%i", m_idx);
     781                 :          16 : }
     782                 :             : 
     783                 :             : /* Dump this to PP in a form suitable for use as a node in .dot output.  */
     784                 :             : 
     785                 :             : void
     786                 :           8 : saved_diagnostic::dump_as_dot_node (pretty_printer *pp) const
     787                 :             : {
     788                 :           8 :   dump_dot_id (pp);
     789                 :           8 :   pp_printf (pp,
     790                 :             :              " [shape=none,margin=0,style=filled,fillcolor=\"red\",label=\"");
     791                 :           8 :   pp_write_text_to_stream (pp);
     792                 :             : 
     793                 :             :   /* Node label.  */
     794                 :           8 :   pp_printf (pp, "DIAGNOSTIC: %s (sd: %i)\n",
     795                 :           8 :              m_d->get_kind (), m_idx);
     796                 :           8 :   if (m_sm)
     797                 :             :     {
     798                 :           8 :       pp_printf (pp, "sm: %s", m_sm->get_name ());
     799                 :           8 :       if (m_state)
     800                 :             :         {
     801                 :           8 :           pp_printf (pp, "; state: ");
     802                 :           8 :           m_state->dump_to_pp (pp);
     803                 :             :         }
     804                 :           8 :       pp_newline (pp);
     805                 :             :     }
     806                 :           8 :   if (m_var)
     807                 :           8 :     pp_printf (pp, "var: %qE\n", m_var);
     808                 :           8 :   if (m_sval)
     809                 :             :     {
     810                 :           8 :       pp_string (pp, "sval: ");
     811                 :           8 :       m_sval->dump_to_pp (pp, true);
     812                 :           8 :       pp_newline (pp);
     813                 :             :     }
     814                 :           8 :   if (m_best_epath)
     815                 :           0 :     pp_printf (pp, "path length: %i\n", get_epath_length ());
     816                 :             : 
     817                 :           8 :   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
     818                 :           8 :   pp_string (pp, "\"];\n\n");
     819                 :             : 
     820                 :             :   /* Show links to duplicates.  */
     821                 :           8 :   for (auto iter : m_duplicates)
     822                 :             :     {
     823                 :           0 :       dump_dot_id (pp);
     824                 :           0 :       pp_string (pp, " -> ");
     825                 :           0 :       iter->dump_dot_id (pp);
     826                 :           0 :       pp_string (pp, " [style=\"dotted\" arrowhead=\"none\"];");
     827                 :           0 :       pp_newline (pp);
     828                 :             :     }
     829                 :           8 : }
     830                 :             : 
     831                 :             : /* Use PF to find the best exploded_path for this saved_diagnostic, if any,
     832                 :             :    and store it in m_best_epath.
     833                 :             :    Return true if a best path was found.  */
     834                 :             : 
     835                 :             : bool
     836                 :        6373 : saved_diagnostic::calc_best_epath (epath_finder *pf)
     837                 :             : {
     838                 :        6373 :   logger *logger = pf->get_logger ();
     839                 :        6373 :   LOG_SCOPE (logger);
     840                 :        6373 :   m_problem = nullptr;
     841                 :             : 
     842                 :        6373 :   m_best_epath = pf->get_best_epath (m_ploc.m_enode,
     843                 :        6373 :                                      *m_d, m_d->get_kind (), m_idx,
     844                 :        6373 :                                      &m_problem);
     845                 :             : 
     846                 :             :   /* Handle failure to find a feasible path.  */
     847                 :        6373 :   if (m_best_epath == nullptr)
     848                 :         279 :     return false;
     849                 :             : 
     850                 :             :   gcc_assert (m_best_epath);
     851                 :             : 
     852                 :             :   return true;
     853                 :        6373 : }
     854                 :             : 
     855                 :             : unsigned
     856                 :        6912 : saved_diagnostic::get_epath_length () const
     857                 :             : {
     858                 :        6912 :   gcc_assert (m_best_epath);
     859                 :        6912 :   return m_best_epath->length ();
     860                 :             : }
     861                 :             : 
     862                 :             : /* Record that OTHER (and its duplicates) are duplicates
     863                 :             :    of this saved_diagnostic.  */
     864                 :             : 
     865                 :             : void
     866                 :        2063 : saved_diagnostic::add_duplicate (saved_diagnostic *other)
     867                 :             : {
     868                 :        2063 :   gcc_assert (other);
     869                 :        2063 :   m_duplicates.reserve (m_duplicates.length ()
     870                 :        2168 :                         + other->m_duplicates.length ()
     871                 :             :                         + 1);
     872                 :        2063 :   m_duplicates.splice (other->m_duplicates);
     873                 :        2063 :   other->m_duplicates.truncate (0);
     874                 :        2063 :   m_duplicates.safe_push (other);
     875                 :        2063 : }
     876                 :             : 
     877                 :             : /* Walk up the sedges of each of the two paths.
     878                 :             :    If the two sequences of sedges do not perfectly correspond,
     879                 :             :    then paths are incompatible.
     880                 :             :    If there is at least one sedge that either cannot be paired up
     881                 :             :    or its counterpart is not equal, then the paths are incompatible
     882                 :             :    and this function returns FALSE.
     883                 :             :    Otherwise return TRUE.
     884                 :             : 
     885                 :             :    Incompatible paths:
     886                 :             : 
     887                 :             :        <cond Y>
     888                 :             :        /      \
     889                 :             :       /        \
     890                 :             :     true      false
     891                 :             :      |          |
     892                 :             :     ...        ...
     893                 :             :      |          |
     894                 :             :     ...       stmt x
     895                 :             :      |
     896                 :             :    stmt x
     897                 :             : 
     898                 :             :    Both LHS_PATH and RHS_PATH final enodes should be
     899                 :             :    over the same gimple statement.  */
     900                 :             : 
     901                 :             : static bool
     902                 :          70 : compatible_epath_p (const exploded_path *lhs_path,
     903                 :             :                     const exploded_path *rhs_path)
     904                 :             : {
     905                 :          70 :   gcc_assert (lhs_path);
     906                 :          70 :   gcc_assert (rhs_path);
     907                 :          70 :   gcc_assert (rhs_path->length () > 0);
     908                 :          70 :   gcc_assert (rhs_path->length () > 0);
     909                 :          70 :   int lhs_eedge_idx = lhs_path->length () - 1;
     910                 :          70 :   int rhs_eedge_idx = rhs_path->length () - 1;
     911                 :          70 :   const exploded_edge *lhs_eedge;
     912                 :          70 :   const exploded_edge *rhs_eedge;
     913                 :             : 
     914                 :        1061 :   while (lhs_eedge_idx >= 0 && rhs_eedge_idx >= 0)
     915                 :             :     {
     916                 :        1130 :       while (lhs_eedge_idx >= 0)
     917                 :             :         {
     918                 :             :           /* Find LHS_PATH's next superedge.  */
     919                 :        1092 :           lhs_eedge = lhs_path->m_edges[lhs_eedge_idx];
     920                 :        1092 :           if (lhs_eedge->m_sedge)
     921                 :             :             break;
     922                 :             :           else
     923                 :          69 :             lhs_eedge_idx--;
     924                 :             :         }
     925                 :        1130 :       while (rhs_eedge_idx >= 0)
     926                 :             :         {
     927                 :             :           /* Find RHS_PATH's next superedge.  */
     928                 :        1092 :           rhs_eedge = rhs_path->m_edges[rhs_eedge_idx];
     929                 :        1092 :           if (rhs_eedge->m_sedge)
     930                 :             :             break;
     931                 :             :           else
     932                 :          69 :             rhs_eedge_idx--;
     933                 :             :         }
     934                 :             : 
     935                 :        1061 :       if (lhs_eedge->m_sedge && rhs_eedge->m_sedge)
     936                 :             :         {
     937                 :        1023 :           if (lhs_eedge->m_sedge != rhs_eedge->m_sedge)
     938                 :             :             /* Both superedges do not match.
     939                 :             :                Superedges are not dependent on the exploded path, so even
     940                 :             :                different epaths will have similar sedges if they follow
     941                 :             :                the same outcome of a conditional node.  */
     942                 :             :             return false;
     943                 :             : 
     944                 :         991 :           lhs_eedge_idx--;
     945                 :         991 :           rhs_eedge_idx--;
     946                 :         991 :           continue;
     947                 :             :         }
     948                 :          38 :       else if (lhs_eedge->m_sedge == nullptr && rhs_eedge->m_sedge == nullptr)
     949                 :             :         /* Both paths were drained up entirely.
     950                 :             :            No discriminant was found.  */
     951                 :             :         return true;
     952                 :             : 
     953                 :             :       /* A superedge was found for only one of the two paths.  */
     954                 :             :       return false;
     955                 :             :     }
     956                 :             : 
     957                 :             :   /* A superedge was found for only one of the two paths.  */
     958                 :           0 :   if (lhs_eedge_idx >= 0 || rhs_eedge_idx >= 0)
     959                 :             :     return false;
     960                 :             : 
     961                 :             :   /* Both paths were drained up entirely.
     962                 :             :      No discriminant was found.  */
     963                 :             :   return true;
     964                 :             : }
     965                 :             : 
     966                 :             : 
     967                 :             : /* Return true if this diagnostic supercedes OTHER, and that OTHER should
     968                 :             :    therefore not be emitted.  */
     969                 :             : 
     970                 :             : bool
     971                 :       27286 : saved_diagnostic::supercedes_p (const saved_diagnostic &other) const
     972                 :             : {
     973                 :       27286 :   if (get_supernode () != other.get_supernode ())
     974                 :             :     return false;
     975                 :             : 
     976                 :             :   /* return early if OTHER won't be superseded anyway.  */
     977                 :        5911 :   if (!m_d->supercedes_p (*other.m_d))
     978                 :             :     return false;
     979                 :             : 
     980                 :             :   /* If the two saved_diagnostics' path are not compatible
     981                 :             :      then they cannot supersede one another.  */
     982                 :          70 :   return compatible_epath_p (m_best_epath.get (), other.m_best_epath.get ());
     983                 :             : }
     984                 :             : 
     985                 :             : /* Move any saved checker_events from this saved_diagnostic to
     986                 :             :    the end of DST_PATH.  */
     987                 :             : 
     988                 :             : void
     989                 :        3993 : saved_diagnostic::add_any_saved_events (checker_path &dst_path)
     990                 :             : {
     991                 :        4431 :   for (auto &event : m_saved_events)
     992                 :             :     {
     993                 :         146 :       dst_path.add_event (std::unique_ptr<checker_event> (event));
     994                 :         146 :       event = nullptr;
     995                 :             :     }
     996                 :        3993 : }
     997                 :             : 
     998                 :             : /* Emit any pending notes owned by this diagnostic.  */
     999                 :             : 
    1000                 :             : void
    1001                 :        3925 : saved_diagnostic::emit_any_notes () const
    1002                 :             : {
    1003                 :        4440 :   for (auto pn : m_notes)
    1004                 :         177 :     pn->emit ();
    1005                 :        3925 : }
    1006                 :             : 
    1007                 :             : /* For SARIF output, add additional properties to the "result" object
    1008                 :             :    for this diagnostic.
    1009                 :             :    This extra data is intended for use when debugging the analyzer.  */
    1010                 :             : 
    1011                 :             : void
    1012                 :          36 : saved_diagnostic::
    1013                 :             : maybe_add_sarif_properties (diagnostics::sarif_object &result_obj) const
    1014                 :             : {
    1015                 :          36 :   auto &props = result_obj.get_or_create_properties ();
    1016                 :             : #define PROPERTY_PREFIX "gcc/analyzer/saved_diagnostic/"
    1017                 :          36 :   if (m_sm)
    1018                 :          16 :     props.set_string (PROPERTY_PREFIX "sm", m_sm->get_name ());
    1019                 :          36 :   props.set (PROPERTY_PREFIX "ploc", m_ploc.to_json ());
    1020                 :          36 :   if (m_var)
    1021                 :          16 :     props.set (PROPERTY_PREFIX "var", tree_to_json (m_var));
    1022                 :          36 :   if (m_sval)
    1023                 :          16 :     props.set (PROPERTY_PREFIX "sval", m_sval->to_json ());
    1024                 :          36 :   if (m_state)
    1025                 :          16 :     props.set (PROPERTY_PREFIX "state", m_state->to_json ());
    1026                 :             :   // TODO: m_best_epath
    1027                 :          36 :   props.set_integer (PROPERTY_PREFIX "idx", m_idx);
    1028                 :          36 :   if (m_duplicates.length () > 0)
    1029                 :             :     {
    1030                 :           4 :       auto duplicates_arr = std::make_unique<json::array> ();
    1031                 :          16 :       for (auto iter : m_duplicates)
    1032                 :             :         {
    1033                 :           4 :           auto sd_obj = std::make_unique<diagnostics::sarif_object> ();
    1034                 :           4 :           iter->maybe_add_sarif_properties (*sd_obj);
    1035                 :           4 :           duplicates_arr->append (std::move (sd_obj));
    1036                 :           4 :         }
    1037                 :           4 :       props.set<json::array> (PROPERTY_PREFIX "duplicates",
    1038                 :             :                               std::move (duplicates_arr));
    1039                 :           4 :     }
    1040                 :             : #undef PROPERTY_PREFIX
    1041                 :             : 
    1042                 :             : #define PROPERTY_PREFIX "gcc/analyzer/pending_diagnostic/"
    1043                 :          36 :   props.set_string (PROPERTY_PREFIX "kind", m_d->get_kind ());
    1044                 :             : #undef PROPERTY_PREFIX
    1045                 :             : 
    1046                 :             :   /* Potentially add pending_diagnostic-specific properties.  */
    1047                 :          36 :   m_d->maybe_add_sarif_properties (result_obj);
    1048                 :          36 : }
    1049                 :             : 
    1050                 :             : /* State for building a checker_path from a particular exploded_path.
    1051                 :             :    In particular, this precomputes reachability information: the set of
    1052                 :             :    source enodes for which a path be found to the diagnostic enode.  */
    1053                 :             : 
    1054                 :        3993 : class path_builder
    1055                 :             : {
    1056                 :             : public:
    1057                 :        3993 :   path_builder (const exploded_graph &eg,
    1058                 :             :                 const exploded_path &epath,
    1059                 :             :                 const feasibility_problem *problem,
    1060                 :             :                 const saved_diagnostic &sd)
    1061                 :        3993 :   : m_eg (eg),
    1062                 :        3993 :     m_diag_enode (epath.get_final_enode ()),
    1063                 :        3993 :     m_sd (sd),
    1064                 :        3993 :     m_reachability (eg, m_diag_enode),
    1065                 :        3993 :     m_feasibility_problem (problem)
    1066                 :        3993 :   {}
    1067                 :             : 
    1068                 :           0 :   const exploded_node *get_diag_node () const { return m_diag_enode; }
    1069                 :             : 
    1070                 :       52547 :   pending_diagnostic *get_pending_diagnostic () const
    1071                 :             :   {
    1072                 :         207 :     return m_sd.m_d.get ();
    1073                 :             :   }
    1074                 :             : 
    1075                 :       30524 :   bool reachable_from_p (const exploded_node *src_enode) const
    1076                 :             :   {
    1077                 :       61048 :     return m_reachability.reachable_from_p (src_enode);
    1078                 :             :   }
    1079                 :             : 
    1080                 :       42185 :   const extrinsic_state &get_ext_state () const { return m_eg.get_ext_state (); }
    1081                 :             : 
    1082                 :       40405 :   const feasibility_problem *get_feasibility_problem () const
    1083                 :             :   {
    1084                 :       40405 :     return m_feasibility_problem;
    1085                 :             :   }
    1086                 :             : 
    1087                 :        4768 :   const state_machine *get_sm () const { return m_sd.m_sm; }
    1088                 :             : 
    1089                 :             : private:
    1090                 :             :   typedef reachability<eg_traits> enode_reachability;
    1091                 :             : 
    1092                 :             :   const exploded_graph &m_eg;
    1093                 :             : 
    1094                 :             :   /* The enode where the diagnostic occurs.  */
    1095                 :             :   const exploded_node *m_diag_enode;
    1096                 :             : 
    1097                 :             :   const saved_diagnostic &m_sd;
    1098                 :             : 
    1099                 :             :   /* Precompute all enodes from which the diagnostic is reachable.  */
    1100                 :             :   enode_reachability m_reachability;
    1101                 :             : 
    1102                 :             :   const feasibility_problem *m_feasibility_problem;
    1103                 :             : };
    1104                 :             : 
    1105                 :             : /* class diagnostic_manager.  */
    1106                 :             : 
    1107                 :             : /* diagnostic_manager's ctor.  */
    1108                 :             : 
    1109                 :        3318 : diagnostic_manager::diagnostic_manager (logger *logger, engine *eng,
    1110                 :        3318 :                                         int verbosity)
    1111                 :        3318 : : log_user (logger), m_eng (eng), m_verbosity (verbosity),
    1112                 :        3318 :   m_num_disabled_diagnostics (0)
    1113                 :             : {
    1114                 :        3318 : }
    1115                 :             : 
    1116                 :             : /* Queue pending_diagnostic D at ENODE for later emission.
    1117                 :             :    Return true/false signifying if the diagnostic was actually added.  */
    1118                 :             : 
    1119                 :             : bool
    1120                 :       10476 : diagnostic_manager::add_diagnostic (const state_machine *sm,
    1121                 :             :                                     pending_location &&ploc,
    1122                 :             :                                     tree var,
    1123                 :             :                                     const svalue *sval,
    1124                 :             :                                     state_machine::state_t state,
    1125                 :             :                                     std::unique_ptr<pending_diagnostic> d)
    1126                 :             : {
    1127                 :       10476 :   LOG_FUNC (get_logger ());
    1128                 :             : 
    1129                 :             :   /* We must have an enode in order to be able to look for paths
    1130                 :             :      through the exploded_graph to the diagnostic.  */
    1131                 :       10476 :   gcc_assert (ploc.m_enode);
    1132                 :             : 
    1133                 :             :   /* If this warning is ultimately going to be rejected by a -Wno-analyzer-*
    1134                 :             :      flag, reject it now.  */
    1135                 :       10476 :   {
    1136                 :       10476 :     location_t loc = ploc.m_event_loc_info.m_loc;
    1137                 :       10476 :     loc = d->fixup_location (loc, true);
    1138                 :       10476 :     int option = d->get_controlling_option ();
    1139                 :       10476 :     if (!warning_enabled_at (loc, option))
    1140                 :             :       {
    1141                 :        4103 :         if (get_logger ())
    1142                 :           0 :           get_logger ()->log ("rejecting disabled warning %qs",
    1143                 :           0 :                               d->get_kind ());
    1144                 :        4103 :         m_num_disabled_diagnostics++;
    1145                 :        4103 :         return false;
    1146                 :             :       }
    1147                 :             :   }
    1148                 :             : 
    1149                 :        6373 :   saved_diagnostic *sd
    1150                 :             :     = new saved_diagnostic (sm,
    1151                 :             :                             std::move (ploc),
    1152                 :             :                             var,
    1153                 :             :                             sval,
    1154                 :             :                             state,
    1155                 :             :                             std::move (d),
    1156                 :       11206 :                             m_saved_diagnostics.length ());
    1157                 :        6373 :   m_saved_diagnostics.safe_push (sd);
    1158                 :        6373 :   sd->m_ploc.m_enode->add_diagnostic (sd);
    1159                 :        6373 :   if (get_logger ())
    1160                 :           0 :     log ("adding saved diagnostic %i at SN %i to EN %i: %qs",
    1161                 :             :          sd->get_index (),
    1162                 :           0 :          sd->get_supernode ()->m_id,
    1163                 :           0 :          sd->m_ploc.m_enode->m_index,
    1164                 :           0 :          sd->m_d->get_kind ());
    1165                 :             :   return true;
    1166                 :       10476 : }
    1167                 :             : 
    1168                 :             : /* Queue pending_diagnostic D at ENODE for later emission.
    1169                 :             :    Return true/false signifying if the diagnostic was actually added.
    1170                 :             :    Take ownership of D (or delete it).  */
    1171                 :             : 
    1172                 :             : bool
    1173                 :        3572 : diagnostic_manager::add_diagnostic (pending_location &&ploc,
    1174                 :             :                                     std::unique_ptr<pending_diagnostic> d)
    1175                 :             : {
    1176                 :        3572 :   gcc_assert (ploc.m_enode);
    1177                 :        3572 :   return add_diagnostic (nullptr, std::move (ploc),
    1178                 :        3572 :                          NULL_TREE, nullptr, 0, std::move (d));
    1179                 :             : }
    1180                 :             : 
    1181                 :             : /* Add PN to the most recent saved_diagnostic.  */
    1182                 :             : 
    1183                 :             : void
    1184                 :         193 : diagnostic_manager::add_note (std::unique_ptr<pending_note> pn)
    1185                 :             : {
    1186                 :         193 :   LOG_FUNC (get_logger ());
    1187                 :         193 :   gcc_assert (pn);
    1188                 :             : 
    1189                 :             :   /* Get most recent saved_diagnostic.  */
    1190                 :         193 :   gcc_assert (m_saved_diagnostics.length () > 0);
    1191                 :         193 :   saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1];
    1192                 :         193 :   sd->add_note (std::move (pn));
    1193                 :         193 : }
    1194                 :             : 
    1195                 :             : /* Add EVENT to the most recent saved_diagnostic.  */
    1196                 :             : 
    1197                 :             : void
    1198                 :         158 : diagnostic_manager::add_event (std::unique_ptr<checker_event> event)
    1199                 :             : {
    1200                 :         158 :   LOG_FUNC (get_logger ());
    1201                 :         158 :   gcc_assert (event);
    1202                 :             : 
    1203                 :             :   /* Get most recent saved_diagnostic.  */
    1204                 :         158 :   gcc_assert (m_saved_diagnostics.length () > 0);
    1205                 :         158 :   saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1];
    1206                 :         158 :   sd->add_event (std::move (event));
    1207                 :         158 : }
    1208                 :             : 
    1209                 :             : /* Return a new json::object of the form
    1210                 :             :    {"diagnostics"  : [obj for saved_diagnostic]}.  */
    1211                 :             : 
    1212                 :             : std::unique_ptr<json::object>
    1213                 :           0 : diagnostic_manager::to_json () const
    1214                 :             : {
    1215                 :           0 :   auto dm_obj = std::make_unique<json::object> ();
    1216                 :             : 
    1217                 :           0 :   {
    1218                 :           0 :     auto sd_arr = std::make_unique<json::array> ();
    1219                 :           0 :     int i;
    1220                 :           0 :     saved_diagnostic *sd;
    1221                 :           0 :     FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
    1222                 :           0 :       sd_arr->append (sd->to_json ());
    1223                 :           0 :     dm_obj->set ("diagnostics", std::move (sd_arr));
    1224                 :           0 :   }
    1225                 :             : 
    1226                 :           0 :   return dm_obj;
    1227                 :             : }
    1228                 :             : 
    1229                 :             : /* A class for identifying sets of duplicated pending_diagnostic.
    1230                 :             : 
    1231                 :             :    We want to find the simplest saved_diagnostic amongst those that share a
    1232                 :             :    dedupe_key.  */
    1233                 :             : 
    1234                 :             : class dedupe_key
    1235                 :             : {
    1236                 :             : public:
    1237                 :        6094 :   dedupe_key (const saved_diagnostic &sd)
    1238                 :        6094 :   : m_sd (sd),
    1239                 :        6094 :     m_loc (sd.m_ploc.m_event_loc_info.m_loc)
    1240                 :             :   {
    1241                 :             :   }
    1242                 :             : 
    1243                 :       60996 :   hashval_t hash () const
    1244                 :             :   {
    1245                 :       60996 :     inchash::hash hstate;
    1246                 :             :     // TODO: m_sd
    1247                 :       60996 :     return hstate.end ();
    1248                 :             :   }
    1249                 :       46754 :   bool operator== (const dedupe_key &other) const
    1250                 :             :   {
    1251                 :       46754 :     return (m_sd == other.m_sd
    1252                 :       46754 :             && m_loc == other.m_loc);
    1253                 :             :   }
    1254                 :             : 
    1255                 :       28813 :   location_t get_location () const { return m_loc; }
    1256                 :             : 
    1257                 :             :   /* A qsort comparator for use by dedupe_winners::emit_best
    1258                 :             :      to sort them into location_t order.  */
    1259                 :             : 
    1260                 :             :   static int
    1261                 :       28813 :   comparator (const void *p1, const void *p2)
    1262                 :             :   {
    1263                 :       28813 :     const dedupe_key *pk1 = *(const dedupe_key * const *)p1;
    1264                 :       28813 :     const dedupe_key *pk2 = *(const dedupe_key * const *)p2;
    1265                 :             : 
    1266                 :       28813 :     location_t loc1 = pk1->get_location ();
    1267                 :       28813 :     location_t loc2 = pk2->get_location ();
    1268                 :             : 
    1269                 :       28813 :     if (int cmp = linemap_compare_locations (line_table, loc2, loc1))
    1270                 :             :       return cmp;
    1271                 :        1391 :     if (int cmp = ((int)pk1->m_sd.get_epath_length ()
    1272                 :        1391 :                    - (int)pk2->m_sd.get_epath_length ()))
    1273                 :             :       return cmp;
    1274                 :         755 :     if (int cmp = strcmp (pk1->m_sd.m_d->get_kind (),
    1275                 :         755 :                           pk2->m_sd.m_d->get_kind ()))
    1276                 :             :       return cmp;
    1277                 :             :     return 0;
    1278                 :             :   }
    1279                 :             : 
    1280                 :             :   const saved_diagnostic &m_sd;
    1281                 :             :   location_t m_loc;
    1282                 :             : };
    1283                 :             : 
    1284                 :             : /* Traits for use by dedupe_winners.  */
    1285                 :             : 
    1286                 :             : class dedupe_hash_map_traits
    1287                 :             : {
    1288                 :             : public:
    1289                 :             :   typedef const dedupe_key *key_type;
    1290                 :             :   typedef saved_diagnostic *value_type;
    1291                 :             :   typedef saved_diagnostic *compare_type;
    1292                 :             : 
    1293                 :       60996 :   static inline hashval_t hash (const key_type &v)
    1294                 :             :   {
    1295                 :       60996 :     return v->hash ();
    1296                 :             :   }
    1297                 :       46754 :   static inline bool equal_keys (const key_type &k1, const key_type &k2)
    1298                 :             :   {
    1299                 :       46754 :     return *k1 == *k2;
    1300                 :             :   }
    1301                 :             :   template <typename T>
    1302                 :             :   static inline void remove (T &)
    1303                 :             :   {
    1304                 :             :     // TODO
    1305                 :             :   }
    1306                 :             :   template <typename T>
    1307                 :          38 :   static inline void mark_deleted (T &entry)
    1308                 :             :   {
    1309                 :          38 :     entry.m_key = reinterpret_cast<key_type> (1);
    1310                 :             :   }
    1311                 :             :   template <typename T>
    1312                 :           0 :   static inline void mark_empty (T &entry)
    1313                 :             :   {
    1314                 :           0 :     entry.m_key = nullptr;
    1315                 :             :   }
    1316                 :             :   template <typename T>
    1317                 :      139809 :   static inline bool is_deleted (const T &entry)
    1318                 :             :   {
    1319                 :      139809 :     return entry.m_key == reinterpret_cast<key_type> (1);
    1320                 :             :   }
    1321                 :             :   template <typename T>
    1322                 :      512889 :   static inline bool is_empty (const T &entry)
    1323                 :             :   {
    1324                 :      512889 :     return entry.m_key == nullptr;
    1325                 :             :   }
    1326                 :             :   static const bool empty_zero_p = true;
    1327                 :             : };
    1328                 :             : 
    1329                 :             : /* A class for deduplicating diagnostics and finding (and emitting) the
    1330                 :             :    best saved_diagnostic within each partition.  */
    1331                 :             : 
    1332                 :             : class dedupe_winners
    1333                 :             : {
    1334                 :             : public:
    1335                 :        1540 :   ~dedupe_winners ()
    1336                 :             :   {
    1337                 :             :     /* Delete all keys, but not the saved_diagnostics.  */
    1338                 :        5533 :     for (map_t::iterator iter = m_map.begin ();
    1339                 :        5533 :          iter != m_map.end ();
    1340                 :        3993 :          ++iter)
    1341                 :        3993 :       delete (*iter).first;
    1342                 :        1540 :   }
    1343                 :             : 
    1344                 :             :   /* Determine an exploded_path for SD using PF and, if it's feasible,
    1345                 :             :      determine if SD is the best seen so far for its dedupe_key.
    1346                 :             :      Record the winning SD for each dedupe_key.  */
    1347                 :             : 
    1348                 :        6373 :   void add (logger *logger,
    1349                 :             :             epath_finder *pf,
    1350                 :             :             saved_diagnostic *sd)
    1351                 :             :   {
    1352                 :             :     /* Determine best epath for SD.  */
    1353                 :        6373 :     if (!sd->calc_best_epath (pf))
    1354                 :         279 :       return;
    1355                 :             : 
    1356                 :        6094 :     const exploded_path *epath = sd->get_best_epath ();
    1357                 :        6094 :     gcc_assert (epath);
    1358                 :             : 
    1359                 :             :     /* Now we have an exploded path, use it for pending_locations that are
    1360                 :             :        affected by such things, and for deduplication.  */
    1361                 :        6094 :     if (sd->m_ploc.m_fixer_for_epath)
    1362                 :        1144 :       sd->m_ploc.m_fixer_for_epath->fixup_for_epath (*epath, sd->m_ploc);
    1363                 :             : 
    1364                 :        6094 :     dedupe_key *key = new dedupe_key (*sd);
    1365                 :        6094 :     if (saved_diagnostic **slot = m_map.get (key))
    1366                 :             :       {
    1367                 :        2063 :         if (logger)
    1368                 :           0 :           logger->log ("already have this dedupe_key");
    1369                 :             : 
    1370                 :        2063 :         saved_diagnostic *cur_best_sd = *slot;
    1371                 :             : 
    1372                 :        2063 :         if (sd->get_epath_length () < cur_best_sd->get_epath_length ())
    1373                 :             :           {
    1374                 :             :             /* We've got a shorter path for the key; replace
    1375                 :             :                the current candidate, marking it as a duplicate of SD.  */
    1376                 :         146 :             if (logger)
    1377                 :           0 :               logger->log ("length %i is better than existing length %i;"
    1378                 :             :                            " taking over this dedupe_key",
    1379                 :             :                            sd->get_epath_length (),
    1380                 :             :                            cur_best_sd->get_epath_length ());
    1381                 :         146 :             sd->add_duplicate (cur_best_sd);
    1382                 :         146 :             *slot = sd;
    1383                 :             :           }
    1384                 :             :         else
    1385                 :             :           /* We haven't beaten the current best candidate; add SD
    1386                 :             :              as a duplicate of it.  */
    1387                 :             :           {
    1388                 :        1917 :             if (logger)
    1389                 :           0 :               logger->log ("length %i isn't better than existing length %i;"
    1390                 :             :                            " dropping this candidate",
    1391                 :             :                            sd->get_epath_length (),
    1392                 :             :                            cur_best_sd->get_epath_length ());
    1393                 :        1917 :             cur_best_sd->add_duplicate (sd);
    1394                 :             :           }
    1395                 :        2063 :         delete key;
    1396                 :             :       }
    1397                 :             :     else
    1398                 :             :       {
    1399                 :             :         /* This is the first candidate for this key.  */
    1400                 :        4031 :         m_map.put (key, sd);
    1401                 :        4031 :         if (logger)
    1402                 :           0 :           logger->log ("first candidate for this dedupe_key");
    1403                 :             :       }
    1404                 :             :   }
    1405                 :             : 
    1406                 :             :   /* Handle interactions between the dedupe winners, so that some
    1407                 :             :      diagnostics can supercede others (of different kinds).
    1408                 :             : 
    1409                 :             :      We want use-after-free to supercede use-of-unitialized-value,
    1410                 :             :      so that if we have these at the same stmt, we don't emit
    1411                 :             :      a use-of-uninitialized, just the use-after-free.  */
    1412                 :             : 
    1413                 :        1540 :   void handle_interactions (diagnostic_manager *dm)
    1414                 :             :   {
    1415                 :        1540 :     LOG_SCOPE (dm->get_logger ());
    1416                 :        1540 :     auto_vec<const dedupe_key *> superceded;
    1417                 :        5571 :     for (auto outer : m_map)
    1418                 :             :       {
    1419                 :        4031 :         const saved_diagnostic *outer_sd = outer.second;
    1420                 :       62558 :         for (auto inner : m_map)
    1421                 :             :           {
    1422                 :       27286 :             const saved_diagnostic *inner_sd = inner.second;
    1423                 :       27286 :             if (inner_sd->supercedes_p (*outer_sd))
    1424                 :             :               {
    1425                 :          38 :                 superceded.safe_push (outer.first);
    1426                 :          38 :                 if (dm->get_logger ())
    1427                 :           0 :                   dm->log ("sd[%i] \"%s\" superceded by sd[%i] \"%s\"",
    1428                 :           0 :                            outer_sd->get_index (), outer_sd->m_d->get_kind (),
    1429                 :           0 :                            inner_sd->get_index (), inner_sd->m_d->get_kind ());
    1430                 :             :                 break;
    1431                 :             :               }
    1432                 :             :           }
    1433                 :             :       }
    1434                 :        1654 :     for (auto iter : superceded)
    1435                 :          38 :       m_map.remove (iter);
    1436                 :        1540 :   }
    1437                 :             : 
    1438                 :             :  /* Emit the simplest diagnostic within each set.  */
    1439                 :             : 
    1440                 :        1540 :   void emit_best (diagnostic_manager *dm,
    1441                 :             :                   const exploded_graph &eg)
    1442                 :             :   {
    1443                 :        1540 :     LOG_SCOPE (dm->get_logger ());
    1444                 :             : 
    1445                 :             :     /* Get keys into a vec for sorting.  */
    1446                 :        1540 :     auto_vec<const dedupe_key *> keys (m_map.elements ());
    1447                 :        1540 :     for (map_t::iterator iter = m_map.begin ();
    1448                 :        5533 :          iter != m_map.end ();
    1449                 :        3993 :          ++iter)
    1450                 :        3993 :       keys.quick_push ((*iter).first);
    1451                 :             : 
    1452                 :        3035 :     dm->log ("# keys after de-duplication: %i", keys.length ());
    1453                 :             : 
    1454                 :             :     /* Sort into a good emission order.  */
    1455                 :        1540 :     keys.qsort (dedupe_key::comparator);
    1456                 :             : 
    1457                 :             :     /* Emit the best saved_diagnostics for each key.  */
    1458                 :             :     int i;
    1459                 :             :     const dedupe_key *key;
    1460                 :        7028 :     FOR_EACH_VEC_ELT (keys, i, key)
    1461                 :             :       {
    1462                 :        3993 :         saved_diagnostic **slot = m_map.get (key);
    1463                 :        3993 :         gcc_assert (*slot);
    1464                 :        3993 :         saved_diagnostic *sd = *slot;
    1465                 :        3993 :         dm->emit_saved_diagnostic (eg, *sd);
    1466                 :             :       }
    1467                 :        1540 :   }
    1468                 :             : 
    1469                 :             : private:
    1470                 :             :   /* This maps from each dedupe_key to a current best saved_diagnostic.  */
    1471                 :             : 
    1472                 :             :   typedef hash_map<const dedupe_key *, saved_diagnostic *,
    1473                 :             :                    dedupe_hash_map_traits> map_t;
    1474                 :             :   map_t m_map;
    1475                 :             : };
    1476                 :             : 
    1477                 :             : /* Emit all saved diagnostics.  */
    1478                 :             : 
    1479                 :             : void
    1480                 :        3318 : diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
    1481                 :             : {
    1482                 :        3318 :   LOG_SCOPE (get_logger ());
    1483                 :        3318 :   auto_timevar tv (TV_ANALYZER_DIAGNOSTICS);
    1484                 :        4858 :   log ("# saved diagnostics: %i", m_saved_diagnostics.length ());
    1485                 :        3318 :   log ("# disabled diagnostics: %i", m_num_disabled_diagnostics);
    1486                 :        3318 :   if (get_logger ())
    1487                 :             :     {
    1488                 :             :       unsigned i;
    1489                 :             :       saved_diagnostic *sd;
    1490                 :           2 :       FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
    1491                 :           0 :         log ("[%i] sd: %qs at EN: %i, SN: %i",
    1492                 :           0 :              i, sd->m_d->get_kind (), sd->m_ploc.m_enode->m_index,
    1493                 :           0 :              sd->get_supernode ()->m_id);
    1494                 :             :     }
    1495                 :             : 
    1496                 :        3318 :   if (m_saved_diagnostics.length () == 0)
    1497                 :        1778 :     return;
    1498                 :             : 
    1499                 :             :   /* Compute the shortest_paths once, sharing it between all diagnostics.  */
    1500                 :        1540 :   epath_finder pf (eg);
    1501                 :             : 
    1502                 :             :   /* Iterate through all saved diagnostics, adding them to a dedupe_winners
    1503                 :             :      instance.  This partitions the saved diagnostics by dedupe_key,
    1504                 :             :      generating exploded_paths for them, and retaining the best one in each
    1505                 :             :      partition.  */
    1506                 :        1540 :   dedupe_winners best_candidates;
    1507                 :             : 
    1508                 :        1540 :   int i;
    1509                 :        1540 :   saved_diagnostic *sd;
    1510                 :        9453 :   FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
    1511                 :        6373 :     best_candidates.add (get_logger (), &pf, sd);
    1512                 :             : 
    1513                 :        1540 :   best_candidates.handle_interactions (this);
    1514                 :             : 
    1515                 :             :   /* For each dedupe-key, call emit_saved_diagnostic on the "best"
    1516                 :             :      saved_diagnostic.  */
    1517                 :        1540 :   best_candidates.emit_best (this, eg);
    1518                 :        3318 : }
    1519                 :             : 
    1520                 :             : /* Custom subclass of diagnostics::metadata which, for SARIF output,
    1521                 :             :    populates the property bag of the diagnostic's "result" object
    1522                 :             :    with information from the saved_diagnostic and the
    1523                 :             :    pending_diagnostic.  */
    1524                 :             : 
    1525                 :        3993 : class pending_diagnostic_metadata : public diagnostics::metadata
    1526                 :             : {
    1527                 :             : public:
    1528                 :        3993 :   pending_diagnostic_metadata (const saved_diagnostic &sd)
    1529                 :        3993 :   : m_sd (sd)
    1530                 :             :   {
    1531                 :             :   }
    1532                 :             : 
    1533                 :             :   void
    1534                 :          32 :   maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
    1535                 :             :     const override
    1536                 :             :   {
    1537                 :          32 :     m_sd.maybe_add_sarif_properties (result_obj);
    1538                 :          32 :   }
    1539                 :             : 
    1540                 :             : private:
    1541                 :             :   const saved_diagnostic &m_sd;
    1542                 :             : };
    1543                 :             : 
    1544                 :             : /* Given a saved_diagnostic SD with m_best_epath through EG,
    1545                 :             :    create an checker_path of suitable events and use it to call
    1546                 :             :    SD's underlying pending_diagnostic "emit" vfunc to emit a diagnostic.  */
    1547                 :             : 
    1548                 :             : void
    1549                 :        3993 : diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
    1550                 :             :                                            saved_diagnostic &sd)
    1551                 :             : {
    1552                 :        3993 :   LOG_SCOPE (get_logger ());
    1553                 :        3993 :   log ("sd[%i]: %qs at SN: %i",
    1554                 :        3993 :        sd.get_index (), sd.m_d->get_kind (), sd.get_supernode ()->m_id);
    1555                 :        5377 :   log ("num dupes: %i", sd.get_num_dupes ());
    1556                 :             : 
    1557                 :        3993 :   const exploded_path *epath = sd.get_best_epath ();
    1558                 :        3993 :   gcc_assert (epath);
    1559                 :             : 
    1560                 :             :   /* Precompute all enodes from which the diagnostic is reachable.  */
    1561                 :        3993 :   path_builder pb (eg, *epath, sd.get_feasibility_problem (), sd);
    1562                 :             : 
    1563                 :             :   /* This is the diagnostics::paths::path subclass that will be built for
    1564                 :             :      the diagnostic.  */
    1565                 :        3993 :   checker_path emission_path (get_logical_location_manager (),
    1566                 :             :                               eg.get_ext_state (),
    1567                 :        3993 :                               get_logger ());
    1568                 :             : 
    1569                 :             :   /* Populate emission_path with a full description of EPATH.  */
    1570                 :        3993 :   build_emission_path (pb, *epath, &emission_path);
    1571                 :             : 
    1572                 :             :   /* Now prune it to just cover the most pertinent events.  */
    1573                 :        3993 :   prune_path (&emission_path, sd.m_sm, sd.m_sval, sd.m_state);
    1574                 :             : 
    1575                 :             :   /* Add any saved events to the path, giving contextual information
    1576                 :             :      about what the analyzer was simulating as the diagnostic was
    1577                 :             :      generated.  These don't get pruned, as they are probably pertinent.  */
    1578                 :        3993 :   sd.add_any_saved_events (emission_path);
    1579                 :             : 
    1580                 :             :   /* Add a final event to the path, covering the diagnostic itself.  */
    1581                 :        3993 :   {
    1582                 :        3993 :     const exploded_node *const enode = epath->get_final_enode ();
    1583                 :        3993 :     sd.m_d->add_final_event (sd.m_sm, enode, sd.m_ploc.m_event_loc_info,
    1584                 :             :                              sd.m_var, sd.m_state, &emission_path);
    1585                 :             :   }
    1586                 :             : 
    1587                 :             :   /* The "final" event might not be final; if the saved_diagnostic has a
    1588                 :             :      trailing eedge stashed, add any events for it.  This is for use
    1589                 :             :      in handling longjmp, to show where a longjmp is rewinding to.  */
    1590                 :        3993 :   if (sd.m_trailing_eedge)
    1591                 :           4 :     add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path, nullptr);
    1592                 :             : 
    1593                 :        3993 :   emission_path.inject_any_inlined_call_events (get_logger ());
    1594                 :             : 
    1595                 :        3993 :   emission_path.prepare_for_emission (sd.m_d.get ());
    1596                 :             : 
    1597                 :        3993 :   location_t loc = sd.m_ploc.m_event_loc_info.m_loc;
    1598                 :        3993 :   loc = sd.m_d->fixup_location (loc, true);
    1599                 :             : 
    1600                 :             :   /* Allow the pending_diagnostic to fix up the locations of events.  */
    1601                 :        3993 :   emission_path.fixup_locations (sd.m_d.get ());
    1602                 :             : 
    1603                 :        3993 :   gcc_rich_location rich_loc (loc);
    1604                 :        3993 :   rich_loc.set_path (&emission_path);
    1605                 :             : 
    1606                 :        3993 :   auto_diagnostic_group d;
    1607                 :        3993 :   auto_cfun sentinel (sd.get_supernode ()->m_fun);
    1608                 :        3993 :   pending_diagnostic_metadata m (sd);
    1609                 :        3993 :   diagnostic_emission_context diag_ctxt (sd, rich_loc, m, get_logger ());
    1610                 :        3993 :   if (sd.m_d->emit (diag_ctxt))
    1611                 :             :     {
    1612                 :        3925 :       sd.emit_any_notes ();
    1613                 :             : 
    1614                 :        3925 :       unsigned num_dupes = sd.get_num_dupes ();
    1615                 :        3925 :       if (flag_analyzer_show_duplicate_count && num_dupes > 0)
    1616                 :           4 :         inform_n (loc, num_dupes,
    1617                 :             :                   "%i duplicate", "%i duplicates",
    1618                 :             :                   num_dupes);
    1619                 :        3925 :       if (flag_dump_analyzer_exploded_paths)
    1620                 :             :         {
    1621                 :           0 :           auto_timevar tv (TV_ANALYZER_DUMP);
    1622                 :           0 :           pretty_printer pp;
    1623                 :           0 :           pp_printf (&pp, "%s.%i.%s.epath.txt",
    1624                 :           0 :                      dump_base_name, sd.get_index (), sd.m_d->get_kind ());
    1625                 :           0 :           char *filename = xstrdup (pp_formatted_text (&pp));
    1626                 :           0 :           epath->dump_to_file (filename, eg.get_ext_state ());
    1627                 :           0 :           inform (loc, "exploded path written to %qs", filename);
    1628                 :           0 :           free (filename);
    1629                 :           0 :         }
    1630                 :             :     }
    1631                 :        3993 : }
    1632                 :             : 
    1633                 :             : const diagnostics::logical_locations::manager &
    1634                 :        3993 : diagnostic_manager::get_logical_location_manager () const
    1635                 :             : {
    1636                 :        3993 :   gcc_assert (global_dc);
    1637                 :        3993 :   auto mgr = global_dc->get_logical_location_manager ();
    1638                 :        3993 :   gcc_assert (mgr);
    1639                 :        3993 :   return *mgr;
    1640                 :             : }
    1641                 :             : 
    1642                 :             : /* Emit a "path" of events to EMISSION_PATH describing the exploded path
    1643                 :             :    EPATH within EG.  */
    1644                 :             : 
    1645                 :             : void
    1646                 :        3993 : diagnostic_manager::build_emission_path (const path_builder &pb,
    1647                 :             :                                          const exploded_path &epath,
    1648                 :             :                                          checker_path *emission_path) const
    1649                 :             : {
    1650                 :        3993 :   LOG_SCOPE (get_logger ());
    1651                 :             : 
    1652                 :        3993 :   interesting_t interest;
    1653                 :        3993 :   pb.get_pending_diagnostic ()->mark_interesting_stuff (&interest);
    1654                 :             : 
    1655                 :             :   /* Add region creation events for any globals of interest, at the
    1656                 :             :      beginning of the path.  */
    1657                 :        3993 :   {
    1658                 :        7915 :     for (auto reg : interest.m_region_creation)
    1659                 :        1326 :       switch (reg->get_memory_space ())
    1660                 :             :         {
    1661                 :        1110 :         default:
    1662                 :        1110 :           continue;
    1663                 :         216 :         case MEMSPACE_CODE:
    1664                 :         216 :         case MEMSPACE_GLOBALS:
    1665                 :         216 :         case MEMSPACE_READONLY_DATA:
    1666                 :         216 :           {
    1667                 :         216 :             const region *base_reg = reg->get_base_region ();
    1668                 :         216 :             if (tree decl = base_reg->maybe_get_decl ())
    1669                 :         207 :               if (DECL_P (decl)
    1670                 :         207 :                   && useful_location_p (DECL_SOURCE_LOCATION (decl)))
    1671                 :             :                 {
    1672                 :         207 :                   emission_path->add_region_creation_events
    1673                 :         207 :                     (pb.get_pending_diagnostic (),
    1674                 :             :                      reg, nullptr,
    1675                 :         207 :                      event_loc_info (DECL_SOURCE_LOCATION (decl),
    1676                 :             :                                      NULL_TREE,
    1677                 :         207 :                                      0),
    1678                 :         207 :                      m_verbosity > 3);
    1679                 :             :                 }
    1680                 :             :           }
    1681                 :        1110 :         }
    1682                 :             :   }
    1683                 :             : 
    1684                 :             :   /* Walk EPATH, adding events as appropriate.  */
    1685                 :       46174 :   for (unsigned i = 0; i < epath.m_edges.length (); i++)
    1686                 :             :     {
    1687                 :       42181 :       const exploded_edge *eedge = epath.m_edges[i];
    1688                 :       42181 :       add_events_for_eedge (pb, *eedge, emission_path, &interest);
    1689                 :             :     }
    1690                 :        3993 :   add_event_on_final_node (pb, epath.get_final_enode (),
    1691                 :             :                            emission_path, &interest);
    1692                 :        3993 : }
    1693                 :             : 
    1694                 :             : /* Emit a region_creation_event when requested on the last statement in
    1695                 :             :    the path.
    1696                 :             : 
    1697                 :             :    If a region_creation_event should be emitted on the last statement of the
    1698                 :             :    path, we need to peek to the successors to get whether the final enode
    1699                 :             :    created a region.
    1700                 :             : */
    1701                 :             : 
    1702                 :             : void
    1703                 :        3993 : diagnostic_manager::add_event_on_final_node (const path_builder &pb,
    1704                 :             :                                              const exploded_node *final_enode,
    1705                 :             :                                              checker_path *emission_path,
    1706                 :             :                                              interesting_t *interest) const
    1707                 :             : {
    1708                 :        3993 :   const program_point &src_point = final_enode->get_point ();
    1709                 :        3993 :   const int src_stack_depth = src_point.get_stack_depth ();
    1710                 :        3993 :   const program_state &src_state = final_enode->get_state ();
    1711                 :        3993 :   const region_model *src_model = src_state.m_region_model;
    1712                 :             : 
    1713                 :        3993 :   unsigned j;
    1714                 :        3993 :   exploded_edge *e;
    1715                 :        7179 :   FOR_EACH_VEC_ELT (final_enode->m_succs, j, e)
    1716                 :             :   {
    1717                 :        3263 :     exploded_node *dst = e->m_dest;
    1718                 :        3263 :     const program_state &dst_state = dst->get_state ();
    1719                 :        3263 :     const region_model *dst_model = dst_state.m_region_model;
    1720                 :        3263 :     if (src_model->get_dynamic_extents ()
    1721                 :        3263 :         != dst_model->get_dynamic_extents ())
    1722                 :             :       {
    1723                 :             :         unsigned i;
    1724                 :             :         const region *reg;
    1725                 :             :         bool emitted = false;
    1726                 :         452 :         FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
    1727                 :             :           {
    1728                 :          92 :             const region *base_reg = reg->get_base_region ();
    1729                 :          92 :             const svalue *old_extents
    1730                 :          92 :         = src_model->get_dynamic_extents (base_reg);
    1731                 :          92 :             const svalue *new_extents
    1732                 :          92 :         = dst_model->get_dynamic_extents (base_reg);
    1733                 :          92 :             if (old_extents == nullptr && new_extents != nullptr)
    1734                 :          81 :               switch (base_reg->get_kind ())
    1735                 :             :                 {
    1736                 :             :                 default:
    1737                 :             :                   break;
    1738                 :          77 :                 case RK_HEAP_ALLOCATED:
    1739                 :          77 :                 case RK_ALLOCA:
    1740                 :          77 :                   emission_path->add_region_creation_events
    1741                 :         154 :                     (pb.get_pending_diagnostic (),
    1742                 :             :                      reg,
    1743                 :             :                      dst_model,
    1744                 :          77 :                      event_loc_info (src_point.get_location (),
    1745                 :             :                                      src_point.get_fndecl (),
    1746                 :         154 :                                      src_stack_depth),
    1747                 :             :                      false);
    1748                 :          77 :                   emitted = true;
    1749                 :          77 :                   break;
    1750                 :             :                 }
    1751                 :             :           }
    1752                 :         360 :         if (emitted)
    1753                 :             :           break;
    1754                 :             :       }
    1755                 :             :   }
    1756                 :        3993 : }
    1757                 :             : 
    1758                 :             : /* Subclass of state_change_visitor that creates state_change_event
    1759                 :             :    instances.  */
    1760                 :             : 
    1761                 :       42185 : class state_change_event_creator : public state_change_visitor
    1762                 :             : {
    1763                 :             : public:
    1764                 :       42185 :   state_change_event_creator (const path_builder &pb,
    1765                 :             :                               const exploded_edge &eedge,
    1766                 :             :                               checker_path *emission_path)
    1767                 :       42185 :     : m_pb (pb),
    1768                 :       42185 :       m_eedge (eedge),
    1769                 :       42185 :       m_emission_path (emission_path)
    1770                 :             :   {}
    1771                 :             : 
    1772                 :          98 :   bool on_global_state_change (const state_machine &sm,
    1773                 :             :                                state_machine::state_t src_sm_val,
    1774                 :             :                                state_machine::state_t dst_sm_val)
    1775                 :             :     final override
    1776                 :             :   {
    1777                 :          98 :     if (&sm != m_pb.get_sm ())
    1778                 :             :       return false;
    1779                 :          55 :     const exploded_node *src_node = m_eedge.m_src;
    1780                 :          55 :     const exploded_node *dst_node = m_eedge.m_dest;
    1781                 :          55 :     const gimple *stmt = m_eedge.maybe_get_stmt ();
    1782                 :          55 :     const program_state &dst_state = dst_node->get_state ();
    1783                 :             : 
    1784                 :          55 :     m_emission_path->add_event
    1785                 :          55 :       (std::make_unique<state_change_event> (m_eedge.m_src,
    1786                 :             :                                              stmt,
    1787                 :             :                                              sm,
    1788                 :         110 :                                              nullptr,
    1789                 :             :                                              src_sm_val,
    1790                 :             :                                              dst_sm_val,
    1791                 :          55 :                                              nullptr,
    1792                 :             :                                              dst_state,
    1793                 :             :                                              src_node));
    1794                 :          55 :     return false;
    1795                 :             :   }
    1796                 :             : 
    1797                 :        4670 :   bool on_state_change (const state_machine &sm,
    1798                 :             :                         state_machine::state_t src_sm_val,
    1799                 :             :                         state_machine::state_t dst_sm_val,
    1800                 :             :                         const svalue *sval,
    1801                 :             :                         const svalue *dst_origin_sval) final override
    1802                 :             :   {
    1803                 :        4670 :     if (&sm != m_pb.get_sm ())
    1804                 :             :       return false;
    1805                 :             : 
    1806                 :        3623 :     const exploded_node *src_node = m_eedge.m_src;
    1807                 :        3623 :     const exploded_node *dst_node = m_eedge.m_dest;
    1808                 :        3623 :     const gimple *stmt = m_eedge.maybe_get_stmt ();
    1809                 :        3623 :     const program_state &dst_state = dst_node->get_state ();
    1810                 :             : 
    1811                 :        3623 :     m_emission_path->add_event
    1812                 :        3623 :       (std::make_unique<state_change_event> (m_eedge.m_src,
    1813                 :             :                                              stmt,
    1814                 :             :                                              sm,
    1815                 :             :                                              sval,
    1816                 :             :                                              src_sm_val,
    1817                 :             :                                              dst_sm_val,
    1818                 :             :                                              dst_origin_sval,
    1819                 :             :                                              dst_state,
    1820                 :             :                                              src_node));
    1821                 :        3623 :     return false;
    1822                 :             :   }
    1823                 :             : 
    1824                 :             :   const path_builder &m_pb;
    1825                 :             :   const exploded_edge &m_eedge;
    1826                 :             :   checker_path *m_emission_path;
    1827                 :             : };
    1828                 :             : 
    1829                 :             : /* Compare SRC_STATE and DST_STATE (which use EXT_STATE), and call
    1830                 :             :    VISITOR's on_state_change for every sm-state change that occurs
    1831                 :             :    to a tree, and on_global_state_change for every global state change
    1832                 :             :    that occurs.
    1833                 :             : 
    1834                 :             :    This determines the state changes that ought to be reported to
    1835                 :             :    the user: a combination of the effects of changes to sm_state_map
    1836                 :             :    (which maps svalues to sm-states), and of region_model changes
    1837                 :             :    (which map trees to svalues).
    1838                 :             : 
    1839                 :             :    Bail out early and return true if any call to on_global_state_change
    1840                 :             :    or on_state_change returns true, otherwise return false.
    1841                 :             : 
    1842                 :             :    This is split out to make it easier to experiment with changes to
    1843                 :             :    exploded_node granularity (so that we can observe what state changes
    1844                 :             :    lead to state_change_events being emitted).  */
    1845                 :             : 
    1846                 :             : bool
    1847                 :       42185 : for_each_state_change (const program_state &src_state,
    1848                 :             :                        const program_state &dst_state,
    1849                 :             :                        const extrinsic_state &ext_state,
    1850                 :             :                        state_change_visitor *visitor)
    1851                 :             : {
    1852                 :       84370 :   gcc_assert (src_state.m_checker_states.length ()
    1853                 :             :               == ext_state.get_num_checkers ());
    1854                 :       84370 :   gcc_assert (dst_state.m_checker_states.length ()
    1855                 :             :               == ext_state.get_num_checkers ());
    1856                 :      335948 :   for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
    1857                 :             :     {
    1858                 :      293763 :       const state_machine &sm = ext_state.get_sm (i);
    1859                 :      293763 :       const sm_state_map &src_smap = *src_state.m_checker_states[i];
    1860                 :      293763 :       const sm_state_map &dst_smap = *dst_state.m_checker_states[i];
    1861                 :             : 
    1862                 :             :       /* Add events for any global state changes.  */
    1863                 :      293763 :       if (src_smap.get_global_state () != dst_smap.get_global_state ())
    1864                 :          98 :         if (visitor->on_global_state_change (sm,
    1865                 :             :                                              src_smap.get_global_state (),
    1866                 :             :                                              dst_smap.get_global_state ()))
    1867                 :             :           return true;
    1868                 :             : 
    1869                 :             :       /* Add events for per-svalue state changes.  */
    1870                 :      333409 :       for (sm_state_map::iterator_t iter = dst_smap.begin ();
    1871                 :      627172 :            iter != dst_smap.end ();
    1872                 :       39646 :            ++iter)
    1873                 :             :         {
    1874                 :       39646 :           const svalue *sval = (*iter).first;
    1875                 :       39646 :           state_machine::state_t dst_sm_val = (*iter).second.m_state;
    1876                 :       39646 :           state_machine::state_t src_sm_val
    1877                 :       39646 :             = src_smap.get_state (sval, ext_state);
    1878                 :       39646 :           if (dst_sm_val != src_sm_val)
    1879                 :             :             {
    1880                 :        4670 :               const svalue *origin_sval = (*iter).second.m_origin;
    1881                 :        4670 :               if (visitor->on_state_change (sm, src_sm_val, dst_sm_val,
    1882                 :             :                                             sval, origin_sval))
    1883                 :           0 :                 return true;
    1884                 :             :             }
    1885                 :             :         }
    1886                 :             :     }
    1887                 :             :   return false;
    1888                 :             : }
    1889                 :             : 
    1890                 :             : /* Subroutine of diagnostic_manager::build_emission_path.
    1891                 :             :    Add any events for EEDGE to EMISSION_PATH.  */
    1892                 :             : 
    1893                 :             : void
    1894                 :       42185 : diagnostic_manager::add_events_for_eedge (const path_builder &pb,
    1895                 :             :                                           const exploded_edge &eedge,
    1896                 :             :                                           checker_path *emission_path,
    1897                 :             :                                           interesting_t *interest) const
    1898                 :             : {
    1899                 :       42185 :   const exploded_node *src_node = eedge.m_src;
    1900                 :       42185 :   const program_point &src_point = src_node->get_point ();
    1901                 :       42185 :   const int src_stack_depth = src_point.get_stack_depth ();
    1902                 :       42185 :   const exploded_node *dst_node = eedge.m_dest;
    1903                 :       42185 :   const program_point &dst_point = dst_node->get_point ();
    1904                 :       42185 :   const int dst_stack_depth = dst_point.get_stack_depth ();
    1905                 :       42185 :   if (get_logger ())
    1906                 :             :     {
    1907                 :           0 :       get_logger ()->start_log_line ();
    1908                 :           0 :       pretty_printer *pp = get_logger ()->get_printer ();
    1909                 :           0 :       pp_printf (pp, "EN %i -> EN %i: ",
    1910                 :           0 :                  eedge.m_src->m_index,
    1911                 :           0 :                  eedge.m_dest->m_index);
    1912                 :           0 :       src_point.print (pp, format (false));
    1913                 :           0 :       pp_string (pp, "-> ");
    1914                 :           0 :       dst_point.print (pp, format (false));
    1915                 :           0 :       get_logger ()->end_log_line ();
    1916                 :             :     }
    1917                 :       42185 :   const program_state &src_state = src_node->get_state ();
    1918                 :       42185 :   const program_state &dst_state = dst_node->get_state ();
    1919                 :             : 
    1920                 :             :   /* Add state change events for the states that have changed.
    1921                 :             :      We add these before events for superedges, so that if we have a
    1922                 :             :      state_change_event due to following an edge, we'll get this sequence
    1923                 :             :      of events:
    1924                 :             : 
    1925                 :             :       | if (!ptr)
    1926                 :             :       |    ~
    1927                 :             :       |    |
    1928                 :             :       |    (1) assuming 'ptr' is non-NULL  (state_change_event)
    1929                 :             :       |    (2) following 'false' branch... (start_cfg_edge_event)
    1930                 :             :      ...
    1931                 :             :       | do_something (ptr);
    1932                 :             :       | ~~~~~~~~~~~~~^~~~~
    1933                 :             :       |              |
    1934                 :             :       |              (3) ...to here        (end_cfg_edge_event).  */
    1935                 :       42185 :   state_change_event_creator visitor (pb, eedge, emission_path);
    1936                 :       42185 :   for_each_state_change (src_state, dst_state, pb.get_ext_state (),
    1937                 :             :                          &visitor);
    1938                 :             : 
    1939                 :             :   /* Give diagnostics an opportunity to inject extra events, or
    1940                 :             :      to override the rest of this function.  */
    1941                 :       42185 :   pending_diagnostic *pd = pb.get_pending_diagnostic ();
    1942                 :       42185 :   if (pd->maybe_add_custom_events_for_eedge (eedge, emission_path))
    1943                 :             :     return;
    1944                 :             : 
    1945                 :             :   /* Allow non-standard edges to add events, e.g. when rewinding from
    1946                 :             :      longjmp to a setjmp.  */
    1947                 :       41243 :   if (eedge.m_custom_info)
    1948                 :        2288 :     eedge.m_custom_info->add_events_to_path (emission_path, eedge, *pd);
    1949                 :             : 
    1950                 :             :   /* Don't add events for insignificant edges at verbosity levels below 3.  */
    1951                 :       41243 :   if (m_verbosity < 3)
    1952                 :       41018 :     if (!significant_edge_p (pb, eedge))
    1953                 :             :       return;
    1954                 :             : 
    1955                 :             :   /* Add events for operations.  */
    1956                 :       40401 :   if (eedge.m_sedge)
    1957                 :       35257 :     if (auto op = eedge.m_sedge->get_op ())
    1958                 :       25937 :       op->add_any_events_for_eedge (eedge, *emission_path);
    1959                 :             : 
    1960                 :             :   /* Add events for function entry.  */
    1961                 :       40401 :   if (dst_point.get_supernode ()->entry_p ())
    1962                 :             :     {
    1963                 :        5096 :       pb.get_pending_diagnostic ()->add_function_entry_event
    1964                 :        5096 :         (eedge, emission_path);
    1965                 :             :       /* Create region_creation_events for on-stack regions within
    1966                 :             :          this frame.  */
    1967                 :        5096 :       if (interest)
    1968                 :             :         {
    1969                 :             :           unsigned i;
    1970                 :             :           const region *reg;
    1971                 :        6561 :           FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
    1972                 :        1465 :             if (const frame_region *frame = reg->maybe_get_frame_region ())
    1973                 :        1942 :               if (frame->get_fndecl () == dst_point.get_fndecl ())
    1974                 :             :                 {
    1975                 :         853 :                   const region *base_reg = reg->get_base_region ();
    1976                 :         853 :                   if (tree decl = base_reg->maybe_get_decl ())
    1977                 :         752 :                     if (DECL_P (decl)
    1978                 :         752 :                         && useful_location_p (DECL_SOURCE_LOCATION (decl)))
    1979                 :             :                       {
    1980                 :         748 :                         emission_path->add_region_creation_events
    1981                 :        1496 :                           (pb.get_pending_diagnostic (),
    1982                 :         748 :                            reg, dst_state.m_region_model,
    1983                 :         748 :                            event_loc_info (DECL_SOURCE_LOCATION (decl),
    1984                 :             :                                            dst_point.get_fndecl (),
    1985                 :         748 :                                            dst_stack_depth),
    1986                 :         748 :                            m_verbosity > 3);
    1987                 :             :                       }
    1988                 :             :                 }
    1989                 :             :         }
    1990                 :             :     }
    1991                 :             : 
    1992                 :             :   /* Look for changes in dynamic extents, which will identify
    1993                 :             :      the creation of heap-based regions and alloca regions.  */
    1994                 :       40401 :   if (interest)
    1995                 :             :     {
    1996                 :       40397 :       const region_model *src_model = src_state.m_region_model;
    1997                 :       40397 :       const region_model *dst_model = dst_state.m_region_model;
    1998                 :       40397 :       if (src_model->get_dynamic_extents ()
    1999                 :       40397 :           != dst_model->get_dynamic_extents ())
    2000                 :             :         {
    2001                 :             :           unsigned i;
    2002                 :             :           const region *reg;
    2003                 :        2547 :           FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
    2004                 :             :             {
    2005                 :         421 :               const region *base_reg = reg->get_base_region ();
    2006                 :         421 :               const svalue *old_extents
    2007                 :         421 :                 = src_model->get_dynamic_extents (base_reg);
    2008                 :         421 :               const svalue *new_extents
    2009                 :         421 :                 = dst_model->get_dynamic_extents (base_reg);
    2010                 :         421 :               if (old_extents == nullptr && new_extents != nullptr)
    2011                 :         277 :                 switch (base_reg->get_kind ())
    2012                 :             :                   {
    2013                 :             :                   default:
    2014                 :             :                     break;
    2015                 :         241 :                   case RK_HEAP_ALLOCATED:
    2016                 :         241 :                   case RK_ALLOCA:
    2017                 :         241 :                     emission_path->add_region_creation_events
    2018                 :         241 :                       (pb.get_pending_diagnostic (),
    2019                 :             :                        reg, dst_model,
    2020                 :         241 :                        event_loc_info (src_point.get_location (),
    2021                 :             :                                        src_point.get_fndecl (),
    2022                 :         482 :                                        src_stack_depth),
    2023                 :         241 :                        m_verbosity > 3);
    2024                 :         241 :                     break;
    2025                 :             :                   }
    2026                 :             :             }
    2027                 :             :         }
    2028                 :             :     }
    2029                 :             : 
    2030                 :       40401 :   if (pb.get_feasibility_problem ()
    2031                 :       40401 :       && &pb.get_feasibility_problem ()->m_eedge == &eedge)
    2032                 :             :     {
    2033                 :           4 :       pretty_printer pp;
    2034                 :           4 :       pp_format_decoder (&pp) = default_tree_printer;
    2035                 :           4 :       pp_string (&pp,
    2036                 :             :                  "this path would have been rejected as infeasible"
    2037                 :             :                  " at this edge: ");
    2038                 :           4 :       pb.get_feasibility_problem ()->dump_to_pp (&pp);
    2039                 :           4 :       emission_path->add_event
    2040                 :           4 :         (std::make_unique<precanned_custom_event>
    2041                 :           4 :            (event_loc_info (dst_point.get_location (),
    2042                 :             :                             dst_point.get_fndecl (),
    2043                 :           8 :                             dst_stack_depth),
    2044                 :           4 :             pp_formatted_text (&pp)));
    2045                 :           4 :     }
    2046                 :       42185 : }
    2047                 :             : 
    2048                 :             : /* Return true if EEDGE is a significant edge in the path to the diagnostic
    2049                 :             :    for PB.
    2050                 :             : 
    2051                 :             :    Consider all of the sibling out-eedges from the same source enode
    2052                 :             :    as EEDGE.
    2053                 :             :    If there's no path from the destinations of those eedges to the
    2054                 :             :    diagnostic enode, then we have to take this eedge and thus it's
    2055                 :             :    significant.
    2056                 :             : 
    2057                 :             :    Conversely if there is a path from the destination of any other sibling
    2058                 :             :    eedge to the diagnostic enode, then this edge is insignificant.
    2059                 :             : 
    2060                 :             :    Example 1: redundant if-else:
    2061                 :             : 
    2062                 :             :      (A) if (...)            A
    2063                 :             :      (B)   ...              / \
    2064                 :             :          else              B   C
    2065                 :             :      (C)   ...              \ /
    2066                 :             :      (D) [DIAGNOSTIC]        D
    2067                 :             : 
    2068                 :             :      D is reachable by either B or C, so neither of these edges
    2069                 :             :      are significant.
    2070                 :             : 
    2071                 :             :    Example 2: pertinent if-else:
    2072                 :             : 
    2073                 :             :      (A) if (...)                         A
    2074                 :             :      (B)   ...                           / \
    2075                 :             :          else                           B   C
    2076                 :             :      (C)   [NECESSARY CONDITION]        |   |
    2077                 :             :      (D) [POSSIBLE DIAGNOSTIC]          D1  D2
    2078                 :             : 
    2079                 :             :      D becomes D1 and D2 in the exploded graph, where the diagnostic occurs
    2080                 :             :      at D2.  D2 is only reachable via C, so the A -> C edge is significant.
    2081                 :             : 
    2082                 :             :    Example 3: redundant loop:
    2083                 :             : 
    2084                 :             :      (A) while (...)          +-->A
    2085                 :             :      (B)   ...                |  / \
    2086                 :             :      (C) ...                  +-B  C
    2087                 :             :      (D) [DIAGNOSTIC]              |
    2088                 :             :                                    D
    2089                 :             : 
    2090                 :             :      D is reachable from both B and C, so the A->C edge is not significant.  */
    2091                 :             : 
    2092                 :             : bool
    2093                 :       41018 : diagnostic_manager::significant_edge_p (const path_builder &pb,
    2094                 :             :                                         const exploded_edge &eedge) const
    2095                 :             : {
    2096                 :       41018 :   int i;
    2097                 :       41018 :   exploded_edge *sibling;
    2098                 :      111291 :   FOR_EACH_VEC_ELT (eedge.m_src->m_succs, i, sibling)
    2099                 :             :     {
    2100                 :       71115 :       if (sibling == &eedge)
    2101                 :       40591 :         continue;
    2102                 :       30524 :       if (pb.reachable_from_p (sibling->m_dest))
    2103                 :             :         {
    2104                 :         842 :           if (get_logger ())
    2105                 :           0 :             get_logger ()->log ("  edge EN: %i -> EN: %i is insignificant as"
    2106                 :             :                                 " EN: %i is also reachable via"
    2107                 :             :                                 " EN: %i -> EN: %i",
    2108                 :           0 :                                 eedge.m_src->m_index, eedge.m_dest->m_index,
    2109                 :           0 :                                 pb.get_diag_node ()->m_index,
    2110                 :           0 :                                 sibling->m_src->m_index,
    2111                 :             :                                 sibling->m_dest->m_index);
    2112                 :         842 :           return false;
    2113                 :             :         }
    2114                 :             :     }
    2115                 :             : 
    2116                 :             :   return true;
    2117                 :             : }
    2118                 :             : 
    2119                 :             : /* Prune PATH, based on the verbosity level, to the most pertinent
    2120                 :             :    events for a diagnostic that involves VAR ending in state STATE
    2121                 :             :    (for state machine SM).
    2122                 :             : 
    2123                 :             :    PATH is updated in place, and the redundant checker_events are deleted.
    2124                 :             : 
    2125                 :             :    As well as deleting events, call record_critical_state on events in
    2126                 :             :    which state critical to the pending_diagnostic is being handled; see
    2127                 :             :    the comment for diagnostic_manager::prune_for_sm_diagnostic.  */
    2128                 :             : 
    2129                 :             : void
    2130                 :        3993 : diagnostic_manager::prune_path (checker_path *path,
    2131                 :             :                                 const state_machine *sm,
    2132                 :             :                                 const svalue *sval,
    2133                 :             :                                 state_machine::state_t state) const
    2134                 :             : {
    2135                 :        3993 :   LOG_FUNC (get_logger ());
    2136                 :        3993 :   path->maybe_log (get_logger (), "path");
    2137                 :        3993 :   prune_for_sm_diagnostic (path, sm, sval, state);
    2138                 :        3993 :   prune_interproc_events (path);
    2139                 :        3993 :   if (! flag_analyzer_show_events_in_system_headers)
    2140                 :        3991 :     prune_system_headers (path);
    2141                 :        3993 :   consolidate_conditions (path);
    2142                 :        3993 :   consolidate_unwind_events (path);
    2143                 :        3993 :   finish_pruning (path);
    2144                 :        3993 :   path->maybe_log (get_logger (), "pruned");
    2145                 :        3993 : }
    2146                 :             : 
    2147                 :             : /* A cheap test to determine if EXPR can be the expression of interest in
    2148                 :             :    an sm-diagnostic, so that we can reject cases where we have a non-lvalue.
    2149                 :             :    We don't have always have a model when calling this, so we can't use
    2150                 :             :    tentative_region_model_context, so there can be false positives.  */
    2151                 :             : 
    2152                 :             : static bool
    2153                 :           0 : can_be_expr_of_interest_p (tree expr)
    2154                 :             : {
    2155                 :           0 :   if (!expr)
    2156                 :             :     return false;
    2157                 :             : 
    2158                 :             :   /* Reject constants.  */
    2159                 :           0 :   if (CONSTANT_CLASS_P (expr))
    2160                 :           0 :     return false;
    2161                 :             : 
    2162                 :             :   /* Otherwise assume that it can be an lvalue.  */
    2163                 :             :   return true;
    2164                 :             : }
    2165                 :             : 
    2166                 :             : /* First pass of diagnostic_manager::prune_path: apply verbosity level,
    2167                 :             :    pruning unrelated state change events.
    2168                 :             : 
    2169                 :             :    Iterate backwards through PATH, skipping state change events that aren't
    2170                 :             :    VAR but update the pertinent VAR when state-copying occurs.
    2171                 :             : 
    2172                 :             :    As well as deleting events, call record_critical_state on events in
    2173                 :             :    which state critical to the pending_diagnostic is being handled, so
    2174                 :             :    that the event's get_desc vfunc can potentially supply a more precise
    2175                 :             :    description of the event to the user.
    2176                 :             :    e.g. improving
    2177                 :             :      "calling 'foo' from 'bar'"
    2178                 :             :    to
    2179                 :             :      "passing possibly-NULL pointer 'ptr' to 'foo' from 'bar' as param 1"
    2180                 :             :    when the diagnostic relates to later dereferencing 'ptr'.  */
    2181                 :             : 
    2182                 :             : void
    2183                 :        3993 : diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
    2184                 :             :                                              const state_machine *sm,
    2185                 :             :                                              const svalue *sval,
    2186                 :             :                                              state_machine::state_t state) const
    2187                 :             : {
    2188                 :        3993 :   int idx = path->num_events () - 1;
    2189                 :       66779 :   while (idx >= 0 && idx < (signed)path->num_events ())
    2190                 :             :     {
    2191                 :       31393 :       checker_event *base_event = path->get_checker_event (idx);
    2192                 :       31393 :       if (get_logger ())
    2193                 :             :         {
    2194                 :           0 :           if (sm)
    2195                 :             :             {
    2196                 :           0 :               if (sval)
    2197                 :             :                 {
    2198                 :           0 :                   label_text sval_desc = sval->get_desc ();
    2199                 :           0 :                   log ("considering event %i (%s), with sval: %qs, state: %qs",
    2200                 :             :                        idx, event_kind_to_string (base_event->get_kind ()),
    2201                 :             :                        sval_desc.get (), state->get_name ());
    2202                 :           0 :                 }
    2203                 :             :               else
    2204                 :           0 :                 log ("considering event %i (%s), with global state: %qs",
    2205                 :             :                      idx, event_kind_to_string (base_event->get_kind ()),
    2206                 :             :                      state->get_name ());
    2207                 :             :             }
    2208                 :             :           else
    2209                 :           0 :             log ("considering event %i", idx);
    2210                 :             :         }
    2211                 :             : 
    2212                 :       31393 :       switch (base_event->get_kind ())
    2213                 :             :         {
    2214                 :           0 :         default:
    2215                 :           0 :           gcc_unreachable ();
    2216                 :             : 
    2217                 :           0 :         case event_kind::debug:
    2218                 :           0 :           if (m_verbosity < 4)
    2219                 :             :             {
    2220                 :           0 :               log ("filtering event %i: debug event", idx);
    2221                 :           0 :               path->delete_event (idx);
    2222                 :             :             }
    2223                 :             :           break;
    2224                 :             : 
    2225                 :             :         case event_kind::custom:
    2226                 :             :           /* Don't filter custom events.  */
    2227                 :             :           break;
    2228                 :             : 
    2229                 :       12917 :         case event_kind::stmt:
    2230                 :       12917 :           {
    2231                 :       12917 :             if (m_verbosity < 4)
    2232                 :             :               {
    2233                 :       12917 :                 log ("filtering event %i: statement event", idx);
    2234                 :       12917 :                 path->delete_event (idx);
    2235                 :             :               }
    2236                 :             :           }
    2237                 :             :           break;
    2238                 :             : 
    2239                 :             :         case event_kind::region_creation:
    2240                 :             :           /* Don't filter these.  */
    2241                 :             :           break;
    2242                 :             : 
    2243                 :        5096 :         case event_kind::function_entry:
    2244                 :        5096 :           if (m_verbosity < 1)
    2245                 :             :             {
    2246                 :          33 :               log ("filtering event %i: function entry", idx);
    2247                 :          33 :               path->delete_event (idx);
    2248                 :             :             }
    2249                 :             :           break;
    2250                 :             : 
    2251                 :        4101 :         case event_kind::state_change:
    2252                 :        4101 :           {
    2253                 :        4101 :             state_change_event *state_change = (state_change_event *)base_event;
    2254                 :        4101 :             gcc_assert (state_change->m_dst_state.m_region_model);
    2255                 :             : 
    2256                 :        4101 :             if (state_change->m_sval == sval)
    2257                 :             :               {
    2258                 :        2164 :                 if (state_change->m_origin)
    2259                 :             :                   {
    2260                 :           0 :                     if (get_logger ())
    2261                 :             :                       {
    2262                 :           0 :                         label_text sval_desc = sval->get_desc ();
    2263                 :           0 :                         label_text origin_sval_desc
    2264                 :           0 :                           = state_change->m_origin->get_desc ();
    2265                 :           0 :                         log ("event %i:"
    2266                 :             :                              " switching var of interest from %qs to %qs",
    2267                 :             :                              idx, sval_desc.get (),
    2268                 :             :                              origin_sval_desc.get ());
    2269                 :           0 :                       }
    2270                 :           0 :                     sval = state_change->m_origin;
    2271                 :             :                   }
    2272                 :        2164 :                 log ("event %i: switching state of interest from %qs to %qs",
    2273                 :        2164 :                      idx, state_change->m_to->get_name (),
    2274                 :        2164 :                      state_change->m_from->get_name ());
    2275                 :        2164 :                 state = state_change->m_from;
    2276                 :             :               }
    2277                 :        1937 :             else if (m_verbosity < 4)
    2278                 :             :               {
    2279                 :        1937 :                 if (get_logger ())
    2280                 :             :                   {
    2281                 :           0 :                     if (state_change->m_sval)
    2282                 :             :                       {
    2283                 :           0 :                         label_text change_sval_desc
    2284                 :           0 :                           = state_change->m_sval->get_desc ();
    2285                 :           0 :                         if (sval)
    2286                 :             :                           {
    2287                 :           0 :                             label_text sval_desc = sval->get_desc ();
    2288                 :           0 :                             log ("filtering event %i:"
    2289                 :             :                                  " state change to %qs unrelated to %qs",
    2290                 :             :                                  idx, change_sval_desc.get (),
    2291                 :             :                                  sval_desc.get ());
    2292                 :           0 :                           }
    2293                 :             :                         else
    2294                 :           0 :                           log ("filtering event %i: state change to %qs",
    2295                 :             :                                idx, change_sval_desc.get ());
    2296                 :           0 :                       }
    2297                 :             :                     else
    2298                 :           0 :                       log ("filtering event %i: global state change", idx);
    2299                 :             :                   }
    2300                 :        1937 :                 path->delete_event (idx);
    2301                 :             :               }
    2302                 :             :           }
    2303                 :             :           break;
    2304                 :             : 
    2305                 :        2660 :         case event_kind::start_cfg_edge:
    2306                 :        2660 :           {
    2307                 :        2660 :             cfg_edge_event *event = (cfg_edge_event *)base_event;
    2308                 :             : 
    2309                 :             :             /* TODO: is this edge significant to var?
    2310                 :             :                See if var can be in other states in the dest, but not
    2311                 :             :                in other states in the src?
    2312                 :             :                Must have multiple sibling edges.  */
    2313                 :             : 
    2314                 :        2660 :             if (event->should_filter_p (m_verbosity))
    2315                 :             :               {
    2316                 :          36 :                 log ("filtering events %i and %i: CFG edge", idx, idx + 1);
    2317                 :          36 :                 path->delete_event (idx);
    2318                 :             :                 /* Also delete the corresponding event_kind::end_cfg_edge.  */
    2319                 :          36 :                 gcc_assert (path->get_checker_event (idx)->get_kind ()
    2320                 :             :                             == event_kind::end_cfg_edge);
    2321                 :          36 :                 path->delete_event (idx);
    2322                 :             :               }
    2323                 :             :           }
    2324                 :             :           break;
    2325                 :             : 
    2326                 :             :         case event_kind::end_cfg_edge:
    2327                 :             :           /* These come in pairs with event_kind::start_cfg_edge events and are
    2328                 :             :              filtered when their start event is filtered.  */
    2329                 :             :           break;
    2330                 :             : 
    2331                 :             :         case event_kind::catch_:
    2332                 :             :         case event_kind::throw_:
    2333                 :             :         case event_kind::unwind:
    2334                 :             :           /* Don't filter these.  */
    2335                 :             :           break;
    2336                 :             : 
    2337                 :        1178 :         case event_kind::call_:
    2338                 :        1178 :           {
    2339                 :        1178 :             call_event *event = (call_event *)base_event;
    2340                 :        1178 :             const region_model *callee_model
    2341                 :        1178 :               = event->m_eedge.m_dest->get_state ().m_region_model;
    2342                 :        1178 :             const region_model *caller_model
    2343                 :        1178 :               = event->m_eedge.m_src->get_state ().m_region_model;
    2344                 :        1178 :             tree callee_var = callee_model->get_representative_tree (sval);
    2345                 :        1178 :             callsite_expr expr;
    2346                 :             : 
    2347                 :        1178 :             tree caller_var;
    2348                 :        1178 :             if (auto op = event->get_call_and_return_op ())
    2349                 :             :               {
    2350                 :        1178 :                 tree callee_fndecl
    2351                 :        1178 :                   = event->m_eedge.m_dest->get_point ().get_fndecl ();
    2352                 :        1178 :                 caller_var
    2353                 :        1178 :                   = op->map_expr_from_callee_to_caller (callee_fndecl,
    2354                 :             :                                                         callee_var,
    2355                 :             :                                                         &expr);
    2356                 :             :               }
    2357                 :             :             else
    2358                 :           0 :               caller_var = caller_model->get_representative_tree (sval);
    2359                 :             : 
    2360                 :        1178 :             if (caller_var)
    2361                 :             :               {
    2362                 :         217 :                 if (get_logger ())
    2363                 :             :                   {
    2364                 :           0 :                     label_text sval_desc = sval->get_desc ();
    2365                 :           0 :                     log ("event %i:"
    2366                 :             :                          " recording critical state for %qs at call"
    2367                 :             :                          " from %qE in callee to %qE in caller",
    2368                 :             :                          idx, sval_desc.get (), callee_var, caller_var);
    2369                 :           0 :                   }
    2370                 :         217 :                 if (expr.param_p ())
    2371                 :         217 :                   event->record_critical_state (caller_var, state);
    2372                 :             :               }
    2373                 :             :           }
    2374                 :        1178 :           break;
    2375                 :             : 
    2376                 :         598 :         case event_kind::return_:
    2377                 :         598 :           {
    2378                 :         598 :             if (sval)
    2379                 :             :               {
    2380                 :         428 :                 return_event *event = (return_event *)base_event;
    2381                 :         428 :                 const region_model *caller_model
    2382                 :         428 :                   = event->m_eedge.m_dest->get_state ().m_region_model;
    2383                 :         428 :                 tree caller_var = caller_model->get_representative_tree (sval);
    2384                 :         428 :                 const region_model *callee_model
    2385                 :         428 :                   = event->m_eedge.m_src->get_state ().m_region_model;
    2386                 :         428 :                 callsite_expr expr;
    2387                 :             : 
    2388                 :         428 :                 tree callee_var;
    2389                 :             : 
    2390                 :         428 :                 if (auto op = event->get_call_and_return_op ())
    2391                 :             :                   {
    2392                 :         428 :                     tree callee_fndecl
    2393                 :         428 :                       = event->m_eedge.m_src->get_point ().get_fndecl ();
    2394                 :         428 :                     callee_var
    2395                 :         428 :                       = op->map_expr_from_caller_to_callee (callee_fndecl,
    2396                 :             :                                                             caller_var,
    2397                 :             :                                                             &expr);
    2398                 :             :                   }
    2399                 :             :                 else
    2400                 :           0 :                   callee_var = callee_model->get_representative_tree (sval);
    2401                 :             : 
    2402                 :         428 :                 if (callee_var)
    2403                 :             :                   {
    2404                 :         169 :                     if (get_logger ())
    2405                 :             :                       {
    2406                 :           0 :                         label_text sval_desc = sval->get_desc ();
    2407                 :           0 :                         log ("event %i:"
    2408                 :             :                              " recording critical state for %qs at return"
    2409                 :             :                              " from %qE in caller to %qE in callee",
    2410                 :             :                              idx, sval_desc.get (), callee_var, callee_var);
    2411                 :           0 :                       }
    2412                 :         169 :                     if (expr.return_value_p ())
    2413                 :          74 :                       event->record_critical_state (callee_var, state);
    2414                 :             :                   }
    2415                 :             :               }
    2416                 :             :           }
    2417                 :             :           break;
    2418                 :             : 
    2419                 :             :         case event_kind::inlined_call:
    2420                 :             :           /* We don't expect to see these yet, as they're added later.
    2421                 :             :              We'd want to keep them around.  */
    2422                 :             :           break;
    2423                 :             : 
    2424                 :             :         case event_kind::setjmp_:
    2425                 :             :           /* TODO: only show setjmp_events that matter i.e. those for which
    2426                 :             :              there is a later rewind event using them.  */
    2427                 :             :         case event_kind::rewind_from_longjmp:
    2428                 :             :         case event_kind::rewind_to_setjmp:
    2429                 :             :           break;
    2430                 :             : 
    2431                 :             :         case event_kind::warning:
    2432                 :             :           /* Always show the final "warning" event in the path.  */
    2433                 :             :           break;
    2434                 :             :         }
    2435                 :       31393 :       idx--;
    2436                 :             :     }
    2437                 :        3993 : }
    2438                 :             : 
    2439                 :             : /* Subroutine of diagnostic_manager::prune_for_sm_diagnostic.
    2440                 :             :    If *EXPR is not suitable to be the expression of interest in
    2441                 :             :    an sm-diagnostic, set *EXPR to NULL and log.  */
    2442                 :             : 
    2443                 :             : void
    2444                 :           0 : diagnostic_manager::update_for_unsuitable_sm_exprs (tree *expr) const
    2445                 :             : {
    2446                 :           0 :   gcc_assert (expr);
    2447                 :           0 :   if (*expr && !can_be_expr_of_interest_p (*expr))
    2448                 :             :     {
    2449                 :           0 :       log ("new var %qE is unsuitable; setting var to NULL", *expr);
    2450                 :           0 :       *expr = NULL_TREE;
    2451                 :             :     }
    2452                 :           0 : }
    2453                 :             : 
    2454                 :             : /* Second pass of diagnostic_manager::prune_path: remove redundant
    2455                 :             :    interprocedural information.
    2456                 :             : 
    2457                 :             :    For example, given:
    2458                 :             :      (1)- calling "f2" from "f1"
    2459                 :             :      (2)--- entry to "f2"
    2460                 :             :      (3)--- calling "f3" from "f2"
    2461                 :             :      (4)----- entry to "f3"
    2462                 :             :      (5)--- returning to "f2" to "f3"
    2463                 :             :      (6)- returning to "f1" to "f2"
    2464                 :             :    with no other intervening events, then none of these events are
    2465                 :             :    likely to be interesting to the user.
    2466                 :             : 
    2467                 :             :    Prune [..., call, function-entry, return, ...] triples repeatedly
    2468                 :             :    until nothing has changed.  For the example above, this would
    2469                 :             :    remove events (3, 4, 5), and then remove events (1, 2, 6).  */
    2470                 :             : 
    2471                 :             : void
    2472                 :        3993 : diagnostic_manager::prune_interproc_events (checker_path *path) const
    2473                 :             : {
    2474                 :        3993 :   bool changed = false;
    2475                 :        4234 :   do
    2476                 :             :     {
    2477                 :        4234 :       changed = false;
    2478                 :        4234 :       int idx = (signed)path->num_events () - 1;
    2479                 :       22116 :       while (idx >= 0)
    2480                 :             :         {
    2481                 :             :           /* Prune [..., call, function-entry, return, ...] triples.  */
    2482                 :       17882 :           if (idx + 2 < (signed)path->num_events ()
    2483                 :        9732 :               && path->get_checker_event (idx)->is_call_p ()
    2484                 :         887 :               && path->get_checker_event (idx + 1)->is_function_entry_p ()
    2485                 :       18761 :               && path->get_checker_event (idx + 2)->is_return_p ())
    2486                 :             :             {
    2487                 :         324 :               if (get_logger ())
    2488                 :             :                 {
    2489                 :           0 :                   label_text desc
    2490                 :           0 :                     (path->get_checker_event (idx)->get_desc
    2491                 :           0 :                        (*global_dc->get_reference_printer ()));
    2492                 :           0 :                   log ("filtering events %i-%i:"
    2493                 :             :                        " irrelevant call/entry/return: %s",
    2494                 :             :                        idx, idx + 2, desc.get ());
    2495                 :           0 :                 }
    2496                 :         324 :               path->delete_event (idx + 2);
    2497                 :         324 :               path->delete_event (idx + 1);
    2498                 :         324 :               path->delete_event (idx);
    2499                 :         324 :               changed = true;
    2500                 :         324 :               idx--;
    2501                 :         324 :               continue;
    2502                 :         324 :             }
    2503                 :             : 
    2504                 :             :           /* Prune [..., call, return, ...] pairs
    2505                 :             :              (for -fanalyzer-verbosity=0).  */
    2506                 :       17558 :           if (idx + 1 < (signed)path->num_events ()
    2507                 :       13245 :               && path->get_checker_event (idx)->is_call_p ()
    2508                 :       18480 :               && path->get_checker_event (idx + 1)->is_return_p ())
    2509                 :             :             {
    2510                 :           4 :               if (get_logger ())
    2511                 :             :                 {
    2512                 :           0 :                   label_text desc
    2513                 :           0 :                     (path->get_checker_event (idx)->get_desc
    2514                 :           0 :                      (*global_dc->get_reference_printer ()));
    2515                 :           0 :                   log ("filtering events %i-%i:"
    2516                 :             :                        " irrelevant call/return: %s",
    2517                 :             :                        idx, idx + 1, desc.get ());
    2518                 :           0 :                 }
    2519                 :           4 :               path->delete_event (idx + 1);
    2520                 :           4 :               path->delete_event (idx);
    2521                 :           4 :               changed = true;
    2522                 :           4 :               idx--;
    2523                 :           4 :               continue;
    2524                 :           4 :             }
    2525                 :             : 
    2526                 :       17554 :           idx--;
    2527                 :             :         }
    2528                 :             : 
    2529                 :             :     }
    2530                 :             :   while (changed);
    2531                 :        3993 : }
    2532                 :             : 
    2533                 :             : /* Remove everything within [call point, IDX]. For consistency,
    2534                 :             :    IDX should represent the return event of the frame to delete,
    2535                 :             :    or if there is none it should be the last event of the frame.
    2536                 :             :    After this function, IDX designates the event prior to calling
    2537                 :             :    this frame.  */
    2538                 :             : 
    2539                 :             : static void
    2540                 :           0 : prune_frame (checker_path *path, int &idx)
    2541                 :             : {
    2542                 :           0 :   gcc_assert (idx >= 0);
    2543                 :           0 :   int nesting = 1;
    2544                 :           0 :   if (path->get_checker_event (idx)->is_return_p ())
    2545                 :           0 :     nesting = 0;
    2546                 :           0 :   do
    2547                 :             :     {
    2548                 :           0 :       if (path->get_checker_event (idx)->is_call_p ())
    2549                 :           0 :         nesting--;
    2550                 :           0 :       else if (path->get_checker_event (idx)->is_return_p ())
    2551                 :           0 :         nesting++;
    2552                 :             : 
    2553                 :           0 :       path->delete_event (idx--);
    2554                 :           0 :     } while (idx >= 0 && nesting != 0);
    2555                 :           0 : }
    2556                 :             : 
    2557                 :             : /* This function is called when fanalyzer-show-events-in-system-headers
    2558                 :             :    is disabled and will prune the diagnostic of all events within a
    2559                 :             :    system header, only keeping the entry and exit events to the header.
    2560                 :             :    This should be called after diagnostic_manager::prune_interproc_events
    2561                 :             :    so that sucessive events [system header call, system header return]
    2562                 :             :    are preserved thereafter.
    2563                 :             : 
    2564                 :             :    Given a diagnostics path diving into a system header in the form
    2565                 :             :    [
    2566                 :             :      prefix events...,
    2567                 :             :      system header call,
    2568                 :             :        system header entry,
    2569                 :             :        events within system headers...,
    2570                 :             :      system header return,
    2571                 :             :      suffix events...
    2572                 :             :    ]
    2573                 :             : 
    2574                 :             :    then transforms it into
    2575                 :             :    [
    2576                 :             :      prefix events...,
    2577                 :             :      system header call,
    2578                 :             :      system header return,
    2579                 :             :      suffix events...
    2580                 :             :    ].  */
    2581                 :             : 
    2582                 :             : void
    2583                 :        3991 : diagnostic_manager::prune_system_headers (checker_path *path) const
    2584                 :             : {
    2585                 :        3991 :   int idx = (signed)path->num_events () - 1;
    2586                 :       19443 :   while (idx >= 0)
    2587                 :             :     {
    2588                 :       15452 :       const checker_event *event = path->get_checker_event (idx);
    2589                 :             :       /* Prune everything between
    2590                 :             :          [..., system entry, (...), system return, ...].  */
    2591                 :       15452 :       if (event->is_return_p ()
    2592                 :       15452 :           && in_system_header_at (event->get_location ()))
    2593                 :             :       {
    2594                 :           0 :         int ret_idx = idx;
    2595                 :           0 :         prune_frame (path, idx);
    2596                 :             : 
    2597                 :           0 :         if (get_logger ())
    2598                 :             :         {
    2599                 :           0 :           log ("filtering system headers events %i-%i:",
    2600                 :             :                idx, ret_idx);
    2601                 :             :         }
    2602                 :             :         // Delete function entry within system headers.
    2603                 :           0 :         if (idx >= 0)
    2604                 :             :           {
    2605                 :           0 :             event = path->get_checker_event (idx);
    2606                 :           0 :             if (event->is_function_entry_p ()
    2607                 :           0 :                 && in_system_header_at (event->get_location ()))
    2608                 :             :               {
    2609                 :           0 :                 if (get_logger ())
    2610                 :             :                   {
    2611                 :           0 :                     label_text desc
    2612                 :           0 :                       (event->get_desc (*global_dc->get_reference_printer ()));
    2613                 :           0 :                     log ("filtering event %i:"
    2614                 :             :                          "system header entry event: %s",
    2615                 :             :                          idx, desc.get ());
    2616                 :           0 :                   }
    2617                 :             : 
    2618                 :           0 :                 path->delete_event (idx);
    2619                 :             :               }
    2620                 :             :           }
    2621                 :             :       }
    2622                 :             : 
    2623                 :       15452 :       idx--;
    2624                 :             :     }
    2625                 :        3991 : }
    2626                 :             : 
    2627                 :             : /* Return true iff event IDX within PATH is on the same line as REF_EXP_LOC.  */
    2628                 :             : 
    2629                 :             : static bool
    2630                 :        2760 : same_line_as_p (const expanded_location &ref_exp_loc,
    2631                 :             :                 checker_path *path, unsigned idx)
    2632                 :             : {
    2633                 :        2760 :   const checker_event *ev = path->get_checker_event (idx);
    2634                 :        2760 :   expanded_location idx_exp_loc = expand_location (ev->get_location ());
    2635                 :        2760 :   gcc_assert (ref_exp_loc.file);
    2636                 :        2760 :   if (idx_exp_loc.file == nullptr)
    2637                 :             :     return false;
    2638                 :        2737 :   if (strcmp (ref_exp_loc.file, idx_exp_loc.file))
    2639                 :             :     return false;
    2640                 :        2737 :   return ref_exp_loc.line == idx_exp_loc.line;
    2641                 :             : }
    2642                 :             : 
    2643                 :             : /* This path-readability optimization reduces the verbosity of compound
    2644                 :             :    conditional statements (without needing to reconstruct the AST, which
    2645                 :             :    has already been lost).
    2646                 :             : 
    2647                 :             :    For example, it converts:
    2648                 :             : 
    2649                 :             :     |   61 |   if (cp[0] != '\0' && cp[0] != '#')
    2650                 :             :     |      |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2651                 :             :     |      |      |              |    |
    2652                 :             :     |      |      |              |    (6) ...to here
    2653                 :             :     |      |      |              (7) following ‘true’ branch...
    2654                 :             :     |      |      (5) following ‘true’ branch...
    2655                 :             :     |   62 |     {
    2656                 :             :     |   63 |       alias = cp++;
    2657                 :             :     |      |               ~~~~
    2658                 :             :     |      |                 |
    2659                 :             :     |      |                 (8) ...to here
    2660                 :             : 
    2661                 :             :    into:
    2662                 :             : 
    2663                 :             :     |   61 |   if (cp[0] != '\0' && cp[0] != '#')
    2664                 :             :     |      |      ~
    2665                 :             :     |      |      |
    2666                 :             :     |      |      (5) following ‘true’ branch...
    2667                 :             :     |   62 |     {
    2668                 :             :     |   63 |       alias = cp++;
    2669                 :             :     |      |               ~~~~
    2670                 :             :     |      |                 |
    2671                 :             :     |      |                 (6) ...to here
    2672                 :             : 
    2673                 :             :    by combining events 5-8 into new events 5-6.
    2674                 :             : 
    2675                 :             :    Find runs of consecutive (start_cfg_edge_event, end_cfg_edge_event) pairs
    2676                 :             :    in which all events apart from the final end_cfg_edge_event are on the same
    2677                 :             :    line, and for which either all the CFG edges are TRUE edges, or all are
    2678                 :             :    FALSE edges.
    2679                 :             : 
    2680                 :             :    Consolidate each such run into a
    2681                 :             :      (start_consolidated_cfg_edges_event, end_consolidated_cfg_edges_event)
    2682                 :             :    pair.  */
    2683                 :             : 
    2684                 :             : void
    2685                 :        3993 : diagnostic_manager::consolidate_conditions (checker_path *path) const
    2686                 :             : {
    2687                 :             :   /* Don't simplify edges if we're debugging them.  */
    2688                 :        3993 :   if (flag_analyzer_verbose_edges)
    2689                 :             :     return;
    2690                 :             : 
    2691                 :       11324 :   for (int start_idx = 0;
    2692                 :       30548 :        start_idx < (signed)path->num_events () - 1;
    2693                 :             :        start_idx++)
    2694                 :             :     {
    2695                 :       11324 :       if (path->cfg_edge_pair_at_p (start_idx))
    2696                 :             :         {
    2697                 :        2512 :           const checker_event *old_start_ev
    2698                 :        2512 :             = path->get_checker_event (start_idx);
    2699                 :        2512 :           expanded_location start_exp_loc
    2700                 :        2512 :             = expand_location (old_start_ev->get_location ());
    2701                 :        2512 :           if (start_exp_loc.file == nullptr)
    2702                 :        2174 :             continue;
    2703                 :        2512 :           if (!same_line_as_p (start_exp_loc, path, start_idx + 1))
    2704                 :        2174 :             continue;
    2705                 :             : 
    2706                 :             :           /* Are we looking for a run of all TRUE edges, or all FALSE edges?  */
    2707                 :         338 :           gcc_assert (old_start_ev->get_kind () == event_kind::start_cfg_edge);
    2708                 :         338 :           const start_cfg_edge_event *old_start_cfg_ev
    2709                 :             :             = (const start_cfg_edge_event *)old_start_ev;
    2710                 :         338 :           bool edge_sense;
    2711                 :         338 :           if (::edge e = old_start_cfg_ev->get_cfg_edge ())
    2712                 :             :             {
    2713                 :         338 :               if (e->flags & EDGE_TRUE_VALUE)
    2714                 :             :                 edge_sense = true;
    2715                 :         175 :               else if (e->flags & EDGE_FALSE_VALUE)
    2716                 :             :                 edge_sense = false;
    2717                 :             :               else
    2718                 :           0 :                 continue;
    2719                 :             :             }
    2720                 :             : 
    2721                 :             :           /* Find a run of CFG start/end event pairs from
    2722                 :             :                [start_idx, next_idx)
    2723                 :             :              where all apart from the final event are on the same line,
    2724                 :             :              and all are either TRUE or FALSE edges, matching the initial.  */
    2725                 :         338 :           int next_idx = start_idx + 2;
    2726                 :         338 :           while (path->cfg_edge_pair_at_p (next_idx)
    2727                 :         450 :                  && same_line_as_p (start_exp_loc, path, next_idx))
    2728                 :             :             {
    2729                 :         143 :               const checker_event *iter_ev
    2730                 :         143 :                 = path->get_checker_event (next_idx);
    2731                 :         143 :               gcc_assert (iter_ev->get_kind () == event_kind::start_cfg_edge);
    2732                 :         143 :               const start_cfg_edge_event *iter_cfg_ev
    2733                 :             :                 = (const start_cfg_edge_event *)iter_ev;
    2734                 :         143 :               ::edge e = iter_cfg_ev->get_cfg_edge ();
    2735                 :         143 :               if (!e)
    2736                 :             :                 break;
    2737                 :         143 :               if (edge_sense)
    2738                 :             :                 {
    2739                 :          99 :                   if (!(e->flags & EDGE_TRUE_VALUE))
    2740                 :             :                     break;
    2741                 :             :                 }
    2742                 :             :               else
    2743                 :             :                 {
    2744                 :          44 :                   if (!(e->flags & EDGE_FALSE_VALUE))
    2745                 :             :                     break;
    2746                 :             :                 }
    2747                 :         112 :               next_idx += 2;
    2748                 :             :             }
    2749                 :             : 
    2750                 :             :           /* If we have more than one pair in the run, consolidate.  */
    2751                 :         338 :           if (next_idx > start_idx + 2)
    2752                 :             :             {
    2753                 :         104 :               const checker_event *old_end_ev
    2754                 :         104 :                 = path->get_checker_event (next_idx - 1);
    2755                 :         104 :               log ("consolidating CFG edge events %i-%i into %i-%i",
    2756                 :             :                    start_idx, next_idx - 1, start_idx, start_idx +1);
    2757                 :         104 :               start_consolidated_cfg_edges_event *new_start_ev
    2758                 :             :                 = new start_consolidated_cfg_edges_event
    2759                 :         104 :                 (event_loc_info (old_start_ev->get_location (),
    2760                 :             :                                  old_start_ev->get_fndecl (),
    2761                 :         104 :                                  old_start_ev->get_stack_depth ()),
    2762                 :         104 :                  edge_sense);
    2763                 :         104 :               checker_event *new_end_ev
    2764                 :             :                 = new end_consolidated_cfg_edges_event
    2765                 :         104 :                 (event_loc_info (old_end_ev->get_location (),
    2766                 :             :                                  old_end_ev->get_fndecl (),
    2767                 :         104 :                                  old_end_ev->get_stack_depth ()));
    2768                 :         104 :               path->replace_event (start_idx, new_start_ev);
    2769                 :         104 :               path->replace_event (start_idx + 1, new_end_ev);
    2770                 :         104 :               path->delete_events (start_idx + 2, next_idx - (start_idx + 2));
    2771                 :             :             }
    2772                 :             :         }
    2773                 :             :     }
    2774                 :             : }
    2775                 :             : 
    2776                 :             : /* Consolidate runs of consecutive unwind_event.  */
    2777                 :             : 
    2778                 :             : void
    2779                 :        3993 : diagnostic_manager::consolidate_unwind_events (checker_path *path) const
    2780                 :             : {
    2781                 :             :   /* Don't simplify edges if we're debugging them.  */
    2782                 :        3993 :   if (flag_analyzer_verbose_edges)
    2783                 :             :     return;
    2784                 :             : 
    2785                 :       11318 :   for (int start_idx = 0;
    2786                 :       30536 :        start_idx < (signed)path->num_events () - 1;
    2787                 :             :        start_idx++)
    2788                 :             :     {
    2789                 :             :       /* Find a run of consecutive unwind_event instances.  */
    2790                 :       11318 :       if (path->get_checker_event (start_idx)->get_kind ()
    2791                 :             :           != event_kind::unwind)
    2792                 :       11309 :         continue;
    2793                 :           9 :       int iter_idx = start_idx + 1;
    2794                 :          15 :       while (iter_idx < (int)path->num_events ())
    2795                 :          15 :         if (path->get_checker_event (iter_idx)->get_kind ()
    2796                 :             :             == event_kind::unwind)
    2797                 :           6 :           ++iter_idx;
    2798                 :             :         else
    2799                 :             :           break;
    2800                 :             : 
    2801                 :             :       /* iter_idx should now be one after the last unwind_event in the run.  */
    2802                 :           9 :       const int last_idx = iter_idx - 1;
    2803                 :           9 :       if (last_idx == start_idx)
    2804                 :           3 :         continue;
    2805                 :             : 
    2806                 :           6 :       gcc_assert (last_idx > start_idx);
    2807                 :             : 
    2808                 :           6 :       log ("consolidating unwind events %i-%i into %i",
    2809                 :             :            start_idx, last_idx, start_idx);
    2810                 :             : 
    2811                 :           6 :       unwind_event *first_event
    2812                 :           6 :         = (unwind_event *)path->get_checker_event (start_idx);
    2813                 :           6 :       const unwind_event *last_event
    2814                 :           6 :         = (const unwind_event *)path->get_checker_event (last_idx);
    2815                 :           6 :       first_event->m_num_frames += last_event->m_num_frames;
    2816                 :           6 :       path->delete_events (start_idx + 1, last_idx - start_idx);
    2817                 :             :     }
    2818                 :             : }
    2819                 :             : 
    2820                 :             : /* Final pass of diagnostic_manager::prune_path.
    2821                 :             : 
    2822                 :             :    If all we're left with is in one function, then filter function entry
    2823                 :             :    events.  */
    2824                 :             : 
    2825                 :             : void
    2826                 :        3993 : diagnostic_manager::finish_pruning (checker_path *path) const
    2827                 :             : {
    2828                 :        3993 :   if (!path->interprocedural_p ())
    2829                 :             :     {
    2830                 :        3225 :       int idx = path->num_events () - 1;
    2831                 :       24135 :       while (idx >= 0 && idx < (signed)path->num_events ())
    2832                 :             :         {
    2833                 :       10455 :           checker_event *base_event = path->get_checker_event (idx);
    2834                 :       10455 :           if (base_event->get_kind () == event_kind::function_entry)
    2835                 :             :             {
    2836                 :        3134 :               log ("filtering event %i:"
    2837                 :             :                    " function entry for purely intraprocedural path", idx);
    2838                 :        3134 :               path->delete_event (idx);
    2839                 :             :             }
    2840                 :       10455 :           idx--;
    2841                 :             :         }
    2842                 :             :     }
    2843                 :        3993 : }
    2844                 :             : 
    2845                 :             : } // namespace ana
    2846                 :             : 
    2847                 :             : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.