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-10-18 14:39:06 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                 :             : #define INCLUDE_VECTOR
      22                 :             : #include "config.h"
      23                 :             : #include "system.h"
      24                 :             : #include "coretypes.h"
      25                 :             : #include "diagnostics/buffering.h"
      26                 :             : #include "diagnostics/sink.h"
      27                 :             : #include "diagnostics/dumping.h"
      28                 :             : 
      29                 :             : namespace diagnostics {
      30                 :             : 
      31                 :             : /* Methods fns of diagnostics::context relating to buffering.  */
      32                 :             : 
      33                 :             : /* If BUFFER_ is non-null, use BUFFER as the active diagnostics::buffer on
      34                 :             :    this context.  BUFFER is borrowed.
      35                 :             : 
      36                 :             :    If BUFFER_ is null, stop any buffering on this context until the next call
      37                 :             :    to this function.  */
      38                 :             : 
      39                 :             : void
      40                 :     2696463 : context::set_diagnostic_buffer (buffer *buffer_)
      41                 :             : {
      42                 :             :   /* Early reject of no-op (to avoid recursively crashing when handling an
      43                 :             :      ICE when inside a nested diagnostics; see PR diagnostics/121876).  */
      44                 :     2696463 :   if (buffer_ == m_diagnostic_buffer)
      45                 :             :     return;
      46                 :             : 
      47                 :             :   /* We don't allow changing buffering within a diagnostic group
      48                 :             :      (to simplify handling of buffered diagnostics within the
      49                 :             :      diagnostic_format implementations).  */
      50                 :     2388290 :   gcc_assert (m_diagnostic_groups.m_group_nesting_depth == 0);
      51                 :             : 
      52                 :             :   /* Likewise, for simplicity, we only allow changing buffers
      53                 :             :      at nesting level 0.  */
      54                 :     2388290 :   gcc_assert (m_diagnostic_groups.m_diagnostic_nesting_level == 0);
      55                 :             : 
      56                 :     2388290 :   m_diagnostic_buffer = buffer_;
      57                 :             : 
      58                 :     2388290 :   if (buffer_)
      59                 :             :     {
      60                 :     1194149 :       buffer_->ensure_per_sink_buffers ();
      61                 :     1194149 :       gcc_assert (buffer_->m_per_sink_buffers);
      62                 :     3582447 :       gcc_assert (buffer_->m_per_sink_buffers->length ()
      63                 :             :                   == m_sinks.length ());
      64                 :     2388298 :       for (unsigned idx = 0; idx < m_sinks.length (); ++idx)
      65                 :             :         {
      66                 :     1194149 :           auto sink_ = m_sinks[idx];
      67                 :     1194149 :           auto per_sink_buffer = (*buffer_->m_per_sink_buffers)[idx];
      68                 :     1194149 :           sink_->set_buffer (per_sink_buffer);
      69                 :             :         }
      70                 :             :     }
      71                 :             :   else
      72                 :     4776564 :     for (auto sink_ : m_sinks)
      73                 :     1194141 :       sink_->set_buffer (nullptr);
      74                 :             : }
      75                 :             : 
      76                 :             : /* Clear BUFFER_ without flushing it.  */
      77                 :             : 
      78                 :             : void
      79                 :    22877713 : context::clear_diagnostic_buffer (buffer &buffer_)
      80                 :             : {
      81                 :    22877713 :   if (buffer_.m_per_sink_buffers)
      82                 :    19924040 :     for (auto per_sink_buffer_ : *buffer_.m_per_sink_buffers)
      83                 :     4981010 :       per_sink_buffer_->clear ();
      84                 :             : 
      85                 :    22877713 :   buffer_.m_diagnostic_counters.clear ();
      86                 :             : 
      87                 :             :   /* We need to reset last_location, otherwise we may skip caret lines
      88                 :             :      when we actually give a diagnostic.  */
      89                 :    22877713 :   m_last_location = UNKNOWN_LOCATION;
      90                 :    22877713 : }
      91                 :             : 
      92                 :             : /* Flush the diagnostics in BUFFER_ to this context, clearing BUFFER_.  */
      93                 :             : 
      94                 :             : void
      95                 :        7230 : context::flush_diagnostic_buffer (buffer &buffer_)
      96                 :             : {
      97                 :        7230 :   bool had_errors
      98                 :        7230 :     = (buffer_.diagnostic_count (kind::error) > 0
      99                 :        7230 :        || buffer_.diagnostic_count (kind::werror) > 0);
     100                 :        7230 :   if (buffer_.m_per_sink_buffers)
     101                 :       28920 :     for (auto per_sink_buffer_ : *buffer_.m_per_sink_buffers)
     102                 :        7230 :       per_sink_buffer_->flush ();
     103                 :        7230 :   buffer_.m_diagnostic_counters.move_to (m_diagnostic_counters);
     104                 :             : 
     105                 :       11286 :   action_after_output (had_errors ? kind::error : kind::warning);
     106                 :        7230 :   check_max_errors (true);
     107                 :        7227 : }
     108                 :             : 
     109                 :             : /* class diagnostics::buffer.  */
     110                 :             : 
     111                 :     8405472 : buffer::buffer (context &ctxt)
     112                 :     8405472 : : m_ctxt (ctxt),
     113                 :     8405472 :   m_per_sink_buffers (nullptr)
     114                 :             : {
     115                 :     8405472 : }
     116                 :             : 
     117                 :     8374585 : buffer::~buffer ()
     118                 :             : {
     119                 :     8374585 :   if (m_per_sink_buffers)
     120                 :             :     {
     121                 :      377656 :       for (auto iter : *m_per_sink_buffers)
     122                 :       94414 :         delete iter;
     123                 :      188828 :       delete m_per_sink_buffers;
     124                 :             :     }
     125                 :     8374585 : }
     126                 :             : 
     127                 :             : void
     128                 :           0 : buffer::dump (FILE *out, int indent) const
     129                 :             : {
     130                 :           0 :   m_diagnostic_counters.dump (out, indent + 2);
     131                 :           0 :   dumping::emit_heading (out, indent, "m_per_sink_buffers");
     132                 :           0 :   if (m_per_sink_buffers)
     133                 :           0 :     for (auto per_sink_buffer_ : *m_per_sink_buffers)
     134                 :           0 :       per_sink_buffer_->dump (out, indent + 2);
     135                 :             :   else
     136                 :           0 :     dumping::emit_none (out, indent + 2);
     137                 :           0 : }
     138                 :             : 
     139                 :             : bool
     140                 :     6006097 : buffer::empty_p () const
     141                 :             : {
     142                 :     6006097 :   if (m_per_sink_buffers)
     143                 :     9577887 :     for (auto per_sink_buffer_ : *m_per_sink_buffers)
     144                 :             :       /* Query initial buffer.  */
     145                 :     3192629 :       return per_sink_buffer_->empty_p ();
     146                 :             :   return true;
     147                 :             : }
     148                 :             : 
     149                 :             : void
     150                 :      103600 : buffer::move_to (buffer &dest)
     151                 :             : {
     152                 :             :   /* Bail if there's nothing to move.  */
     153                 :      103600 :   if (!m_per_sink_buffers)
     154                 :             :     return;
     155                 :             : 
     156                 :      103600 :   m_diagnostic_counters.move_to (dest.m_diagnostic_counters);
     157                 :             : 
     158                 :      103600 :   if (!dest.m_per_sink_buffers)
     159                 :             :     {
     160                 :             :       /* Optimization for the "move to empty" case:
     161                 :             :          simply move the vec to the dest.  */
     162                 :       81115 :       dest.m_per_sink_buffers = m_per_sink_buffers;
     163                 :       81115 :       m_per_sink_buffers = nullptr;
     164                 :       81115 :       return;
     165                 :             :     }
     166                 :             : 
     167                 :       22485 :   dest.ensure_per_sink_buffers ();
     168                 :       22485 :   gcc_assert (m_per_sink_buffers);
     169                 :       67455 :   gcc_assert (m_per_sink_buffers->length ()
     170                 :             :               == m_ctxt.m_sinks.length ());
     171                 :       22485 :   gcc_assert (dest.m_per_sink_buffers);
     172                 :       44970 :   gcc_assert (dest.m_per_sink_buffers->length ()
     173                 :             :               == m_ctxt.m_sinks.length ());
     174                 :       44970 :   for (unsigned idx = 0; idx < m_ctxt.m_sinks.length (); ++idx)
     175                 :             :     {
     176                 :       22485 :       auto per_sink_buffer_src = (*m_per_sink_buffers)[idx];
     177                 :       22485 :       auto per_sink_buffer_dest = (*dest.m_per_sink_buffers)[idx];
     178                 :       22485 :       per_sink_buffer_src->move_to (*per_sink_buffer_dest);
     179                 :             :     }
     180                 :             : }
     181                 :             : 
     182                 :             : /* Lazily get the output formats to create their own kind of buffers.
     183                 :             :    We can't change the output sinks on a context once this has been called
     184                 :             :    on any diagnostics::buffer instances for that context, since there's no
     185                 :             :    way to update all diagnostics::buffer instances for that context.  */
     186                 :             : 
     187                 :             : void
     188                 :     1216634 : buffer::ensure_per_sink_buffers ()
     189                 :             : {
     190                 :     1216634 :   if (!m_per_sink_buffers)
     191                 :             :     {
     192                 :       96383 :       m_per_sink_buffers = new auto_vec<per_sink_buffer *> ();
     193                 :      192766 :       for (unsigned idx = 0; idx < m_ctxt.m_sinks.length (); ++idx)
     194                 :             :         {
     195                 :       96383 :           auto sink_ = m_ctxt.m_sinks[idx];
     196                 :       96383 :           auto per_sink_buffer = sink_->make_per_sink_buffer ();
     197                 :       96383 :           m_per_sink_buffers->safe_push (per_sink_buffer.release ());
     198                 :       96383 :         }
     199                 :             :     }
     200                 :     1216634 :   gcc_assert (m_per_sink_buffers);
     201                 :     3649902 :   gcc_assert (m_per_sink_buffers->length ()
     202                 :             :               == m_ctxt.m_sinks.length ());
     203                 :     1216634 : }
     204                 :             : 
     205                 :             : } // 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.