diff options
Diffstat (limited to 'gcc/fortran/match.c')
-rw-r--r-- | gcc/fortran/match.c | 380 |
1 files changed, 305 insertions, 75 deletions
diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index f3a4a43a34..006ac0312a 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -1,5 +1,5 @@ /* Matching subroutines in all sizes, shapes and colors. - Copyright (C) 2000-2016 Free Software Foundation, Inc. + Copyright (C) 2000-2017 Free Software Foundation, Inc. Contributed by Andy Vaught This file is part of GCC. @@ -102,6 +102,12 @@ gfc_op2string (gfc_intrinsic_op op) case INTRINSIC_NONE: return "none"; + /* DTIO */ + case INTRINSIC_FORMATTED: + return "formatted"; + case INTRINSIC_UNFORMATTED: + return "unformatted"; + default: break; } @@ -153,7 +159,7 @@ gfc_match_member_sep(gfc_symbol *sym) return MATCH_YES; /* Beware ye who enter here. */ - if (!gfc_option.flag_dec_structure || !sym) + if (!flag_dec_structure || !sym) return MATCH_NO; tsym = NULL; @@ -215,7 +221,7 @@ gfc_match_member_sep(gfc_symbol *sym) if (c) goto yes; - gfc_error ("'%s' is neither a defined operator nor a " + gfc_error ("%qs is neither a defined operator nor a " "structure component in dotted string at %C", name); goto error; } @@ -508,7 +514,6 @@ match gfc_match_small_int (int *value) { gfc_expr *expr; - const char *p; match m; int i; @@ -516,15 +521,10 @@ gfc_match_small_int (int *value) if (m != MATCH_YES) return m; - p = gfc_extract_int (expr, &i); + if (gfc_extract_int (expr, &i, 1)) + m = MATCH_ERROR; gfc_free_expr (expr); - if (p != NULL) - { - gfc_error (p); - m = MATCH_ERROR; - } - *value = i; return m; } @@ -541,7 +541,6 @@ gfc_match_small_int (int *value) match gfc_match_small_int_expr (int *value, gfc_expr **expr) { - const char *p; match m; int i; @@ -549,13 +548,8 @@ gfc_match_small_int_expr (int *value, gfc_expr **expr) if (m != MATCH_YES) return m; - p = gfc_extract_int (*expr, &i); - - if (p != NULL) - { - gfc_error (p); - m = MATCH_ERROR; - } + if (gfc_extract_int (*expr, &i, 1)) + m = MATCH_ERROR; *value = i; return m; @@ -954,6 +948,19 @@ gfc_match_intrinsic_op (gfc_intrinsic_op *result) } break; + case 'x': + if (gfc_next_ascii_char () == 'o' + && gfc_next_ascii_char () == 'r' + && gfc_next_ascii_char () == '.') + { + if (!gfc_notify_std (GFC_STD_LEGACY, ".XOR. operator at %C")) + return MATCH_ERROR; + /* Matched ".xor." - equivalent to ".neqv.". */ + *result = INTRINSIC_NEQV; + return MATCH_YES; + } + break; + default: break; } @@ -1594,6 +1601,7 @@ gfc_match_if (gfc_statement *if_type) match ("event post", gfc_match_event_post, ST_EVENT_POST) match ("event wait", gfc_match_event_wait, ST_EVENT_WAIT) match ("exit", gfc_match_exit, ST_EXIT) + match ("fail image", gfc_match_fail_image, ST_FAIL_IMAGE) match ("flush", gfc_match_flush, ST_FLUSH) match ("forall", match_simple_forall, ST_FORALL) match ("go to", gfc_match_goto, ST_GOTO) @@ -1616,6 +1624,9 @@ gfc_match_if (gfc_statement *if_type) match ("where", match_simple_where, ST_WHERE) match ("write", gfc_match_write, ST_WRITE) + if (flag_dec) + match ("type", gfc_match_print, ST_WRITE) + /* The gfc_match_assignment() above may have returned a MATCH_NO where the assignment was to a named constant. Check that special case here. */ @@ -1983,6 +1994,7 @@ gfc_match_type_spec (gfc_typespec *ts) { match m; locus old_locus; + char name[GFC_MAX_SYMBOL_LEN + 1]; gfc_clear_ts (ts); gfc_gobble_whitespace (); @@ -2007,13 +2019,6 @@ gfc_match_type_spec (gfc_typespec *ts) goto kind_selector; } - if (gfc_match ("real") == MATCH_YES) - { - ts->type = BT_REAL; - ts->kind = gfc_default_real_kind; - goto kind_selector; - } - if (gfc_match ("double precision") == MATCH_YES) { ts->type = BT_REAL; @@ -2047,6 +2052,103 @@ gfc_match_type_spec (gfc_typespec *ts) goto kind_selector; } + /* REAL is a real pain because it can be a type, intrinsic subprogram, + or list item in a type-list of an OpenMP reduction clause. Need to + differentiate REAL([KIND]=scalar-int-initialization-expr) from + REAL(A,[KIND]) and REAL(KIND,A). */ + + m = gfc_match (" %n", name); + if (m == MATCH_YES && strcmp (name, "real") == 0) + { + char c; + gfc_expr *e; + locus where; + + ts->type = BT_REAL; + ts->kind = gfc_default_real_kind; + + gfc_gobble_whitespace (); + + /* Prevent REAL*4, etc. */ + c = gfc_peek_ascii_char (); + if (c == '*') + { + gfc_error ("Invalid type-spec at %C"); + return MATCH_ERROR; + } + + /* Found leading colon in REAL::, a trailing ')' in for example + TYPE IS (REAL), or REAL, for an OpenMP list-item. */ + if (c == ':' || c == ')' || (flag_openmp && c == ',')) + return MATCH_YES; + + /* Found something other than the opening '(' in REAL(... */ + if (c != '(') + return MATCH_NO; + else + gfc_next_char (); /* Burn the '('. */ + + /* Look for the optional KIND=. */ + where = gfc_current_locus; + m = gfc_match ("%n", name); + if (m == MATCH_YES) + { + gfc_gobble_whitespace (); + c = gfc_next_char (); + if (c == '=') + { + if (strcmp(name, "a") == 0) + return MATCH_NO; + else if (strcmp(name, "kind") == 0) + goto found; + else + return MATCH_ERROR; + } + else + gfc_current_locus = where; + } + else + gfc_current_locus = where; + +found: + + m = gfc_match_init_expr (&e); + if (m == MATCH_NO || m == MATCH_ERROR) + return MATCH_NO; + + /* If a comma appears, it is an intrinsic subprogram. */ + gfc_gobble_whitespace (); + c = gfc_peek_ascii_char (); + if (c == ',') + { + gfc_free_expr (e); + return MATCH_NO; + } + + /* If ')' appears, we have REAL(initialization-expr), here check for + a scalar integer initialization-expr and valid kind parameter. */ + if (c == ')') + { + if (e->ts.type != BT_INTEGER || e->rank > 0) + { + gfc_free_expr (e); + return MATCH_NO; + } + + gfc_next_char (); /* Burn the ')'. */ + ts->kind = (int) mpz_get_si (e->value.integer); + if (gfc_validate_kind (BT_REAL, ts->kind , true) == -1) + { + gfc_error ("Invalid type-spec at %C"); + return MATCH_ERROR; + } + + gfc_free_expr (e); + + return MATCH_YES; + } + } + /* If a type is not matched, simply return MATCH_NO. */ gfc_current_locus = old_locus; return MATCH_NO; @@ -2054,6 +2156,8 @@ gfc_match_type_spec (gfc_typespec *ts) kind_selector: gfc_gobble_whitespace (); + + /* This prevents INTEGER*4, etc. */ if (gfc_peek_ascii_char () == '*') { gfc_error ("Invalid type-spec at %C"); @@ -2062,13 +2166,9 @@ kind_selector: m = gfc_match_kind_spec (ts, false); + /* No kind specifier found. */ if (m == MATCH_NO) - m = MATCH_YES; /* No kind specifier found. */ - - /* gfortran may have matched REAL(a=1), which is the keyword form of the - intrinsic procedure. */ - if (ts->type == BT_REAL && m == MATCH_ERROR) - m = MATCH_NO; + m = MATCH_YES; return m; } @@ -2632,8 +2732,8 @@ match_exit_cycle (gfc_statement st, gfc_exec_op op) if (o != NULL) { gfc_error (is_oacc (p) - ? "%s statement at %C leaving OpenACC structured block" - : "%s statement at %C leaving OpenMP structured block", + ? G_("%s statement at %C leaving OpenACC structured block") + : G_("%s statement at %C leaving OpenMP structured block"), gfc_ascii_statement (st)); return MATCH_ERROR; } @@ -2676,21 +2776,25 @@ match_exit_cycle (gfc_statement st, gfc_exec_op op) || o->head->op == EXEC_OMP_DO_SIMD || o->head->op == EXEC_OMP_PARALLEL_DO_SIMD)) { - int collapse = 1; + int count = 1; gcc_assert (o->head->next != NULL && (o->head->next->op == EXEC_DO || o->head->next->op == EXEC_DO_WHILE) && o->previous != NULL && o->previous->tail->op == o->head->op); - if (o->previous->tail->ext.omp_clauses != NULL - && o->previous->tail->ext.omp_clauses->collapse > 1) - collapse = o->previous->tail->ext.omp_clauses->collapse; - if (st == ST_EXIT && cnt <= collapse) + if (o->previous->tail->ext.omp_clauses != NULL) + { + if (o->previous->tail->ext.omp_clauses->collapse > 1) + count = o->previous->tail->ext.omp_clauses->collapse; + if (o->previous->tail->ext.omp_clauses->orderedc) + count = o->previous->tail->ext.omp_clauses->orderedc; + } + if (st == ST_EXIT && cnt <= count) { gfc_error ("EXIT statement at %C terminating !$OMP DO loop"); return MATCH_ERROR; } - if (st == ST_CYCLE && cnt < collapse) + if (st == ST_CYCLE && cnt < count) { gfc_error ("CYCLE statement at %C to non-innermost collapsed" " !$OMP DO loop"); @@ -2725,20 +2829,92 @@ gfc_match_cycle (void) } -/* Match a number or character constant after an (ERROR) STOP or PAUSE - statement. */ +/* Match a stop-code after an (ERROR) STOP or PAUSE statement. The + requirements for a stop-code differ 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 matches 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 + +For free-form source code, all standards contain a statement of the form: + + A blank shall be used to separate names, constants, or labels from + adjacent keywords, names, constants, or labels. + +A stop-code is not a name, constant, or label. So, under Fortran 95 and 2003, + + STOP123 + +is valid, but it is invalid Fortran 2008. */ static match gfc_match_stopcode (gfc_statement st) { - gfc_expr *e; + gfc_expr *e = NULL; match m; + bool f95, f03; - e = NULL; + /* Set f95 for -std=f95. */ + f95 = gfc_option.allow_std == (GFC_STD_F95_OBS | GFC_STD_F95 | GFC_STD_F77 + | GFC_STD_F2008_OBS); + + /* Set f03 for -std=f2003. */ + f03 = gfc_option.allow_std == (GFC_STD_F95_OBS | GFC_STD_F95 | GFC_STD_F77 + | GFC_STD_F2008_OBS | GFC_STD_F2003); + + /* Look for a blank between STOP and the stop-code for F2008 or later. */ + if (gfc_current_form != FORM_FIXED && !(f95 || f03)) + { + char c = gfc_peek_ascii_char (); + + /* Look for end-of-statement. There is no stop-code. */ + if (c == '\n' || c == '!' || c == ';') + goto done; + + if (c != ' ') + { + gfc_error ("Blank required in %s statement near %C", + gfc_ascii_statement (st)); + return MATCH_ERROR; + } + } if (gfc_match_eos () != MATCH_YES) { - m = gfc_match_init_expr (&e); + int stopcode; + locus old_locus; + + /* First look for the F95 or F2003 digit [...] construct. */ + old_locus = gfc_current_locus; + m = gfc_match_small_int (&stopcode); + if (m == MATCH_YES && (f95 || f03)) + { + if (stopcode < 0) + { + gfc_error ("STOP code at %C cannot be negative"); + return MATCH_ERROR; + } + + if (stopcode > 99999) + { + gfc_error ("STOP code at %C contains too many digits"); + return MATCH_ERROR; + } + } + + /* Reset the locus and now load gfc_expr. */ + gfc_current_locus = old_locus; + m = gfc_match_expr (&e); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) @@ -2779,6 +2955,22 @@ gfc_match_stopcode (gfc_statement st) if (e != NULL) { + gfc_simplify_expr (e, 0); + + /* Test for F95 and F2003 style STOP stop-code. */ + if (e->expr_type != EXPR_CONSTANT && (f95 || f03)) + { + gfc_error ("STOP code at %L must be a scalar CHARACTER constant or " + "digit[digit[digit[digit[digit]]]]", &e->where); + goto cleanup; + } + + /* Use the machinery for an initialization expression to reduce the + stop-code to a constant. */ + gfc_init_expr_flag = true; + gfc_reduce_init_expr (e); + gfc_init_expr_flag = false; + if (!(e->ts.type == BT_CHARACTER || e->ts.type == BT_INTEGER)) { gfc_error ("STOP code at %L must be either INTEGER or CHARACTER type", @@ -2788,8 +2980,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; } @@ -2801,8 +2992,7 @@ 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 && 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); @@ -2810,6 +3000,8 @@ gfc_match_stopcode (gfc_statement st) } } +done: + switch (st) { case ST_STOP: @@ -2949,7 +3141,7 @@ event_statement (gfc_statement st) { if (saw_stat) { - gfc_error ("Redundant STAT tag found at %L ", &tmp->where); + gfc_error ("Redundant STAT tag found at %L", &tmp->where); goto cleanup; } stat = tmp; @@ -2970,7 +3162,7 @@ event_statement (gfc_statement st) { if (saw_errmsg) { - gfc_error ("Redundant ERRMSG tag found at %L ", &tmp->where); + gfc_error ("Redundant ERRMSG tag found at %L", &tmp->where); goto cleanup; } errmsg = tmp; @@ -2991,7 +3183,7 @@ event_statement (gfc_statement st) { if (saw_until_count) { - gfc_error ("Redundant UNTIL_COUNT tag found at %L ", + gfc_error ("Redundant UNTIL_COUNT tag found at %L", &tmp->where); goto cleanup; } @@ -3074,6 +3266,28 @@ gfc_match_event_wait (void) } +/* Match a FAIL IMAGE statement. */ + +match +gfc_match_fail_image (void) +{ + if (!gfc_notify_std (GFC_STD_F2008_TS, "FAIL IMAGE statement at %C")) + return MATCH_ERROR; + + if (gfc_match_char ('(') == MATCH_YES) + goto syntax; + + new_st.op = EXEC_FAIL_IMAGE; + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_FAIL_IMAGE); + + return MATCH_ERROR; +} + + /* Match LOCK/UNLOCK statement. Syntax: LOCK ( lock-variable [ , lock-stat-list ] ) UNLOCK ( lock-variable [ , sync-stat-list ] ) @@ -3144,7 +3358,7 @@ lock_unlock_statement (gfc_statement st) { if (saw_stat) { - gfc_error ("Redundant STAT tag found at %L ", &tmp->where); + gfc_error ("Redundant STAT tag found at %L", &tmp->where); goto cleanup; } stat = tmp; @@ -3165,7 +3379,7 @@ lock_unlock_statement (gfc_statement st) { if (saw_errmsg) { - gfc_error ("Redundant ERRMSG tag found at %L ", &tmp->where); + gfc_error ("Redundant ERRMSG tag found at %L", &tmp->where); goto cleanup; } errmsg = tmp; @@ -3186,7 +3400,7 @@ lock_unlock_statement (gfc_statement st) { if (saw_acq_lock) { - gfc_error ("Redundant ACQUIRED_LOCK tag found at %L ", + gfc_error ("Redundant ACQUIRED_LOCK tag found at %L", &tmp->where); goto cleanup; } @@ -3356,7 +3570,7 @@ sync_statement (gfc_statement st) { if (saw_stat) { - gfc_error ("Redundant STAT tag found at %L ", &tmp->where); + gfc_error ("Redundant STAT tag found at %L", &tmp->where); goto cleanup; } stat = tmp; @@ -3376,7 +3590,7 @@ sync_statement (gfc_statement st) { if (saw_errmsg) { - gfc_error ("Redundant ERRMSG tag found at %L ", &tmp->where); + gfc_error ("Redundant ERRMSG tag found at %L", &tmp->where); goto cleanup; } errmsg = tmp; @@ -3866,7 +4080,7 @@ alloc_opt_list: /* Enforce C630. */ if (saw_stat) { - gfc_error ("Redundant STAT tag found at %L ", &tmp->where); + gfc_error ("Redundant STAT tag found at %L", &tmp->where); goto cleanup; } @@ -3892,7 +4106,7 @@ alloc_opt_list: /* Enforce C630. */ if (saw_errmsg) { - gfc_error ("Redundant ERRMSG tag found at %L ", &tmp->where); + gfc_error ("Redundant ERRMSG tag found at %L", &tmp->where); goto cleanup; } @@ -3915,7 +4129,7 @@ alloc_opt_list: /* Enforce C630. */ if (saw_source) { - gfc_error ("Redundant SOURCE tag found at %L ", &tmp->where); + gfc_error ("Redundant SOURCE tag found at %L", &tmp->where); goto cleanup; } @@ -3952,7 +4166,7 @@ alloc_opt_list: /* Check F08:C636. */ if (saw_mold) { - gfc_error ("Redundant MOLD tag found at %L ", &tmp->where); + gfc_error ("Redundant MOLD tag found at %L", &tmp->where); goto cleanup; } @@ -4203,7 +4417,7 @@ dealloc_opt_list: { if (saw_stat) { - gfc_error ("Redundant STAT tag found at %L ", &tmp->where); + gfc_error ("Redundant STAT tag found at %L", &tmp->where); gfc_free_expr (tmp); goto cleanup; } @@ -4228,7 +4442,7 @@ dealloc_opt_list: if (saw_errmsg) { - gfc_error ("Redundant ERRMSG tag found at %L ", &tmp->where); + gfc_error ("Redundant ERRMSG tag found at %L", &tmp->where); gfc_free_expr (tmp); goto cleanup; } @@ -5683,6 +5897,7 @@ gfc_match_select_type (void) char name[GFC_MAX_SYMBOL_LEN]; bool class_array; gfc_symbol *sym; + gfc_namespace *ns = gfc_current_ns; m = gfc_match_label (); if (m == MATCH_ERROR) @@ -5692,11 +5907,13 @@ gfc_match_select_type (void) if (m != MATCH_YES) return m; + gfc_current_ns = gfc_build_block_ns (ns); m = gfc_match (" %n => %e", name, &expr2); if (m == MATCH_YES) { - expr1 = gfc_get_expr(); + expr1 = gfc_get_expr (); expr1->expr_type = EXPR_VARIABLE; + expr1->where = expr2->where; if (gfc_get_sym_tree (name, NULL, &expr1->symtree, false)) { m = MATCH_ERROR; @@ -5717,7 +5934,11 @@ gfc_match_select_type (void) { m = gfc_match (" %e ", &expr1); if (m != MATCH_YES) - return m; + { + std::swap (ns, gfc_current_ns); + gfc_free_namespace (ns); + return m; + } } m = gfc_match (" )%t"); @@ -5733,19 +5954,19 @@ gfc_match_select_type (void) allowed by the standard. TODO: see if it is sufficient to exclude component and substring references. */ - class_array = expr1->expr_type == EXPR_VARIABLE - && expr1->ts.type == BT_CLASS - && CLASS_DATA (expr1) - && (strcmp (CLASS_DATA (expr1)->name, "_data") == 0) - && (CLASS_DATA (expr1)->attr.dimension - || CLASS_DATA (expr1)->attr.codimension) - && expr1->ref - && expr1->ref->type == REF_ARRAY - && expr1->ref->next == NULL; + class_array = (expr1->expr_type == EXPR_VARIABLE + && expr1->ts.type == BT_CLASS + && CLASS_DATA (expr1) + && (strcmp (CLASS_DATA (expr1)->name, "_data") == 0) + && (CLASS_DATA (expr1)->attr.dimension + || CLASS_DATA (expr1)->attr.codimension) + && expr1->ref + && expr1->ref->type == REF_ARRAY + && expr1->ref->next == NULL); /* Check for F03:C811. */ if (!expr2 && (expr1->expr_type != EXPR_VARIABLE - || (!class_array && expr1->ref != NULL))) + || (!class_array && expr1->ref != NULL))) { gfc_error ("Selector in SELECT TYPE at %C is not a named variable; " "use associate-name=>"); @@ -5759,12 +5980,16 @@ gfc_match_select_type (void) new_st.ext.block.ns = gfc_current_ns; select_type_push (expr1->symtree->n.sym); + gfc_current_ns = ns; return MATCH_YES; cleanup: gfc_free_expr (expr1); gfc_free_expr (expr2); + gfc_undo_symbols (); + std::swap (ns, gfc_current_ns); + gfc_free_namespace (ns); return m; } @@ -6010,6 +6235,7 @@ match_simple_where (void) c->next = XCNEW (gfc_code); *c->next = new_st; + c->next->loc = gfc_current_locus; gfc_clear_new_st (); new_st.op = EXEC_WHERE; @@ -6066,8 +6292,12 @@ gfc_match_where (gfc_statement *st) c = gfc_get_code (EXEC_WHERE); c->expr1 = expr; + /* Put in the assignment. It will not be processed by add_statement, so we + need to copy the location here. */ + c->next = XCNEW (gfc_code); *c->next = new_st; + c->next->loc = gfc_current_locus; gfc_clear_new_st (); new_st.op = EXEC_WHERE; |