LCOV - code coverage report
Current view: top level - gcc/diagnostics - buffering.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 90.2 % 82 74
Test Date: 2025-09-20 13:40:47 Functions: 88.9 % 9 8
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Support for buffering diagnostics before flushing them to output sinks.
       2                 :             :    Copyright (C) 2024-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 under
       8                 :             : the terms of the GNU General Public License as published by the Free
       9                 :             : Software Foundation; either version 3, or (at your option) any later
      10                 :             : version.
      11                 :             : 
      12                 :             : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13                 :             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14                 :             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15                 :             : 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 "config.h"
      22                 :             : #include "system.h"
      23                 :             : #include "coretypes.h"
      24                 :             : #include "diagnostics/buffering.h"
      25                 :             : #include "diagnostics/sink.h"
      26                 :             : #include "diagnostics/dumping.h"
      27                 :             : 
      28                 :             : namespace diagnostics {
      29                 :             : 
      30                 :             : /* Methods fns of diagnostics::context relating to buffering.  */
      31                 :             : 
      32                 :             : /* If BUFFER_ is non-null, use BUFFER as the active diagnostics::buffer on
      33                 :             :    this context.  BUFFER is borrowed.
      34                 :             : 
      35                 :             :    If BUFFER_ is null, stop any buffering on this context until the next call
      36                 :             :    to this function.  */
      37                 :             : 
      38                 :             : void
      39                 :     2686841 : context::set_diagnostic_buffer (buffer *buffer_)
      40                 :             : {
      41                 :             :   /* Early reject of no-op (to avoid recursively crashing when handling an
      42                 :             :      ICE when inside a nested diagnostics; see PR diagnostics/121876).  */
      43                 :     2686841 :   if (buffer_ == m_diagnostic_buffer)
      44                 :             :     return;
      45                 :             : 
      46                 :             :   /* We don't allow changing buffering within a diagnostic group
      47                 :             :      (to simplify handling of buffered diagnostics within the
      48                 :             :      diagnostic_format implementations).  */
      49                 :     2382048 :   gcc_assert (m_diagnostic_groups.m_group_nesting_depth == 0);
      50                 :             : 
      51                 :             :   /* Likewise, for simplicity, we only allow changing buffers
      52                 :             :      at nesting level 0.  */
      53                 :     2382048 :   gcc_assert (m_diagnostic_groups.m_diagnostic_nesting_level == 0);
      54                 :             : 
      55                 :     2382048 :   m_diagnostic_buffer = buffer_;
      56                 :             : 
      57                 :     2382048 :   if (buffer_)
      58                 :             :     {
      59                 :     1191028 :       buffer_->ensure_per_sink_buffers ();
      60                 :     1191028 :       gcc_assert (buffer_->m_per_sink_buffers);
      61                 :     3573084 :       gcc_assert (buffer_->m_per_sink_buffers->length ()
      62                 :             :                   == m_sinks.length ());
      63                 :     2382056 :       for (unsigned idx = 0; idx < m_sinks.length (); ++idx)
      64                 :             :         {
      65                 :     1191028 :           auto sink_ = m_sinks[idx];
      66                 :     1191028 :           auto per_sink_buffer = (*buffer_->m_per_sink_buffers)[idx];
      67                 :     1191028 :           sink_->set_buffer (per_sink_buffer);
      68                 :             :         }
      69                 :             :     }
      70                 :             :   else
      71                 :     4764080 :     for (auto sink_ : m_sinks)
      72                 :     1191020 :       sink_->set_buffer (nullptr);
      73                 :             : }
      74                 :             : 
      75                 :             : /* Clear BUFFER_ without flushing it.  */
      76                 :             : 
      77                 :             : void
      78                 :    22829483 : context::clear_diagnostic_buffer (buffer &buffer_)
      79                 :             : {
      80                 :    22829483 :   if (buffer_.m_per_sink_buffers)
      81                 :    19842188 :     for (auto per_sink_buffer_ : *buffer_.m_per_sink_buffers)
      82                 :     4960547 :       per_sink_buffer_->clear ();
      83                 :             : 
      84                 :    22829483 :   buffer_.m_diagnostic_counters.clear ();
      85                 :             : 
      86                 :             :   /* We need to reset last_location, otherwise we may skip caret lines
      87                 :             :      when we actually give a diagnostic.  */
      88                 :    22829483 :   m_last_location = UNKNOWN_LOCATION;
      89                 :    22829483 : }
      90                 :             : 
      91                 :             : /* Flush the diagnostics in BUFFER_ to this context, clearing BUFFER_.  */
      92                 :             : 
      93                 :             : void
      94                 :        7205 : context::flush_diagnostic_buffer (buffer &buffer_)
      95                 :             : {
      96                 :        7205 :   bool had_errors
      97                 :        7205 :     = (buffer_.diagnostic_count (kind::error) > 0
      98                 :        7205 :        || buffer_.diagnostic_count (kind::werror) > 0);
      99                 :        7205 :   if (buffer_.m_per_sink_buffers)
     100                 :       28820 :     for (auto per_sink_buffer_ : *buffer_.m_per_sink_buffers)
     101                 :        7205 :       per_sink_buffer_->flush ();
     102                 :        7205 :   buffer_.m_diagnostic_counters.move_to (m_diagnostic_counters);
     103                 :             : 
     104                 :       11260 :   action_after_output (had_errors ? kind::error : kind::warning);
     105                 :        7205 :   check_max_errors (true);
     106                 :        7202 : }
     107                 :             : 
     108                 :             : /* class diagnostics::buffer.  */
     109                 :             : 
     110                 :     8386525 : buffer::buffer (context &ctxt)
     111                 :     8386525 : : m_ctxt (ctxt),
     112                 :     8386525 :   m_per_sink_buffers (nullptr)
     113                 :             : {
     114                 :     8386525 : }
     115                 :             : 
     116                 :     8355625 : buffer::~buffer ()
     117                 :             : {
     118                 :     8355625 :   if (m_per_sink_buffers)
     119                 :             :     {
     120                 :      376952 :       for (auto iter : *m_per_sink_buffers)
     121                 :       94238 :         delete iter;
     122                 :      188476 :       delete m_per_sink_buffers;
     123                 :             :     }
     124                 :     8355625 : }
     125                 :             : 
     126                 :             : void
     127                 :           0 : buffer::dump (FILE *out, int indent) const
     128                 :             : {
     129                 :           0 :   m_diagnostic_counters.dump (out, indent + 2);
     130                 :           0 :   dumping::emit_heading (out, indent, "m_per_sink_buffers");
     131                 :           0 :   if (m_per_sink_buffers)
     132                 :           0 :     for (auto per_sink_buffer_ : *m_per_sink_buffers)
     133                 :           0 :       per_sink_buffer_->dump (out, indent + 2);
     134                 :             :   else
     135                 :           0 :     dumping::emit_none (out, indent + 2);
     136                 :           0 : }
     137                 :             : 
     138                 :             : bool
     139                 :     5993075 : buffer::empty_p () const
     140                 :             : {
     141                 :     5993075 :   if (m_per_sink_buffers)
     142                 :     9555195 :     for (auto per_sink_buffer_ : *m_per_sink_buffers)
     143                 :             :       /* Query initial buffer.  */
     144                 :     3185065 :       return per_sink_buffer_->empty_p ();
     145                 :             :   return true;
     146                 :             : }
     147                 :             : 
     148                 :             : void
     149                 :      103239 : buffer::move_to (buffer &dest)
     150                 :             : {
     151                 :             :   /* Bail if there's nothing to move.  */
     152                 :      103239 :   if (!m_per_sink_buffers)
     153                 :             :     return;
     154                 :             : 
     155                 :      103239 :   m_diagnostic_counters.move_to (dest.m_diagnostic_counters);
     156                 :             : 
     157                 :      103239 :   if (!dest.m_per_sink_buffers)
     158                 :             :     {
     159                 :             :       /* Optimization for the "move to empty" case:
     160                 :             :          simply move the vec to the dest.  */
     161                 :       80859 :       dest.m_per_sink_buffers = m_per_sink_buffers;
     162                 :       80859 :       m_per_sink_buffers = nullptr;
     163                 :       80859 :       return;
     164                 :             :     }
     165                 :             : 
     166                 :       22380 :   dest.ensure_per_sink_buffers ();
     167                 :       22380 :   gcc_assert (m_per_sink_buffers);
     168                 :       67140 :   gcc_assert (m_per_sink_buffers->length ()
     169                 :             :               == m_ctxt.m_sinks.length ());
     170                 :       22380 :   gcc_assert (dest.m_per_sink_buffers);
     171                 :       44760 :   gcc_assert (dest.m_per_sink_buffers->length ()
     172                 :             :               == m_ctxt.m_sinks.length ());
     173                 :       44760 :   for (unsigned idx = 0; idx < m_ctxt.m_sinks.length (); ++idx)
     174                 :             :     {
     175                 :       22380 :       auto per_sink_buffer_src = (*m_per_sink_buffers)[idx];
     176                 :       22380 :       auto per_sink_buffer_dest = (*dest.m_per_sink_buffers)[idx];
     177                 :       22380 :       per_sink_buffer_src->move_to (*per_sink_buffer_dest);
     178                 :             :     }
     179                 :             : }
     180                 :             : 
     181                 :             : /* Lazily get the output formats to create their own kind of buffers.
     182                 :             :    We can't change the output sinks on a context once this has been called
     183                 :             :    on any diagnostics::buffer instances for that context, since there's no
     184                 :             :    way to update all diagnostics::buffer instances for that context.  */
     185                 :             : 
     186                 :             : void
     187                 :     1213408 : buffer::ensure_per_sink_buffers ()
     188                 :             : {
     189                 :     1213408 :   if (!m_per_sink_buffers)
     190                 :             :     {
     191                 :       96227 :       m_per_sink_buffers = new auto_vec<per_sink_buffer *> ();
     192                 :      192454 :       for (unsigned idx = 0; idx < m_ctxt.m_sinks.length (); ++idx)
     193                 :             :         {
     194                 :       96227 :           auto sink_ = m_ctxt.m_sinks[idx];
     195                 :       96227 :           auto per_sink_buffer = sink_->make_per_sink_buffer ();
     196                 :       96227 :           m_per_sink_buffers->safe_push (per_sink_buffer.release ());
     197                 :       96227 :         }
     198                 :             :     }
     199                 :     1213408 :   gcc_assert (m_per_sink_buffers);
     200                 :     3640224 :   gcc_assert (m_per_sink_buffers->length ()
     201                 :             :               == m_ctxt.m_sinks.length ());
     202                 :     1213408 : }
     203                 :             : 
     204                 :             : } // namespace diagnostics
        

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.