mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-20 19:01:12 +08:00
preprocessor: Better line info for <builtin> & <command-line>
With C++ module header units it becomes important to distinguish between macros defined in forced headers (& commandline & builtins) from those defined in the header file being processed. We weren't making that easy because we treated the builtins and command-line locations somewhat file-like, with incrementing line numbers, and showing them as included from line 1 of the main file. This patch does 3 things: 0) extend the idiom that 'line 0' of a file means 'the file as a whole' 1) builtins and command-line macros are shown as-if included from line zero. 2) when emitting preprocessed output we keep resetting the line number so that re-reading that preprocessed output will get the same set of locations for the command line etc. For instance the new c-c++-common/cpp/line-2.c test, now emits In file included from <command-line>: ./line-2.h:4:2: error: #error wrong 4 | #error wrong | ^~~~~ line-2.c:3:11: error: macro "bill" passed 1 arguments, but takes just 0 3 | int bill(1); | ^ In file included from <command-line>: ./line-2.h:3: note: macro "bill" defined here 3 | #define bill() 2 | Before it told you about including from <command-line>:31. the preprocessed output looks like: ... (There's a new optimization in do_line_marker to stop each of these line markers causing a new line map. We can simply rewind the location, and keep using the same line map.) libcpp/ * directives.c (do_linemarker): Optimize rewinding to line zero. * files.c (_cpp_stack_file): Start on line zero when about to inject headers. (cpp_push_include, cpp_push_default_include): Use highest_line as the location. * include/cpplib.h (cpp_read_main_file): Add injecting parm. * init.c (cpp_read_main_file): Likewise, inform _cpp_stack_file. * internal.h (enum include_type): Add IT_MAIN_INJECT. gcc/c-family/ * c-opts.c (c_common_post_options): Add 'injecting' arg to cpp_read_main_file. (c_finish_options): Add linemap_line_start calls for builtin and cmd maps. Force token position to line_table's highest line. * c-ppoutput.c (print_line_1): Refactor, print line zero. (cb_define): Always increment source line. gcc/testsuite/ * c-c++-common/cpp/line-2.c: New. * c-c++-common/cpp/line-2.h: New. * c-c++-common/cpp/line-3.c: New. * c-c++-common/cpp/line-4.c: New. * c-c++-common/cpp/line-4.h: New.
This commit is contained in:
parent
6f9c9ea40a
commit
6bf2ff0d52
@ -1110,7 +1110,11 @@ c_common_post_options (const char **pfilename)
|
||||
input_location = UNKNOWN_LOCATION;
|
||||
|
||||
*pfilename = this_input_filename
|
||||
= cpp_read_main_file (parse_in, in_fnames[0]);
|
||||
= cpp_read_main_file (parse_in, in_fnames[0],
|
||||
/* We'll inject preamble pieces if this is
|
||||
not preprocessed. */
|
||||
!cpp_opts->preprocessed);
|
||||
|
||||
/* Don't do any compilation or preprocessing if there is no input file. */
|
||||
if (this_input_filename == NULL)
|
||||
{
|
||||
@ -1429,6 +1433,7 @@ c_finish_options (void)
|
||||
= linemap_check_ordinary (linemap_add (line_table, LC_RENAME, 0,
|
||||
_("<built-in>"), 0));
|
||||
cb_file_change (parse_in, bltin_map);
|
||||
linemap_line_start (line_table, 0, 1);
|
||||
|
||||
/* Make sure all of the builtins about to be declared have
|
||||
BUILTINS_LOCATION has their location_t. */
|
||||
@ -1452,9 +1457,10 @@ c_finish_options (void)
|
||||
= linemap_check_ordinary (linemap_add (line_table, LC_RENAME, 0,
|
||||
_("<command-line>"), 0));
|
||||
cb_file_change (parse_in, cmd_map);
|
||||
linemap_line_start (line_table, 0, 1);
|
||||
|
||||
/* All command line defines must have the same location. */
|
||||
cpp_force_token_locations (parse_in, cmd_map->start_location);
|
||||
cpp_force_token_locations (parse_in, line_table->highest_line);
|
||||
for (size_t i = 0; i < deferred_count; i++)
|
||||
{
|
||||
struct deferred_opt *opt = &deferred_opts[i];
|
||||
|
@ -560,26 +560,23 @@ print_line_1 (location_t src_loc, const char *special_flags, FILE *stream)
|
||||
if (src_loc != UNKNOWN_LOCATION && !flag_no_line_commands)
|
||||
{
|
||||
const char *file_path = LOCATION_FILE (src_loc);
|
||||
int sysp;
|
||||
size_t to_file_len = strlen (file_path);
|
||||
unsigned char *to_file_quoted =
|
||||
(unsigned char *) alloca (to_file_len * 4 + 1);
|
||||
unsigned char *p;
|
||||
|
||||
print.src_line = LOCATION_LINE (src_loc);
|
||||
print.src_file = file_path;
|
||||
|
||||
/* cpp_quote_string does not nul-terminate, so we have to do it
|
||||
ourselves. */
|
||||
p = cpp_quote_string (to_file_quoted,
|
||||
(const unsigned char *) file_path,
|
||||
to_file_len);
|
||||
unsigned char *p = cpp_quote_string (to_file_quoted,
|
||||
(const unsigned char *) file_path,
|
||||
to_file_len);
|
||||
*p = '\0';
|
||||
fprintf (stream, "# %u \"%s\"%s",
|
||||
print.src_line == 0 ? 1 : print.src_line,
|
||||
to_file_quoted, special_flags);
|
||||
print.src_line, to_file_quoted, special_flags);
|
||||
|
||||
sysp = in_system_header_at (src_loc);
|
||||
int sysp = in_system_header_at (src_loc);
|
||||
if (sysp == 2)
|
||||
fputs (" 3 4", stream);
|
||||
else if (sysp == 1)
|
||||
@ -677,8 +674,7 @@ cb_define (cpp_reader *pfile, location_t line, cpp_hashnode *node)
|
||||
linemap_resolve_location (line_table, line,
|
||||
LRK_MACRO_DEFINITION_LOCATION,
|
||||
&map);
|
||||
if (LINEMAP_LINE (map) != 0)
|
||||
print.src_line++;
|
||||
print.src_line++;
|
||||
}
|
||||
|
||||
static void
|
||||
|
11
gcc/testsuite/c-c++-common/cpp/line-2.c
Normal file
11
gcc/testsuite/c-c++-common/cpp/line-2.c
Normal file
@ -0,0 +1,11 @@
|
||||
int line1;
|
||||
int f = bob;
|
||||
int bill(1);
|
||||
int line4;
|
||||
|
||||
// { dg-do preprocess }
|
||||
// { dg-options "-dD -include $srcdir/c-c++-common/cpp/line-2.h -nostdinc" }
|
||||
|
||||
// { dg-regexp {In file included from <command-line>:\n[^\n]*/line-2.h:4:2: error: #error wrong\n} }
|
||||
|
||||
// { dg-regexp {[^\n]*/line-2.c:3:11: error: macro "bill" passed 1 arguments, but takes just 0\nIn file included from <command-line>:\n[^\n]*/line-2.h:3: note: macro "bill" defined here\n} }
|
5
gcc/testsuite/c-c++-common/cpp/line-2.h
Normal file
5
gcc/testsuite/c-c++-common/cpp/line-2.h
Normal file
@ -0,0 +1,5 @@
|
||||
#define bob 1
|
||||
/* Comment */
|
||||
#define bill() 2
|
||||
#error wrong
|
||||
|
20
gcc/testsuite/c-c++-common/cpp/line-3.c
Normal file
20
gcc/testsuite/c-c++-common/cpp/line-3.c
Normal file
@ -0,0 +1,20 @@
|
||||
# 0 ".../line-1.c"
|
||||
# 0 "<built-in>"
|
||||
# 0 "<command-line>"
|
||||
# 1 "./line-2.h" 1
|
||||
#define bob 1
|
||||
|
||||
#define bill() 2
|
||||
#error wrong
|
||||
# 0 "<command-line>" 2
|
||||
# 1 ".../line-3.c"
|
||||
int line1;
|
||||
int f = bob;
|
||||
int bill(1);
|
||||
int line4;
|
||||
|
||||
// { dg-regexp {In file included from <command-line>:\n[^\n]*/line-2.h:4:2: error: #error wrong\n} }
|
||||
|
||||
// { dg-regexp {[^\n]*/line-3.c:3:11: error: macro "bill" passed 1 arguments, but takes just 0\nIn file included from <command-line>:\n[^\n]*/line-2.h:3: note: macro "bill" defined here\n} }
|
||||
|
||||
// { dg-options "-fpreprocessed -fdirectives-only" }
|
11
gcc/testsuite/c-c++-common/cpp/line-4.c
Normal file
11
gcc/testsuite/c-c++-common/cpp/line-4.c
Normal file
@ -0,0 +1,11 @@
|
||||
int line1;
|
||||
int f = bob;
|
||||
int b = bill();
|
||||
int line4;
|
||||
|
||||
// { dg-do preprocess }
|
||||
// { dg-options "-dD -include $srcdir/c-c++-common/cpp/line-4.h -nostdinc" }
|
||||
|
||||
// { dg-final { scan-file line-4.i {# 0 "[^\n]*/line-4.c"\n# 0 "<built-in>"\n} } }
|
||||
// { dg-final { scan-file line-4.i {# 0 "<command-line>"\n# 1 "[^\n]*/line-4.h" 1\n#define bob 1\n} } }
|
||||
// { dg-final { scan-file line-4.i {#define bill\(\) 2\n# 0 "<command-line>" 2\n# 1 "[^\n]*/line-4.c"\nint line1;\n} } }
|
3
gcc/testsuite/c-c++-common/cpp/line-4.h
Normal file
3
gcc/testsuite/c-c++-common/cpp/line-4.h
Normal file
@ -0,0 +1,3 @@
|
||||
#define bob 1
|
||||
/* Comment */
|
||||
#define bill() 2
|
@ -940,7 +940,7 @@ strtolinenum (const uchar *str, size_t len, linenum_type *nump, bool *wrapped)
|
||||
|
||||
/* Interpret #line command.
|
||||
Note that the filename string (if any) is a true string constant
|
||||
(escapes are interpreted), unlike in #line. */
|
||||
(escapes are interpreted). */
|
||||
static void
|
||||
do_line (cpp_reader *pfile)
|
||||
{
|
||||
@ -1115,27 +1115,43 @@ do_linemarker (cpp_reader *pfile)
|
||||
line_table->seen_line_directive = true;
|
||||
}
|
||||
|
||||
/* Arrange the file_change callback. pfile->line has changed to
|
||||
FILE_LINE of TO_FILE, for reason REASON. SYSP is 1 for a system
|
||||
header, 2 for a system header that needs to be extern "C" protected,
|
||||
and zero otherwise. */
|
||||
/* Arrange the file_change callback. Changing to TO_FILE:TO_LINE for
|
||||
REASON. SYSP is 1 for a system header, 2 for a system header that
|
||||
needs to be extern "C" protected, and zero otherwise. */
|
||||
void
|
||||
_cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason,
|
||||
const char *to_file, linenum_type file_line,
|
||||
const char *to_file, linenum_type to_line,
|
||||
unsigned int sysp)
|
||||
{
|
||||
linemap_assert (reason != LC_ENTER_MACRO);
|
||||
const struct line_map *map = linemap_add (pfile->line_table, reason, sysp,
|
||||
to_file, file_line);
|
||||
|
||||
const line_map_ordinary *ord_map = NULL;
|
||||
if (map != NULL)
|
||||
if (!to_line && reason == LC_RENAME_VERBATIM)
|
||||
{
|
||||
ord_map = linemap_check_ordinary (map);
|
||||
linemap_line_start (pfile->line_table,
|
||||
ORDINARY_MAP_STARTING_LINE_NUMBER (ord_map),
|
||||
127);
|
||||
/* A linemarker moving to line zero. If we're on the second
|
||||
line of the current map, and it also starts at zero, just
|
||||
rewind -- we're probably reading the builtins of a
|
||||
preprocessed source. */
|
||||
line_map_ordinary *last = LINEMAPS_LAST_ORDINARY_MAP (pfile->line_table);
|
||||
if (!ORDINARY_MAP_STARTING_LINE_NUMBER (last)
|
||||
&& SOURCE_LINE (last, pfile->line_table->highest_line) == 2)
|
||||
{
|
||||
ord_map = last;
|
||||
pfile->line_table->highest_location
|
||||
= pfile->line_table->highest_line = MAP_START_LOCATION (last);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ord_map)
|
||||
if (const line_map *map = linemap_add (pfile->line_table, reason, sysp,
|
||||
to_file, to_line))
|
||||
{
|
||||
ord_map = linemap_check_ordinary (map);
|
||||
linemap_line_start (pfile->line_table,
|
||||
ORDINARY_MAP_STARTING_LINE_NUMBER (ord_map),
|
||||
127);
|
||||
}
|
||||
|
||||
if (pfile->cb.file_change)
|
||||
pfile->cb.file_change (pfile, ord_map);
|
||||
}
|
||||
|
@ -947,7 +947,11 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type,
|
||||
pfile->line_table->highest_location--;
|
||||
|
||||
/* Add line map and do callbacks. */
|
||||
_cpp_do_file_change (pfile, LC_ENTER, file->path, 1, sysp);
|
||||
_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);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1475,7 +1479,8 @@ _cpp_compare_file_date (cpp_reader *pfile, const char *fname,
|
||||
bool
|
||||
cpp_push_include (cpp_reader *pfile, const char *fname)
|
||||
{
|
||||
return _cpp_stack_include (pfile, fname, false, IT_CMDLINE, 0);
|
||||
return _cpp_stack_include (pfile, fname, false, IT_CMDLINE,
|
||||
pfile->line_table->highest_line);
|
||||
}
|
||||
|
||||
/* Pushes the given file, implicitly included at the start of a
|
||||
@ -1484,7 +1489,8 @@ cpp_push_include (cpp_reader *pfile, const char *fname)
|
||||
bool
|
||||
cpp_push_default_include (cpp_reader *pfile, const char *fname)
|
||||
{
|
||||
return _cpp_stack_include (pfile, fname, true, IT_DEFAULT, 0);
|
||||
return _cpp_stack_include (pfile, fname, true, IT_DEFAULT,
|
||||
pfile->line_table->highest_line);
|
||||
}
|
||||
|
||||
/* Do appropriate cleanup when a file INC's buffer is popped off the
|
||||
|
@ -979,7 +979,8 @@ extern class mkdeps *cpp_get_deps (cpp_reader *) ATTRIBUTE_PURE;
|
||||
input file, except for preprocessed input. This will generate at
|
||||
least one file change callback, and possibly a line change callback
|
||||
too. If there was an error opening the file, it returns NULL. */
|
||||
extern const char *cpp_read_main_file (cpp_reader *, const char *);
|
||||
extern const char *cpp_read_main_file (cpp_reader *, const char *,
|
||||
bool injecting = false);
|
||||
|
||||
/* Set up built-ins with special behavior. Use cpp_init_builtins()
|
||||
instead unless your know what you are doing. */
|
||||
|
@ -657,10 +657,11 @@ cpp_post_options (cpp_reader *pfile)
|
||||
}
|
||||
|
||||
/* Setup for processing input from the file named FNAME, or stdin if
|
||||
it is the empty string. Return the original filename
|
||||
on success (e.g. foo.i->foo.c), or NULL on failure. */
|
||||
it is the empty string. Return the original filename on success
|
||||
(e.g. foo.i->foo.c), or NULL on failure. INJECTING is true if
|
||||
there may be injected headers before line 1 of the main file. */
|
||||
const char *
|
||||
cpp_read_main_file (cpp_reader *pfile, const char *fname)
|
||||
cpp_read_main_file (cpp_reader *pfile, const char *fname, bool injecting)
|
||||
{
|
||||
if (CPP_OPTION (pfile, deps.style) != DEPS_NONE)
|
||||
{
|
||||
@ -677,16 +678,16 @@ cpp_read_main_file (cpp_reader *pfile, const char *fname)
|
||||
if (_cpp_find_failed (pfile->main_file))
|
||||
return NULL;
|
||||
|
||||
_cpp_stack_file (pfile, pfile->main_file, IT_MAIN, 0);
|
||||
_cpp_stack_file (pfile, pfile->main_file,
|
||||
injecting ? IT_MAIN_INJECT : 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);
|
||||
fname =
|
||||
ORDINARY_MAP_FILE_NAME
|
||||
((LINEMAPS_LAST_ORDINARY_MAP (pfile->line_table)));
|
||||
fname = (ORDINARY_MAP_FILE_NAME
|
||||
((LINEMAPS_LAST_ORDINARY_MAP (pfile->line_table))));
|
||||
}
|
||||
return fname;
|
||||
}
|
||||
|
@ -123,7 +123,9 @@ enum include_type
|
||||
/* Non-directive including mechanisms. */
|
||||
IT_CMDLINE, /* -include */
|
||||
IT_DEFAULT, /* forced header */
|
||||
IT_MAIN, /* main */
|
||||
IT_MAIN, /* main, start on line 1 */
|
||||
IT_MAIN_INJECT, /* main, but there will be an injected preamble
|
||||
before line 1 */
|
||||
|
||||
IT_DIRECTIVE_HWM = IT_IMPORT + 1, /* Directives below this. */
|
||||
IT_HEADER_HWM = IT_DEFAULT + 1 /* Header files below this. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user