This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
[PATCH] PR fortran/77978 -- STOP code fixes
- From: Steve Kargl <sgk at troutmask dot apl dot washington dot edu>
- To: fortran at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Fri, 14 Oct 2016 17:24:53 -0700
- Subject: [PATCH] PR fortran/77978 -- STOP code fixes
- Authentication-results: sourceware.org; auth=none
- Reply-to: kargl at uw dot edu
The attach patch fixes a number of shortcomings with
STOP codes in gfortran. The updated comment in the
code nicely summarizes the problem.
/* Match a number or character constant after an (ERROR) STOP or PAUSE
- statement. */
+ statement. The requirements for a stop-code differs in the standards.
+
+ Fortran 95 has
+
+ R840 stop-stmt is STOP [ stop-code ]
+ R841 stop-code is scalar-char-constant
+ or digit [ digit [ digit [ digit [ digit ] ] ] ]
+
+ Fortran 2003 is the same as Fortran 95 except R840 and R841 are now
+ R849 and R850.
+
+ Fortran 2008 has
+
+ R855 stop-stmt is STOP [ stop-code ]
+ R856 allstop-stmt is ALL STOP [ stop-code ]
+ R857 stop-code is scalar-default-char-constant-expr
+ or scalar-int-constant-expr
+*/
So, the F95/2003 "digit [...]" is not a scalar-int-constant-expr.
It sort of looks like a statement label, but of course it is not
a statement label as the stop code does label anything. Currently,
gfortran parses "digit [...]" as an expression. I've added the
necessary checking that "digit [...]" is valid with one exception.
For the code
program foo
stop merge(667, 668, .true.)
end
gfortran with either -std=f95 or -std=f2003 should reject
this code. My patch does not fix this issue, because it
would (1) require a complete rewrite of gfc_match_stopcode
(which I am not willing to do) and (2) it simply is a vastly
unimportant corner case that gives the desired behavior.
A second issue raised by John in PR fortran/77978 is that
for F95/2003, the following is valid free-form source code:
program foo
stop666
end
but is invalid F2008. The patch fixes this bug, too.
OK to commit?
2016-10-XX Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/77978
* match.c (gfc_match_stopcode): Fix error reporting for several
deficiencies in matching STOP codes.
2016-10-XX Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/77978
* gfortran.dg/pr77978_1.f90: New test.
* gfortran.dg/pr77978_2.f90: Ditto.
* gfortran.dg/pr77978_3.f90: Ditto.
--
Steve
Index: gcc/fortran/match.c
===================================================================
--- gcc/fortran/match.c (revision 241074)
+++ gcc/fortran/match.c (working copy)
@@ -2732,7 +2732,24 @@ gfc_match_cycle (void)
/* Match a number or character constant after an (ERROR) STOP or PAUSE
- statement. */
+ statement. The requirements for a stop-code differs in the standards.
+
+ Fortran 95 has
+
+ R840 stop-stmt is STOP [ stop-code ]
+ R841 stop-code is scalar-char-constant
+ or digit [ digit [ digit [ digit [ digit ] ] ] ]
+
+ Fortran 2003 is the same as Fortran 95 except R840 and R841 are now
+ R849 and R850.
+
+ Fortran 2008 has
+
+ R855 stop-stmt is STOP [ stop-code ]
+ R856 allstop-stmt is ALL STOP [ stop-code ]
+ R857 stop-code is scalar-default-char-constant-expr
+ or scalar-int-constant-expr
+*/
static match
gfc_match_stopcode (gfc_statement st)
@@ -2740,6 +2757,27 @@ gfc_match_stopcode (gfc_statement st)
gfc_expr *e;
match m;
+ /* The default selected Standards. */
+ int std = GFC_STD_GNU | GFC_STD_LEGACY | GFC_STD_F77 | GFC_STD_F95
+ | GFC_STD_F95_OBS | GFC_STD_F95_DEL | GFC_STD_F2003
+ | GFC_STD_F2008 | GFC_STD_F2008_OBS | GFC_STD_F2008_TS;
+
+ if (gfc_current_form != FORM_FIXED)
+ {
+ char c;
+
+ c = gfc_peek_ascii_char ();
+
+ if (c != ' '
+ && gfc_option.allow_std != std
+ && (gfc_option.allow_std & GFC_STD_F2008))
+ {
+ gfc_error ("Blank required in %s statement near %C",
+ gfc_ascii_statement (st));
+ return MATCH_ERROR;
+ }
+ }
+
e = NULL;
if (gfc_match_eos () != MATCH_YES)
@@ -2785,6 +2823,15 @@ gfc_match_stopcode (gfc_statement st)
if (e != NULL)
{
+ gfc_simplify_expr (e, 0);
+
+ if (e->expr_type != EXPR_CONSTANT)
+ {
+ gfc_error ("STOP code at %L must be a constant expression",
+ &e->where);
+ goto cleanup;
+ }
+
if (!(e->ts.type == BT_CHARACTER || e->ts.type == BT_INTEGER))
{
gfc_error ("STOP code at %L must be either INTEGER or CHARACTER type",
@@ -2794,8 +2841,7 @@ gfc_match_stopcode (gfc_statement st)
if (e->rank != 0)
{
- gfc_error ("STOP code at %L must be scalar",
- &e->where);
+ gfc_error ("STOP code at %L must be scalar", &e->where);
goto cleanup;
}
@@ -2807,12 +2853,35 @@ gfc_match_stopcode (gfc_statement st)
goto cleanup;
}
- if (e->ts.type == BT_INTEGER
- && e->ts.kind != gfc_default_integer_kind)
+ if (e->ts.type == BT_INTEGER)
{
- gfc_error ("STOP code at %L must be default integer KIND=%d",
- &e->where, (int) gfc_default_integer_kind);
- goto cleanup;
+ if (e->ts.kind != gfc_default_integer_kind)
+ {
+ gfc_error ("STOP code at %L must be default integer KIND=%d",
+ &e->where, (int) gfc_default_integer_kind);
+ goto cleanup;
+ }
+
+ if (gfc_option.allow_std != std
+ && (((gfc_option.allow_std & GFC_STD_F95)
+ || (gfc_option.allow_std & GFC_STD_F2003))
+ && !(gfc_option.allow_std & GFC_STD_F2008)))
+ {
+ int n;
+ n = mpz_get_si (e->value.integer);
+ if (n < 0)
+ {
+ gfc_error ("STOP code at %L cannot be negative", &e->where);
+ goto cleanup;
+ }
+
+ if (n > 99999)
+ {
+ gfc_error ("STOP code at %L contains too many digits",
+ &e->where);
+ goto cleanup;
+ }
+ }
}
}
Index: gcc/testsuite/gfortran.dg/pr77978_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/pr77978_1.f90 (nonexistent)
+++ gcc/testsuite/gfortran.dg/pr77978_1.f90 (working copy)
@@ -0,0 +1,23 @@
+! { dg-do compile }
+! { dg-options "-std=f95" }
+subroutine a1
+ integer, parameter :: i = -666
+ stop i ! { dg-error "cannot be negative" }
+end subroutine a1
+
+subroutine a2
+ stop -666 ! { dg-error "cannot be negative" }
+end subroutine a2
+
+subroutine a3
+ integer, parameter :: i = 123456
+ stop i ! { dg-error "too many digits" }
+end subroutine a3
+
+subroutine a4
+ stop 123456 ! { dg-error "too many digits" }
+end subroutine a4
+
+subroutine a5
+ stop merge(667,668,.true.)
+end subroutine a5
Index: gcc/testsuite/gfortran.dg/pr77978_2.f90
===================================================================
--- gcc/testsuite/gfortran.dg/pr77978_2.f90 (nonexistent)
+++ gcc/testsuite/gfortran.dg/pr77978_2.f90 (working copy)
@@ -0,0 +1,5 @@
+! { dg-do compile }
+! { dg-options "-std=f2008" }
+subroutine a1
+ stop666 ! { dg-error "Blank required in STOP" }
+end subroutine a1
Index: gcc/testsuite/gfortran.dg/pr77978_3.f90
===================================================================
--- gcc/testsuite/gfortran.dg/pr77978_3.f90 (nonexistent)
+++ gcc/testsuite/gfortran.dg/pr77978_3.f90 (working copy)
@@ -0,0 +1,23 @@
+! { dg-do compile }
+! { dg-options "-std=f2008" }
+subroutine a1
+ integer, parameter :: i = -666
+ stop i
+end subroutine a1
+
+subroutine a2
+ stop -666
+end subroutine a2
+
+subroutine a3
+ integer, parameter :: i = 123456
+ stop i
+end subroutine a3
+
+subroutine a4
+ stop 123456
+end subroutine a4
+
+subroutine a5
+ stop merge(667,668,.true.)
+end subroutine a5