Index: gcc/fortran/io.c =================================================================== --- gcc/fortran/io.c (revision 117533) +++ gcc/fortran/io.c (working copy) @@ -1253,6 +1253,99 @@ } + +/* Check if a given value for a SPECIFIER is either in the list of values + allowed in F95 or F2003, issuing an error message and returning a zero + value it is not allowed. */ +static int +compare_to_allowed_values (const char * specifier, const char * allowed[], + const char * allowed_f2003[], + const char * allowed_gnu[], char * value, + const char * statement, bool warn) +{ + int i; + unsigned int len; + + len = strlen(value); + if (len > 0) + { + for (len--; len > 0; len--) + if (value[len] != ' ') + break; + len++; + } + + for (i = 0; allowed[i]; i++) + if (len == strlen(allowed[i]) + && strncasecmp (value, allowed[i], strlen(allowed[i])) == 0) + return 1; + + for (i = 0; allowed_f2003 && allowed_f2003[i]; i++) + if (len == strlen(allowed_f2003[i]) + && strncasecmp (value, allowed_f2003[i], strlen(allowed_f2003[i])) == 0) + { + notification n = gfc_notification_std (GFC_STD_F2003); + + if (n == WARNING || (warn && n == ERROR)) + { + gfc_warning ("Fortran 2003: %s specifier in %s statement at %C " + "has value '%s'", specifier, statement, + allowed_f2003[i]); + return 1; + } + else + if (n == ERROR) + { + gfc_notify_std (GFC_STD_F2003, "Fortran 2003: %s specifier in " + "%s statement at %C has value '%s'", specifier, + statement, allowed_f2003[i]); + return 0; + } + + /* n == SILENT */ + return 1; + } + + for (i = 0; allowed_gnu && allowed_gnu[i]; i++) + if (len == strlen(allowed_gnu[i]) + && strncasecmp (value, allowed_gnu[i], strlen(allowed_gnu[i])) == 0) + { + notification n = gfc_notification_std (GFC_STD_GNU); + + if (n == WARNING || (warn && n == ERROR)) + { + gfc_warning ("Extension: %s specifier in %s statement at %C " + "has value '%s'", specifier, statement, + allowed_gnu[i]); + return 1; + } + else + if (n == ERROR) + { + gfc_notify_std (GFC_STD_GNU, "Extension: %s specifier in " + "%s statement at %C has value '%s'", specifier, + statement, allowed_gnu[i]); + return 0; + } + + /* n == SILENT */ + return 1; + } + + if (warn) + { + gfc_warning ("%s specifier in %s statement at %C has invalid value '%s'", + specifier, statement, value); + return 1; + } + else + { + gfc_error ("%s specifier in %s statement at %C has invalid value '%s'", + specifier, statement, value); + return 0; + } +} + /* Match an OPEN statement. */ match @@ -1260,6 +1353,7 @@ { gfc_open *open; match m; + bool warn; m = gfc_match_char ('('); if (m == MATCH_NO) @@ -1303,6 +1397,240 @@ goto cleanup; } + warn = (open->err || open->iostat) ? true : false; + /* Checks on the ACCESS specifier. */ + if (open->access && open->access->expr_type == EXPR_CONSTANT) + { + static const char * access_f95[] = { "SEQUENTIAL", "DIRECT", NULL }; + static const char * access_f2003[] = { "STREAM", NULL }; + static const char * access_gnu[] = { "APPEND", NULL }; + + if (!compare_to_allowed_values ("ACCESS", access_f95, access_f2003, + access_gnu, + open->access->value.character.string, + "OPEN", warn)) + goto cleanup; + } + + /* Checks on the ACTION specifier. */ + if (open->action && open->action->expr_type == EXPR_CONSTANT) + { + static const char * action[] = { "READ", "WRITE", "READWRITE", NULL }; + + if (!compare_to_allowed_values ("ACTION", action, NULL, NULL, + open->action->value.character.string, + "OPEN", warn)) + goto cleanup; + } + + /* Checks on the ASYNCHRONOUS specifier. */ + /* TODO: code is ready, just needs uncommenting when async I/O support + is added ;-) + if (open->asynchronous && open->asynchronous->expr_type == EXPR_CONSTANT) + { + static const char * asynchronous[] = { "YES", "NO", NULL }; + + if (!compare_to_allowed_values + ("action", asynchronous, NULL, NULL, + open->asynchronous->value.character.string, "OPEN", warn)) + goto cleanup; + }*/ + + /* Checks on the BLANK specifier. */ + if (open->blank && open->blank->expr_type == EXPR_CONSTANT) + { + static const char * blank[] = { "ZERO", "NULL", NULL }; + + if (!compare_to_allowed_values ("BLANK", blank, NULL, NULL, + open->blank->value.character.string, + "OPEN", warn)) + goto cleanup; + } + + /* Checks on the DECIMAL specifier. */ + /* TODO: uncomment this code when DECIMAL support is added + if (open->decimal && open->decimal->expr_type == EXPR_CONSTANT) + { + static const char * decimal[] = { "COMMA", "POINT", NULL }; + + if (!compare_to_allowed_values ("DECIMAL", decimal, NULL, NULL, + open->decimal->value.character.string, + "OPEN", warn)) + goto cleanup; + } */ + + /* Checks on the DELIM specifier. */ + if (open->delim && open->delim->expr_type == EXPR_CONSTANT) + { + static const char * delim[] = { "APOSTROPHE", "QUOTE", "NONE", NULL }; + + if (!compare_to_allowed_values ("DELIM", delim, NULL, NULL, + open->delim->value.character.string, + "OPEN", warn)) + goto cleanup; + } + + /* Checks on the ENCODING specifier. */ + /* TODO: uncomment this code when ENCODING support is added + if (open->encoding && open->encoding->expr_type == EXPR_CONSTANT) + { + static const char * encoding[] = { "UTF-8", "DEFAULT", NULL }; + + if (!compare_to_allowed_values ("ENCODING", encoding, NULL, NULL, + open->encoding->value.character.string, + "OPEN", warn)) + goto cleanup; + } */ + + /* Checks on the FORM specifier. */ + if (open->form && open->form->expr_type == EXPR_CONSTANT) + { + static const char * form[] = { "FORMATTED", "UNFORMATTED", NULL }; + + if (!compare_to_allowed_values ("FORM", form, NULL, NULL, + open->form->value.character.string, + "OPEN", warn)) + goto cleanup; + } + + /* Checks on the PAD specifier. */ + if (open->pad && open->pad->expr_type == EXPR_CONSTANT) + { + static const char * pad[] = { "YES", "NO", NULL }; + + if (!compare_to_allowed_values ("PAD", pad, NULL, NULL, + open->pad->value.character.string, + "OPEN", warn)) + goto cleanup; + } + + /* Checks on the POSITION specifier. */ + if (open->position && open->position->expr_type == EXPR_CONSTANT) + { + static const char * position[] = { "ASIS", "REWIND", "APPEND", NULL }; + + if (!compare_to_allowed_values ("POSITION", position, NULL, NULL, + open->position->value.character.string, + "OPEN", warn)) + goto cleanup; + } + + /* Checks on the ROUND specifier. */ + /* TODO: uncomment this code when ROUND support is added + if (open->round && open->round->expr_type == EXPR_CONSTANT) + { + static const char * round[] = { "UP", "DOWN", "ZERO", "NEAREST", + "COMPATIBLE", "PROCESSOR_DEFINED", NULL }; + + if (!compare_to_allowed_values ("ROUND", round, NULL, NULL, + open->round->value.character.string, + "OPEN", warn)) + goto cleanup; + } */ + + /* Checks on the SIGN specifier. */ + /* TODO: uncomment this code when SIGN support is added + if (open->sign && open->sign->expr_type == EXPR_CONSTANT) + { + static const char * sign[] = { "PLUS", "SUPPRESS", "PROCESSOR_DEFINED", + NULL }; + + if (!compare_to_allowed_values ("SIGN", sign, NULL, NULL, + open->sign->value.character.string, + "OPEN", warn)) + goto cleanup; + } */ + +#define warn_or_error(...) \ +{ \ + if (warn) \ + gfc_warning (__VA_ARGS__); \ + else \ + { \ + gfc_error (__VA_ARGS__); \ + goto cleanup; \ + } \ +} + + /* Checks on the RECL specifier. */ + if (open->recl && open->recl->expr_type == EXPR_CONSTANT + && open->recl->ts.type == BT_INTEGER + && mpz_sgn (open->recl->value.integer) != 1) + { + warn_or_error ("RECL in OPEN statement at %C must be positive"); + } + + /* Checks on the STATUS specifier. */ + if (open->status && open->status->expr_type == EXPR_CONSTANT) + { + static const char * status[] = { "OLD", "NEW", "SCRATCH", + "REPLACE", "UNKNOWN", NULL }; + + if (!compare_to_allowed_values ("STATUS", status, NULL, NULL, + open->status->value.character.string, + "OPEN", warn)) + goto cleanup; + + /* F2003, 9.4.5: If the STATUS= specifier has the value NEW or REPLACE, + the FILE= specifier shall appear. */ + if (open->file == NULL && + (strncasecmp (open->status->value.character.string, "replace", 7) == 0 + || strncasecmp (open->status->value.character.string, "new", 3) == 0)) + { + warn_or_error ("The STATUS specified in OPEN statement at %C is '%s' " + "and no FILE specifier is present", + open->status->value.character.string); + } + + /* F2003, 9.4.5: If the STATUS= specifier has the value SCRATCH, + the FILE= specifier shall not appear. */ + if (strncasecmp (open->status->value.character.string, "scratch", 7) == 0 + && open->file) + { + warn_or_error ("The STATUS specified in OPEN statement at %C cannot " + "have the value SCRATCH if a FILE specifier " + "is present"); + } + } + + /* Things that are not allowed for unformatted I/O. */ + if (open->form && open->form->expr_type == EXPR_CONSTANT + && (open->delim + /* TODO uncomment this code when F2003 support is finished */ + /* || open->decimal || open->encoding || open->round + || open->sign */ + || open->pad || open->blank) + && strncasecmp (open->form->value.character.string, + "unformatted", 11) == 0) + { + const char * spec = (open->delim ? "DELIM " : (open->pad ? "PAD " : + open->blank ? "BLANK " : "")); + + warn_or_error ("%sspecifier at %C not allowed in OPEN statement for " + "unformatted I/O", spec); + } + + if (open->recl && open->access && open->access->expr_type == EXPR_CONSTANT + && strncasecmp (open->access->value.character.string, "stream", 6) == 0) + { + warn_or_error ("RECL specifier not allowed in OPEN statement at %C for " + "stream I/O"); + } + + if (open->position && open->access && open->access->expr_type == EXPR_CONSTANT + && !(strncasecmp (open->access->value.character.string, + "sequential", 10) == 0 + || strncasecmp (open->access->value.character.string, + "stream", 6) == 0 + || strncasecmp (open->access->value.character.string, + "append", 6) == 0)) + { + warn_or_error ("POSITION specifier in OPEN statement at %C only allowed " + "for stream or sequential ACCESS"); + } + +#undef warn_or_error + new_st.op = EXEC_OPEN; new_st.ext.open = open; return MATCH_YES; @@ -1368,6 +1696,7 @@ { gfc_close *close; match m; + bool warn; m = gfc_match_char ('('); if (m == MATCH_NO) @@ -1411,6 +1740,19 @@ goto cleanup; } + warn = (close->iostat || close->err) ? true : false; + + /* Checks on the STATUS specifier. */ + if (close->status && close->status->expr_type == EXPR_CONSTANT) + { + static const char * status[] = { "KEEP", "DELETE" }; + + if (!compare_to_allowed_values ("STATUS", status, NULL, NULL, + close->status->value.character.string, + "CLOSE", warn)) + goto cleanup; + } + new_st.op = EXEC_CLOSE; new_st.ext.close = close; return MATCH_YES; Index: gcc/testsuite/gfortran.dg/io_constraints_3.f90 =================================================================== --- gcc/testsuite/gfortran.dg/io_constraints_3.f90 (revision 0) +++ gcc/testsuite/gfortran.dg/io_constraints_3.f90 (revision 0) @@ -0,0 +1,191 @@ +! Test some restrictions on the specifiers of OPEN and CLOSE statements. +! Contributed by Francois-Xavier Coudert (coudert@clipper.ens.fr) +! +! { dg-do compile } +! { dg-options "-ffree-line-length-none -pedantic" } + integer,parameter :: mone = -1, zero = 0 + character(len=*),parameter :: foo = "foo" + character(len=20) :: str + integer :: u + +! Test for warnings, when IOSTAT is used + + open(10, iostat=u,access="sequential ") + open(10, iostat=u,access="sequential u") ! { dg-warning "ACCESS specifier in OPEN statement" } + open(10, iostat=u,access=foo) ! { dg-warning "ACCESS specifier in OPEN statement" } + open(10, iostat=u,access="direct") + open(10, iostat=u,access="stream") + open(10, iostat=u,access="append") ! { dg-warning "Extension: ACCESS specifier in OPEN statement" } + + open(10, iostat=u,action="read") + open(10, iostat=u,action="write") + open(10, iostat=u,action="readwrite") + open(10, iostat=u,action=foo) ! { dg-warning "ACTION specifier in OPEN statement" } + + open(10, iostat=u,blank="ZERO") + open(10, iostat=u,blank="nUlL") + open(10, iostat=u,blank="NULLL") ! { dg-warning "BLANK specifier in OPEN statement" } + + open(10, iostat=u,delim="apostrophe") + open(10, iostat=u,delim="quote") + open(10, iostat=u,delim="none") + open(10, iostat=u,delim="") ! { dg-warning "DELIM specifier in OPEN statement" } + + open(10, iostat=u,form="formatted") + open(10, iostat=u,form="unformatted") + open(10, iostat=u,form="default") ! { dg-warning "FORM specifier in OPEN statement" } + + open(10, iostat=u,pad="yes") + open(10, iostat=u,pad="no") + open(10, iostat=u,pad=foo) ! { dg-warning "PAD specifier in OPEN statement" } + + open(10, iostat=u,position="asis") + open(10, iostat=u,position="rewind") + open(10, iostat=u,position="append") + open(10, iostat=u,position=foo) ! { dg-warning "POSITION specifier in OPEN statement" } + + open(10, iostat=u,recl="ee") ! { dg-warning "must be of type INTEGER" } + open(10, iostat=u,recl=0.4) ! { dg-warning "must be of type INTEGER" } + open(10, iostat=u,recl=zero) ! { dg-warning "must be positive" } + open(10, iostat=u,recl=mone) ! { dg-warning "must be positive" } + + open(10, iostat=u,status="unknown") + open(10, iostat=u,status="old") + open(10, iostat=u,status=foo) ! { dg-warning "STATUS specifier in OPEN statement" } + + open(10, iostat=u,status="new") ! { dg-warning "no FILE specifier is present" } + open(10, iostat=u,status="replace ") ! { dg-warning "no FILE specifier is present" } + open(10, iostat=u,status="scratch",file=str) ! { dg-warning "cannot have the value SCRATCH if a FILE specifier is present" } + + open(10, iostat=u,form="unformatted",delim="none") ! { dg-warning "not allowed in OPEN statement for unformatted I/O" } + open(10, iostat=u,form="unformatted",pad="yes") ! { dg-warning "not allowed in OPEN statement for unformatted I/O" } + open(10, iostat=u,form="unformatted",blank="null") ! { dg-warning "not allowed in OPEN statement for unformatted I/O" } + + open(10, iostat=u,access="direct",position="append") ! { dg-warning "only allowed for stream or sequential ACCESS" } + + close(10, iostat=u,status="keep") + close(10, iostat=u,status="delete") + close(10, iostat=u,status=foo) ! { dg-warning "STATUS specifier in CLOSE statement" } + + + +! Test for warnings, when an ERR label is specified + + open(10, err=99,access="sequential ") + open(10, err=99,access="sequential u") ! { dg-warning "ACCESS specifier in OPEN statement" } + open(10, err=99,access=foo) ! { dg-warning "ACCESS specifier in OPEN statement" } + open(10, err=99,access="direct") + open(10, err=99,access="stream") + open(10, err=99,access="append") ! { dg-warning "Extension: ACCESS specifier in OPEN statement" } + + open(10, err=99,action="read") + open(10, err=99,action="write") + open(10, err=99,action="readwrite") + open(10, err=99,action=foo) ! { dg-warning "ACTION specifier in OPEN statement" } + + open(10, err=99,blank="ZERO") + open(10, err=99,blank="nUlL") + open(10, err=99,blank="NULLL") ! { dg-warning "BLANK specifier in OPEN statement" } + + open(10, err=99,delim="apostrophe") + open(10, err=99,delim="quote") + open(10, err=99,delim="none") + open(10, err=99,delim="") ! { dg-warning "DELIM specifier in OPEN statement" } + + open(10, err=99,form="formatted") + open(10, err=99,form="unformatted") + open(10, err=99,form="default") ! { dg-warning "FORM specifier in OPEN statement" } + + open(10, err=99,pad="yes") + open(10, err=99,pad="no") + open(10, err=99,pad=foo) ! { dg-warning "PAD specifier in OPEN statement" } + + open(10, err=99,position="asis") + open(10, err=99,position="rewind") + open(10, err=99,position="append") + open(10, err=99,position=foo) ! { dg-warning "POSITION specifier in OPEN statement" } + + open(10, err=99,recl="ee") ! { dg-warning "must be of type INTEGER" } + open(10, err=99,recl=0.4) ! { dg-warning "must be of type INTEGER" } + open(10, err=99,recl=zero) ! { dg-warning "must be positive" } + open(10, err=99,recl=mone) ! { dg-warning "must be positive" } + + open(10, err=99,status="unknown") + open(10, err=99,status="old") + open(10, err=99,status=foo) ! { dg-warning "STATUS specifier in OPEN statement" } + + open(10, err=99,status="new") ! { dg-warning "no FILE specifier is present" } + open(10, err=99,status="replace ") ! { dg-warning "no FILE specifier is present" } + open(10, err=99,status="scratch",file=str) ! { dg-warning "cannot have the value SCRATCH if a FILE specifier is present" } + + open(10, err=99,form="unformatted",delim="none") ! { dg-warning "not allowed in OPEN statement for unformatted I/O" } + open(10, err=99,form="unformatted",pad="yes") ! { dg-warning "not allowed in OPEN statement for unformatted I/O" } + open(10, err=99,form="unformatted",blank="null") ! { dg-warning "not allowed in OPEN statement for unformatted I/O" } + + open(10, err=99,access="direct",position="append") ! { dg-warning "only allowed for stream or sequential ACCESS" } + + close(10, err=99,status="keep") + close(10, err=99,status="delete") + close(10, err=99,status=foo) ! { dg-warning "STATUS specifier in CLOSE statement" } + + 99 continue + +! Test for errors + + open(10,access="sequential ") + open(10,access="sequential u") ! { dg-error "ACCESS specifier in OPEN statement" } + open(10,access=foo) ! { dg-error "ACCESS specifier in OPEN statement" } + open(10,access="direct") + open(10,access="stream") + open(10,access="append") ! { dg-warning "Extension: ACCESS specifier in OPEN statement" } + + open(10,action="read") + open(10,action="write") + open(10,action="readwrite") + open(10,action=foo) ! { dg-error "ACTION specifier in OPEN statement" } + + open(10,blank="ZERO") + open(10,blank="nUlL") + open(10,blank="NULLL") ! { dg-error "BLANK specifier in OPEN statement" } + + open(10,delim="apostrophe") + open(10,delim="quote") + open(10,delim="none") + open(10,delim="") ! { dg-error "DELIM specifier in OPEN statement" } + + open(10,form="formatted") + open(10,form="unformatted") + open(10,form="default") ! { dg-error "FORM specifier in OPEN statement" } + + open(10,pad="yes") + open(10,pad="no") + open(10,pad=foo) ! { dg-error "PAD specifier in OPEN statement" } + + open(10,position="asis") + open(10,position="rewind") + open(10,position="append") + open(10,position=foo) ! { dg-error "POSITION specifier in OPEN statement" } + + open(10,recl="ee") ! { dg-error "must be of type INTEGER" } + open(10,recl=0.4) ! { dg-error "must be of type INTEGER" } + open(10,recl=zero) ! { dg-error "must be positive" } + open(10,recl=mone) ! { dg-error "must be positive" } + + open(10,status="unknown") + open(10,status="old") + open(10,status=foo) ! { dg-error "STATUS specifier in OPEN statement" } + + open(10,status="new") ! { dg-error "no FILE specifier is present" } + open(10,status="replace ") ! { dg-error "no FILE specifier is present" } + open(10,status="scratch",file=str) ! { dg-error "cannot have the value SCRATCH if a FILE specifier is present" } + + open(10,form="unformatted",delim="none") ! { dg-error "not allowed in OPEN statement for unformatted I/O" } + open(10,form="unformatted",pad="yes") ! { dg-error "not allowed in OPEN statement for unformatted I/O" } + open(10,form="unformatted",blank="null") ! { dg-error "not allowed in OPEN statement for unformatted I/O" } + + open(10,access="direct",position="append") ! { dg-error "only allowed for stream or sequential ACCESS" } + + close(10,status="keep") + close(10,status="delete") + close(10,status=foo) ! { dg-error "STATUS specifier in CLOSE statement" } +end Index: gcc/testsuite/gfortran.dg/open_access_append_1.f90 =================================================================== --- gcc/testsuite/gfortran.dg/open_access_append_1.f90 (revision 117533) +++ gcc/testsuite/gfortran.dg/open_access_append_1.f90 (working copy) @@ -3,10 +3,10 @@ open (10,file="foo") close (10,status="delete") - open (10,file="foo",access="append") ! { dg-output ".*Extension.*" } + open (10,file="foo",access="append") ! { dg-warning "Extension: ACCESS specifier in OPEN statement" } write (10,*) 42 close (10,status="keep") - open (10,file="foo",access="append") ! { dg-output ".*Extension.*" } + open (10,file="foo",access="append") ! { dg-warning "Extension: ACCESS specifier in OPEN statement" } write (10,*) -42 close (10,status="keep") @@ -18,3 +18,4 @@ close (10,status="delete") end +! { dg-output ".*Extension.*Extension" } Index: gcc/testsuite/gfortran.dg/pr20163-2.f =================================================================== --- gcc/testsuite/gfortran.dg/pr20163-2.f (revision 117533) +++ gcc/testsuite/gfortran.dg/pr20163-2.f (working copy) @@ -1,4 +1,4 @@ - open(10,status="foo",err=100) + open(10,status="foo",err=100) ! { dg-warning "STATUS specifier in OPEN statement .* has invalid value" } call abort 100 continue open(10,status="scratch") Index: gcc/testsuite/gfortran.dg/iostat_2.f90 =================================================================== --- gcc/testsuite/gfortran.dg/iostat_2.f90 (revision 117533) +++ gcc/testsuite/gfortran.dg/iostat_2.f90 (working copy) @@ -1,7 +1,7 @@ ! PR libfortran/23784 ! { dg-do run } integer i - close(10, status="whatever", iostat=i) + close(10, status="whatever", iostat=i) ! { dg-warning "STATUS specifier in CLOSE statement.*has invalid value" } if (i == 0) call abort() write(17,*) 'foo' close(17, status="delete") Index: gcc/testsuite/gfortran.dg/label_4.f90 =================================================================== --- gcc/testsuite/gfortran.dg/label_4.f90 (revision 117533) +++ gcc/testsuite/gfortran.dg/label_4.f90 (working copy) @@ -5,4 +5,5 @@ open(unit=12,err=99) 99 print *,"could not open file ..." 98 continue ! { dg-warning "Label 98 .* defined but not used" } + close(unit=12,status="delete") end Index: gcc/testsuite/gfortran.dg/direct_io_2.f90 =================================================================== --- gcc/testsuite/gfortran.dg/direct_io_2.f90 (revision 117533) +++ gcc/testsuite/gfortran.dg/direct_io_2.f90 (working copy) @@ -6,7 +6,7 @@ PROGRAM FM413 IMPLICIT LOGICAL (L) IMPLICIT CHARACTER*14 (C) - OPEN (7, ACCESS = 'DIRECT', RECL = 80, STATUS='REPLACE' ) + OPEN (7, ACCESS = 'DIRECT', RECL = 80, STATUS='REPLACE', FILE="FOO" ) IRECN = 13 IREC = 13 DO 4132 I = 1,100 Index: gcc/testsuite/gfortran.dg/iomsg_1.f90 =================================================================== --- gcc/testsuite/gfortran.dg/iomsg_1.f90 (revision 117533) +++ gcc/testsuite/gfortran.dg/iomsg_1.f90 (working copy) @@ -22,7 +22,7 @@ if (ch .ne. 'Bad unit number in OPEN statement') call abort ! Test iomsg with close - close(23,status="no_idea", err=500, iomsg=ch) + close(23,status="no_idea", err=500, iomsg=ch) ! { dg-warning "STATUS specifier in CLOSE statement.*has invalid value" } 500 continue if (ch .ne. "Bad STATUS parameter in CLOSE statement") call abort end program iomsg_test