+2001-08-03 Neil Booth <neil@cat.daikokuya.demon.co.uk>
+
+ * line-map.c: New.
+ * line-map.h: New.
+ * Makefile.in (line-map.o): New.
+ (LIBCPP_OBJS, LIBCPP_DEPS): Update.
+ * c-lex.c (cb_file_change): Update for new cpp_file_change structure.
+ * cpperror.c (print_containing_files): Similarly.
+ (print_location): Update. Don't output a space before _Pragma.
+ * cppfiles.c (stack_include_file): Set to line 1 immediately.
+ (stack_include_filee, cpp_make_system_header): Update.
+ (_cpp_execute_include): Get logical line number right for calling
+ as-yet-unterminated #include.
+ * cpphash.h (struct cpp_reader): Add line_maps.
+ (_cpp_do_file_change): Update.
+ * cppinit.c (cpp_create_reader): Initialize line maps.
+ (cpp_destroy): Destroy line maps.
+ (cpp_start_read): Get logical line number right.
+ * cpplex.c (parse_string): Only warn once for multi-line strings.
+ Use boolean variable for null warning.
+ * cpplib.c (_cpp_handle_directive): End the directive if it isn't
+ already.
+ (do_include_common): End the directive early.
+ (do_line): Don't warn about out-of-range lines in preprocessed
+ source. Update. Remove unused variables.
+ (_cpp_do_file_change): Update for new line mapping.
+ (pragma_cb): New typedef.
+ (cpp_register_pragma): Stop looking ahead before calling the
+ handler. Clean up.
+ (do_pragma_system_header): End directive early.
+ (cpp_get_line_maps): New.
+ (cpp_pop_buffer): Fudge logical line. Update.
+ * cpplib.h: Include line-map.h
+ (enum cpp_fc_reason): Remove.
+ (struct cpp_file_change): Update.
+ (cpp_get_line_maps): New.
+ * cppmain.c (struct_printer): New member map.
+ (cb_file_change): Update for new mappings.
+ * fix-header.c (cb_file_change): Similarly.
+
2001-08-02 Nick Clifton <nickc@cambridge.redhat.com>
* Makefile.in (libgcc.mk): Define mkinstalldirs.
hashtable.o: hashtable.c hashtable.h $(CONFIG_H) $(SYSTEM_H) $(OBSTACK_H)
+line-map.o: line-map.c line-map.h $(CONFIG_H) $(SYSTEM_H)
+
ggc-none.o: ggc-none.c $(GCONFIG_H) $(SYSTEM_H) $(GGC_H)
$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
LIBCPP_OBJS = cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
cpphash.o cpperror.o cppinit.o cppdefault.o \
- hashtable.o mkdeps.o prefix.o version.o mbchar.o
+ hashtable.o line-map.o mkdeps.o prefix.o version.o mbchar.o
-LIBCPP_DEPS = cpplib.h cpphash.h hashtable.h intl.h $(OBSTACK_H) $(SYSTEM_H)
+LIBCPP_DEPS = cpplib.h cpphash.h line-map.h hashtable.h intl.h \
+ $(OBSTACK_H) $(SYSTEM_H)
# Most of the other archives built/used by this makefile are for
# targets. This one is strictly for the host.
cpp_reader *pfile ATTRIBUTE_UNUSED;
const cpp_file_change *fc;
{
- if (fc->reason == FC_ENTER)
+ unsigned int from_line = SOURCE_LINE (fc->map - 1, fc->line - 1);
+
+ if (fc->reason == LC_ENTER)
{
/* Don't stack the main buffer on the input stack;
we already did in compile_file. */
- if (fc->from.filename)
+ if (MAIN_FILE_P (fc->map))
+ main_input_filename = fc->map->to_file;
+ else
{
- lineno = fc->from.lineno;
- push_srcloc (fc->to.filename, 1);
+ lineno = from_line;
+ push_srcloc (fc->map->to_file, 1);
input_file_stack->indent_level = indent_level;
- (*debug_hooks->start_source_file) (fc->from.lineno, fc->to.filename);
+ (*debug_hooks->start_source_file) (lineno, fc->map->to_file);
#ifndef NO_IMPLICIT_EXTERN_C
if (c_header_level)
++c_header_level;
}
#endif
}
- else
- main_input_filename = fc->to.filename;
}
- else if (fc->reason == FC_LEAVE)
+ else if (fc->reason == LC_LEAVE)
{
/* Popping out of a file. */
if (input_file_stack->next)
}
#endif
pop_srcloc ();
- (*debug_hooks->end_source_file) (input_file_stack->line);
+ (*debug_hooks->end_source_file) (from_line);
}
else
error ("leaving more files than we entered");
}
- update_header_times (fc->to.filename);
+ update_header_times (fc->map->to_file);
in_system_header = fc->sysp != 0;
- input_filename = fc->to.filename;
- lineno = fc->to.lineno; /* Do we need this? */
+ input_filename = fc->map->to_file;
+ lineno = SOURCE_LINE (fc->map, fc->line); /* Do we need this? */
/* Hook for C++. */
extract_interface_info ();
#include "cpphash.h"
#include "intl.h"
-static void print_containing_files PARAMS ((cpp_buffer *));
+static void print_containing_files PARAMS ((struct line_map *,
+ struct line_map *));
static void print_location PARAMS ((cpp_reader *,
const char *,
const cpp_lexer_pos *));
/* Print the file names and line numbers of the #include
commands which led to the current file. */
static void
-print_containing_files (ip)
- cpp_buffer *ip;
+print_containing_files (map_array, map)
+ struct line_map *map_array;
+ struct line_map *map;
{
int first = 1;
- /* Find the other, outer source files. */
- for (ip = ip->prev; ip; ip = ip->prev)
+ for (;;)
{
+ if (MAIN_FILE_P (map))
+ break;
+ map = &map_array[map->included_from];
+
if (first)
{
first = 0;
/* The current line in each outer source file is now the
same as the line of the #include. */
fprintf (stderr, _("In file included from %s:%u"),
- ip->nominal_fname, CPP_BUF_LINE (ip));
+ map->to_file, LAST_SOURCE_LINE (map));
}
else
/* Translators note: this message is used in conjunction
The trailing comma is at the beginning of this message,
and the trailing colon is not translated. */
fprintf (stderr, _(",\n from %s:%u"),
- ip->nominal_fname, CPP_BUF_LINE (ip));
+ map->to_file, LAST_SOURCE_LINE (map));
}
+
fputs (":\n", stderr);
}
line = 0;
else
{
+ struct line_map *map;
+
+ line = pfile->line;
if (type == BUF_PRAGMA)
{
buffer = buffer->prev;
- line = CPP_BUF_LINE (buffer);
col = CPP_BUF_COL (buffer);
}
- else
+
+ map = lookup_line (&pfile->line_maps, line);
+ if (pos == 0)
{
- if (pos == 0)
- pos = cpp_get_line (pfile);
- line = pos->line;
- col = pos->col;
+ pos = cpp_get_line (pfile);
+ line = SOURCE_LINE (map, line);
}
+ else
+ line = pos->line;
+ col = pos->col;
if (col == 0)
col = 1;
if (buffer->prev && ! buffer->include_stack_listed)
{
buffer->include_stack_listed = 1;
- print_containing_files (buffer);
+ print_containing_files (pfile->line_maps.maps, map);
}
}
filename = buffer->nominal_fname;
if (line == 0)
- fprintf (stderr, "%s: ", filename);
+ fprintf (stderr, "%s:", filename);
else if (CPP_OPTION (pfile, show_column) == 0)
- fprintf (stderr, "%s:%u: ", filename, line);
+ fprintf (stderr, "%s:%u:", filename, line);
else
- fprintf (stderr, "%s:%u:%u: ", filename, line, col);
+ fprintf (stderr, "%s:%u:%u:", filename, line, col);
if (type == BUF_PRAGMA)
- fprintf (stderr, "_Pragma: ");
+ fprintf (stderr, "_Pragma:");
+ fputc (' ', stderr);
}
}
/* Generate the call back. */
fp->lineno = 0;
- _cpp_do_file_change (pfile, FC_ENTER, 0, 0);
+ _cpp_do_file_change (pfile, LC_ENTER);
fp->lineno = 1;
}
if (syshdr)
flags = 1 + (externc != 0);
pfile->buffer->sysp = flags;
- _cpp_do_file_change (pfile, FC_RENAME, pfile->buffer->nominal_fname,
- pfile->buffer->lineno);
+ _cpp_do_file_change (pfile, LC_RENAME);
}
/* Report on all files that might benefit from a multiple include guard.
pfile->system_include_depth++;
stack_include_file (pfile, inc);
+ pfile->line++; /* Fake the '\n' at the end of #include. */
if (type == IT_IMPORT)
_cpp_never_reread (inc);
/* Source line tracking. Subtract pseudo_newlines from the actual
line number to get the line number of preprocessed output. Used
for escaped newlines and macro args that cross multiple lines. */
+ struct line_maps line_maps;
unsigned int line;
unsigned int pseudo_newlines;
extern void _cpp_do__Pragma PARAMS ((cpp_reader *));
extern void _cpp_init_directives PARAMS ((cpp_reader *));
extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *));
-extern void _cpp_do_file_change PARAMS ((cpp_reader *, enum cpp_fc_reason,
- const char *, unsigned int));
+extern void _cpp_do_file_change PARAMS ((cpp_reader *, enum lc_reason));
/* Utility routines and macros. */
#define DSC(str) (const U_CHAR *)str, sizeof str - 1
be needed. */
pfile->deps = deps_init ();
+ /* Initialise the line map. */
+ init_line_maps (&pfile->line_maps);
+
/* Initialize lexer state. */
pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
free (context);
}
+ free_line_maps (&pfile->line_maps);
+
result = pfile->errors;
free (pfile);
p = q;
}
+ /* This was zero when the initial buffer was stacked; so we must
+ make up for a non-existent new line, as well as the intervening
+ macro definitions, by setting it to 1. */
+ pfile->line = 1;
+
/* The -imacros files can be scanned now, but the -include files
have to be pushed onto the buffer stack and processed later,
otherwise cppmain.c won't see the tokens. include_head was built
cpp_pool *pool = &pfile->ident_pool;
unsigned char *dest, *limit;
cppchar_t c;
- unsigned int nulls = 0;
+ bool warned_nulls = false, warned_multi = false;
dest = POOL_FRONT (pool);
limit = POOL_LIMIT (pool);
break;
}
- cpp_pedwarn (pfile, "multi-line string literals are deprecated");
+ if (!warned_multi)
+ {
+ warned_multi = true;
+ cpp_pedwarn (pfile, "multi-line string literals are deprecated");
+ }
+
if (pfile->mlstring_pos.line == 0)
pfile->mlstring_pos = pfile->lexer_pos;
*dest++ = '\n';
goto have_char;
}
- else if (c == '\0')
+ else if (c == '\0' && !warned_nulls)
{
- if (nulls++ == 0)
- cpp_warning (pfile, "null character(s) preserved in literal");
+ warned_nulls = true;
+ cpp_warning (pfile, "null character(s) preserved in literal");
}
*dest++ = c;
bol = 1;
pfile->lexer_pos.output_line = buffer->lineno;
/* This is a new line, so clear any white space flag.
- Newlines in arguments are white space (6.10.3.10);
- parse_arg takes care of that. */
+ Newlines in arguments are white space (6.10.3.10);
+ parse_arg takes care of that. */
result->flags &= ~(PREV_WHITE | AVOID_LPASTE);
goto next_char;
}
cpp_token_as_text (pfile, &dname));
}
- end_directive (pfile, skip);
+ if (pfile->state.in_directive)
+ end_directive (pfile, skip);
return skip;
}
{
check_eol (pfile);
/* Get out of macro context, if we are. */
- skip_rest_of_line (pfile);
+ end_directive (pfile, 1);
if (pfile->cb.include)
(*pfile->cb.include) (pfile, pfile->directive->name, &header);
cpp_reader *pfile;
{
cpp_buffer *buffer = pfile->buffer;
- const char *filename = buffer->nominal_fname;
- unsigned int lineno = buffer->lineno;
- enum cpp_fc_reason reason = FC_RENAME;
+ enum lc_reason reason = LC_RENAME;
unsigned long new_lineno;
unsigned int cap;
cpp_token token;
return;
}
- if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap))
+ if (CPP_PEDANTIC (pfile) && ! pfile->state.line_extension
+ && (new_lineno == 0 || new_lineno > cap))
cpp_pedwarn (pfile, "line number out of range");
cpp_get_token (pfile, &token);
flag = read_flag (pfile, flag);
if (flag == 1)
{
- reason = FC_ENTER;
+ reason = LC_ENTER;
flag = read_flag (pfile, flag);
}
else if (flag == 2)
{
- reason = FC_LEAVE;
+ reason = LC_LEAVE;
flag = read_flag (pfile, flag);
}
if (flag == 3)
sysp = 2, read_flag (pfile, flag);
}
- if (reason == FC_ENTER)
+ if (reason == LC_ENTER)
{
/* Fake a buffer stack for diagnostics. */
cpp_push_buffer (pfile, 0, 0, BUF_FAKE, fname);
_cpp_fake_include (pfile, fname);
buffer = pfile->buffer;
}
- else if (reason == FC_LEAVE)
+ else if (reason == LC_LEAVE)
{
if (buffer->type != BUF_FAKE)
cpp_warning (pfile, "file \"%s\" left but not entered",
return;
}
- /* Our line number is incremented after the directive is processed. */
+ end_directive (pfile, 1);
buffer->lineno = new_lineno - 1;
- _cpp_do_file_change (pfile, reason, filename, lineno);
+ _cpp_do_file_change (pfile, reason);
}
-/* Arrange the file_change callback. */
+/* Arrange the file_change callback. It is assumed that the next line
+ is given by incrementing buffer->lineno and pfile->line. */
void
-_cpp_do_file_change (pfile, reason, from_file, from_lineno)
+_cpp_do_file_change (pfile, reason)
cpp_reader *pfile;
- enum cpp_fc_reason reason;
- const char *from_file;
- unsigned int from_lineno;
+ enum lc_reason reason;
{
+ cpp_buffer *buffer;
+ struct line_map *map;
+
+ buffer = pfile->buffer;
+ map = add_line_map (&pfile->line_maps, reason,
+ pfile->line + 1, buffer->nominal_fname, buffer->lineno + 1);
+
if (pfile->cb.file_change)
{
cpp_file_change fc;
- cpp_buffer *buffer = pfile->buffer;
-
+
+ fc.map = map;
+ fc.line = pfile->line + 1;
fc.reason = reason;
- fc.to.filename = buffer->nominal_fname;
- fc.to.lineno = buffer->lineno + 1;
fc.sysp = buffer->sysp;
fc.externc = CPP_OPTION (pfile, cplusplus) && buffer->sysp == 2;
- /* Caller doesn't need to handle FC_ENTER. */
- if (reason == FC_ENTER)
- {
- if (buffer->prev)
- {
- from_file = buffer->prev->nominal_fname;
- from_lineno = buffer->prev->lineno;
- }
- else
- from_file = 0;
- }
- /* Special case for file "foo.i" with "# 1 foo.c" on first line. */
- else if (reason == FC_RENAME && ! buffer->prev
- && pfile->directive_pos.line == 1)
- from_file = 0;
-
- fc.from.filename = from_file;
- fc.from.lineno = from_lineno;
- pfile->cb.file_change (pfile, &fc);
+ (*pfile->cb.file_change) (pfile, &fc);
}
}
/* Sub-handlers for the pragmas needing treatment here.
They return 1 if the token buffer is to be popped, 0 if not. */
+typedef void (*pragma_cb) PARAMS ((cpp_reader *));
struct pragma_entry
{
struct pragma_entry *next;
size_t len;
int isnspace;
union {
- void (*handler) PARAMS ((cpp_reader *));
+ pragma_cb handler;
struct pragma_entry *space;
} u;
};
cpp_reader *pfile;
const char *space;
const char *name;
- void (*handler) PARAMS ((cpp_reader *));
+ pragma_cb handler;
{
struct pragma_entry **x, *new;
size_t len;
do_pragma (pfile)
cpp_reader *pfile;
{
+ pragma_cb handler = NULL;
const struct pragma_entry *p;
cpp_token tok;
- int drop = 0;
p = pfile->pragmas;
pfile->state.prevent_expansion++;
}
else
{
- (*p->u.handler) (pfile);
- drop = 1;
+ handler = p->u.handler;
break;
}
}
}
}
- cpp_stop_lookahead (pfile, drop);
+ cpp_stop_lookahead (pfile, handler != NULL);
pfile->state.prevent_expansion--;
- if (!drop && pfile->cb.def_pragma)
+ if (handler)
+ (*handler) (pfile);
+ else if (pfile->cb.def_pragma)
(*pfile->cb.def_pragma) (pfile);
}
if (buffer->prev == 0)
cpp_warning (pfile, "#pragma system_header ignored outside include file");
else
- cpp_make_system_header (pfile, 1, 0);
-
- check_eol (pfile);
+ {
+ check_eol (pfile);
+ end_directive (pfile, 1);
+ cpp_make_system_header (pfile, 1, 0);
+ }
}
/* Check the modified date of the current include file against a specified
return &pfile->cb;
}
+/* The line map set. */
+struct line_maps *
+cpp_get_line_maps (pfile)
+ cpp_reader *pfile;
+{
+ return &pfile->line_maps;
+}
+
/* Copy the given callbacks structure to our own. */
void
cpp_set_callbacks (pfile, cb)
if (pfile->directive == &dtable[T_LINE])
break;
- _cpp_do_file_change (pfile, FC_LEAVE, buffer->nominal_fname,
- buffer->lineno);
+ pfile->line--; /* We have a '\n' at the end of #include. */
+ _cpp_do_file_change (pfile, LC_LEAVE);
if (pfile->buffer->type == BUF_FILE)
break;
#include <sys/types.h>
#include "hashtable.h"
+#include "line-map.h"
#ifdef __cplusplus
extern "C" {
unsigned char help_only;
};
-/* This structure is passed to the call back when changing file. */
-enum cpp_fc_reason {FC_ENTER = 0, FC_LEAVE, FC_RENAME};
-
-struct cpp_file_loc
-{
- const char *filename;
- unsigned int lineno;
-};
-
typedef struct cpp_file_change cpp_file_change;
struct cpp_file_change
{
- struct cpp_file_loc from; /* Line of #include or #line. */
- struct cpp_file_loc to; /* Line after #include or #line, or start. */
- enum cpp_fc_reason reason; /* Reason for change. */
+ struct line_map *map; /* Line map to use until next callback. */
+ unsigned int line; /* Logical line number of next line. */
+ enum lc_reason reason; /* Reason for change. */
unsigned char sysp; /* Nonzero if system header. */
unsigned char externc; /* Nonzero if wrapper needed. */
};
through the pointer returned from cpp_get_callbacks, or set them
with cpp_set_callbacks. */
extern cpp_options *cpp_get_options PARAMS ((cpp_reader *));
+extern struct line_maps *cpp_get_line_maps PARAMS ((cpp_reader *));
extern cpp_callbacks *cpp_get_callbacks PARAMS ((cpp_reader *));
extern void cpp_set_callbacks PARAMS ((cpp_reader *, cpp_callbacks *));
const char *syshdr_flags; /* system header flags, if any. */
unsigned int lineno; /* line currently being written. */
unsigned char printed; /* nonzero if something output at lineno. */
+ struct line_map *map; /* logical to physical line mappings. */
};
int main PARAMS ((int, char **));
const cpp_file_change *fc;
{
/* Bring current file to correct line (except first file). */
- if (fc->reason == FC_ENTER && fc->from.filename)
- maybe_print_line (fc->from.lineno);
+ if (fc->reason == LC_ENTER && !MAIN_FILE_P (fc->map))
+ maybe_print_line (SOURCE_LINE (fc->map - 1, fc->line - 1));
- print.last_fname = fc->to.filename;
+ print.map = fc->map;
+ print.last_fname = fc->map->to_file;
if (fc->externc)
print.syshdr_flags = " 3 4";
else if (fc->sysp)
{
const char *flags = "";
- print.lineno = fc->to.lineno;
- if (fc->reason == FC_ENTER)
+ print.lineno = SOURCE_LINE (fc->map, fc->line);
+ if (fc->reason == LC_ENTER)
flags = " 1";
- else if (fc->reason == FC_LEAVE)
+ else if (fc->reason == LC_LEAVE)
flags = " 2";
if (! options->no_line_commands)
}
}
+/* Copy a #pragma directive to the preprocessed output. LINE is the
+ line of the current source file, not the logical line. */
static void
cb_def_pragma (pfile)
cpp_reader *pfile;
const cpp_file_change *fc;
{
/* Just keep track of current file name. */
- cur_file = fc->to.filename;
+ cur_file = fc->map->to_file;
}
static void
--- /dev/null
+/* Map logical line numbers to (source file, line number) pairs.
+ Copyright (C) 2001
+ Free Software Foundation, Inc.
+
+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 2, 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; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding! */
+
+#include "config.h"
+#include "system.h"
+#include "line-map.h"
+
+/* Initialize a line map set. */
+
+void
+init_line_maps (set)
+ struct line_maps *set;
+{
+ set->maps = 0;
+ set->allocated = 0;
+ set->used = 0;
+}
+
+/* Free a line map set. */
+
+void free_line_maps (set)
+ struct line_maps *set;
+{
+ if (set->maps)
+ free (set->maps);
+}
+
+/* Add a mapping of logical source line to physical source file and
+ line number. Ther text pointed to by TO_FILE must have a lifetime
+ at least as long as the final call to lookup_line ().
+
+ FROM_LINE should be monotonic increasing across calls to this
+ function. */
+
+struct line_map *
+add_line_map (set, reason, from_line, to_file, to_line)
+ struct line_maps *set;
+ enum lc_reason reason;
+ unsigned int from_line;
+ const char *to_file;
+ unsigned int to_line;
+{
+ struct line_map *map;
+
+ if (set->used && from_line < set->maps[set->used - 1].from_line)
+ abort ();
+
+ if (set->used == set->allocated)
+ {
+ set->allocated = 2 * set->allocated + 256;
+ set->maps = (struct line_map *)
+ xrealloc (set->maps, set->allocated * sizeof (struct line_map));
+ }
+
+ map = &set->maps[set->used];
+ map->from_line = from_line;
+ map->to_file = to_file;
+ map->to_line = to_line;
+
+ if (set->used == 0)
+ map->included_from = -1;
+ else if (reason == LC_ENTER)
+ map->included_from = set->used - 1;
+ else if (reason == LC_RENAME)
+ map->included_from = map[-1].included_from;
+ else if (reason == LC_LEAVE)
+ {
+ if (map[-1].included_from < 0)
+ abort ();
+ map->included_from = set->maps[map[-1].included_from].included_from;
+ }
+
+ set->used++;
+ return map;
+}
+
+/* Translate a logical line number into a (source file, line) pair. */
+
+struct line_map *
+lookup_line (set, line)
+ struct line_maps *set;
+ unsigned int line;
+{
+ unsigned int md, mn = 0, mx = set->used;
+
+ if (mx == 0)
+ abort ();
+
+ while (mx - mn > 1)
+ {
+ md = (mn + mx) / 2;
+ if (set->maps[md].from_line > line)
+ mx = md;
+ else
+ mn = md;
+ }
+
+ return &set->maps[mn];
+}
--- /dev/null
+/* Map logical line numbers to (source file, line number) pairs.
+ Copyright (C) 2001
+ Free Software Foundation, Inc.
+
+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 2, 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; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding! */
+
+#ifndef GCC_LINE_MAP_H
+#define GCC_LINE_MAP_H
+
+/* The logical line FROM_LINE maps to physical source file TO_FILE at
+ line TO_LINE, and subsequently one-to-one until the next line_map
+ structure in the set. */
+struct line_map
+{
+ const char *to_file;
+ unsigned int to_line;
+ unsigned int from_line;
+ int included_from;
+};
+
+/* Contains a sequence of chronological line_map structures. */
+struct line_maps
+{
+ struct line_map *maps;
+ unsigned int allocated;
+ unsigned int used;
+};
+
+/* Reason for adding a line change with add_line_map (). */
+enum lc_reason {LC_ENTER = 0, LC_LEAVE, LC_RENAME};
+
+/* Initialize a line map set. */
+extern void init_line_maps
+ PARAMS ((struct line_maps *));
+
+/* Free a line map set. */
+extern void free_line_maps
+ PARAMS ((struct line_maps *));
+
+/* Add a mapping of logical source line to physical source file and
+ line number. Ther text pointed to by TO_FILE must have a lifetime
+ at least as long as the final call to lookup_line ().
+
+ FROM_LINE should be monotonic increasing across calls to this
+ function. */
+extern struct line_map *add_line_map
+ PARAMS ((struct line_maps *, enum lc_reason,
+ unsigned int from_line, const char *to_file, unsigned int to_line));
+
+/* Given a logical line, returns the map from which the corresponding
+ (source file, line) pair can be deduced. */
+extern struct line_map *lookup_line
+ PARAMS ((struct line_maps *, unsigned int));
+
+/* Converts a map and logical line to source line. */
+#define SOURCE_LINE(MAP, LINE) ((LINE) + (MAP)->to_line - (MAP)->from_line)
+
+/* Returns the last source line within a map. This is the (last) line
+ of the #include, or other directive, that caused a map change. */
+#define LAST_SOURCE_LINE(MAP) SOURCE_LINE (MAP, (MAP)[1].from_line - 1)
+
+#define MAIN_FILE_P(MAP) ((MAP)->included_from < 0)
+
+#endif /* !GCC_LINE_MAP_H */
+2001-08-02 Neil Booth <neil@daikokuya.demon.co.uk>
+
+ * gcc.dg/cpp/19951025-1.c: Update.
+
2001-08-02 Jeffrey Oldham <oldham@codesourcery.com>
* g77.dg/ff90-1.f (s): Fix reference of variable z,
/* { dg-do preprocess } */
-/* { dg-error "include expects" "" { target *-*-* } 4 } */
-/* { dg-error "newline at end" "" { target *-*-* } 4 } */
+/* { dg-error "include expects" "" { target *-*-* } 5 } */
+/* { dg-error "newline at end" "" { target *-*-* } 5 } */
#include /\