From: Dodji Seketeli <dodji@redhat.com>
To: Jakub Jelinek <jakub@redhat.com>
Cc: "GCC Patches" <gcc-patches@gcc.gnu.org>,
"Tom Tromey" <tromey@redhat.com>,
"Manuel López-Ibáñez" <lopezibanez@gmail.com>,
"Bernd Edlinger" <bernd.edlinger@hotmail.de>
Subject: Re: [PATCH] preprocessor/58580 - preprocessor goes OOM with warning for zero literals
Date: Tue, 12 Nov 2013 16:42:00 -0000 [thread overview]
Message-ID: <878uwt63e2.fsf@redhat.com> (raw)
In-Reply-To: <878uwuap4f.fsf@redhat.com> (Dodji Seketeli's message of "Mon, 11 Nov 2013 17:18:24 +0100")
Hello,
Below is the updated patch amended to take your previous comments in
account.
In add_file_to_cache_tab the evicted cache array entry is the one that
was less used.
Incidentally I also fixed some thinkos and issued that I have seen in
the previous patch.
Bootstrapped on x86_64-unknown-linux-gnu against trunk.
libcpp/ChangeLog:
* include/line-map.h (linemap_get_file_highest_location): Declare
new function.
* line-map.c (linemap_get_file_highest_location): Define it.
gcc/ChangeLog:
* input.h (location_get_source_line): Take an additional line_size
parameter.
(void diagnostics_file_cache_fini): Declare new function.
* input.c (struct fcache): New type.
(fcache_tab_size, fcache_buffer_size, fcache_line_record_size):
New static constants.
(diagnostic_file_cache_init, total_lines_num)
(lookup_file_in_cache_tab, evicted_cache_tab_entry)
(add_file_to_cache_tab, lookup_or_add_file_to_cache_tab)
(needs_read, needs_grow, maybe_grow, read_data, maybe_read_data)
(get_next_line, read_next_line, goto_next_line, read_line_num):
New static function definitions.
(diagnostic_file_cache_fini): New function.
(location_get_source_line): Take an additional output line_len
parameter. Re-write using lookup_or_add_file_to_cache_tab and
read_line_num.
* diagnostic.c (diagnostic_finish): Call
diagnostic_file_cache_fini.
(adjust_line): Take an additional input parameter for the length
of the line, rather than calculating it with strlen.
(diagnostic_show_locus): Adjust the use of
location_get_source_line and adjust_line with respect to their new
signature. While displaying a line now, do not stop at the first
null byte. Rather, display the zero byte as a space and keep
going until we reach the size of the line.
* Makefile.in: Add vec.o to OBJS-libcommon
gcc/testsuite/ChangeLog:
* c-c++-common/cpp/warning-zero-in-literals-1.c: New test file.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204453 138bc75d-0d04-0410-961f-82ee72b054a4
---
gcc/Makefile.in | 3 +-
gcc/diagnostic.c | 19 +-
gcc/diagnostic.h | 1 +
gcc/input.c | 637 ++++++++++++++++++++-
gcc/input.h | 5 +-
.../c-c++-common/cpp/warning-zero-in-literals-1.c | Bin 0 -> 240 bytes
libcpp/include/line-map.h | 8 +
libcpp/line-map.c | 40 ++
8 files changed, 674 insertions(+), 39 deletions(-)
create mode 100644 gcc/testsuite/c-c++-common/cpp/warning-zero-in-literals-1.c
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 49285e5..9fe9060 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1469,7 +1469,8 @@ OBJS = \
# Objects in libcommon.a, potentially used by all host binaries and with
# no target dependencies.
-OBJS-libcommon = diagnostic.o diagnostic-color.o pretty-print.o intl.o input.o version.o
+OBJS-libcommon = diagnostic.o diagnostic-color.o pretty-print.o intl.o \
+ vec.o input.o version.o
# Objects in libcommon-target.a, used by drivers and by the core
# compiler and containing target-dependent code.
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 36094a1..6c83f03 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -176,6 +176,8 @@ diagnostic_finish (diagnostic_context *context)
progname);
pp_newline_and_flush (context->printer);
}
+
+ diagnostic_file_cache_fini ();
}
/* Initialize DIAGNOSTIC, where the message MSG has already been
@@ -259,12 +261,13 @@ diagnostic_build_prefix (diagnostic_context *context,
MAX_WIDTH by some margin, then adjust the start of the line such
that the COLUMN is smaller than MAX_WIDTH minus the margin. The
margin is either 10 characters or the difference between the column
- and the length of the line, whatever is smaller. */
+ and the length of the line, whatever is smaller. The length of
+ LINE is given by LINE_WIDTH. */
static const char *
-adjust_line (const char *line, int max_width, int *column_p)
+adjust_line (const char *line, int line_width,
+ int max_width, int *column_p)
{
int right_margin = 10;
- int line_width = strlen (line);
int column = *column_p;
right_margin = MIN (line_width - column, right_margin);
@@ -284,6 +287,7 @@ diagnostic_show_locus (diagnostic_context * context,
const diagnostic_info *diagnostic)
{
const char *line;
+ int line_width;
char *buffer;
expanded_location s;
int max_width;
@@ -297,22 +301,25 @@ diagnostic_show_locus (diagnostic_context * context,
context->last_location = diagnostic->location;
s = expand_location_to_spelling_point (diagnostic->location);
- line = location_get_source_line (s);
+ line = location_get_source_line (s, &line_width);
if (line == NULL)
return;
max_width = context->caret_max_width;
- line = adjust_line (line, max_width, &(s.column));
+ line = adjust_line (line, line_width, max_width, &(s.column));
pp_newline (context->printer);
saved_prefix = pp_get_prefix (context->printer);
pp_set_prefix (context->printer, NULL);
pp_space (context->printer);
- while (max_width > 0 && *line != '\0')
+ while (max_width > 0 && line_width > 0)
{
char c = *line == '\t' ? ' ' : *line;
+ if (c == '\0')
+ c = ' ';
pp_character (context->printer, c);
max_width--;
+ line_width--;
line++;
}
pp_newline (context->printer);
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index cb38d37..3f30e06 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -291,6 +291,7 @@ void default_diagnostic_starter (diagnostic_context *, diagnostic_info *);
void default_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
void diagnostic_set_caret_max_width (diagnostic_context *context, int value);
+void diagnostic_file_cache_fini (void);
/* Pure text formatting support functions. */
extern char *file_name_as_prefix (diagnostic_context *, const char *);
diff --git a/gcc/input.c b/gcc/input.c
index a141a92..5f67d40 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -22,6 +22,86 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "intl.h"
#include "input.h"
+#include "vec.h"
+
+/* This is a cache used by get_next_line to store the content of a
+ file to be searched for file lines. */
+struct fcache
+{
+ /* These are information used to store a line boundary. */
+ struct line_info
+ {
+ /* The line number. It starts from 1. */
+ size_t line_num;
+
+ /* The position (byte count) of the beginning of the line,
+ relative to the file data pointer. This starts at zero. */
+ size_t start_pos;
+
+ /* The position (byte count) of the last byte of the line. This
+ normally points to the '\n' character, or to one byte after the
+ last byte of the file, if the file doesn't contain a '\n'
+ character. */
+ size_t end_pos;
+
+ line_info (size_t l, size_t s, size_t e)
+ : line_num (l), start_pos (s), end_pos (e)
+ {}
+
+ line_info ()
+ :line_num (0), start_pos (0), end_pos (0)
+ {}
+ };
+
+ /* The number of time this file has been accessed. This is used
+ to designate which file cache to evict from the cache
+ array. */
+ unsigned use_count;
+
+ const char *file_path;
+
+ FILE *fp;
+
+ /* This points to the content of the file that we've read so
+ far. */
+ char *data;
+
+ /* The size of the DATA array above.*/
+ size_t size;
+
+ /* The number of bytes read from the underlying file so far. This
+ must be less (or equal) than SIZE above. */
+ size_t nb_read;
+
+ /* The index of the beginning of the current line. */
+ size_t line_start_idx;
+
+ /* The number of the previous line read. This starts at 1. Zero
+ means we've read no line so far. */
+ size_t line_num;
+
+ /* This is the total number of lines of the current file. At the
+ moment, we try to get this information from the line map
+ subsystem. Note that this is just a hint. When using the C++
+ front-end, this hint is correct because the input file is then
+ completely tokenized before parsing starts; so the line map knows
+ the number of lines before compilation really starts. For e.g,
+ the C front-end, it can happen that we start emitting diagnostics
+ before the line map has seen the end of the file. */
+ size_t total_lines;
+
+ /* This is a record of the beginning and end of the lines we've seen
+ while reading the file. This is useful to avoid walking the data
+ from the beginning when we are asked to read a line that is
+ before LINE_START_IDX above. Note that the maximum size of this
+ record is fcache_line_record_size, so that the memory consumption
+ doesn't explode. We thus scale total_lines down to
+ fcache_line_record_size. */
+ vec<line_info, va_heap> line_record;
+
+ fcache ();
+ ~fcache ();
+};
/* Current position in real source file. */
@@ -29,6 +109,11 @@ location_t input_location;
struct line_maps *line_table;
+static fcache *fcache_tab;
+static const size_t fcache_tab_size = 16;
+static const size_t fcache_buffer_size = 4 * 1024;
+static const size_t fcache_line_record_size = 100;
+
/* Expand the source location LOC into a human readable location. If
LOC resolves to a builtin location, the file name of the readable
location is set to the string "<built-in>". If EXPANSION_POINT_P is
@@ -87,56 +172,546 @@ expand_location_1 (source_location loc,
return xloc;
}
-/* Reads one line from file into a static buffer. */
-static const char *
-read_line (FILE *file)
+/* Initialize the set of cache used for files accessed by caret
+ diagnostic. */
+
+static void
+diagnostic_file_cache_init (void)
+{
+ if (fcache_tab == NULL)
+ fcache_tab = new fcache[fcache_tab_size];
+}
+
+/* Free the ressources used by the set of cache used for files accessed
+ by caret diagnostic. */
+
+void
+diagnostic_file_cache_fini (void)
+{
+ if (fcache_tab)
+ {
+ delete [] (fcache_tab);
+ fcache_tab = NULL;
+ }
+}
+
+/* Return the total lines number that have been read so far by the
+ line map (in the preprocessor) so far. For languages like C++ that
+ entirely preprocess the input file before starting to parse, this
+ equals the actual number of lines of the file. */
+
+static size_t
+total_lines_num (const char *file_path)
+{
+ size_t r = 0;
+ source_location l = 0;
+ if (linemap_get_file_highest_location (line_table, file_path, &l))
+ {
+ gcc_assert (l >= RESERVED_LOCATION_COUNT);
+ expanded_location xloc = expand_location (l);
+ r = xloc.line;
+ }
+ return r;
+}
+
+/* Lookup the cache used for the content of a given file accessed by
+ caret diagnostic. Return the found cached file, or NULL if no
+ cached file was found. */
+
+static fcache*
+lookup_file_in_cache_tab (const char *file_path)
+{
+ if (file_path == NULL)
+ return NULL;
+
+ diagnostic_file_cache_init ();
+
+ /* This will contain the found cached file. */
+ fcache *r = NULL;
+ for (unsigned i = 0; i < fcache_tab_size; ++i)
+ {
+ fcache *c = &fcache_tab[i];
+ if (c->file_path && !strcmp (c->file_path, file_path))
+ {
+ ++c->use_count;
+ r = c;
+ }
+ }
+
+ if (r)
+ ++r->use_count;
+
+ return r;
+}
+
+/* Return the file cache that has been less used, recently, or the
+ first empty one. If HIGHEST_USE_COUNT is non-null,
+ *HIGHEST_USE_COUNT is set to the highest use count of the entries
+ in the cache table. */
+
+static fcache*
+evicted_cache_tab_entry (unsigned *highest_use_count)
+{
+ diagnostic_file_cache_init ();
+
+ fcache *to_evict = &fcache_tab[0];
+ unsigned huc = to_evict->use_count;
+ for (unsigned i = 1; i < fcache_tab_size; ++i)
+ {
+ fcache *c = &fcache_tab[i];
+ bool c_is_empty = (c->file_path == NULL);
+
+ if (c->use_count < to_evict->use_count
+ || (to_evict->file_path && c_is_empty))
+ /* We evict C because it's either an entry with a lower use
+ count or one that is empty. */
+ to_evict = c;
+
+ if (huc < c->use_count)
+ huc = c->use_count;
+
+ if (c_is_empty)
+ /* We've reached the end of the cache; subsequent elements are
+ all empty. */
+ break;
+ }
+
+ if (highest_use_count)
+ *highest_use_count = huc;
+
+ return to_evict;
+}
+
+/* Create the cache used for the content of a given file to be
+ accessed by caret diagnostic. This cache is added to an array of
+ cache and can be retrieved by lookup_file_in_cache_tab. This
+ function returns the created cache. Note that only the last
+ fcache_tab_size files are cached. */
+
+static fcache*
+add_file_to_cache_tab (const char *file_path)
+{
+
+ FILE *fp = fopen (file_path, "r");
+ if (ferror (fp))
+ {
+ fclose (fp);
+ return NULL;
+ }
+
+ unsigned highest_use_count = 0;
+ fcache *r = evicted_cache_tab_entry (&highest_use_count);
+ r->file_path = file_path;
+ if (r->fp)
+ fclose (r->fp);
+ r->fp = fp;
+ r->nb_read = 0;
+ r->line_start_idx = 0;
+ r->line_num = 0;
+ r->line_record.truncate (0);
+ /* Ensure that this cache entry doesn't get evicted next time
+ add_file_to_cache_tab is called. */
+ r->use_count = ++highest_use_count;
+ r->total_lines = total_lines_num (file_path);
+
+ return r;
+}
+
+/* Lookup the cache used for the content of a given file accessed by
+ caret diagnostic. If no cached file was found, create a new cache
+ for this file, add it to the array of cached file and return
+ it. */
+
+static fcache*
+lookup_or_add_file_to_cache_tab (const char *file_path)
+{
+ fcache *r = lookup_file_in_cache_tab (file_path);
+ if (r == NULL)
+ r = add_file_to_cache_tab (file_path);
+ return r;
+}
+
+/* Default constructor for a cache of file used by caret
+ diagnostic. */
+
+fcache::fcache ()
+: use_count (0), file_path (NULL), fp (NULL), data (0),
+ size (0), nb_read (0), line_start_idx (0), line_num (0),
+ total_lines (0)
+{
+ line_record.create (0);
+}
+
+/* Destructor for a cache of file used by caret diagnostic. */
+
+fcache::~fcache ()
+{
+ if (fp)
+ {
+ fclose (fp);
+ fp = NULL;
+ }
+ if (data)
+ {
+ XDELETEVEC (data);
+ data = 0;
+ }
+ line_record.release ();
+}
+
+/* Returns TRUE iff the cache would need to be filled with data coming
+ from the file. That is, either the cache is empty or full or the
+ current line is empty. Note that if the cache is full, it would
+ need to be extended and filled again. */
+
+static bool
+needs_read (fcache *c)
+{
+ return (c->nb_read == 0
+ || c->nb_read == c->size
+ || (c->line_start_idx >= c->nb_read - 1));
+}
+
+/* Return TRUE iff the cache is full and thus needs to be
+ extended. */
+
+static bool
+needs_grow (fcache *c)
+{
+ return c->nb_read == c->size;
+}
+
+/* Grow the cache if it needs to be extended. */
+
+static void
+maybe_grow (fcache *c)
+{
+ if (!needs_grow (c))
+ return;
+
+ size_t size = c->size == 0 ? fcache_buffer_size : c->size * 2;
+ c->data = XRESIZEVEC (char, c->data, size + 1);
+ c->size = size;
+}
+
+/* Read more data into the cache. Extends the cache if need be.
+ Returns TRUE iff new data could be read. */
+
+static bool
+read_data (fcache *c)
+{
+ if (feof (c->fp) || ferror (c->fp))
+ return false;
+
+ maybe_grow (c);
+
+ char * from = c->data + c->nb_read;
+ size_t to_read = c->size - c->nb_read;
+ size_t nb_read = fread (from, 1, to_read, c->fp);
+
+ if (ferror (c->fp))
+ return false;
+
+ c->nb_read += nb_read;
+ return !!nb_read;
+}
+
+/* Read new data iff the cache needs to be filled with more data
+ coming from the file FP. Return TRUE iff the cache was filled with
+ mode data. */
+
+static bool
+maybe_read_data (fcache *c)
{
- static char *string;
- static size_t string_len;
- size_t pos = 0;
- char *ptr;
+ if (!needs_read (c))
+ return false;
+ return read_data (c);
+}
+
+/* Read a new line from file FP, using C as a cache for the data
+ coming from the file. Upon successful completion, *LINE is set to
+ the beginning of the line found. Space for that line has been
+ allocated in the cache thus *LINE has the same life time as C.
+ This function returns the length of the line, including the
+ terminal '\n' character. Note that subsequent calls to
+ get_next_line return the next lines of the file and might overwrite
+ the content of *LINE. */
+
+static ssize_t
+get_next_line (fcache *c, char **line)
+{
+ /* Fill the cache with data to process. */
+ maybe_read_data (c);
+
+ size_t remaining_size = c->nb_read - c->line_start_idx;
+ if (remaining_size == 0)
+ /* There is no more data to process. */
+ return 0;
+
+ char *line_start = c->data + c->line_start_idx;
- if (!string_len)
+ char *next_line_start = NULL;
+ size_t line_len = 0;
+ char *line_end = (char *) memchr (line_start, '\n', remaining_size);
+ if (line_end == NULL)
{
- string_len = 200;
- string = XNEWVEC (char, string_len);
+ /* We haven't found the end-of-line delimiter in the cache.
+ Fill the cache with more data from the file and look for the
+ '\n'. */
+ while (maybe_read_data (c))
+ {
+ line_start = c->data + c->line_start_idx;
+ remaining_size = c->nb_read - c->line_start_idx;
+ line_end = (char *) memchr (line_start, '\n', remaining_size);
+ if (line_end != NULL)
+ {
+ next_line_start = line_end + 1;
+ line_len = line_end - line_start + 1;
+ break;
+ }
+ }
+ if (line_end == NULL)
+ {
+ /* We've loadded all the file into the cache and still no
+ '\n'. Let's say the line ends up at the byte after the
+ last byte of the file. */
+ line_end = c->data + c->nb_read;
+ line_len = c->nb_read - c->line_start_idx;
+ }
}
+ else
+ {
+ next_line_start = line_end + 1;
+ line_len = line_end - line_start + 1;;
+ }
+
+ if (ferror (c->fp))
+ return -1;
+
+ /* At this point, we've found the end of the of line. It either
+ points to the '\n' or to one byte after the last byte of the
+ file. */
+ gcc_assert (line_end != NULL);
- while ((ptr = fgets (string + pos, string_len - pos, file)))
+ if (c->line_start_idx < c->nb_read)
+ *line = line_start;
+
+ gcc_assert (line_len > 0);
+
+ ++c->line_num;
+
+ /* Before we update our line record, make sure the hint about the
+ total number of lines of the file is correct. If it's not, then
+ we give up recording line boundaries from now on. */
+ bool update_line_record = true;
+ if (c->line_num > c->total_lines)
+ update_line_record = false;
+
+ /* Now update our line record so that re-reading lines from the
+ before c->line_start_idx is faster. */
+ if (update_line_record
+ && c->line_record.length () < fcache_line_record_size)
{
- size_t len = strlen (string + pos);
+ /* If the file lines fits in the line record, we just record all
+ its lines ...*/
+ if (c->total_lines <= fcache_line_record_size
+ && c->line_num > c->line_record.length ())
+ c->line_record.safe_push (fcache::line_info (c->line_num,
+ c->line_start_idx,
+ line_end - c->data));
+ else if (c->total_lines > fcache_line_record_size)
+ {
+ /* ... otherwise, we just scale total_lines down to
+ (fcache_line_record_size lines. */
+ size_t n = (c->line_num * fcache_line_record_size) / c->total_lines;
+ if (c->line_record.length () == 0
+ || n >= c->line_record.length ())
+ c->line_record.safe_push (fcache::line_info (c->line_num,
+ c->line_start_idx,
+ line_end - c->data));
+ }
+ }
+
+ /* Update c->line_start_idx so that it points to the next line to be
+ read. */
+ if (next_line_start)
+ c->line_start_idx = next_line_start - c->data;
+ else
+ /* We didn't find any terminal '\n'. Let's consider that the end
+ of line is the end of the data in the cache. The next
+ invocation of get_next_line will either read more data from the
+ underlying file or return false early because we've reached the
+ end of the file. */
+ c->line_start_idx = c->nb_read;
+
+ return line_len;
+}
- if (string[pos + len - 1] == '\n')
+/* Reads the next line from FILE into *LINE. If *LINE is too small
+ (or NULL) it is allocated (or extended) to have enough space to
+ containe the line. *LINE_LENGTH must contain the size of the
+ initial*LINE buffer. It's then updated by this function to the
+ actual length of the returned line. Note that the returned line
+ can contain several zero bytes. Also note that the returned string
+ is allocated in static storage that is going to be re-used by
+ subsequent invocations of read_line. */
+
+static bool
+read_next_line (fcache *cache, char ** line, ssize_t *line_len)
+{
+ char *l = NULL;
+ ssize_t len = get_next_line (cache, &l);
+
+ if (len > 0)
+ {
+ if (*line == NULL)
{
- string[pos + len - 1] = 0;
- return string;
+ *line = XNEWVEC (char, len);
+ *line_len = len;
}
- pos += len;
- string = XRESIZEVEC (char, string, string_len * 2);
- string_len *= 2;
+ else
+ if (*line_len < len)
+ *line = XRESIZEVEC (char, *line, len);
+
+ memmove (*line, l, len);
+ (*line)[len - 1] = '\0';
+ *line_len = --len;
+ return true;
}
-
- return pos ? string : NULL;
+
+ return false;
+}
+
+/* Consume the next bytes coming from the cache (or from its
+ underlying file if there are remaining unread bytes in the file)
+ until we reach the next end-of-line (or end-of-file). There is no
+ copying from the cache involved. Return TRUE upon successful
+ completion. */
+
+static bool
+goto_next_line (fcache *cache)
+{
+ char *l = NULL;
+ ssize_t len = get_next_line (cache, &l);
+ return (len > 0 );
+}
+
+/* Read an arbitrary line number LINE_NUM from the file cached in C.
+ The line is copied into *LINE. *LINE_LEN must have been set to the
+ length of *LINE. If *LINE is too small (or NULL) it's extended (or
+ allocated) and *LINE_LEN is adjusted accordingly. *LINE ends up
+ with a terminal zero byte and can contain additional zero bytes.
+ This function returns bool if a line was read. */
+
+static bool
+read_line_num (fcache *c, size_t line_num,
+ char ** line, ssize_t *line_len)
+{
+ gcc_assert (line_num > 0);
+
+ if (line_num <= c->line_num)
+ {
+ /* We've been asked to read lines that are before c->line_num.
+ So lets use our line record (if it's not empty) to try to
+ avoid re-reading the file from the beginning again. */
+
+ if (c->line_record.is_empty ())
+ {
+ c->line_start_idx = 0;
+ c->line_num = 0;
+ }
+ else
+ {
+ fcache::line_info *i = NULL;
+ if (c->total_lines <= fcache_line_record_size)
+ {
+ /* In languages where the input file is not totally
+ preprocessed up front, the c->total_lines hint
+ can be smaller than the number of lines of the
+ file. In that case, only the first
+ c->total_lines have been recorded.
+
+ Otherwise, the first c->total_lines we've read have
+ their start/end recorded here. */
+ i = (line_num <= c->total_lines)
+ ? &c->line_record[line_num - 1]
+ : &c->line_record[c->total_lines - 1];
+ gcc_assert (i->line_num <= line_num);
+ }
+ else
+ {
+ /* So the file had more lines than our line record
+ size. Thus the number of lines we've recorded has
+ been scaled down to fcache_line_reacord_size. Let's
+ pick the start/end of the recorded line that is
+ closest to line_num. */
+ size_t n = (line_num <= c->total_lines)
+ ? line_num * fcache_line_record_size / c->total_lines
+ : c ->line_record.length () - 1;
+ if (n < c->line_record.length ())
+ {
+ i = &c->line_record[n];
+ gcc_assert (i->line_num <= line_num);
+ }
+ }
+
+ if (i && i->line_num == line_num)
+ {
+ /* We have the start/end of the line. Let's just copy
+ it again and we are done. */
+ ssize_t len = i->end_pos - i->start_pos + 1;
+ if (*line_len < len)
+ *line = XRESIZEVEC (char, *line, len);
+ memmove (*line, c->data + i->start_pos, len);
+ (*line)[len - 1] = '\0';
+ *line_len = --len;
+ return true;
+ }
+
+ if (i)
+ {
+ c->line_start_idx = i->start_pos;
+ c->line_num = i->line_num - 1;
+ }
+ else
+ {
+ c->line_start_idx = 0;
+ c->line_num = 0;
+ }
+ }
+ }
+
+ /* Let's walk from line c->line_num up to line_num - 1, without
+ copying any line. */
+ while (c->line_num < line_num - 1)
+ if (!goto_next_line (c))
+ return false;
+
+ /* The line we want is the next one. Let's read and copy it back to
+ the caller. */
+ return read_next_line (c, line, line_len);
}
/* Return the physical source line that corresponds to xloc in a
buffer that is statically allocated. The newline is replaced by
- the null character. */
+ the null character. Note that the line can contain several null
+ characters, so LINE_LEN, if non-null, points to the actual length
+ of the line. */
const char *
-location_get_source_line (expanded_location xloc)
+location_get_source_line (expanded_location xloc,
+ int *line_len)
{
- const char *buffer;
- int lines = 1;
- FILE *stream = xloc.file ? fopen (xloc.file, "r") : NULL;
- if (!stream)
- return NULL;
+ static char *buffer;
+ static ssize_t len;
+
+ fcache * c = lookup_or_add_file_to_cache_tab (xloc.file);
+ bool read = read_line_num (c, xloc.line, &buffer, &len);
- while ((buffer = read_line (stream)) && lines < xloc.line)
- lines++;
+ if (read && line_len)
+ *line_len = len;
- fclose (stream);
- return buffer;
+ return read ? buffer : NULL;
}
/* Expand the source location LOC into a human readable location. If
diff --git a/gcc/input.h b/gcc/input.h
index 8fdc7b2..c82023f 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -37,7 +37,8 @@ extern char builtins_location_check[(BUILTINS_LOCATION
< RESERVED_LOCATION_COUNT) ? 1 : -1];
extern expanded_location expand_location (source_location);
-extern const char *location_get_source_line (expanded_location xloc);
+extern const char *location_get_source_line (expanded_location xloc,
+ int *line_size);
extern expanded_location expand_location_to_spelling_point (source_location);
extern source_location expansion_point_location_if_in_system_header (source_location);
@@ -65,4 +66,6 @@ extern location_t input_location;
void dump_line_table_statistics (void);
+void diagnostics_file_cache_fini (void);
+
#endif
diff --git a/gcc/testsuite/c-c++-common/cpp/warning-zero-in-literals-1.c b/gcc/testsuite/c-c++-common/cpp/warning-zero-in-literals-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff2ed962ac96e47ae05b0b040f4e10b8e09637e2
GIT binary patch
literal 240
zcmdPbSEyD<N!LxuS12e-Ehx%QPAx80sO92PVo*}h*HVDUmM0eFW#*+TDCL#r<R~O(
UBo-wmm!uXcDby-x=?^KT09Xk|)&Kwi
literal 0
HcmV?d00001
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index a0d6da1..3504fd6 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -756,6 +756,14 @@ struct linemap_stats
long duplicated_macro_maps_locations_size;
};
+/* Return the highest location emitted for a given file for which
+ there is a line map in SET. FILE_NAME is the file name to
+ consider. If the function returns TRUE, *LOC is set to the highest
+ location emitted for that file. */
+bool linemap_get_file_highest_location (struct line_maps * set,
+ const char *file_name,
+ source_location*LOC);
+
/* Compute and return statistics about the memory consumption of some
parts of the line table SET. */
void linemap_get_statistics (struct line_maps *, struct linemap_stats *);
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 2ad7ad2..98db486 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1502,6 +1502,46 @@ linemap_dump_location (struct line_maps *set,
path, from, l, c, s, (void*)map, e, loc, location);
}
+/* Return the highest location emitted for a given file for which
+ there is a line map in SET. FILE_NAME is the file name to
+ consider. If the function returns TRUE, *LOC is set to the highest
+ location emitted for that file. */
+
+bool
+linemap_get_file_highest_location (struct line_maps *set,
+ const char *file_name,
+ source_location *loc)
+{
+ /* If the set is empty or no ordinary map has been created then
+ there is no file to look for ... */
+ if (set == NULL || set->info_ordinary.used == 0)
+ return false;
+
+ /* Now look for the last ordinary map created for FILE_NAME. */
+ int i;
+ for (i = set->info_ordinary.used - 1; i >= 0; --i)
+ {
+ const char *fname = set->info_ordinary.maps[i].d.ordinary.to_file;
+ if (fname && !strcmp (fname, file_name))
+ break;
+ }
+
+ if (i < 0)
+ return false;
+
+ /* The highest location for a given map is either the starting
+ location of the next map minus one, or -- if the map is the
+ latest one -- the highest location of the set. */
+ source_location result;
+ if (i == (int) set->info_ordinary.used - 1)
+ result = set->highest_location;
+ else
+ result = set->info_ordinary.maps[i + 1].start_location - 1;
+
+ *loc = result;
+ return true;
+}
+
/* Compute and return statistics about the memory consumption of some
parts of the line table SET. */
--
Dodji
next prev parent reply other threads:[~2013-11-12 15:33 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-10-31 14:48 Bernd Edlinger
2013-10-31 15:06 ` Jakub Jelinek
2013-10-31 15:19 ` Dodji Seketeli
2013-10-31 18:26 ` Jakub Jelinek
2013-11-04 11:52 ` Dodji Seketeli
2013-11-04 11:59 ` Jakub Jelinek
2013-11-04 15:42 ` Dodji Seketeli
2013-11-05 0:10 ` Bernd Edlinger
2013-11-05 9:50 ` Dodji Seketeli
2013-11-05 11:19 ` Bernd Edlinger
2013-11-05 11:43 ` Dodji Seketeli
2013-11-06 22:27 ` Bernd Edlinger
2013-11-04 12:06 ` Bernd Edlinger
2013-11-04 12:15 ` Jakub Jelinek
2013-11-04 12:32 ` Bernd Edlinger
2013-11-04 15:21 ` Dodji Seketeli
2013-11-11 10:49 ` Dodji Seketeli
2013-11-11 14:35 ` Jakub Jelinek
2013-11-11 17:13 ` Dodji Seketeli
2013-11-12 16:42 ` Dodji Seketeli [this message]
2013-11-13 5:10 ` Bernd Edlinger
2013-11-13 9:40 ` Dodji Seketeli
2013-11-13 9:43 ` Bernd Edlinger
2013-11-13 9:49 ` Dodji Seketeli
2013-11-13 9:49 ` Dodji Seketeli
2013-11-13 9:51 ` Jakub Jelinek
2013-11-14 15:12 ` Dodji Seketeli
2013-12-09 20:11 ` Tom Tromey
2014-01-21 12:28 ` Bernd Edlinger
2014-01-22 8:16 ` Dodji Seketeli
2014-01-23 17:12 ` Jakub Jelinek
2014-01-24 2:58 ` Bernd Edlinger
2014-01-24 7:53 ` Dodji Seketeli
2014-01-24 15:05 ` Markus Trippelsdorf
2014-01-24 15:41 ` Dodji Seketeli
2014-01-24 15:44 ` Jakub Jelinek
2014-01-24 16:09 ` Dodji Seketeli
2014-01-24 16:13 ` Jakub Jelinek
2014-01-24 23:02 ` Markus Trippelsdorf
2014-01-24 23:20 ` Markus Trippelsdorf
2014-01-28 13:20 ` Dodji Seketeli
2014-01-28 13:23 ` Dodji Seketeli
2014-01-28 18:40 ` H.J. Lu
2014-01-29 11:28 ` Dodji Seketeli
-- strict thread matches above, loose matches on Subject: below --
2013-10-31 13:45 Dodji Seketeli
2013-10-31 17:30 ` Manuel López-Ibáñez
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=878uwt63e2.fsf@redhat.com \
--to=dodji@redhat.com \
--cc=bernd.edlinger@hotmail.de \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
--cc=lopezibanez@gmail.com \
--cc=tromey@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).