diff options
author | Steven G. Kargl <kargls@comcast.net> | 2009-03-31 04:38:12 +0000 |
---|---|---|
committer | Steven G. Kargl <kargl@gcc.gnu.org> | 2009-03-31 04:38:12 +0000 |
commit | 3759634f3208cbc1226bec19d22cbff989a287c3 (patch) | |
tree | 68d7f06e5527fece36527f377f12c08b89a27d34 /gcc | |
parent | 9752c4ad248eb383f72f9bd354af4c1890f1f1a3 (diff) | |
download | gcc-3759634f3208cbc1226bec19d22cbff989a287c3.zip gcc-3759634f3208cbc1226bec19d22cbff989a287c3.tar.gz gcc-3759634f3208cbc1226bec19d22cbff989a287c3.tar.bz2 |
alloc_alloc_expr_1.f90: Adjust for new error message.
2008-12-10 Steven G. Kargl <kargls@comcast.net>
* gfortran.dg/alloc_alloc_expr_1.f90: Adjust for new error message.
* gfortran.dg/allocate_alloc_opt_1.f90: New test.
* gfortran.dg/allocate_alloc_opt_2.f90: Ditto.
* gfortran.dg/allocate_alloc_opt_3.f90: Ditto.
* gfortran.dg/deallocate_alloc_opt_1.f90: Ditto.
* gfortran.dg/deallocate_alloc_opt_2.f90: Ditto.
* gfortran.dg/deallocate_alloc_opt_3.f90: Ditto.
2008-12-10 Steven G. Kargl <kargls@comcast.net>
* trans-stmt.c(gfc_trans_allocate): Add translation of ERRMSG.
(gfc_trans_deallocate): Add translation of ERRMSG. Remove stale
comments. Minor whitespace cleanup.
* resolve.c(is_scalar_expr_ptr): Whitespace cleanup.
(resolve_deallocate_expr (gfc_expr *e): Update error message.
(resolve_allocate_expr): Remove dead code. Update error message.
Move error checking to ...
(resolve_allocate_deallocate): ... here. Add additional error
checking for STAT, ERRMSG, and allocate-objects.
* match.c(gfc_match_allocate,gfc_match_deallocate): Parse ERRMSG.
Check for redundant uses of STAT and ERRMSG. Reword error message
and add checking for pointer, allocatable, and proc_pointer attributes.
From-SVN: r145331
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/fortran/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/fortran/match.c | 161 | ||||
-rw-r--r-- | gcc/fortran/resolve.c | 127 | ||||
-rw-r--r-- | gcc/fortran/trans-stmt.c | 114 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/alloc_alloc_expr_1.f90 | 4 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/allocate_alloc_opt_1.f90 | 40 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/allocate_alloc_opt_2.f90 | 12 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/allocate_alloc_opt_3.f90 | 33 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/deallocate_alloc_opt_1.f90 | 40 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/deallocate_alloc_opt_2.f90 | 12 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/deallocate_alloc_opt_3.f90 | 29 |
12 files changed, 502 insertions, 97 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 28764ec..09c6961 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,19 @@ +2009-03-30 Steven G. Kargl <kargls@comcast.net> + + PR fortran/38389 + * trans-stmt.c(gfc_trans_allocate): Add translation of ERRMSG. + (gfc_trans_deallocate): Add translation of ERRMSG. Remove stale + comments. Minor whitespace cleanup. + * resolve.c(is_scalar_expr_ptr): Whitespace cleanup. + (resolve_deallocate_expr (gfc_expr *e): Update error message. + (resolve_allocate_expr): Remove dead code. Update error message. + Move error checking to ... + (resolve_allocate_deallocate): ... here. Add additional error + checking for STAT, ERRMSG, and allocate-objects. + * match.c(gfc_match_allocate,gfc_match_deallocate): Parse ERRMSG. + Check for redundant uses of STAT and ERRMSG. Reword error message + and add checking for pointer, allocatable, and proc_pointer attributes. + 2009-03-30 Paul Thomas <pault@gcc.gnu.org> PR fortran/22571 diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index c8fd30d..a5c9f32 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -2222,11 +2222,13 @@ match gfc_match_allocate (void) { gfc_alloc *head, *tail; - gfc_expr *stat; + gfc_expr *stat, *errmsg, *tmp; match m; + bool saw_stat, saw_errmsg; head = tail = NULL; - stat = NULL; + stat = errmsg = tmp = NULL; + saw_stat = saw_errmsg = false; if (gfc_match_char ('(') != MATCH_YES) goto syntax; @@ -2250,35 +2252,92 @@ gfc_match_allocate (void) if (gfc_check_do_variable (tail->expr->symtree)) goto cleanup; - if (gfc_pure (NULL) - && gfc_impure_variable (tail->expr->symtree->n.sym)) + if (gfc_pure (NULL) && gfc_impure_variable (tail->expr->symtree->n.sym)) { - gfc_error ("Bad allocate-object in ALLOCATE statement at %C for a " - "PURE procedure"); + gfc_error ("Bad allocate-object at %C for a PURE procedure"); goto cleanup; } if (tail->expr->ts.type == BT_DERIVED) tail->expr->ts.derived = gfc_use_derived (tail->expr->ts.derived); + /* FIXME: disable the checking on derived types and arrays. */ + if (!(tail->expr->ref + && (tail->expr->ref->type == REF_COMPONENT + || tail->expr->ref->type == REF_ARRAY)) + && tail->expr->symtree->n.sym + && !(tail->expr->symtree->n.sym->attr.allocatable + || tail->expr->symtree->n.sym->attr.pointer + || tail->expr->symtree->n.sym->attr.proc_pointer)) + { + gfc_error ("Allocate-object at %C is not a nonprocedure pointer " + "or an allocatable variable"); + goto cleanup; + } + if (gfc_match_char (',') != MATCH_YES) break; - m = gfc_match (" stat = %v", &stat); +alloc_opt_list: + + m = gfc_match (" stat = %v", &tmp); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_YES) - break; + { + if (saw_stat) + { + gfc_error ("Redundant STAT tag found at %L ", &tmp->where); + gfc_free_expr (tmp); + goto cleanup; + } + + stat = tmp; + saw_stat = true; + + if (gfc_check_do_variable (stat->symtree)) + goto cleanup; + + if (gfc_match_char (',') == MATCH_YES) + goto alloc_opt_list; + } + + m = gfc_match (" errmsg = %v", &tmp); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_YES) + { + if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ERRMSG at %L", + &tmp->where) == FAILURE) + goto cleanup; + + if (saw_errmsg) + { + gfc_error ("Redundant ERRMSG tag found at %L ", &tmp->where); + gfc_free_expr (tmp); + goto cleanup; + } + + errmsg = tmp; + saw_errmsg = true; + + if (gfc_match_char (',') == MATCH_YES) + goto alloc_opt_list; + } + + gfc_gobble_whitespace (); + + if (gfc_peek_char () == ')') + break; } - if (stat != NULL) - gfc_check_do_variable(stat->symtree); if (gfc_match (" )%t") != MATCH_YES) goto syntax; new_st.op = EXEC_ALLOCATE; new_st.expr = stat; + new_st.expr2 = errmsg; new_st.ext.alloc_list = head; return MATCH_YES; @@ -2287,6 +2346,7 @@ syntax: gfc_syntax_error (ST_ALLOCATE); cleanup: + gfc_free_expr (errmsg); gfc_free_expr (stat); gfc_free_alloc_list (head); return MATCH_ERROR; @@ -2367,11 +2427,13 @@ match gfc_match_deallocate (void) { gfc_alloc *head, *tail; - gfc_expr *stat; + gfc_expr *stat, *errmsg, *tmp; match m; + bool saw_stat, saw_errmsg; head = tail = NULL; - stat = NULL; + stat = errmsg = tmp = NULL; + saw_stat = saw_errmsg = false; if (gfc_match_char ('(') != MATCH_YES) goto syntax; @@ -2395,32 +2457,88 @@ gfc_match_deallocate (void) if (gfc_check_do_variable (tail->expr->symtree)) goto cleanup; - if (gfc_pure (NULL) - && gfc_impure_variable (tail->expr->symtree->n.sym)) + if (gfc_pure (NULL) && gfc_impure_variable (tail->expr->symtree->n.sym)) { - gfc_error ("Illegal deallocate-expression in DEALLOCATE at %C " - "for a PURE procedure"); + gfc_error ("Illegal allocate-object at %C for a PURE procedure"); + goto cleanup; + } + + /* FIXME: disable the checking on derived types. */ + if (!(tail->expr->ref + && (tail->expr->ref->type == REF_COMPONENT + || tail->expr->ref->type == REF_ARRAY)) + && tail->expr->symtree->n.sym + && !(tail->expr->symtree->n.sym->attr.allocatable + || tail->expr->symtree->n.sym->attr.pointer + || tail->expr->symtree->n.sym->attr.proc_pointer)) + { + gfc_error ("Allocate-object at %C is not a nonprocedure pointer " + "or an allocatable variable"); goto cleanup; } if (gfc_match_char (',') != MATCH_YES) break; - m = gfc_match (" stat = %v", &stat); +dealloc_opt_list: + + m = gfc_match (" stat = %v", &tmp); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_YES) - break; - } + { + if (saw_stat) + { + gfc_error ("Redundant STAT tag found at %L ", &tmp->where); + gfc_free_expr (tmp); + goto cleanup; + } + + stat = tmp; + saw_stat = true; + + if (gfc_check_do_variable (stat->symtree)) + goto cleanup; + + if (gfc_match_char (',') == MATCH_YES) + goto dealloc_opt_list; + } - if (stat != NULL) - gfc_check_do_variable(stat->symtree); + m = gfc_match (" errmsg = %v", &tmp); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_YES) + { + if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ERRMSG at %L", + &tmp->where) == FAILURE) + goto cleanup; + + if (saw_errmsg) + { + gfc_error ("Redundant ERRMSG tag found at %L ", &tmp->where); + gfc_free_expr (tmp); + goto cleanup; + } + + errmsg = tmp; + saw_errmsg = true; + + if (gfc_match_char (',') == MATCH_YES) + goto dealloc_opt_list; + } + + gfc_gobble_whitespace (); + + if (gfc_peek_char () == ')') + break; + } if (gfc_match (" )%t") != MATCH_YES) goto syntax; new_st.op = EXEC_DEALLOCATE; new_st.expr = stat; + new_st.expr2 = errmsg; new_st.ext.alloc_list = head; return MATCH_YES; @@ -2429,6 +2547,7 @@ syntax: gfc_syntax_error (ST_DEALLOCATE); cleanup: + gfc_free_expr (errmsg); gfc_free_expr (stat); gfc_free_alloc_list (head); return MATCH_ERROR; diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 81d5ed8..4ab9df6 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -2034,16 +2034,16 @@ is_scalar_expr_ptr (gfc_expr *expr) } else { - /* We have constant lower and upper bounds. If the - difference between is 1, it can be considered a - scalar. */ - start = (int) mpz_get_si - (ref->u.ar.as->lower[0]->value.integer); - end = (int) mpz_get_si - (ref->u.ar.as->upper[0]->value.integer); - if (end - start + 1 != 1) - retval = FAILURE; - } + /* We have constant lower and upper bounds. If the + difference between is 1, it can be considered a + scalar. */ + start = (int) mpz_get_si + (ref->u.ar.as->lower[0]->value.integer); + end = (int) mpz_get_si + (ref->u.ar.as->upper[0]->value.integer); + if (end - start + 1 != 1) + retval = FAILURE; + } } else retval = FAILURE; @@ -5181,8 +5181,8 @@ resolve_deallocate_expr (gfc_expr *e) if (allocatable == 0 && attr.pointer == 0) { bad: - gfc_error ("Expression in DEALLOCATE statement at %L must be " - "ALLOCATABLE or a POINTER", &e->where); + gfc_error ("Allocate-object at %L must be ALLOCATABLE or a POINTER", + &e->where); } if (check_intent_in @@ -5267,11 +5267,6 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) if (gfc_resolve_expr (e) == FAILURE) return FAILURE; - if (code->expr && code->expr->expr_type == EXPR_VARIABLE) - sym = code->expr->symtree->n.sym; - else - sym = NULL; - /* Make sure the expression is allocatable or a pointer. If it is pointer, the next-to-last reference must be a pointer. */ @@ -5290,14 +5285,6 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) pointer = e->symtree->n.sym->attr.pointer; dimension = e->symtree->n.sym->attr.dimension; - if (sym == e->symtree->n.sym && sym->ts.type != BT_DERIVED) - { - gfc_error ("The STAT variable '%s' in an ALLOCATE statement must " - "not be allocated in the same statement at %L", - sym->name, &e->where); - return FAILURE; - } - for (ref = e->ref; ref; ref2 = ref, ref = ref->next) { if (pointer) @@ -5328,8 +5315,8 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) if (allocatable == 0 && pointer == 0) { - gfc_error ("Expression in ALLOCATE statement at %L must be " - "ALLOCATABLE or a POINTER", &e->where); + gfc_error ("Allocate-object at %L must be ALLOCATABLE or a POINTER", + &e->where); return FAILURE; } @@ -5424,26 +5411,83 @@ check_symbols: static void resolve_allocate_deallocate (gfc_code *code, const char *fcn) { - gfc_symbol *s = NULL; - gfc_alloc *a; + gfc_expr *stat, *errmsg, *pe, *qe; + gfc_alloc *a, *p, *q; + + stat = code->expr ? code->expr : NULL; - if (code->expr) - s = code->expr->symtree->n.sym; + errmsg = code->expr2 ? code->expr2 : NULL; - if (s) + /* Check the stat variable. */ + if (stat) { - if (s->attr.intent == INTENT_IN) - gfc_error ("STAT variable '%s' of %s statement at %C cannot " - "be INTENT(IN)", s->name, fcn); + if (stat->symtree->n.sym->attr.intent == INTENT_IN) + gfc_error ("Stat-variable '%s' at %L cannot be INTENT(IN)", + stat->symtree->n.sym->name, &stat->where); - if (gfc_pure (NULL) && gfc_impure_variable (s)) - gfc_error ("Illegal STAT variable in %s statement at %C " - "for a PURE procedure", fcn); + if (gfc_pure (NULL) && gfc_impure_variable (stat->symtree->n.sym)) + gfc_error ("Illegal stat-variable at %L for a PURE procedure", + &stat->where); + + if (stat->ts.type != BT_INTEGER + && !(stat->ref && (stat->ref->type == REF_ARRAY + || stat->ref->type == REF_COMPONENT))) + gfc_error ("Stat-variable at %L must be a scalar INTEGER " + "variable", &stat->where); + + for (p = code->ext.alloc_list; p; p = p->next) + if (p->expr->symtree->n.sym->name == stat->symtree->n.sym->name) + gfc_error ("Stat-variable at %L shall not be %sd within " + "the same %s statement", &stat->where, fcn, fcn); } - if (s && code->expr->ts.type != BT_INTEGER) - gfc_error ("STAT tag in %s statement at %L must be " - "of type INTEGER", fcn, &code->expr->where); + /* Check the errmsg variable. */ + if (errmsg) + { + if (!stat) + gfc_warning ("ERRMSG at %L is useless without a STAT tag", + &errmsg->where); + + if (errmsg->symtree->n.sym->attr.intent == INTENT_IN) + gfc_error ("Errmsg-variable '%s' at %L cannot be INTENT(IN)", + errmsg->symtree->n.sym->name, &errmsg->where); + + if (gfc_pure (NULL) && gfc_impure_variable (errmsg->symtree->n.sym)) + gfc_error ("Illegal errmsg-variable at %L for a PURE procedure", + &errmsg->where); + + if (errmsg->ts.type != BT_CHARACTER + && !(errmsg->ref + && (errmsg->ref->type == REF_ARRAY + || errmsg->ref->type == REF_COMPONENT))) + gfc_error ("Errmsg-variable at %L must be a scalar CHARACTER " + "variable", &errmsg->where); + + for (p = code->ext.alloc_list; p; p = p->next) + if (p->expr->symtree->n.sym->name == errmsg->symtree->n.sym->name) + gfc_error ("Errmsg-variable at %L shall not be %sd within " + "the same %s statement", &errmsg->where, fcn, fcn); + } + + /* Check that an allocate-object appears only once in the statement. + FIXME: Checking derived types is disabled. */ + for (p = code->ext.alloc_list; p; p = p->next) + { + pe = p->expr; + if ((pe->ref && pe->ref->type != REF_COMPONENT) + && (pe->symtree->n.sym->ts.type != BT_DERIVED)) + { + for (q = p->next; q; q = q->next) + { + qe = q->expr; + if ((qe->ref && qe->ref->type != REF_COMPONENT) + && (qe->symtree->n.sym->ts.type != BT_DERIVED) + && (pe->symtree->n.sym->name == qe->symtree->n.sym->name)) + gfc_error ("Allocate-object at %L also appears at %L", + &pe->where, &qe->where); + } + } + } if (strcmp (fcn, "ALLOCATE") == 0) { @@ -5457,6 +5501,7 @@ resolve_allocate_deallocate (gfc_code *code, const char *fcn) } } + /************ SELECT CASE resolution subroutines ************/ /* Callback function for our mergesort variant. Determines interval diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 0e51bda..24e7b80 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -3932,9 +3932,12 @@ gfc_trans_allocate (gfc_code * code) if (!code->ext.alloc_list) return NULL_TREE; + pstat = stat = error_label = tmp = NULL_TREE; + gfc_start_block (&block); - if (code->expr) + /* Either STAT= and/or ERRMSG is present. */ + if (code->expr || code->expr2) { tree gfc_int4_type_node = gfc_get_int_type (4); @@ -3944,8 +3947,6 @@ gfc_trans_allocate (gfc_code * code) error_label = gfc_build_label_decl (NULL_TREE); TREE_USED (error_label) = 1; } - else - pstat = stat = error_label = NULL_TREE; for (al = code->ext.alloc_list; al != NULL; al = al->next) { @@ -3971,7 +3972,7 @@ gfc_trans_allocate (gfc_code * code) fold_convert (TREE_TYPE (se.expr), tmp)); gfc_add_expr_to_block (&se.pre, tmp); - if (code->expr) + if (code->expr || code->expr2) { tmp = build1_v (GOTO_EXPR, error_label); parm = fold_build2 (NE_EXPR, boolean_type_node, @@ -3994,7 +3995,7 @@ gfc_trans_allocate (gfc_code * code) gfc_add_expr_to_block (&block, tmp); } - /* Assign the value to the status variable. */ + /* STAT block. */ if (code->expr) { tmp = build1_v (LABEL_EXPR, error_label); @@ -4006,29 +4007,45 @@ gfc_trans_allocate (gfc_code * code) gfc_add_modify (&block, se.expr, tmp); } + /* ERRMSG block. */ + if (code->expr2) + { + /* A better error message may be possible, but not required. */ + const char *msg = "Attempt to allocate an allocated object"; + tree errmsg, slen, dlen; + + gfc_init_se (&se, NULL); + gfc_conv_expr_lhs (&se, code->expr2); + + errmsg = gfc_create_var (pchar_type_node, "ERRMSG"); + + gfc_add_modify (&block, errmsg, + gfc_build_addr_expr (pchar_type_node, + gfc_build_localized_cstring_const (msg))); + + slen = build_int_cst (gfc_charlen_type_node, ((int) strlen (msg))); + dlen = gfc_get_expr_charlen (code->expr2); + slen = fold_build2 (MIN_EXPR, TREE_TYPE (slen), dlen, slen); + + dlen = build_call_expr (built_in_decls[BUILT_IN_MEMCPY], 3, + gfc_build_addr_expr (pvoid_type_node, se.expr), errmsg, slen); + + tmp = fold_build2 (NE_EXPR, boolean_type_node, stat, + build_int_cst (TREE_TYPE (stat), 0)); + + tmp = build3_v (COND_EXPR, tmp, dlen, build_empty_stmt ()); + + gfc_add_expr_to_block (&block, tmp); + } + return gfc_finish_block (&block); } -/* Translate a DEALLOCATE statement. - There are two cases within the for loop: - (1) deallocate(a1, a2, a3) is translated into the following sequence - _gfortran_deallocate(a1, 0B) - _gfortran_deallocate(a2, 0B) - _gfortran_deallocate(a3, 0B) - where the STAT= variable is passed a NULL pointer. - (2) deallocate(a1, a2, a3, stat=i) is translated into the following - astat = 0 - _gfortran_deallocate(a1, &stat) - astat = astat + stat - _gfortran_deallocate(a2, &stat) - astat = astat + stat - _gfortran_deallocate(a3, &stat) - astat = astat + stat - In case (1), we simply return at the end of the for loop. In case (2) - we set STAT= astat. */ +/* Translate a DEALLOCATE statement. */ + tree -gfc_trans_deallocate (gfc_code * code) +gfc_trans_deallocate (gfc_code *code) { gfc_se se; gfc_alloc *al; @@ -4036,14 +4053,17 @@ gfc_trans_deallocate (gfc_code * code) tree apstat, astat, pstat, stat, tmp; stmtblock_t block; + pstat = apstat = stat = astat = tmp = NULL_TREE; + gfc_start_block (&block); - /* Set up the optional STAT= */ - if (code->expr) + /* Count the number of failed deallocations. If deallocate() was + called with STAT= , then set STAT to the count. If deallocate + was called with ERRMSG, then set ERRMG to a string. */ + if (code->expr || code->expr2) { tree gfc_int4_type_node = gfc_get_int_type (4); - /* Variable used with the library call. */ stat = gfc_create_var (gfc_int4_type_node, "stat"); pstat = gfc_build_addr_expr (NULL_TREE, stat); @@ -4054,8 +4074,6 @@ gfc_trans_deallocate (gfc_code * code) /* Initialize astat to 0. */ gfc_add_modify (&block, astat, build_int_cst (TREE_TYPE (astat), 0)); } - else - pstat = apstat = stat = astat = NULL_TREE; for (al = code->ext.alloc_list; al != NULL; al = al->next) { @@ -4069,8 +4087,7 @@ gfc_trans_deallocate (gfc_code * code) se.descriptor_only = 1; gfc_conv_expr (&se, expr); - if (expr->ts.type == BT_DERIVED - && expr->ts.derived->attr.alloc_comp) + if (expr->ts.type == BT_DERIVED && expr->ts.derived->attr.alloc_comp) { gfc_ref *ref; gfc_ref *last = NULL; @@ -4081,7 +4098,7 @@ gfc_trans_deallocate (gfc_code * code) /* Do not deallocate the components of a derived type ultimate pointer component. */ if (!(last && last->u.c.component->attr.pointer) - && !(!last && expr->symtree->n.sym->attr.pointer)) + && !(!last && expr->symtree->n.sym->attr.pointer)) { tmp = gfc_deallocate_alloc_comp (expr->ts.derived, se.expr, expr->rank); @@ -4104,7 +4121,7 @@ gfc_trans_deallocate (gfc_code * code) /* Keep track of the number of failed deallocations by adding stat of the last deallocation to the running total. */ - if (code->expr) + if (code->expr || code->expr2) { apstat = fold_build2 (PLUS_EXPR, TREE_TYPE (stat), astat, stat); gfc_add_modify (&se.pre, astat, apstat); @@ -4115,7 +4132,7 @@ gfc_trans_deallocate (gfc_code * code) } - /* Assign the value to the status variable. */ + /* Set STAT. */ if (code->expr) { gfc_init_se (&se, NULL); @@ -4124,6 +4141,37 @@ gfc_trans_deallocate (gfc_code * code) gfc_add_modify (&block, se.expr, tmp); } + /* Set ERRMSG. */ + if (code->expr2) + { + /* A better error message may be possible, but not required. */ + const char *msg = "Attempt to deallocate an unallocated object"; + tree errmsg, slen, dlen; + + gfc_init_se (&se, NULL); + gfc_conv_expr_lhs (&se, code->expr2); + + errmsg = gfc_create_var (pchar_type_node, "ERRMSG"); + + gfc_add_modify (&block, errmsg, + gfc_build_addr_expr (pchar_type_node, + gfc_build_localized_cstring_const (msg))); + + slen = build_int_cst (gfc_charlen_type_node, ((int) strlen (msg))); + dlen = gfc_get_expr_charlen (code->expr2); + slen = fold_build2 (MIN_EXPR, TREE_TYPE (slen), dlen, slen); + + dlen = build_call_expr (built_in_decls[BUILT_IN_MEMCPY], 3, + gfc_build_addr_expr (pvoid_type_node, se.expr), errmsg, slen); + + tmp = fold_build2 (NE_EXPR, boolean_type_node, astat, + build_int_cst (TREE_TYPE (astat), 0)); + + tmp = build3_v (COND_EXPR, tmp, dlen, build_empty_stmt ()); + + gfc_add_expr_to_block (&block, tmp); + } + return gfc_finish_block (&block); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index daa4544..aadb0da 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2009-03-30 Steven G. Kargl <kargls@comcast.net> + + PR fortran/38389 + * gfortran.dg/alloc_alloc_expr_1.f90: Adjust for new error message. + * gfortran.dg/allocate_alloc_opt_1.f90: New test. + * gfortran.dg/allocate_alloc_opt_2.f90: Ditto. + * gfortran.dg/allocate_alloc_opt_3.f90: Ditto. + * gfortran.dg/deallocate_alloc_opt_1.f90: Ditto. + * gfortran.dg/deallocate_alloc_opt_2.f90: Ditto. + * gfortran.dg/deallocate_alloc_opt_3.f90: Ditto. + 2009-03-30 Paul Thomas <pault@gcc.gnu.org> PR fortran/22571 diff --git a/gcc/testsuite/gfortran.dg/alloc_alloc_expr_1.f90 b/gcc/testsuite/gfortran.dg/alloc_alloc_expr_1.f90 index 5545b0d..516ccd4 100644 --- a/gcc/testsuite/gfortran.dg/alloc_alloc_expr_1.f90 +++ b/gcc/testsuite/gfortran.dg/alloc_alloc_expr_1.f90 @@ -18,9 +18,9 @@ program fc011 integer, pointer :: PTR integer, allocatable :: ALLOCS(:) - allocate (PTR, stat=PTR) ! { dg-error "allocated in the same statement" } + allocate (PTR, stat=PTR) ! { dg-error "in the same ALLOCATE statement" } - allocate (ALLOCS(10),stat=ALLOCS(1)) ! { dg-error "allocated in the same statement" } + allocate (ALLOCS(10),stat=ALLOCS(1)) ! { dg-error "in the same ALLOCATE statement" } ALLOCATE(PTR,ALLOCS(PTR)) ! { dg-error "same ALLOCATE statement" } diff --git a/gcc/testsuite/gfortran.dg/allocate_alloc_opt_1.f90 b/gcc/testsuite/gfortran.dg/allocate_alloc_opt_1.f90 new file mode 100644 index 0000000..cd611cc --- /dev/null +++ b/gcc/testsuite/gfortran.dg/allocate_alloc_opt_1.f90 @@ -0,0 +1,40 @@ +! { dg-do compile } +program a + + implicit none + + real x + integer j, k, n(4) + character(len=70) err + character(len=70), allocatable :: error(:) + + integer, allocatable :: i(:) + + type b + integer, allocatable :: c(:), d(:) + end type b + + type(b) e, f(3) + + allocate(i(2), stat=x) ! { dg-error "must be a scalar INTEGER" } + allocate(i(2), stat=j, stat=k) ! { dg-error "Redundant STAT" } + allocate(i(2)) + allocate(i(2))) ! { dg-error "Syntax error in ALLOCATE" } + allocate(i(2), errmsg=err, errmsg=err) ! { dg-error "Redundant ERRMSG" } + allocate(i(2), errmsg=err) ! { dg-warning "useless without a STAT" } + allocate(i(2), stat=j, errmsg=x) ! { dg-error "must be a scalar CHARACTER" } + + allocate(err) ! { dg-error "nonprocedure pointer or an allocatable" } + + allocate(error(2),stat=j,errmsg=error) ! { dg-error "shall not be ALLOCATEd within" } + allocate(i(2), stat = i) ! { dg-error "shall not be ALLOCATEd within" } + + allocate(n) ! { dg-error "must be ALLOCATABLE or a POINTER" } + + allocate(i(2), i(2)) ! { dg-error "Allocate-object at" } + + ! These should not fail the check for duplicate alloc-objects. + allocate(f(1)%c(2), f(2)%d(2)) + allocate(e%c(2), e%d(2)) + +end program a diff --git a/gcc/testsuite/gfortran.dg/allocate_alloc_opt_2.f90 b/gcc/testsuite/gfortran.dg/allocate_alloc_opt_2.f90 new file mode 100644 index 0000000..b6d6ca5 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/allocate_alloc_opt_2.f90 @@ -0,0 +1,12 @@ +! { dg-do compile } +subroutine sub(i, j, err) + implicit none + character(len=*), intent(in) :: err + integer, intent(in) :: j + integer, intent(in), allocatable :: i(:) + integer, allocatable :: m(:) + integer n + allocate(i(2)) ! { dg-error "Cannot allocate" "" } + allocate(m(2), stat=j) ! { dg-error "cannot be" "" } + allocate(m(2),stat=n,errmsg=err) ! { dg-error "cannot be" "" } +end subroutine sub diff --git a/gcc/testsuite/gfortran.dg/allocate_alloc_opt_3.f90 b/gcc/testsuite/gfortran.dg/allocate_alloc_opt_3.f90 new file mode 100644 index 0000000..d8c177f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/allocate_alloc_opt_3.f90 @@ -0,0 +1,33 @@ +! { dg-do run } +program a + + implicit none + + integer n + character(len=70) e1 + character(len=30) e2 + integer, allocatable :: i(:) + + e1 = 'No error' + allocate(i(4), stat=n, errmsg=e1) + if (trim(e1) /= 'No error') call abort + deallocate(i) + + e2 = 'No error' + allocate(i(4),stat=n, errmsg=e2) + if (trim(e2) /= 'No error') call abort + deallocate(i) + + + e1 = 'No error' + allocate(i(4), stat=n, errmsg=e1) + allocate(i(4), stat=n, errmsg=e1) + if (trim(e1) /= 'Attempt to allocate an allocated object') call abort + deallocate(i) + + e2 = 'No error' + allocate(i(4), stat=n, errmsg=e2) + allocate(i(4), stat=n, errmsg=e2) + if (trim(e2) /= 'Attempt to allocate an allocat') call abort + +end program a diff --git a/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_1.f90 b/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_1.f90 new file mode 100644 index 0000000..75da701 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_1.f90 @@ -0,0 +1,40 @@ +! { dg-do compile } +program a + + implicit none + + real x + integer j, k, n(4) + character(len=70) err + character(len=70), allocatable :: error(:) + + integer, allocatable :: i(:) + + type b + integer, allocatable :: c(:), d(:) + end type b + + type(b) e, f(3) + + deallocate(i, stat=x) ! { dg-error "must be a scalar INTEGER" } + deallocate(i, stat=j, stat=k) ! { dg-error "Redundant STAT" } + deallocate(i) + deallocate(i)) ! { dg-error "Syntax error in DEALLOCATE" } + deallocate(i, errmsg=err, errmsg=err) ! { dg-error "Redundant ERRMSG" } + deallocate(i, errmsg=err) ! { dg-warning "useless without a STAT" } + deallocate(i, stat=j, errmsg=x) ! { dg-error "must be a scalar CHARACTER" } + + deallocate(err) ! { dg-error "nonprocedure pointer or an allocatable" } + + deallocate(error,stat=j,errmsg=error) ! { dg-error "shall not be DEALLOCATEd within" } + deallocate(i, stat = i) ! { dg-error "shall not be DEALLOCATEd within" } + + deallocate(n) ! { dg-error "must be ALLOCATABLE or a POINTER" } + + deallocate(i, i) ! { dg-error "Allocate-object at" } + + ! These should not fail the check for duplicate alloc-objects. + deallocate(f(1)%c, f(2)%d) + deallocate(e%c, e%d) + +end program a diff --git a/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_2.f90 b/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_2.f90 new file mode 100644 index 0000000..0c3e869 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_2.f90 @@ -0,0 +1,12 @@ +! { dg-do compile } +subroutine sub(i, j, err) + implicit none + character(len=*), intent(in) :: err + integer, intent(in) :: j + integer, intent(in), allocatable :: i(:) + integer, allocatable :: m(:) + integer n + deallocate(i) ! { dg-error "Cannot deallocate" "" } + deallocate(m, stat=j) ! { dg-error "cannot be" "" } + deallocate(m,stat=n,errmsg=err) ! { dg-error "cannot be" "" } +end subroutine sub diff --git a/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_3.f90 b/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_3.f90 new file mode 100644 index 0000000..67ec14a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/deallocate_alloc_opt_3.f90 @@ -0,0 +1,29 @@ +! { dg-do run } +program a + + implicit none + + integer n + character(len=70) e1 + character(len=30) e2 + integer, allocatable :: i(:) + + e1 = 'No error' + allocate(i(4)) + deallocate(i, stat=n, errmsg=e1) + if (trim(e1) /= 'No error') call abort + + e2 = 'No error' + allocate(i(4)) + deallocate(i, stat=n, errmsg=e2) + if (trim(e2) /= 'No error') call abort + + e1 = 'No error' + deallocate(i, stat=n, errmsg=e1) + if (trim(e1) /= 'Attempt to deallocate an unallocated object') call abort + + e2 = 'No error' + deallocate(i, stat=n, errmsg=e2) + if (trim(e2) /= 'Attempt to deallocate an unall') call abort + +end program a |