diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 5f17e5edc6b7d6c143c1bf44260b7593b203f036..8fd316abb0f22dd87a010921f27dea5a8226b632 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,5 +1,25 @@
 2005-07-14  Jakub Jelinek  <jakub@redhat.com>
 
+	* gfortran.h (MAX_ERROR_MESSAGE): Remove.
+	(gfc_error_buf): Add allocated and index fields.  Change message
+	field from array to a pointer.
+	* error.c (use_warning_buffer, error_ptr, warning_ptr): Remove.
+	(cur_error_buffer): New variable.
+	(error_char): Use cur_error_buffer->{message,index} instead of
+	{warning,error}_{buffer.message,ptr}.  Reallocate message buffer
+	if too small.
+	(gfc_warning, gfc_notify_std, gfc_error, gfc_error_now): Setup
+	cur_error_buffer and its index rather than {warning,error}_ptr
+	and use_warning_buffer.
+	(gfc_warning_check, gfc_error_check): Don't print anything if
+	message is NULL.
+	(gfc_push_error): Allocate saved message with xstrdup.
+	(gfc_pop_error): Free saved message with gfc_free.
+	(gfc_free_error): New function.
+	* primary.c (match_complex_constant): Call gfc_free_error if
+	gfc_pop_error will not be called.
+	* match.c (gfc_match_st_function): Likewise.
+
 	PR fortran/22417
 	* scanner.c (preprocessor_line): Don't treat flag 3 as the start of a new
 	file.  Fix file left but not entered warning.
diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
index fe7decc5dfbf75250ab04cd92abc4603ccede885..009419a0979614c48e73c930437ada7eaf88716e 100644
--- a/gcc/fortran/error.c
+++ b/gcc/fortran/error.c
@@ -33,12 +33,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 
 int gfc_suppress_error = 0;
 
-static int terminal_width, buffer_flag, errors,
-  use_warning_buffer, warnings;
+static int terminal_width, buffer_flag, errors, warnings;
 
-static char *error_ptr, *warning_ptr;
-
-static gfc_error_buf error_buffer, warning_buffer;
+static gfc_error_buf error_buffer, warning_buffer, *cur_error_buffer;
 
 
 /* Per-file error initialization.  */
@@ -70,18 +67,16 @@ error_char (char c)
 {
   if (buffer_flag)
     {
-      if (use_warning_buffer)
+      if (cur_error_buffer->index >= cur_error_buffer->allocated)
 	{
-	  *warning_ptr++ = c;
-	  if (warning_ptr - warning_buffer.message >= MAX_ERROR_MESSAGE)
-	    gfc_internal_error ("error_char(): Warning buffer overflow");
-	}
-      else
-	{
-	  *error_ptr++ = c;
-	  if (error_ptr - error_buffer.message >= MAX_ERROR_MESSAGE)
-	    gfc_internal_error ("error_char(): Error buffer overflow");
+	  cur_error_buffer->allocated =
+	    cur_error_buffer->allocated
+	    ? cur_error_buffer->allocated * 2 : 1000;
+	  cur_error_buffer->message
+	    = xrealloc (cur_error_buffer->message,
+			cur_error_buffer->allocated);
 	}
+      cur_error_buffer->message[cur_error_buffer->index++] = c;
     }
   else
     {
@@ -89,11 +84,16 @@ error_char (char c)
 	{
 	  /* We build up complete lines before handing things
 	     over to the library in order to speed up error printing.  */
-	  static char line[MAX_ERROR_MESSAGE + 1];
-	  static int index = 0;
+	  static char *line;
+	  static size_t allocated = 0, index = 0;
 
+	  if (index + 1 >= allocated)
+	    {
+	      allocated = allocated ? allocated * 2 : 1000;
+	      line = xrealloc (line, allocated);
+	    }
 	  line[index++] = c;
-	  if (c == '\n' || index == MAX_ERROR_MESSAGE)
+	  if (c == '\n')
 	    {
 	      line[index] = '\0';
 	      fputs (line, stderr);
@@ -470,8 +470,8 @@ gfc_warning (const char *format, ...)
     return;
 
   warning_buffer.flag = 1;
-  warning_ptr = warning_buffer.message;
-  use_warning_buffer = 1;
+  warning_buffer.index = 0;
+  cur_error_buffer = &warning_buffer;
 
   va_start (argp, format);
   if (buffer_flag == 0)
@@ -503,18 +503,9 @@ gfc_notify_std (int std, const char *format, ...)
   if (gfc_suppress_error)
     return warning ? SUCCESS : FAILURE;
   
-  if (warning)
-    {
-      warning_buffer.flag = 1;
-      warning_ptr = warning_buffer.message;
-      use_warning_buffer = 1;
-    }
-  else
-    {
-      error_buffer.flag = 1;
-      error_ptr = error_buffer.message;
-      use_warning_buffer = 0;
-    }
+  cur_error_buffer = warning ? &warning_buffer : &error_buffer;
+  cur_error_buffer->flag = 1;
+  cur_error_buffer->index = 0;
 
   if (buffer_flag == 0)
     {
@@ -577,7 +568,8 @@ gfc_warning_check (void)
   if (warning_buffer.flag)
     {
       warnings++;
-      fputs (warning_buffer.message, stderr);
+      if (warning_buffer.message != NULL)
+	fputs (warning_buffer.message, stderr);
       warning_buffer.flag = 0;
     }
 }
@@ -594,8 +586,8 @@ gfc_error (const char *format, ...)
     return;
 
   error_buffer.flag = 1;
-  error_ptr = error_buffer.message;
-  use_warning_buffer = 0;
+  error_buffer.index = 0;
+  cur_error_buffer = &error_buffer;
 
   va_start (argp, format);
   if (buffer_flag == 0)
@@ -616,7 +608,8 @@ gfc_error_now (const char *format, ...)
   int i;
 
   error_buffer.flag = 1;
-  error_ptr = error_buffer.message;
+  error_buffer.index = 0;
+  cur_error_buffer = &error_buffer;
 
   i = buffer_flag;
   buffer_flag = 0;
@@ -691,7 +684,8 @@ gfc_error_check (void)
   if (error_buffer.flag)
     {
       errors++;
-      fputs (error_buffer.message, stderr);
+      if (error_buffer.message != NULL)
+	fputs (error_buffer.message, stderr);
       error_buffer.flag = 0;
     }
 
@@ -706,7 +700,7 @@ gfc_push_error (gfc_error_buf * err)
 {
   err->flag = error_buffer.flag;
   if (error_buffer.flag)
-    strcpy (err->message, error_buffer.message);
+    err->message = xstrdup (error_buffer.message);
 
   error_buffer.flag = 0;
 }
@@ -719,7 +713,22 @@ gfc_pop_error (gfc_error_buf * err)
 {
   error_buffer.flag = err->flag;
   if (error_buffer.flag)
-    strcpy (error_buffer.message, err->message);
+    {
+      size_t len = strlen (err->message) + 1;
+      gcc_assert (len <= error_buffer.allocated);
+      memcpy (error_buffer.message, err->message, len);
+      gfc_free (err->message);
+    }
+}
+
+
+/* Free a pushed error state, but keep the current error state.  */
+
+void
+gfc_free_error (gfc_error_buf * err)
+{
+  if (err->flag)
+    gfc_free (err->message);
 }
 
 
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 71b6c19b9325416980340e6784dbac16a0344094..dea08c3e20de9d5310a6f59fec128f512b330ee1 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -58,7 +58,6 @@ char *alloca ();
 #define GFC_MAX_LINE 132	/* Characters beyond this are not seen.  */
 #define GFC_MAX_DIMENSIONS 7	/* Maximum dimensions in an array.  */
 #define GFC_LETTERS 26		/* Number of letters in the alphabet.  */
-#define MAX_ERROR_MESSAGE 1000	/* Maximum length of an error message.  */
 
 #define free(x) Use_gfc_free_instead_of_free()
 #define gfc_is_whitespace(c) ((c==' ') || (c=='\t'))
@@ -1548,7 +1547,8 @@ const char * gfc_get_string (const char *, ...) ATTRIBUTE_PRINTF_1;
 typedef struct gfc_error_buf
 {
   int flag;
-  char message[MAX_ERROR_MESSAGE];
+  size_t allocated, index;
+  char *message;
 } gfc_error_buf;
 
 void gfc_error_init_1 (void);
@@ -1574,6 +1574,7 @@ try gfc_notify_std (int, const char *, ...) ATTRIBUTE_GCC_GFC(2,3);
 
 void gfc_push_error (gfc_error_buf *);
 void gfc_pop_error (gfc_error_buf *);
+void gfc_free_error (gfc_error_buf *);
 
 void gfc_status (const char *, ...) ATTRIBUTE_PRINTF_1;
 void gfc_status_char (char);
diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c
index f63eaf6bed3a192c45a17af41c41836d21f5a224..7f249eecf10e01df60dba94b7b79515fcd5a6963 100644
--- a/gcc/fortran/match.c
+++ b/gcc/fortran/match.c
@@ -2650,6 +2650,8 @@ gfc_match_st_function (void)
   m = gfc_match (" = %e%t", &expr);
   if (m == MATCH_NO)
     goto undo_error;
+
+  gfc_free_error (&old_error);
   if (m == MATCH_ERROR)
     return m;
 
diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c
index 36e5eb96f37c65e375cf225ec0d16d58d4e642b9..888caffa5c281748b402eeefa2ceea9457f68e67 100644
--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -1117,7 +1117,10 @@ match_complex_constant (gfc_expr ** result)
 
   m = match_complex_part (&real);
   if (m == MATCH_NO)
-    goto cleanup;
+    {
+      gfc_free_error (&old_error);
+      goto cleanup;
+    }
 
   if (gfc_match_char (',') == MATCH_NO)
     {
@@ -1132,7 +1135,10 @@ match_complex_constant (gfc_expr ** result)
      sort. These sort of lists are matched prior to coming here.  */
 
   if (m == MATCH_ERROR)
-    goto cleanup;
+    {
+      gfc_free_error (&old_error);
+      goto cleanup;
+    }
   gfc_pop_error (&old_error);
 
   m = match_complex_part (&imag);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d0c2c653efab2fdf402bd25b3d8dd05c3e40ce48..334e96e46385cabef4161288a45174506393ce0f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,7 @@
 2005-07-14  Jakub Jelinek  <jakub@redhat.com>
 
+	* gfortran.dg/g77/cpp6.f: New test.
+
 	PR fortran/22417
 	* gfortran.dg/g77/cpp5.F: New test.
 	* gfortran.dg/g77/cpp5.h: New file.
diff --git a/gcc/testsuite/gfortran.dg/g77/cpp6.f b/gcc/testsuite/gfortran.dg/g77/cpp6.f
new file mode 100644
index 0000000000000000000000000000000000000000..5f973c15b2b7f67148074749ffed969891f9acec
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/g77/cpp6.f
@@ -0,0 +1,20 @@
+# 1 "test.F"
+# 1 "<built-in>"
+# 1 "<command line>"
+# 1 "test.F"
+	! { dg-do compile }
+
+# 1 "A234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" 1
+
+# 1 "B234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" 1
+
+# 1 "C234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" 1
+
+# 1 "D234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" 1
+	PARAMETER (I=1)
+
+# 2 "C234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" 2
+# 2 "B234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" 2
+# 2 "A234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" 2
+# 3 "test.F" 2
+	END