https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98882
--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
It isn't just on empty files, but on any files that don't end with newline.
I believe the
/* Files always end in a newline. We rely on this for
character peeking safety. */
gcc_assert (buffer->rlimit[-1] == '\n');
assert is just wrong.
It isn't buffer->rlimit[-1] that should be '\n', it is actually
buffer->rlimit[0] that should be end of line terminator, buffer->rlimit[-1] is
the last character of the buffer, so whatever is in the buffer (and empty files
have buffer->cur == buffer->rlimit and thus have even nothing there at all so
rlimit[-1] access is invalid).
Another problem is though that even buffer->rlimit[0] == '\n' is not
guaranteed.
libcpp/charset.c has:
/* If the file is using old-school Mac line endings (\r only),
terminate with another \r, not an \n, so that we do not mistake
the \r\n sequence for a single DOS line ending and erroneously
issue the "No newline at end of file" diagnostic. */
if (to.len && to.text[to.len - 1] == '\r')
to.text[to.len] = '\r';
else
to.text[to.len] = '\n';
So, I think we can assert that buffer->rlimit[0] == '\n' || buffer->rlimit[0]
== '\r' and in the
case '\r': /* MAC line ending, or Windows \r\n */
if (*pos == '\n')
pos++;
/* FALLTHROUGH */
and
else if (*pos == '\r')
{
if (pos[1] == '\n')
pos++;
pos++;
goto next_line;
}
goto dflt;
and
case '\r':
if (*pos == '\n')
pos++;
(twice) cases unfortunately need to compare pos against limit.