+ warn = (open->err || open->iostat) ? true : false;
+
+ /* Checks on NEWUNIT specifier. */
+ if (open->newunit)
+ {
+ if (open->unit)
+ {
+ gfc_error ("UNIT specifier not allowed with NEWUNIT at %C");
+ goto cleanup;
+ }
+
+ if (!(open->file || (open->status
+ && gfc_wide_strncasecmp (open->status->value.character.string,
+ "scratch", 7) == 0)))
+ {
+ gfc_error ("NEWUNIT specifier must have FILE= "
+ "or STATUS='scratch' at %C");
+ goto cleanup;
+ }
+ }
+ else if (!open->unit)
+ {
+ gfc_error ("OPEN statement at %C must have UNIT or NEWUNIT specified");
+ goto cleanup;
+ }
+
+ /* 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. */
+ if (open->asynchronous)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ASYNCHRONOUS= at %C "
+ "not allowed in Fortran 95") == FAILURE)
+ goto cleanup;
+
+ if (open->asynchronous->expr_type == EXPR_CONSTANT)
+ {
+ static const char * asynchronous[] = { "YES", "NO", NULL };
+
+ if (!compare_to_allowed_values ("ASYNCHRONOUS", asynchronous,
+ NULL, NULL, open->asynchronous->value.character.string,
+ "OPEN", warn))
+ goto cleanup;
+ }
+ }
+
+ /* Checks on the BLANK specifier. */
+ if (open->blank)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: BLANK= at %C "
+ "not allowed in Fortran 95") == FAILURE)
+ goto cleanup;
+
+ if (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. */
+ if (open->decimal)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: DECIMAL= at %C "
+ "not allowed in Fortran 95") == FAILURE)
+ goto cleanup;
+
+ if (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)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: DELIM= at %C "
+ "not allowed in Fortran 95") == FAILURE)
+ goto cleanup;
+
+ if (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. */
+ if (open->encoding)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ENCODING= at %C "
+ "not allowed in Fortran 95") == FAILURE)
+ goto cleanup;
+
+ if (open->encoding->expr_type == EXPR_CONSTANT)
+ {
+ static const char * encoding[] = { "DEFAULT", "UTF-8", 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. */
+ if (open->round)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran F2003: ROUND= at %C "
+ "not allowed in Fortran 95") == FAILURE)
+ goto cleanup;
+
+ if (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. */
+ if (open->sign)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: SIGN= at %C "
+ "not allowed in Fortran 95") == FAILURE)
+ goto cleanup;
+
+ if (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
+ && (gfc_wide_strncasecmp (open->status->value.character.string,
+ "replace", 7) == 0
+ || gfc_wide_strncasecmp (open->status->value.character.string,
+ "new", 3) == 0))
+ {
+ char *s = gfc_widechar_to_char (open->status->value.character.string,
+ -1);
+ warn_or_error ("The STATUS specified in OPEN statement at %C is "
+ "'%s' and no FILE specifier is present", s);
+ gfc_free (s);
+ }
+
+ /* F2003, 9.4.5: If the STATUS= specifier has the value SCRATCH,
+ the FILE= specifier shall not appear. */
+ if (gfc_wide_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 || open->decimal || open->encoding || open->round
+ || open->sign || open->pad || open->blank)
+ && gfc_wide_strncasecmp (open->form->value.character.string,
+ "unformatted", 11) == 0)
+ {
+ const char *spec = (open->delim ? "DELIM "
+ : (open->pad ? "PAD " : open->blank
+ ? "BLANK " : ""));
+
+ warn_or_error ("%s specifier at %C not allowed in OPEN statement for "
+ "unformatted I/O", spec);
+ }
+
+ if (open->recl && open->access && open->access->expr_type == EXPR_CONSTANT
+ && gfc_wide_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
+ && !(gfc_wide_strncasecmp (open->access->value.character.string,
+ "sequential", 10) == 0
+ || gfc_wide_strncasecmp (open->access->value.character.string,
+ "stream", 6) == 0
+ || gfc_wide_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
+