+2020-05-08 Nathan Sidwell <nathan@acm.org>
+
+ Reimplement directives only processing.
+ * c-ppoutput.c (token_streamer): Ne.
+ (directives_only_cb): New. Swallow ...
+ (print_lines_directives_only): ... this.
+ (scan_translation_unit_directives_only): Reimplment using the
+ published interface.
+
2020-05-07 Marek Polacek <polacek@redhat.com>
* c-format.c (badwords): Add "nonstatic".
/* General output routines. */
static void scan_translation_unit (cpp_reader *);
-static void print_lines_directives_only (int, const void *, size_t);
static void scan_translation_unit_directives_only (cpp_reader *);
static void scan_translation_unit_trad (cpp_reader *);
static void account_for_newlines (const unsigned char *, size_t);
print.prev_was_system_token = false;
}
+// FIXME: Ideally we'd just turn the entirety of the print struct into
+// an encapsulated streamer ...
+
+class token_streamer
+{
+ bool avoid_paste;
+ bool do_line_adjustments;
+ bool in_pragma;
+ bool line_marker_emitted;
+
+ public:
+ token_streamer (cpp_reader *pfile)
+ :avoid_paste (false),
+ do_line_adjustments (cpp_get_options (pfile)->lang != CLK_ASM
+ && !flag_no_line_commands),
+ in_pragma (false),
+ line_marker_emitted (false)
+ {
+ }
+
+ void begin_pragma ()
+ {
+ in_pragma = true;
+ }
+
+ void stream (cpp_reader *pfile, const cpp_token *tok, location_t);
+};
+
+void
+token_streamer::stream (cpp_reader *pfile, const cpp_token *token,
+ location_t loc)
+{
+ if (token->type == CPP_PADDING)
+ {
+ avoid_paste = true;
+ if (print.source == NULL
+ || (!(print.source->flags & PREV_WHITE)
+ && token->val.source == NULL))
+ print.source = token->val.source;
+ return;
+ }
+
+ if (token->type == CPP_EOF)
+ return;
+
+ /* Subtle logic to output a space if and only if necessary. */
+ if (avoid_paste)
+ {
+ int src_line = LOCATION_LINE (loc);
+
+ if (print.source == NULL)
+ print.source = token;
+
+ if (src_line != print.src_line
+ && do_line_adjustments
+ && !in_pragma)
+ {
+ line_marker_emitted = do_line_change (pfile, token, loc, false);
+ putc (' ', print.outf);
+ print.printed = true;
+ }
+ else if (print.source->flags & PREV_WHITE
+ || (print.prev
+ && cpp_avoid_paste (pfile, print.prev, token))
+ || (print.prev == NULL && token->type == CPP_HASH))
+ {
+ putc (' ', print.outf);
+ print.printed = true;
+ }
+ }
+ else if (token->flags & PREV_WHITE)
+ {
+ int src_line = LOCATION_LINE (loc);
+
+ if (src_line != print.src_line
+ && do_line_adjustments
+ && !in_pragma)
+ line_marker_emitted = do_line_change (pfile, token, loc, false);
+ putc (' ', print.outf);
+ print.printed = true;
+ }
+
+ avoid_paste = false;
+ print.source = NULL;
+ print.prev = token;
+ if (token->type == CPP_PRAGMA)
+ {
+ const char *space;
+ const char *name;
+
+ line_marker_emitted = maybe_print_line (token->src_loc);
+ fputs ("#pragma ", print.outf);
+ c_pp_lookup_pragma (token->val.pragma, &space, &name);
+ if (space)
+ fprintf (print.outf, "%s %s", space, name);
+ else
+ fprintf (print.outf, "%s", name);
+ print.printed = true;
+ in_pragma = true;
+ }
+ else if (token->type == CPP_PRAGMA_EOL)
+ {
+ maybe_print_line (UNKNOWN_LOCATION);
+ in_pragma = false;
+ }
+ else
+ {
+ if (cpp_get_options (parse_in)->debug)
+ linemap_dump_location (line_table, token->src_loc, print.outf);
+
+ if (do_line_adjustments
+ && !in_pragma
+ && !line_marker_emitted
+ && print.prev_was_system_token != !!in_system_header_at (loc)
+ && !is_location_from_builtin_token (loc))
+ /* The system-ness of this token is different from the one of
+ the previous token. Let's emit a line change to mark the
+ new system-ness before we emit the token. */
+ {
+ do_line_change (pfile, token, loc, false);
+ print.prev_was_system_token = !!in_system_header_at (loc);
+ }
+ cpp_output_token (token, print.outf);
+ line_marker_emitted = false;
+ print.printed = true;
+ }
+
+ /* CPP_COMMENT tokens and raw-string literal tokens can have
+ embedded new-line characters. Rather than enumerating all the
+ possible token types just check if token uses val.str union
+ member. */
+ if (cpp_token_val_index (token) == CPP_TOKEN_FLD_STR)
+ account_for_newlines (token->val.str.text, token->val.str.len);
+}
+
/* Writes out the preprocessed file, handling spacing and paste
avoidance issues. */
static void
}
static void
-print_lines_directives_only (int lines, const void *buf, size_t size)
+directives_only_cb (cpp_reader *pfile, CPP_DO_task task, void *data_, ...)
{
- print.src_line += lines;
- fwrite (buf, 1, size, print.outf);
+ va_list args;
+ va_start (args, data_);
+
+ token_streamer *streamer = reinterpret_cast <token_streamer *> (data_);
+ switch (task)
+ {
+ default:
+ gcc_unreachable ();
+
+ case CPP_DO_print:
+ {
+ print.src_line += va_arg (args, unsigned);
+
+ const void *buf = va_arg (args, const void *);
+ size_t size = va_arg (args, size_t);
+ fwrite (buf, 1, size, print.outf);
+ }
+ break;
+
+ case CPP_DO_location:
+ maybe_print_line (va_arg (args, location_t));
+ break;
+
+ case CPP_DO_token:
+ {
+ const cpp_token *token = va_arg (args, const cpp_token *);
+ location_t spelling_loc = va_arg (args, location_t);
+ streamer->stream (pfile, token, spelling_loc);
+ }
+ break;
+ }
+
+ va_end (args);
}
/* Writes out the preprocessed file, handling spacing and paste
static void
scan_translation_unit_directives_only (cpp_reader *pfile)
{
- struct _cpp_dir_only_callbacks cb;
-
- cb.print_lines = print_lines_directives_only;
- cb.maybe_print_line = maybe_print_line;
-
- _cpp_preprocess_dir_only (pfile, &cb);
+ token_streamer streamer (pfile);
+ cpp_directive_only_process (pfile, &streamer, directives_only_cb);
}
/* Adjust print.src_line for newlines embedded in output. */
putc ('\n', stream);
print.printed = false;
- if (!flag_no_line_commands)
+ if (src_loc != UNKNOWN_LOCATION && !flag_no_line_commands)
{
const char *file_path = LOCATION_FILE (src_loc);
int sysp;
+2020-05-08 Nathan Sidwell <nathan@acm.org>
+
+ * gcc.dg/cpp/counter-[23].c: Move to c-c+_-common/cpp.
+ * gcc.dg/cpp/dir-only-*: Likewise.
+ * c-c++-common/cpp/dir-only-[78].c: New.
+
2020-05-08 Richard Biener <rguenther@suse.de>
* gcc.dg/vect/bb-slp-pr68892.c: Adjust for not supported
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+/* { dg-do preprocess } */
+/* { dg-options -fdirectives-only } */
+
+/* Tests __COUNTER__ macro expansion is disabled inside directives with
+ -fdirectives-only. */
+
+#ifdef __COUNTER__ /* Macro not expanded. */
+#endif
+
+#if __COUNTER__ == 0 /* { dg-error "__COUNTER__ expanded inside directive with -fdirectives-only" } */
+#endif
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+/* { dg-do preprocess } */
+/* { dg-options "-fdirectives-only -fpreprocessed" } */
+
+/* Tests __COUNTER__ macro expansion is enabled outside directives with
+ -fdirectives-only. */
+
+int zero = __COUNTER__;
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+/* { dg-do preprocess } */
+/* { dg-options -fdirectives-only } */
+
+/* Tests scan_translation_unit_directives_only()'s handling of corner cases. */
+
+/* Ignore directives inside block comments...
+#error directive inside block comment
+*/
+
+// Escaped newline doesn't terminate line comment \
+#error directive inside line comment
+
+/* A comment canot start inside a string. */
+const char *c1 = "/*";
+#define NOT_IN_COMMENT
+const char *c2 = "*/";
+#ifndef NOT_IN_COMMENT
+#error Comment started inside a string literal
+#endif
+
+/* Escaped newline handling. */
+int i; \
+#error ignored escaped newline
+ \
+ \
+#define BOL
+#ifndef BOL
+#error escaped newline did not preserve beginning of line
+#endif
+
+/* Handles \\ properly at the end of a string. */
+"string ends in \\"/*
+#error Missed string terminator.
+*/
+
+/* Handles macro expansion in preprocessing directives. */
+#define HEADER "dir-only-1.h"
+#include HEADER
+#ifndef GOT_HEADER
+#error Failed to include header.
+#endif
+
+/\
+*
+#define IN_COMMENT
+*/
+#ifdef IN_COMMENT
+#error Escaped newline breaks block comment initiator.
+#endif
+
+/*
+*\
+/
+#define NOT_IN_COMMENT2
+/**/
+#ifndef NOT_IN_COMMENT2
+#error Escaped newline breaks block comment terminator.
+#endif
+
+/* Test escaped newline inside character escape sequence. */
+"\\
+\"/*
+#error Missed string terminator
+*/
+
+/* Block comments don't mask trailing preprocessing
+ directive. */ #define NOT_MASKED
+#ifndef NOT_MASKED
+#error Comment masks trailing directive.
+#endif
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+#define GOT_HEADER
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+/* { dg-do preprocess } */
+/* { dg-options "-fpreprocessed -fdirectives-only -DNOT_SET" } */
+
+/* Tests -fdirectives-only + -fpreprocessed. */
+
+/* Check this is not defined. */
+#ifdef NOT_SET
+#error Command line macro not disabled.
+#endif
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+/* { dg-do preprocess } */
+/* { dg-options "-fdirectives-only -H" } */
+/* { dg-message "dir-only-3a\.h\n\[^\n\]*dir-only-3b\.h\n\[^\n\]*dir-only-3a\.h\n" "include guard check" { target *-*-* } 0 } */
+
+/* Tests include guards. */
+
+#include "dir-only-3a.h"
+#include "dir-only-3b.h"
+#include "dir-only-3b.h"
+#include "dir-only-3a.h"
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+extern int outside_guard
+
+#ifndef DIR_ONLY_3A_H
+#define DIR_ONLY_3A_H
+#endif
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+#ifndef DIR_ONLY_3B_H
+#define DIR_ONLY_3B_H
+
+extern int inside guard;
+
+#endif
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+/* { dg-do preprocess } */
+/* { dg-options "-fdirectives-only -Wunused-macros" } */
+/* { dg-error "'-fdirectives-only' is incompatible with '-Wunused-macros'\n" "'-Wunused-macros' check" { target *-*-* } 0 } */
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+/* C++ silently ignores traditional! */
+/* { dg-do preprocess { target c } } */
+/* { dg-options "-fdirectives-only -traditional" } */
+/* { dg-error "'-fdirectives-only' is incompatible with '-traditional'\n" "'-traditional' check" { target *-*-* } 0 } */
--- /dev/null
+/* Copyright 2007 Free Software Foundation, Inc.
+ Contributed by Ollie Wild <aaw@google.com>. */
+
+/* { dg-do preprocess } */
+/* { dg-options -fdirectives-only } */
+
+/* { dg-error "unterminated comment" }
--- /dev/null
+// { dg-do preprocess }
+// { dg-options "-std=c++11" { target c++ } }
+// { dg-options "-std=gnu99" { target c } }
+// { dg-additional-options -fdirectives-only }
+
+R"stuff(
+)nope"
+#error in raw literal
+)stuff"
+// comment
+#define bob 1
+// " comment
+#if !bob
+#error "no bob"
+#endif
+
+bob\
+\
+R"regular string not an erroneous raw one"
+
+"regular"R"***(not a raw string"
+#define HERE 1
+ //)***"
+#ifndef HERE
+#error "oops no HERE"
+#endif
+ /* comment */
+
+
+0e+R"*(not a raw string"
+#define CPP_NUM 1
+ //)*"
+#ifndef CPP_NUM
+#error "oops no CPP_NUM"
+#endif
--- /dev/null
+// { dg-do preprocess { target c++ } }
+// { dg-options "-std=c++14" }
+// { dg-additional-options -fdirectives-only }
+
+012'bcd
+#define A 1
+// '
+#ifndef A
+#error Fell into first char const
+#endif
+enum { A = 195'936'478 }; 'a'
+#define AA 1
+ // 'a
+#ifndef AA
+#error Fell into early char const
+#endif
+
+012\
+'bcd
+#define B 1
+// '
+#ifndef B
+#error Fell into second char const
+#endif
+
+.012'b
+#define C 1
+// '
+#ifndef C
+#error Fell into third char const
+#endif
+
+.0e+12'b
+#define D 1
+// '
+#ifndef D
+#error Fell into fourth char const
+#endif
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-/* { dg-do preprocess } */
-/* { dg-options -fdirectives-only } */
-
-/* Tests __COUNTER__ macro expansion is disabled inside directives with
- -fdirectives-only. */
-
-#ifdef __COUNTER__ /* Macro not expanded. */
-#endif
-
-#if __COUNTER__ == 0 /* { dg-error "__COUNTER__ expanded inside directive with -fdirectives-only" } */
-#endif
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-/* { dg-do preprocess } */
-/* { dg-options "-fdirectives-only -fpreprocessed" } */
-
-/* Tests __COUNTER__ macro expansion is enabled outside directives with
- -fdirectives-only. */
-
-int zero = __COUNTER__;
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-/* { dg-do preprocess } */
-/* { dg-options -fdirectives-only } */
-
-/* Tests scan_translation_unit_directives_only()'s handling of corner cases. */
-
-/* Ignore directives inside block comments...
-#error directive inside block comment
-*/
-
-// Escaped newline doesn't terminate line comment \
-#error directive inside line comment
-
-/* A comment canot start inside a string. */
-const char *c1 = "/*";
-#define NOT_IN_COMMENT
-const char *c2 = "*/";
-#ifndef NOT_IN_COMMENT
-#error Comment started inside a string literal
-#endif
-
-/* Escaped newline handling. */
-int i; \
-#error ignored escaped newline
- \
- \
-#define BOL
-#ifndef BOL
-#error escaped newline did not preserve beginning of line
-#endif
-
-/* Handles \\ properly at the end of a string. */
-"string ends in \\"/*
-#error Missed string terminator.
-*/
-
-/* Handles macro expansion in preprocessing directives. */
-#define HEADER "dir-only-1.h"
-#include HEADER
-#ifndef GOT_HEADER
-#error Failed to include header.
-#endif
-
-/\
-*
-#define IN_COMMENT
-*/
-#ifdef IN_COMMENT
-#error Escaped newline breaks block comment initiator.
-#endif
-
-/*
-*\
-/
-#define NOT_IN_COMMENT2
-/**/
-#ifndef NOT_IN_COMMENT2
-#error Escaped newline breaks block comment terminator.
-#endif
-
-/* Test escaped newline inside character escape sequence. */
-"\\
-\"/*
-#error Missed string terminator
-*/
-
-/* Block comments don't mask trailing preprocessing
- directive. */ #define NOT_MASKED
-#ifndef NOT_MASKED
-#error Comment masks trailing directive.
-#endif
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-#define GOT_HEADER
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-/* { dg-do preprocess } */
-/* { dg-options "-fpreprocessed -fdirectives-only -DNOT_SET" } */
-
-/* Tests -fdirectives-only + -fpreprocessed. */
-
-/* Check this is not defined. */
-#ifdef NOT_SET
-#error Command line macro not disabled.
-#endif
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-/* { dg-do preprocess } */
-/* { dg-options "-fdirectives-only -H" } */
-/* { dg-message "dir-only-3a\.h\n\[^\n\]*dir-only-3b\.h\n\[^\n\]*dir-only-3a\.h\n" "include guard check" { target *-*-* } 0 } */
-
-/* Tests include guards. */
-
-#include "dir-only-3a.h"
-#include "dir-only-3b.h"
-#include "dir-only-3b.h"
-#include "dir-only-3a.h"
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-extern int outside_guard
-
-#ifndef DIR_ONLY_3A_H
-#define DIR_ONLY_3A_H
-#endif
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-#ifndef DIR_ONLY_3B_H
-#define DIR_ONLY_3B_H
-
-extern int inside guard;
-
-#endif
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-/* { dg-do preprocess } */
-/* { dg-options "-fdirectives-only -Wunused-macros" } */
-/* { dg-error "'-fdirectives-only' is incompatible with '-Wunused-macros'\n" "'-Wunused-macros' check" { target *-*-* } 0 } */
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-/* { dg-do preprocess } */
-/* { dg-options "-fdirectives-only -traditional" } */
-/* { dg-error "'-fdirectives-only' is incompatible with '-traditional'\n" "'-traditional' check" { target *-*-* } 0 } */
+++ /dev/null
-/* Copyright 2007 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>. */
-
-/* { dg-do preprocess } */
-/* { dg-options -fdirectives-only } */
-
-/* { dg-error "unterminated comment" }
+2020-05-08 Nathan Sidwell <nathan@acm.org>
+
+ Reimplement directives only processing, support raw literals.
+ * directives-only.c: Delete.
+ * Makefile.in (libcpp_a_OBJS, libcpp_a_SOURCES): Remove it.
+ * include/cpplib.h (enum CPP_DO_task): New enum.
+ (cpp_directive_only_preprocess): Declare.
+ * internal.h (_cpp_dir_only_callbacks): Delete.
+ (_cpp_preprocess_dir_only): Delete.
+ * lex.c (do_peek_backslask, do_peek_next, do_peek_prev): New.
+ (cpp_directives_only_process): New implementation.
+
2020-02-14 Jakub Jelinek <jakub@redhat.com>
Partially implement P1042R1: __VA_OPT__ wording clarifications
DEPMODE = $(CXXDEPMODE)
-libcpp_a_OBJS = charset.o directives.o directives-only.o errors.o \
+libcpp_a_OBJS = charset.o directives.o errors.o \
expr.o files.o identifiers.o init.o lex.o line-map.o macro.o \
mkdeps.o pch.o symtab.o traditional.o
-libcpp_a_SOURCES = charset.c directives.c directives-only.c errors.c \
+libcpp_a_SOURCES = charset.c directives.c errors.c \
expr.c files.c identifiers.c init.c lex.c line-map.c macro.c \
mkdeps.c pch.c symtab.c traditional.c
+++ /dev/null
-/* CPP Library - directive only preprocessing for distributed compilation.
- Copyright (C) 2007-2020 Free Software Foundation, Inc.
- Contributed by Ollie Wild <aaw@google.com>.
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 3, or (at your option) any
-later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "cpplib.h"
-#include "internal.h"
-
-/* DO (Directive only) flags. */
-#define DO_BOL (1 << 0) /* At the beginning of a logical line. */
-#define DO_STRING (1 << 1) /* In a string constant. */
-#define DO_CHAR (1 << 2) /* In a character constant. */
-#define DO_BLOCK_COMMENT (1 << 3) /* In a block comment. */
-#define DO_LINE_COMMENT (1 << 4) /* In a single line "//-style" comment. */
-
-#define DO_LINE_SPECIAL (DO_STRING | DO_CHAR | DO_LINE_COMMENT)
-#define DO_SPECIAL (DO_LINE_SPECIAL | DO_BLOCK_COMMENT)
-
-/* Writes out the preprocessed file, handling spacing and paste
- avoidance issues. */
-void
-_cpp_preprocess_dir_only (cpp_reader *pfile,
- const struct _cpp_dir_only_callbacks *cb)
-{
- struct cpp_buffer *buffer;
- const unsigned char *cur, *base, *next_line, *rlimit;
- cppchar_t c, last_c;
- unsigned flags;
- linenum_type lines;
- int col;
- location_t loc;
-
- restart:
- /* Buffer initialization ala _cpp_clean_line(). */
- buffer = pfile->buffer;
- buffer->cur_note = buffer->notes_used = 0;
- buffer->cur = buffer->line_base = buffer->next_line;
- buffer->need_line = false;
-
- /* This isn't really needed. It prevents a compiler warning, though. */
- loc = pfile->line_table->highest_line;
-
- /* Scan initialization. */
- next_line = cur = base = buffer->cur;
- rlimit = buffer->rlimit;
- flags = DO_BOL;
- lines = 0;
- col = 1;
-
- for (last_c = '\n', c = *cur; cur < rlimit; last_c = c, c = *++cur, ++col)
- {
- /* Skip over escaped newlines. */
- if (__builtin_expect (c == '\\', false))
- {
- const unsigned char *tmp = cur + 1;
-
- while (is_nvspace (*tmp) && tmp < rlimit)
- tmp++;
- if (*tmp == '\r')
- tmp++;
- if (*tmp == '\n' && tmp < rlimit)
- {
- CPP_INCREMENT_LINE (pfile, 0);
- lines++;
- col = 0;
- cur = tmp;
- c = last_c;
- continue;
- }
- }
-
- if (__builtin_expect (last_c == '#', false) && !(flags & DO_SPECIAL))
- {
- if (c != '#' && (flags & DO_BOL))
- {
- class line_maps *line_table;
-
- if (!pfile->state.skipping && next_line != base)
- cb->print_lines (lines, base, next_line - base);
-
- /* Prep things for directive handling. */
- buffer->next_line = cur;
- buffer->need_line = true;
- _cpp_get_fresh_line (pfile);
-
- /* Ensure proper column numbering for generated error messages. */
- buffer->line_base -= col - 1;
-
- _cpp_handle_directive (pfile, false /* ignore indented */);
-
- /* Sanitize the line settings. Duplicate #include's can mess
- things up. */
- line_table = pfile->line_table;
- line_table->highest_location = line_table->highest_line;
-
- /* The if block prevents us from outputing line information when
- the file ends with a directive and no newline. Note that we
- must use pfile->buffer, not buffer. */
- if (pfile->buffer->next_line < pfile->buffer->rlimit)
- cb->maybe_print_line (pfile->line_table->highest_line);
-
- goto restart;
- }
-
- flags &= ~DO_BOL;
- pfile->mi_valid = false;
- }
- else if (__builtin_expect (last_c == '/', false) \
- && !(flags & DO_SPECIAL) && c != '*' && c != '/')
- {
- /* If a previous slash is not starting a block comment, clear the
- DO_BOL flag. */
- flags &= ~DO_BOL;
- pfile->mi_valid = false;
- }
-
- switch (c)
- {
- case '/':
- if ((flags & DO_BLOCK_COMMENT) && last_c == '*')
- {
- flags &= ~DO_BLOCK_COMMENT;
- c = 0;
- }
- else if (!(flags & DO_SPECIAL) && last_c == '/')
- flags |= DO_LINE_COMMENT;
- else if (!(flags & DO_SPECIAL))
- /* Mark the position for possible error reporting. */
- loc = linemap_position_for_column (pfile->line_table, col);
-
- break;
-
- case '*':
- if (!(flags & DO_SPECIAL))
- {
- if (last_c == '/')
- flags |= DO_BLOCK_COMMENT;
- else
- {
- flags &= ~DO_BOL;
- pfile->mi_valid = false;
- }
- }
-
- break;
-
- case '\'':
- case '"':
- {
- unsigned state = (c == '"') ? DO_STRING : DO_CHAR;
-
- if (!(flags & DO_SPECIAL))
- {
- flags |= state;
- flags &= ~DO_BOL;
- pfile->mi_valid = false;
- }
- else if ((flags & state) && last_c != '\\')
- flags &= ~state;
-
- break;
- }
-
- case '\\':
- {
- if ((flags & (DO_STRING | DO_CHAR)) && last_c == '\\')
- c = 0;
-
- if (!(flags & DO_SPECIAL))
- {
- flags &= ~DO_BOL;
- pfile->mi_valid = false;
- }
-
- break;
- }
-
- case '\n':
- CPP_INCREMENT_LINE (pfile, 0);
- lines++;
- col = 0;
- flags &= ~DO_LINE_SPECIAL;
- if (!(flags & DO_SPECIAL))
- flags |= DO_BOL;
- break;
-
- case '#':
- next_line = cur;
- /* Don't update DO_BOL yet. */
- break;
-
- case ' ': case '\t': case '\f': case '\v': case '\0':
- break;
-
- default:
- if (!(flags & DO_SPECIAL))
- {
- flags &= ~DO_BOL;
- pfile->mi_valid = false;
- }
- break;
- }
- }
-
- if (flags & DO_BLOCK_COMMENT)
- cpp_error_with_line (pfile, CPP_DL_ERROR, loc, 0, "unterminated comment");
-
- if (!pfile->state.skipping && cur != base)
- {
- /* If the file was not newline terminated, add rlimit, which is
- guaranteed to point to a newline, to the end of our range. */
- if (cur[-1] != '\n')
- {
- cur++;
- CPP_INCREMENT_LINE (pfile, 0);
- lines++;
- }
-
- cb->print_lines (lines, base, cur - base);
- }
-
- _cpp_pop_buffer (pfile);
- if (pfile->buffer)
- goto restart;
-}
/* In lex.c */
extern void cpp_force_token_locations (cpp_reader *, location_t);
extern void cpp_stop_forcing_token_locations (cpp_reader *);
+enum CPP_DO_task
+{
+ CPP_DO_print,
+ CPP_DO_location,
+ CPP_DO_token
+};
+
+extern void cpp_directive_only_process (cpp_reader *pfile,
+ void *data,
+ void (*cb) (cpp_reader *,
+ CPP_DO_task,
+ void *data, ...));
/* In expr.c */
extern enum cpp_ttype cpp_userdef_string_remove_type
extern void _cpp_pop_buffer (cpp_reader *);
extern char *_cpp_bracket_include (cpp_reader *);
-/* In directives.c */
-struct _cpp_dir_only_callbacks
-{
- /* Called to print a block of lines. */
- void (*print_lines) (int, const void *, size_t);
- bool (*maybe_print_line) (location_t);
-};
-
-extern void _cpp_preprocess_dir_only (cpp_reader *,
- const struct _cpp_dir_only_callbacks *);
-
/* In traditional.c. */
extern bool _cpp_scan_out_logical_line (cpp_reader *, cpp_macro *, bool);
extern bool _cpp_read_logical_line_trad (cpp_reader *);
{
r->forced_token_location = 0;
}
+
+/* We're looking at \, if it's escaping EOL, look past it. If at
+ LIMIT, don't advance. */
+
+static const unsigned char *
+do_peek_backslash (const unsigned char *peek, const unsigned char *limit)
+{
+ const unsigned char *probe = peek;
+
+ if (__builtin_expect (peek[1] == '\n', true))
+ {
+ eol:
+ probe += 2;
+ if (__builtin_expect (probe < limit, true))
+ {
+ peek = probe;
+ if (*peek == '\\')
+ /* The user might be perverse. */
+ return do_peek_backslash (peek, limit);
+ }
+ }
+ else if (__builtin_expect (peek[1] == '\r', false))
+ {
+ if (probe[2] == '\n')
+ probe++;
+ goto eol;
+ }
+
+ return peek;
+}
+
+static const unsigned char *
+do_peek_next (const unsigned char *peek, const unsigned char *limit)
+{
+ if (__builtin_expect (*peek == '\\', false))
+ peek = do_peek_backslash (peek, limit);
+ return peek;
+}
+
+static const unsigned char *
+do_peek_prev (const unsigned char *peek, const unsigned char *bound)
+{
+ if (peek == bound)
+ return NULL;
+
+ unsigned char c = *--peek;
+ if (__builtin_expect (c == '\n', false)
+ || __builtin_expect (c == 'r', false))
+ {
+ if (peek == bound)
+ return peek;
+ int ix = -1;
+ if (c == '\n' && peek[ix] == '\r')
+ {
+ if (peek + ix == bound)
+ return peek;
+ ix--;
+ }
+
+ if (peek[ix] == '\\')
+ return do_peek_prev (peek + ix, bound);
+
+ return peek;
+ }
+ else
+ return peek;
+}
+
+/* Directives-only scanning. Somewhat more relaxed than correct
+ parsing -- some ill-formed programs will not be rejected. */
+
+void
+cpp_directive_only_process (cpp_reader *pfile,
+ void *data,
+ void (*cb) (cpp_reader *, CPP_DO_task, void *, ...))
+{
+ do
+ {
+ restart:
+ /* Buffer initialization, but no line cleaning. */
+ cpp_buffer *buffer = pfile->buffer;
+ buffer->cur_note = buffer->notes_used = 0;
+ buffer->cur = buffer->line_base = buffer->next_line;
+ buffer->need_line = false;
+ /* Files always end in a newline. We rely on this for
+ character peeking safety. */
+ gcc_assert (buffer->rlimit[-1] == '\n');
+
+ const unsigned char *base = buffer->cur;
+ unsigned line_count = 0;
+ const unsigned char *line_start = base;
+
+ bool bol = true;
+ bool raw = false;
+
+ const unsigned char *lwm = base;
+ for (const unsigned char *pos = base, *limit = buffer->rlimit;
+ pos < limit;)
+ {
+ unsigned char c = *pos++;
+ /* This matches the switch in _cpp_lex_direct. */
+ switch (c)
+ {
+ case ' ': case '\t': case '\f': case '\v':
+ /* Whitespace, do nothing. */
+ break;
+
+ case '\r': /* MAC line ending, or Windows \r\n */
+ if (*pos == '\n')
+ pos++;
+ /* FALLTHROUGH */
+
+ case '\n':
+ bol = true;
+
+ next_line:
+ CPP_INCREMENT_LINE (pfile, 0);
+ line_count++;
+ line_start = pos;
+ break;
+
+ case '\\':
+ /* <backslash><newline> is removed, and doesn't undo any
+ preceeding escape or whatnot. */
+ if (*pos == '\n')
+ {
+ pos++;
+ goto next_line;
+ }
+ else if (*pos == '\r')
+ {
+ if (pos[1] == '\n')
+ pos++;
+ pos++;
+ goto next_line;
+ }
+ goto dflt;
+
+ case '#':
+ if (bol)
+ {
+ /* Line directive. */
+ if (pos - 1 > base && !pfile->state.skipping)
+ cb (pfile, CPP_DO_print, data,
+ line_count, base, pos - 1 - base);
+
+ /* Prep things for directive handling. */
+ buffer->next_line = pos;
+ buffer->need_line = true;
+ _cpp_get_fresh_line (pfile);
+
+ /* Ensure proper column numbering for generated
+ error messages. */
+ buffer->line_base -= pos - line_start;
+
+ _cpp_handle_directive (pfile, line_start + 1 != pos);
+
+ /* Sanitize the line settings. Duplicate #include's can
+ mess things up. */
+ // FIXME: Necessary?
+ pfile->line_table->highest_location
+ = pfile->line_table->highest_line;
+
+ if (!pfile->state.skipping
+ && pfile->buffer->next_line < pfile->buffer->rlimit)
+ cb (pfile, CPP_DO_location, data,
+ pfile->line_table->highest_line);
+
+ goto restart;
+ }
+ goto dflt;
+
+ case '/':
+ {
+ const unsigned char *peek = do_peek_next (pos, limit);
+ if (!(*peek == '/' || *peek == '*'))
+ goto dflt;
+
+ /* Line or block comment */
+ bool is_block = *peek == '*';
+ bool star = false;
+ bool esc = false;
+ location_t sloc
+ = linemap_position_for_column (pfile->line_table,
+ pos - line_start);
+
+ while (pos < limit)
+ {
+ char c = *pos++;
+ switch (c)
+ {
+ case '\\':
+ esc = true;
+ break;
+
+ case '\r':
+ if (*pos == '\n')
+ pos++;
+ /* FALLTHROUGH */
+
+ case '\n':
+ {
+ CPP_INCREMENT_LINE (pfile, 0);
+ line_count++;
+ line_start = pos;
+ if (!esc && !is_block)
+ {
+ bol = true;
+ goto done_comment;
+ }
+ }
+ if (!esc)
+ star = false;
+ esc = false;
+ break;
+
+ case '*':
+ if (pos > peek && !esc)
+ star = is_block;
+ esc = false;
+ break;
+
+ case '/':
+ if (star)
+ goto done_comment;
+ /* FALLTHROUGH */
+
+ default:
+ star = false;
+ esc = false;
+ break;
+ }
+ }
+ cpp_error_with_line (pfile, CPP_DL_ERROR, sloc, 0,
+ "unterminated comment");
+ done_comment:
+ lwm = pos;
+ break;
+ }
+
+ case '\'':
+ if (!CPP_OPTION (pfile, digit_separators))
+ goto delimited_string;
+
+ /* Possibly a number punctuator. */
+ if (!ISIDNUM (*do_peek_next (pos, limit)))
+ goto delimited_string;
+
+ goto quote_peek;
+
+ case '\"':
+ if (!CPP_OPTION (pfile, rliterals))
+ goto delimited_string;
+
+ quote_peek:
+ {
+ /* For ' see if it's a number punctuator
+ \.?<digit>(<digit>|<identifier-nondigit>
+ |'<digit>|'<nondigit>|[eEpP]<sign>|\.)* */
+ /* For " see if it's a raw string
+ {U,L,u,u8}R. This includes CPP_NUMBER detection,
+ because that could be 0e+R. */
+ const unsigned char *peek = pos - 1;
+ bool quote_first = c == '"';
+ bool quote_eight = false;
+ bool maybe_number_start = false;
+ bool want_number = false;
+
+ while ((peek = do_peek_prev (peek, lwm)))
+ {
+ unsigned char p = *peek;
+ if (quote_first)
+ {
+ if (!raw)
+ {
+ if (p != 'R')
+ break;
+ raw = true;
+ continue;
+ }
+
+ quote_first = false;
+ if (p == 'L' || p == 'U' || p == 'u')
+ ;
+ else if (p == '8')
+ quote_eight = true;
+ else
+ goto second_raw;
+ }
+ else if (quote_eight)
+ {
+ if (p != 'u')
+ {
+ raw = false;
+ break;
+ }
+ quote_eight = false;
+ }
+ else if (c == '"')
+ {
+ second_raw:;
+ if (!want_number && ISIDNUM (p))
+ {
+ raw = false;
+ break;
+ }
+ }
+
+ if (ISDIGIT (p))
+ maybe_number_start = true;
+ else if (p == '.')
+ want_number = true;
+ else if (ISIDNUM (p))
+ maybe_number_start = false;
+ else if (p == '+' || p == '-')
+ {
+ if (const unsigned char *peek_prev
+ = do_peek_prev (peek, lwm))
+ {
+ p = *peek_prev;
+ if (p == 'e' || p == 'E'
+ || p == 'p' || p == 'P')
+ {
+ want_number = true;
+ maybe_number_start = false;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else if (p == '\'' || p == '\"')
+ {
+ /* If this is lwm, this must be the end of a
+ previous string. So this is a trailing
+ literal type, (a) if those are allowed,
+ and (b) maybe_start is false. Otherwise
+ this must be a CPP_NUMBER because we've
+ met another ', and we'd have checked that
+ in its own right. */
+ if (peek == lwm && CPP_OPTION (pfile, uliterals))
+ {
+ if (!maybe_number_start && !want_number)
+ /* Must be a literal type. */
+ raw = false;
+ }
+ else if (p == '\''
+ && CPP_OPTION (pfile, digit_separators))
+ maybe_number_start = true;
+ break;
+ }
+ else if (c == '\'')
+ break;
+ else if (!quote_first && !quote_eight)
+ break;
+ }
+
+ if (maybe_number_start)
+ {
+ if (c == '\'')
+ /* A CPP NUMBER. */
+ goto dflt;
+ raw = false;
+ }
+
+ goto delimited_string;
+ }
+
+ delimited_string:
+ {
+ /* (Possibly raw) string or char literal. */
+ unsigned char end = c;
+ int delim_len = -1;
+ const unsigned char *delim = NULL;
+ location_t sloc = linemap_position_for_column (pfile->line_table,
+ pos - line_start);
+ int esc = 0;
+
+ if (raw)
+ {
+ /* There can be no line breaks in the delimiter. */
+ delim = pos;
+ for (delim_len = 0; (c = *pos++) != '('; delim_len++)
+ {
+ if (delim_len == 16)
+ {
+ cpp_error_with_line (pfile, CPP_DL_ERROR,
+ sloc, 0,
+ "raw string delimiter"
+ " longer than %d"
+ " characters",
+ delim_len);
+ raw = false;
+ pos = delim;
+ break;
+ }
+ if (strchr (") \\\t\v\f\n", c))
+ {
+ cpp_error_with_line (pfile, CPP_DL_ERROR,
+ sloc, 0,
+ "invalid character '%c'"
+ " in raw string"
+ " delimiter", c);
+ raw = false;
+ pos = delim;
+ break;
+ }
+ if (pos >= limit)
+ goto bad_string;
+ }
+ }
+
+ while (pos < limit)
+ {
+ char c = *pos++;
+ switch (c)
+ {
+ case '\\':
+ if (!raw)
+ esc++;
+ break;
+
+ case '\r':
+ if (*pos == '\n')
+ pos++;
+ /* FALLTHROUGH */
+
+ case '\n':
+ {
+ CPP_INCREMENT_LINE (pfile, 0);
+ line_count++;
+ line_start = pos;
+ }
+ if (esc)
+ esc--;
+ break;
+
+ case ')':
+ if (raw
+ && pos + delim_len + 1 < limit
+ && pos[delim_len] == end
+ && !memcmp (delim, pos, delim_len))
+ {
+ pos += delim_len + 1;
+ raw = false;
+ goto done_string;
+ }
+ break;
+
+ default:
+ if (!raw && !(esc & 1) && c == end)
+ goto done_string;
+ esc = 0;
+ break;
+ }
+ }
+ bad_string:
+ cpp_error_with_line (pfile, CPP_DL_ERROR, sloc, 0,
+ "unterminated literal");
+
+ done_string:
+ raw = false;
+ lwm = pos - 1;
+ }
+ goto dflt;
+
+ default:
+ dflt:
+ bol = false;
+ pfile->mi_valid = false;
+ break;
+ }
+ }
+
+ if (buffer->rlimit > base && !pfile->state.skipping)
+ cb (pfile, CPP_DO_print, data, line_count, base, buffer->rlimit - base);
+
+ _cpp_pop_buffer (pfile);
+ }
+ while (pfile->buffer);
+}