LCOV - code coverage report
Current view: top level - gcc/c-family - c-ppoutput.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 98.9 % 450 445
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 29 29
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Preprocess only, using cpplib.
       2              :    Copyright (C) 1995-2026 Free Software Foundation, Inc.
       3              :    Written by Per Bothner, 1994-95.
       4              : 
       5              :    This program is free software; you can redistribute it and/or modify it
       6              :    under the terms of the GNU General Public License as published by the
       7              :    Free Software Foundation; either version 3, or (at your option) any
       8              :    later version.
       9              : 
      10              :    This program is distributed in the hope that it will be useful,
      11              :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :    GNU General Public License for more details.
      14              : 
      15              :    You should have received a copy of the GNU General Public License
      16              :    along with this program; see the file COPYING3.  If not see
      17              :    <http://www.gnu.org/licenses/>.  */
      18              : 
      19              : #include "config.h"
      20              : #include "system.h"
      21              : #include "coretypes.h"
      22              : #include "c-common.h"         /* For flags.  */
      23              : #include "../libcpp/internal.h"
      24              : #include "langhooks.h"
      25              : #include "c-pragma.h"         /* For parse_in.  */
      26              : #include "file-prefix-map.h"    /* remap_macro_filename()  */
      27              : 
      28              : class token_streamer;
      29              : 
      30              : /* Encapsulates state used to convert a stream of tokens into a text
      31              :    file.  */
      32              : static struct
      33              : {
      34              :   FILE *outf;                   /* Stream to write to.  */
      35              :   const cpp_token *prev;        /* Previous token.  */
      36              :   const cpp_token *source;      /* Source token for spacing.  */
      37              :   unsigned src_line;            /* Line number currently being written.  */
      38              :   bool printed;                 /* True if something output at line.  */
      39              :   bool first_time;              /* pp_file_change hasn't been called yet.  */
      40              :   bool prev_was_system_token;   /* True if the previous token was a
      41              :                                    system token.*/
      42              :   const char *src_file;         /* Current source file.  */
      43              :   token_streamer *streamer;     /* Instance of class token_streamer using this
      44              :                                    object.  */
      45              : } print;
      46              : 
      47              : /* Defined and undefined macros being queued for output with -dU at
      48              :    the next newline.  */
      49              : struct macro_queue
      50              : {
      51              :   struct macro_queue *next;     /* Next macro in the list.  */
      52              :   char *macro;                  /* The name of the macro if not
      53              :                                    defined, the full definition if
      54              :                                    defined.  */
      55              : };
      56              : static macro_queue *define_queue, *undef_queue;
      57              : 
      58              : /* General output routines.  */
      59              : static void scan_translation_unit (cpp_reader *);
      60              : static void scan_translation_unit_directives_only (cpp_reader *);
      61              : static void scan_translation_unit_trad (cpp_reader *);
      62              : static void account_for_newlines (const unsigned char *, size_t);
      63              : static int dump_macro (cpp_reader *, cpp_hashnode *, void *);
      64              : static void dump_queued_macros (cpp_reader *);
      65              : 
      66              : static bool print_line_1 (location_t, const char*, FILE *);
      67              : static bool print_line (location_t, const char *);
      68              : static bool maybe_print_line_1 (location_t, FILE *);
      69              : static bool maybe_print_line (location_t);
      70              : static bool do_line_change (cpp_reader *, const cpp_token *,
      71              :                             location_t, int);
      72              : 
      73              : /* Callback routines for the parser.   Most of these are active only
      74              :    in specific modes.  */
      75              : static void cb_line_change (cpp_reader *, const cpp_token *, int);
      76              : static void cb_define (cpp_reader *, location_t, cpp_hashnode *);
      77              : static void cb_undef (cpp_reader *, location_t, cpp_hashnode *);
      78              : static void cb_used_define (cpp_reader *, location_t, cpp_hashnode *);
      79              : static void cb_used_undef (cpp_reader *, location_t, cpp_hashnode *);
      80              : static void cb_include (cpp_reader *, location_t, const unsigned char *,
      81              :                         const char *, int, const cpp_token **);
      82              : static void cb_ident (cpp_reader *, location_t, const cpp_string *);
      83              : static void cb_def_pragma (cpp_reader *, location_t);
      84              : static void cb_read_pch (cpp_reader *pfile, const char *name,
      85              :                          int fd, const char *orig_name);
      86              : 
      87              : /* Preprocess and output.  */
      88              : void
      89         6767 : preprocess_file (cpp_reader *pfile)
      90              : {
      91              :   /* A successful cpp_read_main_file guarantees that we can call
      92              :      cpp_scan_nooutput or cpp_get_token next.  */
      93         6767 :   if (flag_no_output && pfile->buffer)
      94              :     {
      95          107 :       if (flag_modules)
      96              :         {
      97              :           /* For macros from imported headers we need directives_only_cb.  */
      98           15 :           scan_translation_unit_directives_only (pfile);
      99              :         }
     100              :       else
     101              :         {
     102              :           /* Scan -included buffers, then the main file.  */
     103          179 :           while (pfile->buffer->prev)
     104           87 :             cpp_scan_nooutput (pfile);
     105           92 :           cpp_scan_nooutput (pfile);
     106              :         }
     107              :     }
     108         6660 :   else if (cpp_get_options (pfile)->traditional)
     109         2925 :     scan_translation_unit_trad (pfile);
     110         3735 :   else if (cpp_get_options (pfile)->directives_only
     111           80 :            && !cpp_get_options (pfile)->preprocessed)
     112           72 :     scan_translation_unit_directives_only (pfile);
     113              :   else
     114         3663 :     scan_translation_unit (pfile);
     115              : 
     116              :   /* -dM command line option.  Should this be elsewhere?  */
     117         6591 :   if (flag_dump_macros == 'M')
     118           80 :     cpp_forall_identifiers (pfile, dump_macro, NULL);
     119              : 
     120              :   /* Flush any pending output.  */
     121         6591 :   if (print.printed)
     122         4776 :     putc ('\n', print.outf);
     123         6591 : }
     124              : 
     125              : /* Don't emit #pragma or #ident directives if we are processing
     126              :    assembly language; the assembler may choke on them.  */
     127              : static bool
     128       118355 : should_output_pragmas ()
     129              : {
     130       118355 :   return cpp_get_options (parse_in)->lang != CLK_ASM;
     131              : }
     132              : 
     133              : /* Set up the callbacks as appropriate.  */
     134              : void
     135         6772 : init_pp_output (FILE *out_stream)
     136              : {
     137         6772 :   cpp_callbacks *cb = cpp_get_callbacks (parse_in);
     138              : 
     139         6772 :   if (!flag_no_output)
     140              :     {
     141         6665 :       cb->line_change = cb_line_change;
     142         6665 :       if (should_output_pragmas ())
     143              :         {
     144         5685 :           cb->ident      = cb_ident;
     145         5685 :           cb->def_pragma = cb_def_pragma;
     146              :         }
     147              :     }
     148              : 
     149         6772 :   if (flag_dump_includes)
     150            1 :     cb->include  = cb_include;
     151              : 
     152         6772 :   if (flag_pch_preprocess)
     153              :     {
     154          468 :       cb->valid_pch = c_common_valid_pch;
     155          468 :       cb->read_pch = cb_read_pch;
     156              :     }
     157              : 
     158         6772 :   if (flag_dump_macros == 'N' || flag_dump_macros == 'D')
     159              :     {
     160          214 :       cb->define = cb_define;
     161          214 :       cb->undef  = cb_undef;
     162              :     }
     163              : 
     164         6772 :   if (flag_dump_macros == 'U')
     165              :     {
     166           23 :       cb->before_define = dump_queued_macros;
     167           23 :       cb->used_define = cb_used_define;
     168           23 :       cb->used_undef = cb_used_undef;
     169              :     }
     170              : 
     171         6772 :   cb->has_attribute = c_common_has_attribute;
     172         6772 :   cb->has_builtin = c_common_has_builtin;
     173         6772 :   cb->has_feature = c_common_has_feature;
     174         6772 :   cb->get_source_date_epoch = cb_get_source_date_epoch;
     175         6772 :   cb->get_suggestion = cb_get_suggestion;
     176         6772 :   cb->remap_filename = remap_macro_filename;
     177              : 
     178              :   /* Initialize the print structure.  */
     179         6772 :   print.src_line = 1;
     180         6772 :   print.printed = false;
     181         6772 :   print.prev = 0;
     182         6772 :   print.outf = out_stream;
     183         6772 :   print.first_time = 1;
     184         6772 :   print.src_file = "";
     185         6772 :   print.prev_was_system_token = false;
     186         6772 :   print.streamer = nullptr;
     187         6772 : }
     188              : 
     189              : // FIXME: Ideally we'd just turn the entirety of the print struct into
     190              : // an encapsulated streamer ...
     191              : 
     192              : class token_streamer
     193              : {
     194              :   bool avoid_paste;
     195              :   bool do_line_adjustments;
     196              :   bool in_pragma;
     197              : 
     198              :  public:
     199         3750 :   token_streamer (cpp_reader *pfile)
     200         3750 :     :avoid_paste (false),
     201         7500 :     do_line_adjustments (cpp_get_options (pfile)->lang != CLK_ASM
     202         3750 :                          && !flag_no_line_commands),
     203         3750 :     in_pragma (false)
     204              :     {
     205         3750 :       gcc_assert (!print.streamer);
     206         3750 :       print.streamer = this;
     207         3750 :     }
     208              : 
     209          162 :   void begin_pragma ()
     210              :   {
     211          162 :     in_pragma = true;
     212          162 :   }
     213              : 
     214              :   void stream (cpp_reader *pfile, const cpp_token *tok, location_t);
     215              : };
     216              : 
     217              : void
     218     35740083 : token_streamer::stream (cpp_reader *pfile, const cpp_token *token,
     219              :                         location_t loc)
     220              : {
     221              :   /* Keep input_location up to date, since it is needed for processing early
     222              :      pragmas such as #pragma GCC diagnostic.  */
     223     35740083 :   input_location = loc;
     224              : 
     225     35740083 :   if (token->type == CPP_PADDING)
     226              :     {
     227      2437823 :       avoid_paste = true;
     228      2437823 :       if (print.source == NULL
     229       316813 :           || (!(print.source->flags & PREV_WHITE)
     230       106465 :               && token->val.source == NULL))
     231      2149806 :         print.source = token->val.source;
     232      2437823 :       return;
     233              :     }
     234              : 
     235     33302260 :   if (token->type == CPP_EOF)
     236              :     return;
     237              : 
     238              :   /* Keep track when we move into and out of system locations.  */
     239     33298773 :   const bool is_system_token = in_system_header_at (loc);
     240     33298773 :   const bool system_state_changed
     241     33298773 :     = (is_system_token != print.prev_was_system_token);
     242     33298773 :   print.prev_was_system_token = is_system_token;
     243              : 
     244              :   /* Subtle logic to output a space if and only if necessary.  */
     245     33298773 :   bool line_marker_emitted = false;
     246     33298773 :   if (avoid_paste)
     247              :     {
     248      1568037 :       unsigned src_line = LOCATION_LINE (loc);
     249              : 
     250      1568037 :       if (print.source == NULL)
     251       665654 :         print.source = token;
     252              : 
     253      1568037 :       if (src_line != print.src_line
     254         5386 :           && do_line_adjustments
     255         5348 :           && !in_pragma)
     256              :         {
     257         5331 :           line_marker_emitted = do_line_change (pfile, token, loc, false);
     258         5331 :           putc (' ', print.outf);
     259         5331 :           print.printed = true;
     260              :         }
     261      1562706 :       else if (print.source->flags & PREV_WHITE
     262       548657 :                || (print.prev
     263       471504 :                    && cpp_avoid_paste (pfile, print.prev, token))
     264      2109317 :                || (print.prev == NULL && token->type == CPP_HASH))
     265              :         {
     266      1016112 :           putc (' ', print.outf);
     267      1016112 :           print.printed = true;
     268              :         }
     269              :     }
     270     31730736 :   else if (token->flags & PREV_WHITE && token->type != CPP_PRAGMA)
     271              :     {
     272     13678538 :       unsigned src_line = LOCATION_LINE (loc);
     273              : 
     274     13678538 :       if (src_line != print.src_line
     275         7331 :           && do_line_adjustments
     276          507 :           && !in_pragma)
     277          381 :         line_marker_emitted = do_line_change (pfile, token, loc, false);
     278     13678538 :       putc (' ', print.outf);
     279     13678538 :       print.printed = true;
     280              :     }
     281              : 
     282     33298773 :   avoid_paste = false;
     283     33298773 :   print.source = NULL;
     284     33298773 :   print.prev = token;
     285     33298773 :   if (token->type == CPP_PRAGMA)
     286              :     {
     287        33384 :       in_pragma = true;
     288        33384 :       if (should_output_pragmas ())
     289              :         {
     290        33384 :           const char *space;
     291        33384 :           const char *name;
     292              : 
     293        33384 :           line_marker_emitted = maybe_print_line (token->src_loc);
     294        33384 :           fputs ("#pragma ", print.outf);
     295        33384 :           c_pp_lookup_pragma (token->val.pragma, &space, &name);
     296        33384 :           if (space)
     297        33366 :             fprintf (print.outf, "%s %s", space, name);
     298              :           else
     299           18 :             fprintf (print.outf, "%s", name);
     300        33384 :           print.printed = true;
     301              :         }
     302        33384 :       if (token->val.pragma >= PRAGMA_FIRST_EXTERNAL)
     303        33290 :         c_pp_invoke_early_pragma_handler (token->val.pragma);
     304              :     }
     305     33265389 :   else if (token->type == CPP_PRAGMA_EOL)
     306              :     {
     307        33546 :       if (should_output_pragmas ())
     308        33546 :         maybe_print_line (UNKNOWN_LOCATION);
     309        33546 :       in_pragma = false;
     310              :     }
     311     33231843 :   else if (token->type == CPP_EMBED)
     312              :     {
     313          130 :       char buf[76 + 6];
     314          130 :       maybe_print_line (token->src_loc);
     315          130 :       gcc_checking_assert (token->val.str.len != 0);
     316          130 :       fputs ("#embed \".\" __gnu__::__base64__(", print.outf);
     317          130 :       if (token->val.str.len > 30)
     318              :         {
     319          130 :           fputs (" \\\n", print.outf);
     320          130 :           print.src_line++;
     321              :         }
     322          130 :       buf[0] = '"';
     323          130 :       memcpy (buf + 1 + 76, "\" \\\n", 5);
     324          130 :       unsigned int j = 1;
     325          130 :       static const char base64_enc[] =
     326              :         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     327          130 :       for (unsigned i = 0; ; i += 3)
     328              :         {
     329       196824 :           unsigned char a = token->val.str.text[i];
     330       196824 :           unsigned char b = 0, c = 0;
     331       196824 :           unsigned int n = token->val.str.len - i;
     332       196824 :           if (n > 1)
     333       196778 :             b = token->val.str.text[i + 1];
     334       196778 :           if (n > 2)
     335       196738 :             c = token->val.str.text[i + 2];
     336       196824 :           unsigned long v = ((((unsigned long) a) << 16)
     337       196824 :                              | (((unsigned long) b) << 8)
     338       196824 :                              | c);
     339       196824 :           buf[j++] = base64_enc[(v >> 18) & 63];
     340       196824 :           buf[j++] = base64_enc[(v >> 12) & 63];
     341       196824 :           buf[j++] = base64_enc[(v >> 6) & 63];
     342       196824 :           buf[j++] = base64_enc[v & 63];
     343       196824 :           if (j == 76 + 1 || n <= 3)
     344              :             {
     345        10438 :               if (n < 3)
     346              :                 {
     347           86 :                   buf[j - 1] = '=';
     348           86 :                   if (n == 1)
     349           46 :                     buf[j - 2] = '=';
     350              :                 }
     351        10438 :               if (n <= 3)
     352          130 :                 memcpy (buf + j, "\")", 3);
     353              :               else
     354        10308 :                 print.src_line++;
     355        10438 :               fputs (buf, print.outf);
     356        10438 :               j = 1;
     357        10438 :               if (n <= 3)
     358              :                 break;
     359              :             }
     360       196694 :         }
     361          130 :       print.printed = true;
     362          130 :       maybe_print_line (token->src_loc);
     363          130 :       return;
     364              :     }
     365              :   else
     366              :     {
     367     33231713 :       if (cpp_get_options (parse_in)->debug)
     368            3 :         linemap_dump_location (line_table, token->src_loc, print.outf);
     369              : 
     370     33231713 :       if (do_line_adjustments
     371     32758527 :           && !in_pragma
     372     32713767 :           && !line_marker_emitted
     373     32713767 :           && system_state_changed
     374     33244872 :           && !is_location_from_builtin_token (loc))
     375              :         /* The system-ness of this token is different from the one of
     376              :            the previous token.  Let's emit a line change to mark the
     377              :            new system-ness before we emit the token.  */
     378              :         {
     379        13158 :           line_marker_emitted = do_line_change (pfile, token, loc, false);
     380              :         }
     381     33231713 :       if (!in_pragma || should_output_pragmas ())
     382              :         {
     383     33231713 :           cpp_output_token (token, print.outf);
     384     33231713 :           print.printed = true;
     385              :         }
     386              :     }
     387              : 
     388              :   /* CPP_COMMENT tokens and raw-string literal tokens can have
     389              :      embedded new-line characters.  Rather than enumerating all the
     390              :      possible token types just check if token uses val.str union
     391              :      member.  */
     392     33298643 :   if (cpp_token_val_index (token) == CPP_TOKEN_FLD_STR)
     393       701691 :     account_for_newlines (token->val.str.text, token->val.str.len);
     394              : }
     395              : 
     396              : /* Writes out the preprocessed file, handling spacing and paste
     397              :    avoidance issues.  */
     398              : 
     399              : static void
     400         3663 : scan_translation_unit (cpp_reader *pfile)
     401              : {
     402         3663 :   token_streamer streamer (pfile);
     403         3663 :   uintptr_t filter = 0;
     404              : 
     405         3663 :   if (lang_hooks.preprocess_token)
     406         1297 :     filter = lang_hooks.preprocess_token (pfile, NULL, filter);
     407              : 
     408         3663 :   print.source = NULL;
     409     71321115 :   for (;;)
     410              :     {
     411     35662389 :       location_t spelling_loc;
     412     35662389 :       const cpp_token *token
     413     35662389 :         = cpp_get_token_with_location (pfile, &spelling_loc);
     414              : 
     415     35662213 :       streamer.stream (pfile, token, spelling_loc);
     416     35662213 :       if (filter)
     417              :         {
     418       763255 :           unsigned flags = lang_hooks.preprocess_token (pfile, token, filter);
     419       763255 :           if (flags & lang_hooks::PT_begin_pragma)
     420          132 :             streamer.begin_pragma ();
     421              :         }
     422     35662213 :       if (token->type == CPP_EOF)
     423              :         break;
     424     35658726 :     }
     425              : 
     426         3487 :   if (filter)
     427          117 :     lang_hooks.preprocess_token (pfile, NULL, filter);
     428         3487 : }
     429              : 
     430              : class do_streamer : public token_streamer
     431              : {
     432              :  public:
     433              :   uintptr_t filter;
     434              : 
     435           87 :   do_streamer (cpp_reader *pfile, uintptr_t filter)
     436          174 :     :token_streamer (pfile), filter (filter)
     437              :     {
     438              :     }
     439              : };
     440              : 
     441              : static void
     442       122365 : directives_only_cb (cpp_reader *pfile, CPP_DO_task task, void *data_, ...)
     443              : {
     444       122365 :   va_list args;
     445       122365 :   va_start (args, data_);
     446              : 
     447       122365 :   do_streamer *streamer = reinterpret_cast <do_streamer *> (data_);
     448       122365 :   switch (task)
     449              :     {
     450            0 :     default:
     451            0 :       gcc_unreachable ();
     452              : 
     453        31237 :     case CPP_DO_print:
     454        31237 :       if (!flag_no_output)
     455              :         {
     456        31126 :           print.src_line += va_arg (args, unsigned);
     457              : 
     458        31126 :           const void *buf = va_arg (args, const void *);
     459        31126 :           size_t size = va_arg (args, size_t);
     460        31126 :           fwrite (buf, 1, size, print.outf);
     461              :         }
     462              :       break;
     463              : 
     464        89633 :     case CPP_DO_location:
     465        89633 :       if (!flag_no_output)
     466        89384 :         maybe_print_line (va_arg (args, location_t));
     467              :       break;
     468              : 
     469         1495 :     case CPP_DO_token:
     470         1495 :       {
     471         1495 :         const cpp_token *token = va_arg (args, const cpp_token *);
     472         1495 :         unsigned flags = 0;
     473         1495 :         if (streamer->filter)
     474          270 :           flags = lang_hooks.preprocess_token (pfile, token, streamer->filter);
     475         1495 :         if (!flag_no_output)
     476              :           {
     477         1363 :             location_t spelling_loc = va_arg (args, location_t);
     478         1363 :             streamer->stream (pfile, token, spelling_loc);
     479         1363 :             if (flags & lang_hooks::PT_begin_pragma)
     480           30 :               streamer->begin_pragma ();
     481              :           }
     482              :       }
     483              :       break;
     484              :     }
     485              : 
     486       122365 :   va_end (args);
     487       122365 : }
     488              : 
     489              : /* Writes out the preprocessed file, handling spacing and paste
     490              :    avoidance issues.  */
     491              : static void
     492           87 : scan_translation_unit_directives_only (cpp_reader *pfile)
     493              : {
     494           87 :   uintptr_t filter = 0;
     495           87 :   if (lang_hooks.preprocess_token)
     496           69 :     filter = lang_hooks.preprocess_token (pfile, NULL, filter);
     497           87 :   do_streamer streamer (pfile, filter);
     498           87 :   cpp_directive_only_process (pfile, &streamer, directives_only_cb);
     499           87 :   if (streamer.filter)
     500           24 :     lang_hooks.preprocess_token (pfile, NULL, streamer.filter);
     501           87 : }
     502              : 
     503              : /* Adjust print.src_line for newlines embedded in output.  For example, if a raw
     504              :    string literal contains newlines, then we need to increment our notion of the
     505              :    current line to keep in sync and avoid outputting a line marker
     506              :    unnecessarily.  If a raw string literal containing newlines is the result of
     507              :    macro expansion, then we have the opposite problem, where the token takes up
     508              :    more lines in the output than it did in the input, and hence a line marker is
     509              :    needed to restore the correct state for subsequent lines.  In this case,
     510              :    incrementing print.src_line still does the job, because it will cause us to
     511              :    emit the line marker the next time a token is streamed.  */
     512              : static void
     513       701866 : account_for_newlines (const unsigned char *str, size_t len)
     514              : {
     515      3589756 :   while (len--)
     516      2887890 :     if (*str++ == '\n')
     517          654 :       print.src_line++;
     518       701866 : }
     519              : 
     520              : /* Writes out a traditionally preprocessed file.  */
     521              : static void
     522         2925 : scan_translation_unit_trad (cpp_reader *pfile)
     523              : {
     524       535270 :   while (_cpp_read_logical_line_trad (pfile))
     525              :     {
     526       529420 :       size_t len = pfile->out.cur - pfile->out.base;
     527       529420 :       maybe_print_line (pfile->out.first_line);
     528       529420 :       fwrite (pfile->out.base, 1, len, print.outf);
     529       529420 :       print.printed = true;
     530       529420 :       if (!CPP_OPTION (pfile, discard_comments))
     531          175 :         account_for_newlines (pfile->out.base, len);
     532              :     }
     533         2925 : }
     534              : 
     535              : /* If the token read on logical line LINE needs to be output on a
     536              :    different line to the current one, output the required newlines or
     537              :    a line marker.  If a line marker was emitted, return TRUE otherwise
     538              :    return FALSE.  */
     539              : 
     540              : static bool
     541      5958386 : maybe_print_line_1 (location_t src_loc, FILE *stream)
     542              : {
     543      5958386 :   bool emitted_line_marker = false;
     544      5958386 :   unsigned src_line = LOCATION_LINE (src_loc);
     545      5958386 :   const char *src_file = LOCATION_FILE (src_loc);
     546              : 
     547              :   /* End the previous line of text.  */
     548      5958386 :   if (print.printed)
     549              :     {
     550      5476974 :       putc ('\n', stream);
     551      5476974 :       print.src_line++;
     552      5476974 :       print.printed = false;
     553              :     }
     554              : 
     555      5958386 :   if (!flag_no_line_commands
     556      5946625 :       && src_line >= print.src_line
     557      5805420 :       && src_line < print.src_line + 8
     558      5634487 :       && src_loc != UNKNOWN_LOCATION
     559      5634485 :       && strcmp (src_file, print.src_file) == 0)
     560              :     {
     561      7621406 :       while (src_line > print.src_line)
     562              :         {
     563      1986927 :           putc ('\n', stream);
     564      1986927 :           print.src_line++;
     565              :         }
     566              :     }
     567              :   else
     568       323907 :     emitted_line_marker = print_line_1 (src_loc, "", stream);
     569              : 
     570      5958386 :   return emitted_line_marker;
     571              : }
     572              : 
     573              : /* If the token read on logical line LINE needs to be output on a
     574              :    different line to the current one, output the required newlines or
     575              :    a line marker.  If a line marker was emitted, return TRUE otherwise
     576              :    return FALSE.  */
     577              : 
     578              : static bool
     579      5958386 : maybe_print_line (location_t src_loc)
     580              : {
     581      5958386 :   if (cpp_get_options (parse_in)->debug)
     582            2 :     linemap_dump_location (line_table, src_loc,
     583              :                            print.outf);
     584      5958386 :   return maybe_print_line_1 (src_loc, print.outf);
     585              : }
     586              : 
     587              : /* Output a line marker for logical line LINE.  Special flags are "1"
     588              :    or "2" indicating entering or leaving a file.  If the line marker
     589              :    was effectively emitted, return TRUE otherwise return FALSE.  */
     590              : 
     591              : static bool
     592       469941 : print_line_1 (location_t src_loc, const char *special_flags, FILE *stream)
     593              : {
     594       469941 :   bool emitted_line_marker = false;
     595              : 
     596              :   /* End any previous line of text.  */
     597       469941 :   if (print.printed)
     598        22775 :     putc ('\n', stream);
     599       469941 :   print.printed = false;
     600              : 
     601       469941 :   if (src_loc != UNKNOWN_LOCATION && !flag_no_line_commands)
     602              :     {
     603       424634 :       const char *file_path = LOCATION_FILE (src_loc);
     604       424634 :       size_t to_file_len = strlen (file_path);
     605       424634 :       unsigned char *to_file_quoted =
     606       424634 :          (unsigned char *) alloca (to_file_len * 4 + 1);
     607              : 
     608              :       /* cpp_quote_string does not nul-terminate, so we have to do it
     609              :          ourselves.  */
     610       424634 :       unsigned char *p = cpp_quote_string (to_file_quoted,
     611              :                                            (const unsigned char *) file_path,
     612              :                                            to_file_len);
     613       424634 :       *p = '\0';
     614              : 
     615       424634 :       print.src_line = LOCATION_LINE (src_loc);
     616       424634 :       print.src_file = file_path;
     617              : 
     618       424634 :       fprintf (stream, "# %u \"%s\"%s",
     619              :                print.src_line, to_file_quoted, special_flags);
     620              : 
     621       424634 :       int sysp = in_system_header_at (src_loc);
     622       424634 :       if (sysp == 2)
     623            0 :         fputs (" 3 4", stream);
     624       424634 :       else if (sysp == 1)
     625       162030 :         fputs (" 3", stream);
     626              : 
     627       424634 :       putc ('\n', stream);
     628       424634 :       emitted_line_marker = true;
     629              :     }
     630              : 
     631       469941 :   return emitted_line_marker;
     632              : }
     633              : 
     634              : /* Output a line marker for logical line LINE.  Special flags are "1"
     635              :    or "2" indicating entering or leaving a file.  Return TRUE if a
     636              :    line marker was effectively emitted, FALSE otherwise.  */
     637              : 
     638              : static bool
     639       146034 : print_line (location_t src_loc, const char *special_flags)
     640              : {
     641       146034 :     if (cpp_get_options (parse_in)->debug)
     642            6 :       linemap_dump_location (line_table, src_loc,
     643              :                              print.outf);
     644       146034 :     return print_line_1 (src_loc, special_flags, print.outf);
     645              : }
     646              : 
     647              : /* Helper function for cb_line_change and scan_translation_unit.
     648              :    Return TRUE if a line marker is emitted, FALSE otherwise.  */
     649              : static bool
     650      4996383 : do_line_change (cpp_reader *pfile, const cpp_token *token,
     651              :                 location_t src_loc, int parsing_args)
     652              : {
     653      4996383 :   bool emitted_line_marker = false;
     654      4996383 :   if (define_queue || undef_queue)
     655           21 :     dump_queued_macros (pfile);
     656              : 
     657      4996383 :   if (token->type == CPP_EOF || parsing_args)
     658              :     return false;
     659              : 
     660      4974151 :   emitted_line_marker = maybe_print_line (src_loc);
     661      4974151 :   print.prev = 0;
     662      4974151 :   print.source = 0;
     663              : 
     664              :   /* Supply enough spaces to put this token in its original column,
     665              :      one space per column greater than 2, since scan_translation_unit
     666              :      will provide a space if PREV_WHITE.  Don't bother trying to
     667              :      reconstruct tabs; we can't get it right in general, and nothing
     668              :      ought to care.  Some things do care; the fault lies with them.
     669              : 
     670              :      Also do not output the spaces if this is a CPP_PRAGMA token.  In this
     671              :      case, libcpp has provided the location of the first token after #pragma,
     672              :      so we would start at the wrong column.  */
     673      4974151 :   if (!CPP_OPTION (pfile, traditional) && token->type != CPP_PRAGMA)
     674              :     {
     675      4940885 :       int spaces = LOCATION_COLUMN (src_loc) - 2;
     676      4940885 :       print.printed = true;
     677              : 
     678     18924518 :       while (-- spaces >= 0)
     679     13983633 :         putc (' ', print.outf);
     680              :     }
     681              : 
     682              :   return emitted_line_marker;
     683              : }
     684              : 
     685              : /* Called when a line of output is started.  TOKEN is the first token
     686              :    of the line, and at end of file will be CPP_EOF.  */
     687              : static void
     688      4977513 : cb_line_change (cpp_reader *pfile, const cpp_token *token,
     689              :                 int parsing_args)
     690              : {
     691      4977513 :   do_line_change (pfile, token, token->src_loc, parsing_args);
     692      4977513 : }
     693              : 
     694              : static void
     695            2 : cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, location_t line,
     696              :           const cpp_string *str)
     697              : {
     698            2 :   maybe_print_line (line);
     699            2 :   fprintf (print.outf, "#ident %s\n", str->text);
     700            2 :   print.src_line++;
     701            2 : }
     702              : 
     703              : static void
     704       205945 : cb_define (cpp_reader *pfile, location_t line, cpp_hashnode *node)
     705              : {
     706       205945 :   const line_map_ordinary *map;
     707              : 
     708       205945 :   maybe_print_line (line);
     709       205945 :   fputs ("#define ", print.outf);
     710              : 
     711              :   /* 'D' is whole definition; 'N' is name only.  */
     712       205945 :   if (flag_dump_macros == 'D')
     713        52693 :     fputs ((const char *) cpp_macro_definition (pfile, node),
     714              :            print.outf);
     715              :   else
     716       153252 :     fputs ((const char *) NODE_NAME (node), print.outf);
     717              : 
     718       205945 :   putc ('\n', print.outf);
     719       205945 :   print.printed = false;
     720       205945 :   linemap_resolve_location (line_table, line,
     721              :                             LRK_MACRO_DEFINITION_LOCATION,
     722              :                             &map);
     723       205945 :   print.src_line++;
     724       205945 : }
     725              : 
     726              : static void
     727        27647 : cb_undef (cpp_reader *pfile, location_t line, cpp_hashnode *node)
     728              : {
     729        27647 :   if (lang_hooks.preprocess_undef)
     730            0 :     lang_hooks.preprocess_undef (pfile, line, node);
     731        27647 :   maybe_print_line (line);
     732        27647 :   fprintf (print.outf, "#undef %s\n", NODE_NAME (node));
     733        27647 :   print.src_line++;
     734        27647 : }
     735              : 
     736              : static void
     737           22 : cb_used_define (cpp_reader *pfile, location_t line ATTRIBUTE_UNUSED,
     738              :                 cpp_hashnode *node)
     739              : {
     740           22 :   if (cpp_user_macro_p (node))
     741              :     {
     742           21 :       macro_queue *q;
     743           21 :       q = XNEW (macro_queue);
     744           21 :       q->macro = xstrdup ((const char *) cpp_macro_definition (pfile, node));
     745           21 :       q->next = define_queue;
     746           21 :       define_queue = q;
     747              :     }
     748           22 : }
     749              : 
     750              : static void
     751           11 : cb_used_undef (cpp_reader *pfile ATTRIBUTE_UNUSED,
     752              :                location_t line ATTRIBUTE_UNUSED,
     753              :                cpp_hashnode *node)
     754              : {
     755           11 :   macro_queue *q;
     756           11 :   q = XNEW (macro_queue);
     757           11 :   q->macro = xstrdup ((const char *) NODE_NAME (node));
     758           11 :   q->next = undef_queue;
     759           11 :   undef_queue = q;
     760           11 : }
     761              : 
     762              : static void
     763         9294 : dump_queued_macros (cpp_reader *pfile ATTRIBUTE_UNUSED)
     764              : {
     765         9294 :   macro_queue *q;
     766              : 
     767              :   /* End the previous line of text.  */
     768         9294 :   if (print.printed)
     769              :     {
     770           12 :       putc ('\n', print.outf);
     771           12 :       print.src_line++;
     772           12 :       print.printed = false;
     773              :     }
     774              : 
     775         9315 :   for (q = define_queue; q;)
     776              :     {
     777           21 :       macro_queue *oq;
     778           21 :       fputs ("#define ", print.outf);
     779           21 :       fputs (q->macro, print.outf);
     780           21 :       putc ('\n', print.outf);
     781           21 :       print.printed = false;
     782           21 :       print.src_line++;
     783           21 :       oq = q;
     784           21 :       q = q->next;
     785           21 :       free (oq->macro);
     786           21 :       free (oq);
     787              :     }
     788         9294 :   define_queue = NULL;
     789         9305 :   for (q = undef_queue; q;)
     790              :     {
     791           11 :       macro_queue *oq;
     792           11 :       fprintf (print.outf, "#undef %s\n", q->macro);
     793           11 :       print.src_line++;
     794           11 :       oq = q;
     795           11 :       q = q->next;
     796           11 :       free (oq->macro);
     797           11 :       free (oq);
     798              :     }
     799         9294 :   undef_queue = NULL;
     800         9294 : }
     801              : 
     802              : static void
     803            1 : cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, location_t line,
     804              :             const unsigned char *dir, const char *header, int angle_brackets,
     805              :             const cpp_token **comments)
     806              : {
     807            1 :   maybe_print_line (line);
     808            1 :   if (angle_brackets)
     809            0 :     fprintf (print.outf, "#%s <%s>", dir, header);
     810              :   else
     811            1 :     fprintf (print.outf, "#%s \"%s\"", dir, header);
     812              : 
     813            1 :   if (comments != NULL)
     814              :     {
     815            2 :       while (*comments != NULL)
     816              :         {
     817            1 :           if ((*comments)->flags & PREV_WHITE)
     818            1 :             putc (' ', print.outf);
     819            1 :           cpp_output_token (*comments, print.outf);
     820            1 :           ++comments;
     821              :         }
     822              :     }
     823              : 
     824            1 :   putc ('\n', print.outf);
     825            1 :   print.printed = false;
     826            1 :   print.src_line++;
     827            1 : }
     828              : 
     829              : /* Callback called when -fworking-director and -E to emit working
     830              :    directory in cpp output file.  */
     831              : 
     832              : void
     833         2245 : pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir)
     834              : {
     835         2245 :   size_t to_file_len = strlen (dir);
     836         2245 :   unsigned char *to_file_quoted =
     837         2245 :      (unsigned char *) alloca (to_file_len * 4 + 1);
     838         2245 :   unsigned char *p;
     839              : 
     840              :   /* cpp_quote_string does not nul-terminate, so we have to do it ourselves.  */
     841         2245 :   p = cpp_quote_string (to_file_quoted, (const unsigned char *) dir, to_file_len);
     842         2245 :   *p = '\0';
     843         2245 :   fprintf (print.outf, "# 1 \"%s//\"\n", to_file_quoted);
     844         2245 : }
     845              : 
     846              : /* The file name, line number or system header flags have changed, as
     847              :    described in MAP.  */
     848              : 
     849              : void
     850       157702 : pp_file_change (const line_map_ordinary *map)
     851              : {
     852       157702 :   const char *flags = "";
     853              : 
     854       157702 :   if (flag_no_line_commands)
     855              :     return;
     856              : 
     857       152480 :   if (map != NULL)
     858              :     {
     859       146044 :       input_location = map->start_location;
     860       146044 :       if (print.first_time)
     861              :         {
     862              :           /* Avoid printing foo.i when the main file is foo.c.  */
     863         6622 :           if (!cpp_get_options (parse_in)->preprocessed)
     864         6612 :             print_line (map->start_location, flags);
     865         6622 :           print.first_time = 0;
     866              :         }
     867              :       else
     868              :         {
     869              :           /* Bring current file to correct line when entering a new file.  */
     870       139422 :           if (map->reason == LC_ENTER)
     871              :             {
     872        59640 :               maybe_print_line (linemap_included_from (map));
     873        59640 :               flags = " 1";
     874              :             }
     875        79782 :           else if (map->reason == LC_LEAVE)
     876        59636 :             flags = " 2";
     877       139422 :           print_line (map->start_location, flags);
     878              :         }
     879              :     }
     880              : }
     881              : 
     882              : /* Copy a #pragma directive to the preprocessed output.  */
     883              : static void
     884         5006 : cb_def_pragma (cpp_reader *pfile, location_t line)
     885              : {
     886         5006 :   maybe_print_line (line);
     887         5006 :   fputs ("#pragma ", print.outf);
     888         5006 :   cpp_output_line (pfile, print.outf);
     889         5006 :   print.printed = false;
     890         5006 :   print.src_line++;
     891         5006 : }
     892              : 
     893              : /* Stream a token as if we had seen it directly ourselves; needed
     894              :    in case a token was lexed externally, e.g. while processing a
     895              :    pragma.  */
     896              : void
     897        76507 : c_pp_stream_token (cpp_reader *pfile, const cpp_token *tok, location_t loc)
     898              : {
     899        76507 :   gcc_assert (print.streamer);
     900        76507 :   print.streamer->stream (pfile, tok, loc);
     901        76507 : }
     902              : 
     903              : /* Dump out the hash table.  */
     904              : static int
     905       343524 : dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED)
     906              : {
     907       343524 :   if (cpp_user_macro_p (node))
     908              :     {
     909        54531 :       fputs ("#define ", print.outf);
     910        54531 :       fputs ((const char *) cpp_macro_definition (pfile, node),
     911              :              print.outf);
     912        54531 :       putc ('\n', print.outf);
     913        54531 :       print.printed = false;
     914        54531 :       print.src_line++;
     915              :     }
     916              : 
     917       343524 :   return 1;
     918              : }
     919              : 
     920              : /* Load in the PCH file NAME, open on FD.  It was originally searched for
     921              :    by ORIG_NAME.  Also, print out a #include command so that the PCH
     922              :    file can be loaded when the preprocessed output is compiled.  */
     923              : 
     924              : static void
     925           24 : cb_read_pch (cpp_reader *pfile, const char *name,
     926              :              int fd, const char *orig_name ATTRIBUTE_UNUSED)
     927              : {
     928           24 :   c_common_read_pch (pfile, name, fd, orig_name);
     929              : 
     930           24 :   fprintf (print.outf, "#pragma GCC pch_preprocess \"%s\"\n", name);
     931           24 :   print.src_line++;
     932              : 
     933              :   /* The process of reading the PCH has destroyed the frontend parser,
     934              :      so ask the frontend to reinitialize it, in case we need it to
     935              :      process any #pragma directives encountered while preprocessing.  */
     936           24 :   c_init_preprocess ();
     937           24 : }
        

Generated by: LCOV version 2.4-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.