diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index f599bd625a588fdce26ffdd83777499dfb8c2b00..00dcfddb6f6f114b4dbd1c473cb22723f8f12da7 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,16 @@
+2005-12-30  Francois-Xavier Coudert  <coudert@clipper.ens.fr>
+
+	PR fortran/25106
+	* parse.c (next_free): Use new prototype for gfc_match_st_label.
+	Correctly emit hard error if a label is zero.
+	* match.c (gfc_match_st_label): Never allow zero as a valid
+	label.
+	(gfc_match, gfc_match_do, gfc_match_goto): Use new prototype for
+	gfc_match_st_label.
+	* primary.c (): Use new prototype for gfc_match_st_label.
+	* io.c (): Likewise.
+	* match.h: Likewise.
+
 2005-12-02  Richard Guenther  <rguenther@suse.de>
 
 	* trans.h (build1_v): Use build1, not build to build the
diff --git a/gcc/fortran/io.c b/gcc/fortran/io.c
index 9ef97e84b7dc79372963b2572da8bff46eb8772a..6adc1efb613a05385b0da19430a4d5b157f96c85 100644
--- a/gcc/fortran/io.c
+++ b/gcc/fortran/io.c
@@ -1591,7 +1591,7 @@ match_dt_format (gfc_dt * dt)
       return MATCH_YES;
     }
 
-  if (gfc_match_st_label (&label, 0) == MATCH_YES)
+  if (gfc_match_st_label (&label) == MATCH_YES)
     {
       if (dt->format_expr != NULL || dt->format_label != NULL)
 	{
diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c
index 97e8f5a434f910c490a9aaf8446d151aca715d3a..8ca7ed6adaaf49a3e9bc8cf4622fc53b1d79be10 100644
--- a/gcc/fortran/match.c
+++ b/gcc/fortran/match.c
@@ -217,7 +217,7 @@ gfc_match_small_int (int *value)
    do most of the work.  */
 
 match
-gfc_match_st_label (gfc_st_label ** label, int allow_zero)
+gfc_match_st_label (gfc_st_label ** label)
 {
   locus old_loc;
   match m;
@@ -229,13 +229,16 @@ gfc_match_st_label (gfc_st_label ** label, int allow_zero)
   if (m != MATCH_YES)
     return m;
 
-  if (((i == 0) && allow_zero) || i <= 99999)
+  if (i > 0 && i <= 99999)
     {
       *label = gfc_get_st_label (i);
       return MATCH_YES;
     }
 
-  gfc_error ("Statement label at %C is out of range");
+  if (i == 0)
+    gfc_error ("Statement label at %C is zero");
+  else
+    gfc_error ("Statement label at %C is out of range");
   gfc_current_locus = old_loc;
   return MATCH_ERROR;
 }
@@ -690,7 +693,7 @@ loop:
 
 	case 'l':
 	  label = va_arg (argp, gfc_st_label **);
-	  n = gfc_match_st_label (label, 0);
+	  n = gfc_match_st_label (label);
 	  if (n != MATCH_YES)
 	    {
 	      m = n;
@@ -1242,7 +1245,7 @@ gfc_match_do (void)
   if (gfc_match (" do") != MATCH_YES)
     return MATCH_NO;
 
-  m = gfc_match_st_label (&label, 0);
+  m = gfc_match_st_label (&label);
   if (m == MATCH_ERROR)
     goto cleanup;
 
@@ -1275,7 +1278,7 @@ gfc_match_do (void)
   gfc_match_label ();		/* This won't error */
   gfc_match (" do ");		/* This will work */
 
-  gfc_match_st_label (&label, 0);	/* Can't error out */
+  gfc_match_st_label (&label);	/* Can't error out */
   gfc_match_char (',');		/* Optional comma */
 
   m = gfc_match_iterator (&iter, 0);
@@ -1585,7 +1588,7 @@ gfc_match_goto (void)
 
       do
 	{
-	  m = gfc_match_st_label (&label, 0);
+	  m = gfc_match_st_label (&label);
 	  if (m != MATCH_YES)
 	    goto syntax;
 
@@ -1631,7 +1634,7 @@ gfc_match_goto (void)
 
   do
     {
-      m = gfc_match_st_label (&label, 0);
+      m = gfc_match_st_label (&label);
       if (m != MATCH_YES)
 	goto syntax;
 
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index a698102fb059bf44122b77742496e0f1dbeffa62..a3c1d813c14bea29938c5aa6829e404367c54a3a 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -41,7 +41,7 @@ extern gfc_st_label *gfc_statement_label;
 match gfc_match_space (void);
 match gfc_match_eos (void);
 match gfc_match_small_literal_int (int *);
-match gfc_match_st_label (gfc_st_label **, int);
+match gfc_match_st_label (gfc_st_label **);
 match gfc_match_label (void);
 match gfc_match_small_int (int *);
 int gfc_match_strings (mstring *);
diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
index 0fc8f966adab0dd5efc044ee42437e75d56b8fbb..311d10a3cebccb8502006cea70a95c74c0f27fae 100644
--- a/gcc/fortran/parse.c
+++ b/gcc/fortran/parse.c
@@ -318,30 +318,25 @@ next_free (void)
   if (ISDIGIT (c))
     {
       /* Found a statement label?  */
-      m = gfc_match_st_label (&gfc_statement_label, 0);
+      m = gfc_match_st_label (&gfc_statement_label);
 
       d = gfc_peek_char ();
       if (m != MATCH_YES || !gfc_is_whitespace (d))
 	{
+	  gfc_match_small_literal_int (&c);
+	  if (c == 0)
+	    gfc_error_now ("Statement label at %C is zero");
+	  else
+	    gfc_error_now ("Statement label at %C is out of range");
+
 	  do
-	    {
-	      /* Skip the bad statement label.  */
-	      gfc_warning_now ("Ignoring bad statement label at %C");
-	      c = gfc_next_char ();
-	    }
-	  while (ISDIGIT (c));
+	    c = gfc_next_char ();
+	  while (ISDIGIT(c));
 	}
       else
 	{
 	  label_locus = gfc_current_locus;
 
-	  if (gfc_statement_label->value == 0)
-	    {
-	      gfc_warning_now ("Ignoring statement label of zero at %C");
-	      gfc_free_st_label (gfc_statement_label);
-	      gfc_statement_label = NULL;
-	    }
-
 	  gfc_gobble_whitespace ();
 
 	  if (gfc_match_eos () == MATCH_YES)
diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c
index d2b7068956f1a20a715d8138b4adb992dfb22930..234a803bfabdeed31a550c8d66163b33ad6b982b 100644
--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -1474,7 +1474,7 @@ gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist ** argp)
 
       if (sub_flag && gfc_match_char ('*') == MATCH_YES)
 	{
-	  m = gfc_match_st_label (&label, 0);
+	  m = gfc_match_st_label (&label);
 	  if (m == MATCH_NO)
 	    gfc_error ("Expected alternate return label at %C");
 	  if (m != MATCH_YES)