aboutsummaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2020-10-08 12:11:37 -0700
committerNathan Sidwell <nathan@acm.org>2020-10-08 12:16:21 -0700
commitd1c566d72d9361b37213881222c7e2713cdf05b7 (patch)
treeaa7640d9fb655ceb26caddbd903344fb6662a1e1 /libcpp
parentcd23ed8af236db2d28314e0652d04e5a0e1540b6 (diff)
downloadgcc-d1c566d72d9361b37213881222c7e2713cdf05b7.zip
gcc-d1c566d72d9361b37213881222c7e2713cdf05b7.tar.gz
gcc-d1c566d72d9361b37213881222c7e2713cdf05b7.tar.bz2
libcpp: Directly peek for initial line marker
Using the tokenizer to sniff for an initial line marker for preprocessed input is a little brittle, particularly with -fdirectives-only. If there is no marker we'll happily munch initial comments. This patch directly sniffs the buffer. This is safe because the initial line marker was machine generated and must be right at the beginning of the file. Anything else is not such a line marker. The same is true for the initial directory marker. For that tokenizing the string is simplest, but at that point it's either a regular line marker or a directory marker. If it's a regular marker, unwinding tokens is fine. libcpp/ * internal.h (enum include_type): Rename IT_MAIN_INJECT to IT_PRE_MAIN. * init.c (cpp_read_main_file): If there is no line marker, adjust the initial line marker. (read_original_filename): Return bool, peek the buffer directly before trying to tokenize. (read_original_directory): Likewise. Directly prod the string literal. * files.c (_cpp_stack_file): Adjust for IT_PRE_MAIN change.
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/files.c10
-rw-r--r--libcpp/init.c142
-rw-r--r--libcpp/internal.h4
3 files changed, 89 insertions, 67 deletions
diff --git a/libcpp/files.c b/libcpp/files.c
index b890b8e..5af4136 100644
--- a/libcpp/files.c
+++ b/libcpp/files.c
@@ -948,10 +948,12 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type,
/* Add line map and do callbacks. */
_cpp_do_file_change (pfile, LC_ENTER, file->path,
- /* With preamble injection, start on line zero, so
- the preamble doesn't appear to have been
- included from line 1. */
- type == IT_MAIN_INJECT ? 0 : 1, sysp);
+ /* With preamble injection, start on line zero,
+ so the preamble doesn't appear to have been
+ included from line 1. Likewise when
+ starting preprocessed, we expect an initial
+ locating line. */
+ type == IT_PRE_MAIN ? 0 : 1, sysp);
return true;
}
diff --git a/libcpp/init.c b/libcpp/init.c
index aba5854..84c0a9e 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -36,7 +36,7 @@ along with this program; see the file COPYING3. If not see
static void init_library (void);
static void mark_named_operators (cpp_reader *, int);
-static void read_original_filename (cpp_reader *);
+static bool read_original_filename (cpp_reader *);
static void read_original_directory (cpp_reader *);
static void post_options (cpp_reader *);
@@ -681,94 +681,114 @@ cpp_read_main_file (cpp_reader *pfile, const char *fname, bool injecting)
return NULL;
_cpp_stack_file (pfile, pfile->main_file,
- injecting ? IT_MAIN_INJECT : IT_MAIN, 0);
+ injecting || CPP_OPTION (pfile, preprocessed)
+ ? IT_PRE_MAIN : IT_MAIN, 0);
/* For foo.i, read the original filename foo.c now, for the benefit
of the front ends. */
if (CPP_OPTION (pfile, preprocessed))
- read_original_filename (pfile);
+ if (!read_original_filename (pfile))
+ {
+ /* We're on line 1 after all. */
+ auto *last = linemap_check_ordinary
+ (LINEMAPS_LAST_MAP (pfile->line_table, false));
+ last->to_line = 1;
+ /* Inform of as-if a file change. */
+ _cpp_do_file_change (pfile, LC_RENAME_VERBATIM, LINEMAP_FILE (last),
+ LINEMAP_LINE (last), LINEMAP_SYSP (last));
+ }
return ORDINARY_MAP_FILE_NAME (LINEMAPS_LAST_ORDINARY_MAP (pfile->line_table));
}
-/* For preprocessed files, if the first tokens are of the form # NUM.
- handle the directive so we know the original file name. This will
- generate file_change callbacks, which the front ends must handle
- appropriately given their state of initialization. */
-static void
+/* For preprocessed files, if the very first characters are
+ '#<SPACE>[01]<SPACE>', then handle a line directive so we know the
+ original file name. This will generate file_change callbacks,
+ which the front ends must handle appropriately given their state of
+ initialization. We peek directly into the character buffer, so
+ that we're not confused by otherwise-skipped white space &
+ comments. We can be very picky, because this should have been
+ machine-generated text (by us, no less). This way we do not
+ interfere with the module directive state machine. */
+
+static bool
read_original_filename (cpp_reader *pfile)
{
- const cpp_token *token, *token1;
-
- /* Lex ahead; if the first tokens are of the form # NUM, then
- process the directive, otherwise back up. */
- token = _cpp_lex_direct (pfile);
- if (token->type == CPP_HASH)
+ auto *buf = pfile->buffer->next_line;
+
+ if (pfile->buffer->rlimit - buf > 4
+ && buf[0] == '#'
+ && buf[1] == ' '
+ // Also permit '1', as that's what used to be here
+ && (buf[2] == '0' || buf[2] == '1')
+ && buf[3] == ' ')
{
- pfile->state.in_directive = 1;
- token1 = _cpp_lex_direct (pfile);
- _cpp_backup_tokens (pfile, 1);
- pfile->state.in_directive = 0;
-
- /* If it's a #line directive, handle it. */
- if (token1->type == CPP_NUMBER
- && _cpp_handle_directive (pfile, token->flags & PREV_WHITE))
+ const cpp_token *token = _cpp_lex_direct (pfile);
+ gcc_checking_assert (token->type == CPP_HASH);
+ if (_cpp_handle_directive (pfile, token->flags & PREV_WHITE))
{
read_original_directory (pfile);
- return;
+ return true;
}
}
- /* Backup as if nothing happened. */
- _cpp_backup_tokens (pfile, 1);
+ return false;
}
/* For preprocessed files, if the tokens following the first filename
line is of the form # <line> "/path/name//", handle the
- directive so we know the original current directory. */
+ directive so we know the original current directory.
+
+ As with the first line peeking, we can do this without lexing by
+ being picky. */
static void
read_original_directory (cpp_reader *pfile)
{
- const cpp_token *hash, *token;
-
- /* Lex ahead; if the first tokens are of the form # NUM, then
- process the directive, otherwise back up. */
- hash = _cpp_lex_direct (pfile);
- if (hash->type != CPP_HASH)
+ auto *buf = pfile->buffer->next_line;
+
+ if (pfile->buffer->rlimit - buf > 4
+ && buf[0] == '#'
+ && buf[1] == ' '
+ // Also permit '1', as that's what used to be here
+ && (buf[2] == '0' || buf[2] == '1')
+ && buf[3] == ' ')
{
- _cpp_backup_tokens (pfile, 1);
- return;
- }
-
- token = _cpp_lex_direct (pfile);
+ const cpp_token *hash = _cpp_lex_direct (pfile);
+ gcc_checking_assert (hash->type == CPP_HASH);
+ pfile->state.in_directive = 1;
+ const cpp_token *number = _cpp_lex_direct (pfile);
+ gcc_checking_assert (number->type == CPP_NUMBER);
+ const cpp_token *string = _cpp_lex_direct (pfile);
+ pfile->state.in_directive = 0;
- if (token->type != CPP_NUMBER)
- {
- _cpp_backup_tokens (pfile, 2);
- return;
- }
+ const unsigned char *text = nullptr;
+ size_t len = 0;
+ if (string->type == CPP_STRING)
+ {
+ /* The string value includes the quotes. */
+ text = string->val.str.text;
+ len = string->val.str.len;
+ }
+ if (len < 5
+ || !IS_DIR_SEPARATOR (text[len - 2])
+ || !IS_DIR_SEPARATOR (text[len - 3]))
+ {
+ /* That didn't work out, back out. */
+ _cpp_backup_tokens (pfile, 3);
+ return;
+ }
- token = _cpp_lex_direct (pfile);
+ if (pfile->cb.dir_change)
+ {
+ /* Smash the string directly, it's dead at this point */
+ char *smashy = (char *)text;
+ smashy[len - 3] = 0;
+
+ pfile->cb.dir_change (pfile, smashy + 1);
+ }
- if (token->type != CPP_STRING
- || ! (token->val.str.len >= 5
- && IS_DIR_SEPARATOR (token->val.str.text[token->val.str.len-2])
- && IS_DIR_SEPARATOR (token->val.str.text[token->val.str.len-3])))
- {
- _cpp_backup_tokens (pfile, 3);
- return;
+ /* We should be at EOL. */
}
-
- if (pfile->cb.dir_change)
- {
- char *debugdir = (char *) alloca (token->val.str.len - 3);
-
- memcpy (debugdir, (const char *) token->val.str.text + 1,
- token->val.str.len - 4);
- debugdir[token->val.str.len - 4] = '\0';
-
- pfile->cb.dir_change (pfile, debugdir);
- }
}
/* This is called at the end of preprocessing. It pops the last
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 4bafe1c..b728df7 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -124,8 +124,8 @@ enum include_type
IT_CMDLINE, /* -include */
IT_DEFAULT, /* forced header */
IT_MAIN, /* main, start on line 1 */
- IT_MAIN_INJECT, /* main, but there will be an injected preamble
- before line 1 */
+ IT_PRE_MAIN, /* main, but there will be a preamble before line
+ 1 */
IT_DIRECTIVE_HWM = IT_IMPORT + 1, /* Directives below this. */
IT_HEADER_HWM = IT_DEFAULT + 1 /* Header files below this. */