diff options
author | Nathan Sidwell <nathan@acm.org> | 2020-10-08 12:11:37 -0700 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2020-10-08 12:16:21 -0700 |
commit | d1c566d72d9361b37213881222c7e2713cdf05b7 (patch) | |
tree | aa7640d9fb655ceb26caddbd903344fb6662a1e1 /libcpp/init.c | |
parent | cd23ed8af236db2d28314e0652d04e5a0e1540b6 (diff) | |
download | gcc-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/init.c')
-rw-r--r-- | libcpp/init.c | 142 |
1 files changed, 81 insertions, 61 deletions
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 |