From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4466 invoked by alias); 12 Nov 2013 15:33:57 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 4436 invoked by uid 89); 12 Nov 2013 15:33:56 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL,BAYES_50,RDNS_NONE,SPF_HELO_PASS,URIBL_BLOCKED autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from Unknown (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 12 Nov 2013 15:33:53 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id rACFXiue017414 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 12 Nov 2013 10:33:45 -0500 Received: from localhost (ovpn-113-88.phx2.redhat.com [10.3.113.88]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id rACFXgqY012006 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 12 Nov 2013 10:33:43 -0500 Received: by localhost (Postfix, from userid 1000) id AB9CE16503A; Tue, 12 Nov 2013 16:33:41 +0100 (CET) From: Dodji Seketeli To: Jakub Jelinek Cc: GCC Patches , Tom Tromey , Manuel =?utf-8?B?TMOzcGV6LUliw6HDsWV6?= , Bernd Edlinger Subject: Re: [PATCH] preprocessor/58580 - preprocessor goes OOM with warning for zero literals References: <20131031144309.GR27813@tucnak.zalov.cz> <87y559xz7y.fsf@redhat.com> <20131031173649.GW27813@tucnak.zalov.cz> <87zjpbb5qu.fsf@redhat.com> <20131111142159.GZ27813@tucnak.zalov.cz> <878uwuap4f.fsf@redhat.com> X-URL: http://www.redhat.com Date: Tue, 12 Nov 2013 16:42:00 -0000 In-Reply-To: <878uwuap4f.fsf@redhat.com> (Dodji Seketeli's message of "Mon, 11 Nov 2013 17:18:24 +0100") Message-ID: <878uwt63e2.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-SW-Source: 2013-11/txt/msg01291.txt.bz2 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_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 "". 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 zcmdPbSEyDinfo_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