diff options
author | Jakub Jelinek <jakub@redhat.com> | 2009-05-14 02:00:27 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2009-05-14 02:00:27 +0200 |
commit | 7e2791428f91a88bfe3762fa1456f435fc25e2b0 (patch) | |
tree | 939aa9b645af6be87061269b8b1cd513bd796d30 /gcc/fortran | |
parent | 00b0c19b4bbfa483925a177ed3e6ce2e1f42444b (diff) | |
download | gcc-7e2791428f91a88bfe3762fa1456f435fc25e2b0.zip gcc-7e2791428f91a88bfe3762fa1456f435fc25e2b0.tar.gz gcc-7e2791428f91a88bfe3762fa1456f435fc25e2b0.tar.bz2 |
re PR fortran/39865 (ICE in gfc_conv_scalarized_array_ref)
PR fortran/39865
* io.c (resolve_tag_format): CHARACTER array in FMT= argument
isn't an extension. Reject non-CHARACTER array element of
assumed shape or pointer or assumed size array.
* trans-array.c (array_parameter_size): New function.
(gfc_conv_array_parameter): Add size argument. Call
array_parameter_size if it is non-NULL.
* trans-array.h (gfc_conv_array_parameter): Adjust prototype.
* trans-expr.c (gfc_conv_function_call, gfc_trans_arrayfunc_assign):
Adjust callers.
* trans-intrinsic.c (gfc_conv_intrinsic_loc): Likewise.
* trans-io.c (gfc_convert_array_to_string): Rewritten.
* gfortran.dg/pr39865.f90: New test.
* gfortran.dg/hollerith.f90: Don't expect errors for CHARACTER
arrays in FMT=.
* gfortran.dg/hollerith_f95.f90: Likewise.
* gfortran.dg/hollerith6.f90: New test.
* gfortran.dg/hollerith7.f90: New test.
From-SVN: r147507
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/fortran/io.c | 43 | ||||
-rw-r--r-- | gcc/fortran/trans-array.c | 44 | ||||
-rw-r--r-- | gcc/fortran/trans-array.h | 2 | ||||
-rw-r--r-- | gcc/fortran/trans-expr.c | 7 | ||||
-rw-r--r-- | gcc/fortran/trans-intrinsic.c | 2 | ||||
-rw-r--r-- | gcc/fortran/trans-io.c | 84 |
7 files changed, 130 insertions, 67 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 0798407..db5f373 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,18 @@ +2009-05-14 Jakub Jelinek <jakub@redhat.com> + + PR fortran/39865 + * io.c (resolve_tag_format): CHARACTER array in FMT= argument + isn't an extension. Reject non-CHARACTER array element of + assumed shape or pointer or assumed size array. + * trans-array.c (array_parameter_size): New function. + (gfc_conv_array_parameter): Add size argument. Call + array_parameter_size if it is non-NULL. + * trans-array.h (gfc_conv_array_parameter): Adjust prototype. + * trans-expr.c (gfc_conv_function_call, gfc_trans_arrayfunc_assign): + Adjust callers. + * trans-intrinsic.c (gfc_conv_intrinsic_loc): Likewise. + * trans-io.c (gfc_convert_array_to_string): Rewritten. + 2009-05-13 Steven G. Kargl <kargl@gcc.gnu.org> * gfortran.h (gfc_code): Rename struct member expr to expr1. diff --git a/gcc/fortran/io.c b/gcc/fortran/io.c index eb0e3ae..c902257 100644 --- a/gcc/fortran/io.c +++ b/gcc/fortran/io.c @@ -1,5 +1,5 @@ /* Deal with I/O statements & related stuff. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by Andy Vaught @@ -1234,8 +1234,11 @@ resolve_tag_format (const gfc_expr *e) /* If e's rank is zero and e is not an element of an array, it should be of integer or character type. The integer variable should be ASSIGNED. */ - if (e->symtree == NULL || e->symtree->n.sym->as == NULL - || e->symtree->n.sym->as->rank == 0) + if (e->rank == 0 + && (e->expr_type != EXPR_VARIABLE + || e->symtree == NULL + || e->symtree->n.sym->as == NULL + || e->symtree->n.sym->as->rank == 0)) { if (e->ts.type != BT_CHARACTER && e->ts.type != BT_INTEGER) { @@ -1266,20 +1269,34 @@ resolve_tag_format (const gfc_expr *e) return SUCCESS; } - /* If rank is nonzero, we allow the type to be character under GFC_STD_GNU - and other type under GFC_STD_LEGACY. It may be assigned an Hollerith - constant. */ - if (e->ts.type == BT_CHARACTER) - { - if (gfc_notify_std (GFC_STD_GNU, "Extension: Character array " - "in FORMAT tag at %L", &e->where) == FAILURE) - return FAILURE; - } - else + /* If rank is nonzero and type is not character, we allow it under GFC_STD_LEGACY. + It may be assigned an Hollerith constant. */ + if (e->ts.type != BT_CHARACTER) { if (gfc_notify_std (GFC_STD_LEGACY, "Extension: Non-character " "in FORMAT tag at %L", &e->where) == FAILURE) return FAILURE; + + if (e->rank == 0 && e->symtree->n.sym->as->type == AS_ASSUMED_SHAPE) + { + gfc_error ("Non-character assumed shape array element in FORMAT" + " tag at %L", &e->where); + return FAILURE; + } + + if (e->rank == 0 && e->symtree->n.sym->as->type == AS_ASSUMED_SIZE) + { + gfc_error ("Non-character assumed size array element in FORMAT" + " tag at %L", &e->where); + return FAILURE; + } + + if (e->rank == 0 && e->symtree->n.sym->attr.pointer) + { + gfc_error ("Non-character pointer array element in FORMAT tag at %L", + &e->where); + return FAILURE; + } } return SUCCESS; diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 71db46d..f4276ca 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -5339,13 +5339,41 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss) gfc_cleanup_loop (&loop); } +/* Helper function for gfc_conv_array_parameter if array size needs to be + computed. */ + +static void +array_parameter_size (tree desc, gfc_expr *expr, tree *size) +{ + tree elem; + if (GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) + *size = GFC_TYPE_ARRAY_SIZE (TREE_TYPE (desc)); + else if (expr->rank > 1) + *size = build_call_expr (gfor_fndecl_size0, 1, + gfc_build_addr_expr (NULL, desc)); + else + { + tree ubound = gfc_conv_descriptor_ubound (desc, gfc_index_zero_node); + tree lbound = gfc_conv_descriptor_lbound (desc, gfc_index_zero_node); + + *size = fold_build2 (MINUS_EXPR, gfc_array_index_type, ubound, lbound); + *size = fold_build2 (PLUS_EXPR, gfc_array_index_type, *size, + gfc_index_one_node); + *size = fold_build2 (MAX_EXPR, gfc_array_index_type, *size, + gfc_index_zero_node); + } + elem = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (desc))); + *size = fold_build2 (MULT_EXPR, gfc_array_index_type, *size, + fold_convert (gfc_array_index_type, elem)); +} /* Convert an array for passing as an actual parameter. */ /* TODO: Optimize passing g77 arrays. */ void gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77, - const gfc_symbol *fsym, const char *proc_name) + const gfc_symbol *fsym, const char *proc_name, + tree *size) { tree ptr; tree desc; @@ -5394,6 +5422,8 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77, se->expr = tmp; else se->expr = gfc_build_addr_expr (NULL_TREE, tmp); + if (size) + array_parameter_size (tmp, expr, size); return; } if (sym->attr.allocatable) @@ -5401,10 +5431,11 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77, if (sym->attr.dummy || sym->attr.result) { gfc_conv_expr_descriptor (se, expr, ss); - se->expr = gfc_conv_array_data (se->expr); + tmp = se->expr; } - else - se->expr = gfc_conv_array_data (tmp); + if (size) + array_parameter_size (tmp, expr, size); + se->expr = gfc_conv_array_data (tmp); return; } } @@ -5413,6 +5444,8 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77, { /* Result of the enclosing function. */ gfc_conv_expr_descriptor (se, expr, ss); + if (size) + array_parameter_size (se->expr, expr, size); se->expr = gfc_build_addr_expr (NULL_TREE, se->expr); if (g77 && TREE_TYPE (TREE_TYPE (se->expr)) != NULL_TREE @@ -5426,6 +5459,9 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77, /* Every other type of array. */ se->want_pointer = 1; gfc_conv_expr_descriptor (se, expr, ss); + if (size) + array_parameter_size (build_fold_indirect_ref (se->expr), + expr, size); } /* Deallocate the allocatable components of structures that are diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h index 49818d4..3f8809d 100644 --- a/gcc/fortran/trans-array.h +++ b/gcc/fortran/trans-array.h @@ -106,7 +106,7 @@ void gfc_conv_tmp_ref (gfc_se *); void gfc_conv_expr_descriptor (gfc_se *, gfc_expr *, gfc_ss *); /* Convert an array for passing as an actual function parameter. */ void gfc_conv_array_parameter (gfc_se *, gfc_expr *, gfc_ss *, int, - const gfc_symbol *, const char *); + const gfc_symbol *, const char *, tree *); /* Evaluate and transpose a matrix expression. */ void gfc_conv_array_transpose (gfc_se *, gfc_expr *); diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 70c44f3..cf17598 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -2424,7 +2424,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, f = f || !sym->attr.always_explicit; argss = gfc_walk_expr (arg->expr); - gfc_conv_array_parameter (se, arg->expr, argss, f, NULL, NULL); + gfc_conv_array_parameter (se, arg->expr, argss, f, + NULL, NULL, NULL); } /* TODO -- the following two lines shouldn't be necessary, but @@ -2676,7 +2677,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, fsym ? fsym->attr.intent : INTENT_INOUT); else gfc_conv_array_parameter (&parmse, e, argss, f, fsym, - sym->name); + sym->name, NULL); /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is allocated on entry, it must be deallocated. */ @@ -4352,7 +4353,7 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2) gfc_start_block (&se.pre); se.want_pointer = 1; - gfc_conv_array_parameter (&se, expr1, ss, 0, NULL, NULL); + gfc_conv_array_parameter (&se, expr1, ss, 0, NULL, NULL, NULL); se.direct_byref = 1; se.ss = gfc_walk_expr (expr2); diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index d00a35b..33cc7f5 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -4394,7 +4394,7 @@ gfc_conv_intrinsic_loc (gfc_se * se, gfc_expr * expr) if (ss == gfc_ss_terminator) gfc_conv_expr_reference (se, arg_expr); else - gfc_conv_array_parameter (se, arg_expr, ss, 1, NULL, NULL); + gfc_conv_array_parameter (se, arg_expr, ss, 1, NULL, NULL, NULL); se->expr= convert (gfc_get_int_type (gfc_index_integer_kind), se->expr); /* Create a temporary variable for loc return value. Without this, diff --git a/gcc/fortran/trans-io.c b/gcc/fortran/trans-io.c index 09f35b7..24f156e 100644 --- a/gcc/fortran/trans-io.c +++ b/gcc/fortran/trans-io.c @@ -567,65 +567,57 @@ set_parameter_ref (stmtblock_t *block, stmtblock_t *postblock, /* Given an array expr, find its address and length to get a string. If the array is full, the string's address is the address of array's first element - and the length is the size of the whole array. If it is an element, the + and the length is the size of the whole array. If it is an element, the string's address is the element's address and the length is the rest size of - the array. -*/ + the array. */ static void gfc_convert_array_to_string (gfc_se * se, gfc_expr * e) { - tree tmp; - tree array; - tree type; tree size; - int rank; - gfc_symbol *sym; - - sym = e->symtree->n.sym; - rank = sym->as->rank - 1; - if (e->ref->u.ar.type == AR_FULL) - { - se->expr = gfc_get_symbol_decl (sym); - se->expr = gfc_conv_array_data (se->expr); - } - else + if (e->rank == 0) { + tree type, array, tmp; + gfc_symbol *sym; + int rank; + + /* If it is an element, we need its address and size of the rest. */ + gcc_assert (e->expr_type == EXPR_VARIABLE); + gcc_assert (e->ref->u.ar.type == AR_ELEMENT); + sym = e->symtree->n.sym; + rank = sym->as->rank - 1; gfc_conv_expr (se, e); - } - - array = sym->backend_decl; - type = TREE_TYPE (array); - if (GFC_ARRAY_TYPE_P (type)) - size = GFC_TYPE_ARRAY_SIZE (type); - else - { - gcc_assert (GFC_DESCRIPTOR_TYPE_P (type)); - size = gfc_conv_array_stride (array, rank); - tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, - gfc_conv_array_ubound (array, rank), - gfc_conv_array_lbound (array, rank)); - tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type, tmp, - gfc_index_one_node); - size = fold_build2 (MULT_EXPR, gfc_array_index_type, tmp, size); - } + array = sym->backend_decl; + type = TREE_TYPE (array); - gcc_assert (size); + if (GFC_ARRAY_TYPE_P (type)) + size = GFC_TYPE_ARRAY_SIZE (type); + else + { + gcc_assert (GFC_DESCRIPTOR_TYPE_P (type)); + size = gfc_conv_array_stride (array, rank); + tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, + gfc_conv_array_ubound (array, rank), + gfc_conv_array_lbound (array, rank)); + tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type, tmp, + gfc_index_one_node); + size = fold_build2 (MULT_EXPR, gfc_array_index_type, tmp, size); + } + gcc_assert (size); - /* If it is an element, we need the its address and size of the rest. */ - if (e->ref->u.ar.type == AR_ELEMENT) - { size = fold_build2 (MINUS_EXPR, gfc_array_index_type, size, - TREE_OPERAND (se->expr, 1)); + TREE_OPERAND (se->expr, 1)); se->expr = gfc_build_addr_expr (NULL_TREE, se->expr); + tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type)); + size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, + fold_convert (gfc_array_index_type, tmp)); + se->string_length = fold_convert (gfc_charlen_type_node, size); + return; } - tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type)); - size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, - fold_convert (gfc_array_index_type, tmp)); - + gfc_conv_array_parameter (se, e, gfc_walk_expr (e), 1, NULL, NULL, &size); se->string_length = fold_convert (gfc_charlen_type_node, size); } @@ -654,7 +646,9 @@ set_string (stmtblock_t * block, stmtblock_t * postblock, tree var, var, p->field_len, NULL_TREE); /* Integer variable assigned a format label. */ - if (e->ts.type == BT_INTEGER && e->symtree->n.sym->attr.assign == 1) + if (e->ts.type == BT_INTEGER + && e->rank == 0 + && e->symtree->n.sym->attr.assign == 1) { char * msg; tree cond; @@ -680,7 +674,7 @@ set_string (stmtblock_t * block, stmtblock_t * postblock, tree var, if (e->ts.type == BT_CHARACTER && e->rank == 0) gfc_conv_expr (&se, e); /* Array assigned Hollerith constant or character array. */ - else if (e->symtree && (e->symtree->n.sym->as->rank > 0)) + else if (e->rank > 0 || (e->symtree && e->symtree->n.sym->as->rank > 0)) gfc_convert_array_to_string (&se, e); else gcc_unreachable (); |