This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
The attached patch is a reworking of how character variables are handled. There are still a few bits missing, but most things (including arrays) should now work. Tested on i686-linux. Applied to tree-ssa branch. Paul 2003-04-04 Paul Brook <paul@codesourcery.com> PR 13252 PR 14081 * f95-lang.c (gfc_init_builtin_functions): Add stack_alloc, stack_save and stack_restore. * gfortran.h (struct gfc_charlen): Add backend_decl. * trans-array.c (gfc_trans_allocate_temp_array, gfc_conv_temp_array_ref, gfc_conv_resolve_dependencies, (gfc_conv_loop_setup, gfc_array_allocate, gfc_conv_array_init_size): Remove old, broken string handling. (gfc_trans_auto_array_allocation, gfc_trans_g77_array, gfc_trans_dummy_array_bias, gfc_conv_expr_descriptor, gfc_trans_deferred_array): Handle character arrays. * trans-const.c (gfc_conv_const_charlen): New function. * trans-const.h (gfc_conv_const_charlen): Add prototype. * trans-decl.c (gfc_finish_var_decl): Don't mark automatic variables as static. (gfc_build_dummy_array_decl): Handle arrays with unknown element size. (gfc_create_string_length): New function. (gfc_get_symbol_decl): Create lengths for character variables. (gfc_get_fake_result_decl): Ditto. (gfc_build_function_decl): Only set length for assumed length character arguments. (gfc_trans_dummy_character): New function. (gfc_trans_auto_character_variable): Rewrite. (gfc_trans_deferred_vars): Handle more types of character variable. (gfc_create_module_variable): String lengths have moved. (gfc_generate_function_code): Initialize deferred var chain earlier. * trans-expr.c (gfc_conv_init_string_length): Rename ... (gfc_trans_init_string_length): ... to this. (gfc_conv_component_ref, gfc_conv_variable, gfc_conv_concat_op, gfc_conv_function_call): Update to new format for character variables. (gfc_conv_string_length): Remove. (gfc_conv_string_parameter): Update assertion. * trans-intrinsic.c (gfc_conv_intrinsic_len): Use new location. * trans-io.c (set_string): Use new macro names. * trans-stmt.c (gfc_trans_label_assign. gfc_trans_goto): Ditto. * trans-types.c (gfc_get_character_type): Use existing length expr. (gfc_is_nodesc_array): Make public. (gfc_get_dtype_cst): Rename ... (gfc_get_dtype): ... to this. Handle unknown size arrays. (gfc_get_nodesc_array_type): Use new name. (gfc_sym_type): New character variable code. (gfc_get_derived_type): Ditto. (gfc_get_function_type): Evaluate character variable lengths. * trans-types.h (gfc_strlen_kind): Define. (gfc_is_nodesc_array): Add prototype. * trans.h: Update prototypes. (struct lang_type): Update comments. (GFC_DECL_STRING_LEN): New name for GFC_DECL_STRING_LENGTH. (GFC_KNOWN_SIZE_STRING_TYPE): Remove. testsuite * gfortran.fortran-torture/execute/strarray_1.f90: New test. * gfortran.fortran-torture/execute/strarray_2.f90: New test. * gfortran.fortran-torture/execute/strarray_3.f90: New test. * gfortran.fortran-torture/execute/strarray_4.f90: New test. * gfortran.fortran-torture/execute/strcommon_1.f90: New test.
Index: f95-lang.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/f95-lang.c,v retrieving revision 1.1.2.18 diff -u -p -r1.1.2.18 f95-lang.c --- a/f95-lang.c 16 Feb 2004 12:36:08 -0000 1.1.2.18 +++ b/f95-lang.c 4 Apr 2004 15:39:12 -0000 @@ -826,6 +826,22 @@ gfc_init_builtin_functions (void) ftype = build_function_type (pvoid_type_node, tmp); gfc_define_builtin ("__builtin_adjust_trampoline", ftype, BUILT_IN_ADJUST_TRAMPOLINE, "adjust_trampoline", true); + + tmp = tree_cons (NULL_TREE, pvoid_type_node, voidchain); + tmp = tree_cons (NULL_TREE, size_type_node, voidchain); + ftype = build_function_type (pvoid_type_node, tmp); + gfc_define_builtin ("__builtin_stack_alloc", ftype, BUILT_IN_STACK_ALLOC, + "stack_alloc", false); + + /* The stack_save and stack_restore builtins aren't used directly. They + are inserted during gimplification to implement stack_alloc calls. */ + ftype = build_function_type (pvoid_type_node, voidchain); + gfc_define_builtin ("__builtin_stack_save", ftype, BUILT_IN_STACK_SAVE, + "stack_save", false); + tmp = tree_cons (NULL_TREE, pvoid_type_node, voidchain); + ftype = build_function_type (void_type_node, tmp); + gfc_define_builtin ("__builtin_stack_restore", ftype, BUILT_IN_STACK_RESTORE, + "stack_restore", false); } #undef DEFINE_MATH_BUILTIN Index: gfortran.h =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/gfortran.h,v retrieving revision 1.1.2.11 diff -u -p -r1.1.2.11 gfortran.h --- a/gfortran.h 4 Apr 2004 15:33:41 -0000 1.1.2.11 +++ b/gfortran.h 4 Apr 2004 15:39:12 -0000 @@ -480,6 +480,7 @@ typedef struct gfc_charlen { struct gfc_expr *length; struct gfc_charlen *next; + tree backend_decl; } gfc_charlen; Index: trans-array.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-array.c,v retrieving revision 1.1.2.18 diff -u -p -r1.1.2.18 trans-array.c --- a/trans-array.c 4 Apr 2004 11:50:00 -0000 1.1.2.18 +++ b/trans-array.c 4 Apr 2004 21:34:24 -0000 @@ -530,11 +530,7 @@ gfc_trans_allocate_temp_array (gfc_loopi desc = gfc_create_var (type, "atmp"); GFC_DECL_PACKED_ARRAY (desc) = 1; if (string_length) - { - gfc_allocate_lang_decl (desc); - GFC_DECL_STRING (desc) = 1; - GFC_DECL_STRING_LENGTH (desc) = string_length; - } + GFC_DECL_STRING (desc) = 1; info->descriptor = desc; size = integer_one_node; @@ -572,8 +568,9 @@ gfc_trans_allocate_temp_array (gfc_loopi size = gfc_evaluate_now (size, &loop->pre); } + /* TODO: Where does the string length go? */ if (string_length) - gfc_todo_error ("Arrays of strings"); + gfc_todo_error ("temporary arrays of strings"); /* Get the size of the array. */ nelem = size; @@ -1442,8 +1439,9 @@ gfc_conv_tmp_array_ref (gfc_se * se) tree desc; desc = se->ss->data.info.descriptor; + /* TODO: We need the string length. */ if (GFC_DECL_STRING (desc)) - se->string_length = GFC_DECL_STRING_LENGTH (desc); + gfc_todo_error ("temporary arrays of strings"); gfc_conv_scalarized_array_ref (se, NULL); } @@ -2183,8 +2181,7 @@ gfc_conv_resolve_dependencies (gfc_loopi loop->temp_ss->type = GFC_SS_TEMP; loop->temp_ss->data.temp.type = gfc_get_element_type (TREE_TYPE (dest->data.info.descriptor)); - loop->temp_ss->data.temp.string_length = - gfc_conv_string_length (dest->data.info.descriptor); + loop->temp_ss->data.temp.string_length = NULL_TREE; loop->temp_ss->data.temp.dimen = loop->dimen; loop->temp_ss->next = gfc_ss_terminator; gfc_add_ss_to_loop (loop, loop->temp_ss); @@ -2429,14 +2426,13 @@ gfc_conv_loop_setup (gfc_loopinfo * loop static tree gfc_array_init_size (tree descriptor, int rank, tree * poffset, gfc_expr ** lower, gfc_expr ** upper, - stmtblock_t * pblock, tree * pstring) + stmtblock_t * pblock) { tree type; tree tmp; tree size; tree offset; tree stride; - tree string_len; gfc_expr *ubound; gfc_se se; int n; @@ -2509,23 +2505,11 @@ gfc_array_init_size (tree descriptor, in stride = gfc_evaluate_now (stride, pblock); } - if (pstring && *pstring) - { - string_len = *pstring; - string_len = fold (build (MULT_EXPR, gfc_array_index_type, stride, - string_len)); - } - else - string_len = NULL_TREE; - /* The stride is the number of elements in the array, so multiply by the size of an element to get the total size. */ tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type)); size = fold (build (MULT_EXPR, gfc_array_index_type, stride, tmp)); - if (string_len) - size = fold (build (PLUS_EXPR, gfc_array_index_type, size, string_len)); - if (poffset != NULL) { offset = gfc_evaluate_now (offset, pblock); @@ -2549,7 +2533,6 @@ gfc_array_allocate (gfc_se * se, gfc_ref tree allocate; tree offset; tree size; - tree len; gfc_expr **lower; gfc_expr **upper; @@ -2578,9 +2561,8 @@ gfc_array_allocate (gfc_se * se, gfc_ref break; } - len = se->string_length; size = gfc_array_init_size (se->expr, ref->u.ar.as->rank, &offset, - lower, upper, &se->pre, &len); + lower, upper, &se->pre); /* Allocate memory to store the data. */ tmp = gfc_conv_descriptor_data (se->expr); @@ -2604,12 +2586,6 @@ gfc_array_allocate (gfc_se * se, gfc_ref tmp = gfc_conv_descriptor_offset (se->expr); gfc_add_modify_expr (&se->pre, tmp, offset); - - /* Initialize the pointers for a character array. */ - if (len) - { - gfc_todo_error ("arrays of strings"); - } } @@ -2845,37 +2821,74 @@ gfc_trans_auto_array_allocation (tree de tree fndecl; tree size; tree offset; + tree args; + bool onstack; assert (!(sym->attr.pointer || sym->attr.allocatable)); - if (sym->ts.type == BT_CHARACTER) - gfc_todo_error ("arrays of strings"); + /* Do nothing for USEd variables. */ + if (sym->attr.use_assoc) + return fnbody; type = TREE_TYPE (decl); assert (GFC_ARRAY_TYPE_P (type)); - if (TREE_CODE (type) != POINTER_TYPE) + onstack = TREE_CODE (type) != POINTER_TYPE; + + /* We never generate initialization code of module variables. */ + if (fnbody == NULL_TREE) { - /* TODO: Put large arrays on the heap. */ - if (sym->value && !sym->attr.use_assoc) + assert (onstack); + + /* Generate static initializer. */ + if (sym->value) { DECL_INITIAL (decl) = gfc_conv_array_initializer (TREE_TYPE (decl), sym->value); } - return fnbody; } - /* Module variables are always static because there's nowhere to put the - initialization code. */ - assert (fnbody != NULL_TREE); - + gfc_start_block (&block); + + /* Evaluate character string length. */ + if (sym->ts.type == BT_CHARACTER + && onstack && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + { + gfc_trans_init_string_length (sym->ts.cl, &block); + + DECL_DEFER_OUTPUT (decl) = 1; + + /* Generate code to allocate the automatic variable. It will be + freed automatically. */ + tmp = gfc_build_addr_expr (NULL, decl); + args = gfc_chainon_list (NULL_TREE, tmp); + args = gfc_chainon_list (args, sym->ts.cl->backend_decl); + tmp = gfc_build_function_call (built_in_decls[BUILT_IN_STACK_ALLOC], + args); + gfc_add_expr_to_block (&block, tmp); + } + + if (onstack) + { + if (sym->value) + { + DECL_INITIAL (decl) = + gfc_conv_array_initializer (TREE_TYPE (decl), sym->value); + } + + gfc_add_expr_to_block (&block, fnbody); + return gfc_finish_block (&block); + } + type = TREE_TYPE (type); assert (!sym->attr.use_assoc); assert (!TREE_STATIC (decl)); assert (!sym->module[0]); - gfc_start_block (&block); + if (sym->ts.type == BT_CHARACTER + && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + gfc_trans_init_string_length (sym->ts.cl, &block); size = gfc_trans_array_bounds (type, sym, &offset, &block); @@ -2898,7 +2911,7 @@ gfc_trans_auto_array_allocation (tree de gfc_add_modify_expr (&block, decl, tmp); /* Set offset of the array. */ - if (!INTEGER_CST_P (GFC_TYPE_ARRAY_OFFSET (type))) + if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset); @@ -2939,13 +2952,23 @@ gfc_trans_g77_array (gfc_symbol * sym, t gfc_start_block (&block); + if (sym->ts.type == BT_CHARACTER + && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + gfc_trans_init_string_length (sym->ts.cl, &block); + /* Evaluate the bounds of the array. */ gfc_trans_array_bounds (type, sym, &offset, &block); /* Set the offset. */ - if (!INTEGER_CST_P (GFC_TYPE_ARRAY_OFFSET (type))) + if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset); + /* Set the pointer itself if we aren't using the parameter dirtectly. */ + if (TREE_CODE (parm) != PARM_DECL) + { + tmp = convert (TREE_TYPE (parm), GFC_DECL_SAVED_DESCRIPTOR (parm)); + gfc_add_modify_expr (&block, parm, tmp); + } tmp = gfc_finish_block (&block); gfc_set_backend_locus (&loc); @@ -2995,7 +3018,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * int checkparm; int no_repack; - if (sym->attr.dummy && TREE_CODE (tmpdesc) == PARM_DECL) + if (sym->attr.dummy && gfc_is_nodesc_array (sym)) return gfc_trans_g77_array (sym, body); gfc_get_backend_locus (&loc); @@ -3008,6 +3031,10 @@ gfc_trans_dummy_array_bias (gfc_symbol * dumdesc = gfc_build_indirect_ref (dumdesc); gfc_start_block (&block); + if (sym->ts.type == BT_CHARACTER + && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + gfc_trans_init_string_length (sym->ts.cl, &block); + checkparm = (sym->as->type == AS_EXPLICIT && flag_bounds_check); no_repack = !(GFC_DECL_PACKED_ARRAY (tmpdesc) @@ -3184,7 +3211,8 @@ gfc_trans_dummy_array_bias (gfc_symbol * } /* Set the offset. */ - gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset); + if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset); stmt = gfc_finish_block (&block); @@ -3265,9 +3293,6 @@ gfc_conv_expr_descriptor (gfc_se * se, g assert (ss != gfc_ss_terminator); - if (expr->ts.type == BT_CHARACTER) - gfc_todo_error ("Character string array actual parameters"); - /* TODO: Pass constant array constructors without a temporary. */ /* If we have a linear array section, we can pass it directly. Otherwise we need to copy it into a temporary. */ @@ -3367,8 +3392,6 @@ gfc_conv_expr_descriptor (gfc_se * se, g if (need_tmp) { /* Tell the scalarizer to make a temporary. */ - if (expr->ts.type == BT_CHARACTER) - gfc_todo_error ("Passing character string expressions"); loop.temp_ss = gfc_get_ss (); loop.temp_ss->type = GFC_SS_TEMP; loop.temp_ss->next = gfc_ss_terminator; @@ -3689,13 +3712,9 @@ gfc_trans_deferred_array (gfc_symbol * s gfc_init_block (&fnblock); assert (TREE_CODE (sym->backend_decl) == VAR_DECL); - if (GFC_DECL_STRING (sym->backend_decl)) - { - tmp = GFC_DECL_STRING_LENGTH (sym->backend_decl); - if (!INTEGER_CST_P (tmp)) - gfc_conv_init_string_length (sym, &fnblock); - } - + if (sym->ts.type == BT_CHARACTER + && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + gfc_trans_init_string_length (sym->ts.cl, &fnblock); /* Parameter variables don't need anything special. */ if (sym->attr.dummy) Index: trans-common.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-common.c,v retrieving revision 1.1.2.4 diff -u -p -r1.1.2.4 trans-common.c --- a/trans-common.c 5 Dec 2003 10:29:26 -0000 1.1.2.4 +++ b/trans-common.c 4 Apr 2004 22:58:52 -0000 @@ -95,6 +95,7 @@ Boston, MA 02111-1307, USA. */ #include "gfortran.h" #include "trans.h" #include "trans-types.h" +#include "trans-const.h" typedef struct segment_info @@ -312,8 +313,6 @@ create_common (gfc_symbol *sym) { h->sym->backend_decl = build (COMPONENT_REF, TREE_TYPE (h->field), decl, h->field); - if (h->sym->ts.type == BT_CHARACTER) - gfc_todo_error ("CHARACTER inside COMMON block or EQUIVALENCE list"); next_s = h->next; gfc_free (h); @@ -345,6 +344,8 @@ calculate_length (gfc_symbol *symbol) int j, element_size; mpz_t elements; + if (symbol->ts.type == BT_CHARACTER) + gfc_conv_const_charlen (symbol->ts.cl); element_size = int_size_in_bytes (gfc_typenode_for_spec (&symbol->ts)); if (symbol->as == NULL) return element_size; @@ -448,6 +449,8 @@ calculate_offset (gfc_expr *s) case AR_ELEMENT: a = element_number (&reference->u.ar); + if (element_type->type == BT_CHARACTER) + gfc_conv_const_charlen (element_type->cl); element_size = int_size_in_bytes (gfc_typenode_for_spec (element_type)); offset += a * element_size; Index: trans-const.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-const.c,v retrieving revision 1.1.2.5 diff -u -p -r1.1.2.5 trans-const.c --- a/trans-const.c 4 Apr 2004 11:50:00 -0000 1.1.2.5 +++ b/trans-const.c 4 Apr 2004 17:52:22 -0000 @@ -121,6 +121,22 @@ gfc_conv_string_init (tree length, gfc_e return str; } + +/* Create a tree node for the string length if it is constant. */ + +void +gfc_conv_const_charlen (gfc_charlen * cl) +{ + if (cl->backend_decl) + return; + + if (cl->length && cl->length->expr_type == EXPR_CONSTANT) + { + cl->backend_decl = gfc_conv_mpz_to_tree (cl->length->value.integer, + cl->length->ts.kind); + } +} + void gfc_init_constants (void) { Index: trans-const.h =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-const.h,v retrieving revision 1.1.2.3 diff -u -p -r1.1.2.3 trans-const.h --- a/trans-const.h 4 Apr 2004 11:50:00 -0000 1.1.2.3 +++ b/trans-const.h 4 Apr 2004 17:35:40 -0000 @@ -39,6 +39,9 @@ tree gfc_build_string_const (int, const /* Translate a string constant for a static initializer. */ tree gfc_conv_string_init (tree, gfc_expr *); +/* Create a tree node for the string length if it is constant. */ +void gfc_conv_const_charlen (gfc_charlen *); + /* Initialise the nodes for constants. */ void gfc_init_constants (void); Index: trans-decl.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-decl.c,v retrieving revision 1.1.2.34 diff -u -p -r1.1.2.34 trans-decl.c --- a/trans-decl.c 4 Apr 2004 11:50:00 -0000 1.1.2.34 +++ b/trans-decl.c 4 Apr 2004 22:19:38 -0000 @@ -420,6 +420,7 @@ gfc_finish_var_decl (tree decl, gfc_symb /* Keep variables larger than max-stack-var-size off stack. */ if (!sym->ns->proc_name->attr.recursive + && INTEGER_CST_P (DECL_SIZE_UNIT (decl)) && !gfc_can_put_var_on_stack (DECL_SIZE_UNIT (decl))) TREE_STATIC (decl) = 1; } @@ -532,7 +533,9 @@ gfc_build_qualified_array (tree decl, gf } -/* Get a temporary decl for a dummy array parameter. */ +/* For some dummy arguments we don't use the actual argument directly. + Instead we create a local decl and use that. This allows us to preform + initialization, and construct full type information. */ static tree gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) @@ -543,6 +546,7 @@ gfc_build_dummy_array_decl (gfc_symbol * char *name; int packed; int n; + bool known_size; if (sym->attr.pointer || sym->attr.allocatable) return dummy; @@ -553,45 +557,63 @@ gfc_build_dummy_array_decl (gfc_symbol * type = TREE_TYPE (dummy); assert (TREE_CODE (dummy) == PARM_DECL - && POINTER_TYPE_P (type)); + && POINTER_TYPE_P (type)); - if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type))) + /* Do we know the element size. */ + known_size = sym->ts.type != BT_CHARACTER + || INTEGER_CST_P (sym->ts.cl->backend_decl); + + if (known_size && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type))) { + /* For descriptorless arrays with known element size the actual + argument is sufficient. */ assert (GFC_ARRAY_TYPE_P (type)); gfc_build_qualified_array (dummy, sym); return dummy; } type = TREE_TYPE (type); - - as = sym->as; - packed = 0; - if (!gfc_option.flag_repack_arrays) + if (GFC_DESCRIPTOR_TYPE_P (type)) { - if (as->type == AS_ASSUMED_SIZE) - packed = 2; + /* Create a decriptorless array pointer. */ + as = sym->as; + packed = 0; + if (!gfc_option.flag_repack_arrays) + { + if (as->type == AS_ASSUMED_SIZE) + packed = 2; + } + else + { + if (as->type == AS_EXPLICIT) + { + packed = 2; + for (n = 0; n < as->rank; n++) + { + if (!(as->upper[n] + && as->lower[n] + && as->upper[n]->expr_type == EXPR_CONSTANT + && as->lower[n]->expr_type == EXPR_CONSTANT)) + packed = 1; + } + } + else + packed = 1; + } + + type = gfc_typenode_for_spec (&sym->ts); + type = gfc_get_nodesc_array_type (type, sym->as, packed); } else { - if (as->type == AS_EXPLICIT) - { - packed = 2; - for (n = 0; n < as->rank; n++) - { - if (!(as->upper[n] - && as->lower[n] - && as->upper[n]->expr_type == EXPR_CONSTANT - && as->lower[n]->expr_type == EXPR_CONSTANT)) - packed = 1; - } - } - else - packed = 1; + /* We now have an expression for the element size, so create a fully + qualified type. Reset sym->backend decl or this will just return the + old type. */ + sym->backend_decl = NULL_TREE; + type = gfc_sym_type (sym); + packed = 2; } - type = gfc_get_nodesc_array_type (gfc_get_element_type (type), sym->as, - packed); - ASM_FORMAT_PRIVATE_NAME (name, IDENTIFIER_POINTER (DECL_NAME (dummy)), 0); decl = build_decl (VAR_DECL, get_identifier (name), type); @@ -600,8 +622,9 @@ gfc_build_dummy_array_decl (gfc_symbol * TREE_STATIC (decl) = 0; DECL_EXTERNAL (decl) = 0; - if (sym->as->type == AS_DEFERRED) - internal_error ("possible gfortran frontend bug: deferred shape dummy array"); + /* We should never get deferred shape arrays here. We used to because of + frontend bugs. */ + assert (sym->as->type != AS_DEFERRED); switch (packed) { @@ -634,6 +657,36 @@ gfc_build_dummy_array_decl (gfc_symbol * } +/* Return a constant or a variable to use as a string length. Does not + add the decl to the current scope. */ + +static tree +gfc_create_string_length (gfc_symbol * sym) +{ + tree length; + + assert (sym->ts.cl); + gfc_conv_const_charlen (sym->ts.cl); + + if (sym->ts.cl->backend_decl == NULL_TREE) + { + char name[GFC_MAX_MANGLED_SYMBOL_LEN + 2]; + + /* Also prefix the mangled name. */ + strcpy (&name[1], sym->name); + name[0] = '.'; + length = build_decl (VAR_DECL, get_identifier (name), + gfc_strlen_type_node); + DECL_ARTIFICIAL (length) = 1; + TREE_USED (length) = 1; + gfc_defer_symbol_init (sym); + sym->ts.cl->backend_decl = length; + } + + return sym->ts.cl->backend_decl; +} + + /* Return the decl for a gfc_symbol, create it if it doesn't already exist. */ @@ -641,7 +694,7 @@ tree gfc_get_symbol_decl (gfc_symbol * sym) { tree decl; - tree length; + tree length = NULL_TREE; gfc_se se; int byref; @@ -665,12 +718,27 @@ gfc_get_symbol_decl (gfc_symbol * sym) /* Dummy variables should already have been created. */ assert (sym->backend_decl); + /* Create a character length variable. */ + if (sym->ts.type == BT_CHARACTER) + { + if (sym->ts.cl->backend_decl == NULL_TREE) + { + length = gfc_create_string_length (sym); + if (TREE_CODE (length) != INTEGER_CST) + { + gfc_finish_var_decl (length, sym); + gfc_defer_symbol_init (sym); + } + } + } + /* Use a copy of the descriptor for dummy arrays. */ if (sym->attr.dimension && !TREE_USED (sym->backend_decl)) { sym->backend_decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); } + TREE_USED (sym->backend_decl) = 1; return sym->backend_decl; } @@ -691,6 +759,12 @@ gfc_get_symbol_decl (gfc_symbol * sym) if (sym->attr.intrinsic) internal_error ("intrinsic variable which isn't a procedure"); + /* Create string length decl first so that they can be used in the + type declaration. */ + if (sym->ts.type == BT_CHARACTER) + length = gfc_create_string_length (sym); + + /* Create the decl for the variable. */ decl = build_decl (VAR_DECL, gfc_sym_identifier (sym), gfc_sym_type (sym)); /* Symbols from modules have its assembler name should be mangled. @@ -717,16 +791,16 @@ gfc_get_symbol_decl (gfc_symbol * sym) { gfc_allocate_lang_decl (decl); GFC_DECL_ASSIGN (decl) = 1; - GFC_DECL_STRING_LENGTH (decl) = - gfc_create_var (gfc_strlen_type_node, sym->name); + length = gfc_create_var (gfc_strlen_type_node, sym->name); + GFC_DECL_STRING_LEN (decl) = length; GFC_DECL_ASSIGN_ADDR (decl) = gfc_create_var (pvoid_type_node, sym->name); - TREE_STATIC (GFC_DECL_STRING_LENGTH (decl)) = 1; + /* TODO: Need to check we don't change TREE_STATIC (decl) later. */ + TREE_STATIC (length) = TREE_STATIC (decl); /* STRING_LENGTH is also used as flag. Less than -1 means that ASSIGN_ADDR can not be used. Equal -1 means that ASSIGN_ADDR is the target label's address. Other value is the length of format string and ASSIGN_ADDR is the address of format string. */ - DECL_INITIAL (GFC_DECL_STRING_LENGTH (decl)) = - build_int_2 (-2, -1); + DECL_INITIAL (length) = build_int_2 (-2, -1); } /* TODO: Initialization of pointer variables. */ @@ -734,22 +808,19 @@ gfc_get_symbol_decl (gfc_symbol * sym) { case BT_CHARACTER: /* Character variables need special handling. */ - /* Character lengths are common for a whole array. */ gfc_allocate_lang_decl (decl); GFC_DECL_STRING (decl) = 1; - if (sym->ts.cl->length->expr_type == EXPR_CONSTANT) + if (TREE_CODE (length) == INTEGER_CST) { - length = - gfc_conv_mpz_to_tree (sym->ts.cl->length->value.integer, 4); - - /* Static initializer. */ - if (sym->value) + /* Static initializer for string scalars. + Initialization of string arrays is handled elsewhere. */ + if (sym->value && sym->attr.dimension == 0) { assert (TREE_STATIC (decl)); if (sym->attr.pointer) - gfc_todo_error ("initialization of pointers"); + gfc_todo_error ("initialization of character pointers"); DECL_INITIAL (decl) = gfc_conv_string_init (length, sym->value); } } @@ -757,28 +828,18 @@ gfc_get_symbol_decl (gfc_symbol * sym) { char name[GFC_MAX_MANGLED_SYMBOL_LEN + 2]; - /* Create annother variable to hold the length. Prefix the name - to avoid conflicts. */ - strcpy (&name[1], sym->name); - name[0] = '.'; - length = build_decl (VAR_DECL, get_identifier (name), - gfc_strlen_type_node); - - DECL_ARTIFICIAL (decl) = 1; - /* Also prefix the mangled name for symbols from modules. */ if (sym->module[0]) { + /* Also prefix the mangled name for symbols from modules. */ + strcpy (&name[1], sym->name); + name[0] = '.'; strcpy (&name[1], IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (length))); SET_DECL_ASSEMBLER_NAME (decl, get_identifier (name)); } gfc_finish_var_decl (length, sym); - /* Remember this variable for allocation/cleanup. */ - gfc_defer_symbol_init (sym); assert (!sym->value); } - - GFC_DECL_STRING_LENGTH (decl) = length; break; case BT_DERIVED: @@ -922,7 +983,7 @@ gfc_build_function_decl (gfc_symbol * sy assert (!sym->backend_decl); assert (!sym->attr.external); - /* Allow only one nesting level. Allow external declarations. */ + /* Allow only one nesting level. Allow public declarations. */ assert (current_function_decl == NULL_TREE || DECL_CONTEXT (current_function_decl) == NULL_TREE); @@ -939,6 +1000,7 @@ gfc_build_function_decl (gfc_symbol * sy attr = sym->attr; result_decl = NULL_TREE; + /* TODO: Shouldn't this just be TREE_TYPE (TREE_TYPE (fndecl)). */ if (attr.function) { if (gfc_return_by_reference (sym)) @@ -953,7 +1015,7 @@ gfc_build_function_decl (gfc_symbol * sy } else { - /* Look for an alternate return placeholders. */ + /* Look for alternate return placeholders. */ int has_alternate_returns = 0; for (f = sym->formal; f; f = f->next) { @@ -1039,27 +1101,22 @@ gfc_build_function_decl (gfc_symbol * sy /* Length of character result */ type = TREE_VALUE (typelist); assert (type == gfc_strlen_type_node); + length = build_decl (PARM_DECL, get_identifier (".__result"), type); + if (!sym->ts.cl->length) + { + sym->ts.cl->backend_decl = length; + TREE_USED (length) = 1; + } + assert (TREE_CODE (length) == PARM_DECL); arglist = chainon (arglist, length); typelist = TREE_CHAIN (typelist); DECL_CONTEXT (length) = fndecl; DECL_ARG_TYPE (length) = type; TREE_READONLY (length) = 1; gfc_finish_decl (length, NULL_TREE); - - if (sym->ts.cl - && sym->ts.cl->length - && sym->ts.cl->length->expr_type == EXPR_CONSTANT) - { - length = gfc_conv_mpz_to_tree - (sym->ts.cl->length->value.integer, 4); - } - else - TREE_USED (length) = 1; - - GFC_DECL_STRING_LENGTH (parm) = length; } } @@ -1108,7 +1165,7 @@ gfc_build_function_decl (gfc_symbol * sy assert (type == gfc_strlen_type_node); strcpy (&name[1], f->sym->name); - name[0] = '.'; + name[0] = '_'; length = build_decl (PARM_DECL, get_identifier (name), type); arglist = chainon (arglist, length); @@ -1117,18 +1174,15 @@ gfc_build_function_decl (gfc_symbol * sy TREE_READONLY (length) = 1; gfc_finish_decl (length, NULL_TREE); - gfc_allocate_lang_decl (parm); GFC_DECL_STRING (parm) = 1; - if (f->sym->ts.cl - && f->sym->ts.cl->length - && f->sym->ts.cl->length->expr_type == EXPR_CONSTANT) - { - length = gfc_conv_mpz_to_tree ( - f->sym->ts.cl->length->value.integer, 4); - } - else - TREE_USED (length) = 1; - GFC_DECL_STRING_LENGTH (parm) = length; + /* TODO: Check string lengths when -fbounds-check. */ + + /* Use the passed value for assumed length variables. */ + if (!f->sym->ts.cl->length) + { + TREE_USED (length) = 1; + f->sym->ts.cl->backend_decl = length; + } parm = TREE_CHAIN (parm); typelist = TREE_CHAIN (typelist); @@ -1150,6 +1204,8 @@ tree gfc_get_fake_result_decl (gfc_symbol * sym) { tree decl; + tree length; + char name[GFC_MAX_SYMBOL_LEN + 10]; if (current_fake_result_decl != NULL_TREE) @@ -1160,6 +1216,13 @@ gfc_get_fake_result_decl (gfc_symbol * s if (!sym) return NULL_TREE; + if (sym->ts.type == BT_CHARACTER + && !sym->ts.cl->backend_decl) + { + length = gfc_create_string_length (sym); + gfc_finish_var_decl (length, sym); + } + if (gfc_return_by_reference (sym)) { decl = DECL_ARGUMENTS (sym->backend_decl); @@ -1487,44 +1550,55 @@ gfc_build_builtin_function_decls (void) } +/* Exaluate the length of dummy character variables. */ + +static tree +gfc_trans_dummy_character (gfc_charlen * cl, tree fnbody) +{ + stmtblock_t body; + + gfc_finish_decl (cl->backend_decl, NULL_TREE); + + gfc_start_block (&body); + + /* Evaluate the string length expression. */ + gfc_trans_init_string_length (cl, &body); + + gfc_add_expr_to_block (&body, fnbody); + return gfc_finish_block (&body); +} + + /* Allocate and cleanup an automatic character variable. */ static tree gfc_trans_auto_character_variable (gfc_symbol * sym, tree fnbody) { - tree tmp; - tree args; - tree len; - stmtblock_t block; stmtblock_t body; + tree decl; + tree args; + tree tmp; + assert (sym->backend_decl); assert (sym->ts.cl && sym->ts.cl->length); - assert (sym->backend_decl != NULL_TREE); gfc_start_block (&body); - gfc_start_block (&block); - len = gfc_conv_init_string_length (sym, &block); - args = gfc_chainon_list (NULL_TREE, len); - tmp = gfc_build_function_call (gfor_fndecl_internal_malloc, args); - tmp = convert (TREE_TYPE (sym->backend_decl), tmp); - gfc_add_modify_expr (&block, sym->backend_decl, tmp); + /* Evaluate the string length expression. */ + gfc_trans_init_string_length (sym->ts.cl, &body); - tmp = gfc_finish_block (&block); - gfc_add_expr_to_block (&body, tmp); + decl = sym->backend_decl; - gfc_add_expr_to_block (&body, fnbody); - - gfc_start_block (&block); + DECL_DEFER_OUTPUT (decl) = 1; - tmp = convert (pvoid_type_node, sym->backend_decl); + /* Generate code to allocate the automatic variable. It will be freed + automatically. */ + tmp = gfc_build_addr_expr (NULL, decl); args = gfc_chainon_list (NULL_TREE, tmp); - tmp = gfc_build_function_call (gfor_fndecl_internal_free, args); - gfc_add_expr_to_block (&block, tmp); - - tmp = gfc_finish_block (&block); + args = gfc_chainon_list (args, sym->ts.cl->backend_decl); + tmp = gfc_build_function_call (built_in_decls[BUILT_IN_STACK_ALLOC], args); gfc_add_expr_to_block (&body, tmp); - + gfc_add_expr_to_block (&body, fnbody); return gfc_finish_block (&body); } @@ -1557,14 +1631,17 @@ gfc_trans_deferred_vars (gfc_symbol * pr current_fake_result_decl, fnbody); } - else if (proc_sym->ts.type != BT_CHARACTER) + else if (proc_sym->ts.type == BT_CHARACTER) + { + if (TREE_CODE (proc_sym->ts.cl->backend_decl) == VAR_DECL) + fnbody = gfc_trans_dummy_character (proc_sym->ts.cl, fnbody); + } + else gfc_todo_error ("Deferred non-array return by reference"); } for (sym = proc_sym->tlink; sym != proc_sym; sym = sym->tlink) { - /* For now this is only array variables, but may get extended to - derived types. */ if (sym->attr.dimension) { switch (sym->as->type) @@ -1619,7 +1696,10 @@ gfc_trans_deferred_vars (gfc_symbol * pr { gfc_get_backend_locus (&loc); gfc_set_backend_locus (&sym->declared_at); - fnbody = gfc_trans_auto_character_variable (sym, fnbody); + if (sym->attr.dummy || sym->attr.result) + fnbody = gfc_trans_dummy_character (sym->ts.cl, fnbody); + else + fnbody = gfc_trans_auto_character_variable (sym, fnbody); gfc_set_backend_locus (&loc); } else @@ -1703,7 +1783,7 @@ gfc_create_module_variable (gfc_symbol * { tree length; - length = GFC_DECL_STRING_LENGTH (decl); + length = sym->ts.cl->backend_decl; if (!INTEGER_CST_P (length)) { pushdecl (length); @@ -1820,10 +1900,17 @@ gfc_generate_function_code (gfc_namespac tree result; gfc_symbol *sym; + sym = ns->proc_name; + /* Check that the frontend isn't still using this. */ + assert (sym->tlink == NULL); + + sym->tlink = sym; + /* Create the declaration for functions with global scope. */ - if (!ns->proc_name->backend_decl) + if (!sym->backend_decl) gfc_build_function_decl (ns->proc_name); + fndecl = sym->backend_decl; old_context = current_function_decl; if (old_context) @@ -1833,10 +1920,6 @@ gfc_generate_function_code (gfc_namespac saved_function_decls = NULL_TREE; } - sym = ns->proc_name; - - fndecl = sym->backend_decl; - /* let GCC know the current scope is this function */ current_function_decl = fndecl; @@ -1876,10 +1959,6 @@ gfc_generate_function_code (gfc_namespac /* function.c requires a push at the start of the function */ pushlevel (0); - /* Check that the frontend isn't still using this. */ - assert (sym->tlink == NULL); - sym->tlink = sym; - gfc_start_block (&block); gfc_generate_contained_functions (ns); Index: trans-expr.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-expr.c,v retrieving revision 1.1.2.20 diff -u -p -r1.1.2.20 trans-expr.c --- a/trans-expr.c 4 Apr 2004 15:33:41 -0000 1.1.2.20 +++ b/trans-expr.c 4 Apr 2004 23:03:42 -0000 @@ -142,20 +142,18 @@ gfc_conv_expr_present (gfc_symbol * sym) /* Generate code to initialize a string length variable. Returns the value. */ -tree -gfc_conv_init_string_length (gfc_symbol * sym, stmtblock_t * pblock) +void +gfc_trans_init_string_length (gfc_charlen * cl, stmtblock_t * pblock) { gfc_se se; tree tmp; gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->ts.cl->length, gfc_strlen_type_node); + gfc_conv_expr_type (&se, cl->length, gfc_strlen_type_node); gfc_add_block_to_block (pblock, &se.pre); - tmp = GFC_DECL_STRING_LENGTH (sym->backend_decl); + tmp = cl->backend_decl; gfc_add_modify_expr (pblock, tmp, se.expr); - - return se.expr; } static void @@ -229,7 +227,7 @@ gfc_conv_component_ref (gfc_se * se, gfc if (c->ts.type == BT_CHARACTER) { - tmp = GFC_DECL_STRING_LENGTH (field); + tmp = c->ts.cl->backend_decl; assert (tmp); if (!INTEGER_CST_P (tmp)) gfc_todo_error ("Unknown length character component"); @@ -306,8 +304,8 @@ gfc_conv_variable (gfc_se * se, gfc_expr /* For character variables, also get the length. */ if (sym->ts.type == BT_CHARACTER) { - assert (GFC_DECL_STRING (se->expr)); - se->string_length = GFC_DECL_STRING_LENGTH (se->expr); + assert (sym->attr.in_common || GFC_DECL_STRING (se->expr)); + se->string_length = sym->ts.cl->backend_decl; assert (se->string_length); } @@ -691,11 +689,8 @@ gfc_conv_concat_op (gfc_se * se, gfc_exp gfc_add_block_to_block (&se->pre, &rse.pre); type = gfc_get_character_type (expr->ts.kind, expr->ts.cl); - if (GFC_KNOWN_SIZE_STRING_TYPE (type)) - { - len = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); - } - else + len = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + if (len == NULL_TREE) { len = fold (build (PLUS_EXPR, TREE_TYPE (lse.string_length), lse.string_length, rse.string_length)); @@ -1000,9 +995,12 @@ gfc_conv_function_call (gfc_se * se, gfc } else if (sym->ts.type == BT_CHARACTER) { + assert (sym->ts.cl && sym->ts.cl->length + && sym->ts.cl->length->expr_type == EXPR_CONSTANT); + len = gfc_conv_mpz_to_tree + (sym->ts.cl->length->value.integer, sym->ts.cl->length->ts.kind); + sym->ts.cl->backend_decl = len; type = gfc_get_character_type (sym->ts.kind, sym->ts.cl); - assert (GFC_KNOWN_SIZE_STRING_TYPE (type)); - len = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); type = build_pointer_type (type); var = gfc_conv_string_tmp (se, type, len); @@ -1549,23 +1547,8 @@ gfc_trans_pointer_assignment (gfc_expr * } -/* Get the decl for the length of a string from an expression. */ - -tree -gfc_conv_string_length (tree expr) -{ - /* TODO: string lengths of components. */ - while (TREE_CODE (expr) == INDIRECT_REF) - expr = TREE_OPERAND (expr, 0); - - if (!(DECL_P (expr) && GFC_DECL_STRING (expr))) - return NULL_TREE; - - return GFC_DECL_STRING_LENGTH (expr); -} - - /* Makes sure se is suitable for passing as a function string parameter. */ +/* TODO: Need to check all callers fo this function. It may be abused. */ void gfc_conv_string_parameter (gfc_se * se) @@ -1581,9 +1564,7 @@ gfc_conv_string_parameter (gfc_se * se) type = TREE_TYPE (se->expr); if (TYPE_STRING_FLAG (type)) { - assert (TREE_CODE (se->expr) == VAR_DECL - || TREE_CODE (se->expr) == COMPONENT_REF - || TREE_CODE (se->expr) == PARM_DECL); + assert (TREE_CODE (se->expr) != INDIRECT_REF); se->expr = gfc_build_addr_expr (pchar_type_node, se->expr); } Index: trans-intrinsic.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-intrinsic.c,v retrieving revision 1.1.2.26 diff -u -p -r1.1.2.26 trans-intrinsic.c --- a/trans-intrinsic.c 10 Jan 2004 21:09:18 -0000 1.1.2.26 +++ b/trans-intrinsic.c 4 Apr 2004 15:39:12 -0000 @@ -1878,7 +1878,7 @@ gfc_conv_intrinsic_len (gfc_se * se, gfc decl = gfc_get_fake_result_decl (sym); assert (GFC_DECL_STRING (decl)); - len = GFC_DECL_STRING_LENGTH (decl); + len = sym->ts.cl->backend_decl; assert (len); } else Index: trans-io.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-io.c,v retrieving revision 1.1.2.8 diff -u -p -r1.1.2.8 trans-io.c --- a/trans-io.c 24 Mar 2004 10:52:54 -0000 1.1.2.8 +++ b/trans-io.c 4 Apr 2004 15:39:12 -0000 @@ -394,11 +394,11 @@ set_string (stmtblock_t * block, stmtblo { msg = gfc_build_string_const (37, "Assigned label is not a format label"); - tmp = GFC_DECL_STRING_LENGTH (se.expr); + tmp = GFC_DECL_STRING_LEN (se.expr); tmp = build (LE_EXPR, boolean_type_node, tmp, integer_minus_one_node); gfc_trans_runtime_check (tmp, msg, &se.pre); gfc_add_modify_expr (&se.pre, io, GFC_DECL_ASSIGN_ADDR (se.expr)); - gfc_add_modify_expr (&se.pre, len, GFC_DECL_STRING_LENGTH (se.expr)); + gfc_add_modify_expr (&se.pre, len, GFC_DECL_STRING_LEN (se.expr)); } else { Index: trans-stmt.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-stmt.c,v retrieving revision 1.1.2.15 diff -u -p -r1.1.2.15 trans-stmt.c --- a/trans-stmt.c 11 Jan 2004 23:28:53 -0000 1.1.2.15 +++ b/trans-stmt.c 4 Apr 2004 15:39:12 -0000 @@ -99,7 +99,7 @@ gfc_trans_label_assign (gfc_code * code) gfc_init_se (&se, NULL); gfc_start_block (&se.pre); gfc_conv_expr (&se, code->expr); - len = GFC_DECL_STRING_LENGTH (se.expr); + len = GFC_DECL_STRING_LEN (se.expr); addr = GFC_DECL_ASSIGN_ADDR (se.expr); label_tree = gfc_get_label_decl (code->label); @@ -146,7 +146,7 @@ gfc_trans_goto (gfc_code * code) gfc_conv_expr (&se, code->expr); assign_error = gfc_build_string_const (37, "Assigned label is not a target label"); - tmp = GFC_DECL_STRING_LENGTH (se.expr); + tmp = GFC_DECL_STRING_LEN (se.expr); tmp = build (NE_EXPR, boolean_type_node, tmp, integer_minus_one_node); gfc_trans_runtime_check (tmp, assign_error, &se.pre); Index: trans-types.c =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-types.c,v retrieving revision 1.1.2.13 diff -u -p -r1.1.2.13 trans-types.c --- a/trans-types.c 4 Apr 2004 15:33:41 -0000 1.1.2.13 +++ b/trans-types.c 4 Apr 2004 22:36:56 -0000 @@ -282,19 +282,11 @@ gfc_get_character_type (int kind, gfc_ch fatal_error ("character kind=%d not available", kind); } - if (cl && cl->length && cl->length->expr_type == EXPR_CONSTANT) - { - len = gfc_conv_mpz_to_tree (cl->length->value.integer, - cl->length->ts.kind); - } - else - len = NULL_TREE; + len = (cl == 0) ? NULL_TREE : cl->backend_decl; bounds = build_range_type (gfc_array_index_type, integer_one_node, len); type = build_array_type (base, bounds); TYPE_STRING_FLAG (type) = 1; - if (len != NULL_TREE) - GFC_KNOWN_SIZE_STRING_TYPE (type) = 1; return type; } @@ -454,7 +446,7 @@ gfc_get_element_type (tree type) /* Returns true if the array sym does not require a descriptor. */ -static int +int gfc_is_nodesc_array (gfc_symbol * sym) { assert (sym->attr.dimension); @@ -545,12 +537,13 @@ gfc_get_desc_dim_type (void) } static tree -gfc_get_dtype_cst (tree type, int rank) +gfc_get_dtype (tree type, int rank) { tree size; int n; - unsigned HOST_WIDE_INT lo; - unsigned HOST_WIDE_INT hi; + HOST_WIDE_INT i; + tree tmp; + tree dtype; if (GFC_DESCRIPTOR_TYPE_P (type) || GFC_ARRAY_TYPE_P (type)) return (GFC_TYPE_ARRAY_DTYPE (type)); @@ -574,32 +567,46 @@ gfc_get_dtype_cst (tree type, int rank) n = GFC_DTYPE_COMPLEX; break; - /* Arrays have already been dealt with. */ + /* Arrays have already been dealt with. */ case RECORD_TYPE: n = GFC_DTYPE_DERIVED; break; -/* Arrays of strings are currently broken. */ -#if 0 + case ARRAY_TYPE: n = GFC_DTYPE_CHARACTER; break; -#endif + default: abort (); } assert (rank <= GFC_DTYPE_RANK_MASK); size = TYPE_SIZE_UNIT (type); - assert (INTEGER_CST_P (size)); - if (tree_int_cst_lt (gfc_max_array_element_size, size)) - internal_error ("Array element size too big"); - - lo = TREE_INT_CST_LOW (size) << GFC_DTYPE_SIZE_SHIFT; - hi = TREE_INT_CST_HIGH (size) << GFC_DTYPE_SIZE_SHIFT - | (lo >> (sizeof (HOST_WIDE_INT) * 8 - GFC_DTYPE_SIZE_SHIFT)); - lo |= rank | (n << GFC_DTYPE_TYPE_SHIFT); + + i = rank | (n << GFC_DTYPE_TYPE_SHIFT); + if (size && INTEGER_CST_P (size)) + { + if (tree_int_cst_lt (gfc_max_array_element_size, size)) + internal_error ("Array element size too big"); + + i += TREE_INT_CST_LOW (size) << GFC_DTYPE_SIZE_SHIFT; + } + dtype = build_int_2 (i, 0); + TREE_TYPE (dtype) = gfc_array_index_type; - return build_int_2 (lo, hi); + if (size && !INTEGER_CST_P (size)) + { + tmp = build_int_2 (GFC_DTYPE_SIZE_SHIFT, 0); + TREE_TYPE (tmp) = gfc_array_index_type; + tmp = fold (build (LSHIFT_EXPR, gfc_array_index_type, size, tmp)); + dtype = fold (build (PLUS_EXPR, gfc_array_index_type, tmp, dtype)); + } + /* If we don't know the size we leave it as zero. This should never happen + for anything that is actually used. */ + /* TODO: Check this is actually true, particularly when repacking + assumed size parameters. */ + + return dtype; } @@ -709,7 +716,7 @@ gfc_get_nodesc_array_type (tree etype, g else GFC_TYPE_ARRAY_SIZE (type) = NULL_TREE; - GFC_TYPE_ARRAY_DTYPE (type) = gfc_get_dtype_cst (etype, as->rank); + GFC_TYPE_ARRAY_DTYPE (type) = gfc_get_dtype (etype, as->rank); GFC_TYPE_ARRAY_RANK (type) = as->rank; range = build_range_type (gfc_array_index_type, integer_zero_node, NULL_TREE); @@ -771,7 +778,7 @@ gfc_get_array_type_bounds (tree etype, i TYPE_LANG_SPECIFIC (fat_type) = (struct lang_type *) ggc_alloc_cleared (sizeof (struct lang_type)); GFC_TYPE_ARRAY_RANK (fat_type) = dimen; - GFC_TYPE_ARRAY_DTYPE (fat_type) = gfc_get_dtype_cst (etype, dimen); + GFC_TYPE_ARRAY_DTYPE (fat_type) = gfc_get_dtype (etype, dimen); tmp = TYPE_NAME (etype); if (tmp && TREE_CODE (tmp) == TYPE_DECL) @@ -905,7 +912,6 @@ tree gfc_sym_type (gfc_symbol * sym) { tree type; - tree base_type; int byref; if (sym->attr.flavor == FL_PROCEDURE && !sym->attr.function) @@ -924,46 +930,36 @@ gfc_sym_type (gfc_symbol * sym) if (sym->attr.function && sym->result) sym = sym->result; - base_type = type = gfc_typenode_for_spec (&sym->ts); + type = gfc_typenode_for_spec (&sym->ts); if (sym->attr.dummy && !sym->attr.function) byref = 1; else byref = 0; - if (sym->ts.type == BT_CHARACTER) - { - if (sym->attr.dimension - || sym->attr.pointer || sym->attr.allocatable - || sym->attr.function || sym->attr.result) - type = build_pointer_type (type); - } - if (sym->attr.dimension) { - /* The string code is currently very broken. I need to figure out a way - of doing it that works with descriptorless arrays. */ - if (sym->ts.type == BT_CHARACTER) - gfc_todo_error ("arrays of strings"); - if (gfc_is_nodesc_array (sym)) { - type = gfc_get_nodesc_array_type (type, sym->as, - byref ? 2 : 3); - byref = 0; + /* If this is a character argument of unknown length, just use the + base type. */ + if (sym->ts.type != BT_CHARACTER + || !(sym->attr.dummy || sym->attr.function || sym->attr.result) + || sym->ts.cl->backend_decl) + { + type = gfc_get_nodesc_array_type (type, sym->as, + byref ? 2 : 3); + byref = 0; + } } else type = gfc_build_array_type (type, sym->as); } - else if (sym->ts.type != BT_CHARACTER) + else { if (sym->attr.allocatable || sym->attr.pointer) type = gfc_build_pointer_type (sym, type); } - else if (!(GFC_KNOWN_SIZE_STRING_TYPE (base_type) || sym->attr.dummy)) - { - type = build_pointer_type (type); - } /* We currently pass all parameters by reference. See f95_get_function_decl. For dummy function parameters return the @@ -1016,7 +1012,6 @@ static tree gfc_get_derived_type (gfc_symbol * derived) { tree typenode, field, field_type, fieldlist; - tree tmp; gfc_component *c; assert (derived && derived->attr.flavor == FL_DERIVED); @@ -1059,7 +1054,16 @@ gfc_get_derived_type (gfc_symbol * deriv } } else - field_type = gfc_typenode_for_spec (&c->ts); + { + if (c->ts.type == BT_CHARACTER) + { + /* Evaluate the string length. */ + gfc_conv_const_charlen (c->ts.cl); + assert (c->ts.cl->backend_decl); + } + + field_type = gfc_typenode_for_spec (&c->ts); + } /* This returns an array descriptor type. Initialisation may be required. */ @@ -1083,16 +1087,6 @@ gfc_get_derived_type (gfc_symbol * deriv DECL_PACKED (field) |= TYPE_PACKED (typenode); - if (c->ts.type == BT_CHARACTER) - { - gfc_allocate_lang_decl (field); - tmp = TREE_TYPE (field); - assert (TREE_CODE (tmp) == ARRAY_TYPE); - tmp = TYPE_MAX_VALUE (TYPE_DOMAIN (tmp)); - assert (INTEGER_CST_P (tmp)); - GFC_DECL_STRING_LENGTH (field) = tmp; - } - assert (!c->backend_decl); c->backend_decl = field; } @@ -1157,9 +1151,16 @@ gfc_get_function_type (gfc_symbol * sym) arg = sym->result; else arg = sym; + + if (arg->ts.type == BT_CHARACTER) + gfc_conv_const_charlen (arg->ts.cl); + type = gfc_sym_type (arg); - if (arg->ts.type == BT_DERIVED || arg->attr.dimension) + if (arg->ts.type == BT_DERIVED + || arg->attr.dimension + || arg->ts.type == BT_CHARACTER) type = build_reference_type (type); + typelist = gfc_chainon_list (typelist, type); if (arg->ts.type == BT_CHARACTER) typelist = gfc_chainon_list (typelist, gfc_strlen_type_node); @@ -1171,6 +1172,11 @@ gfc_get_function_type (gfc_symbol * sym) arg = f->sym; if (arg) { + /* Evaluate constant character lengths here so that they can be + included in the type. */ + if (arg->ts.type == BT_CHARACTER) + gfc_conv_const_charlen (arg->ts.cl); + if (arg->attr.flavor == FL_PROCEDURE) { type = gfc_get_function_type (arg); Index: trans-types.h =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans-types.h,v retrieving revision 1.1.2.2 diff -u -p -r1.1.2.2 trans-types.h --- a/trans-types.h 2 Aug 2003 00:26:48 -0000 1.1.2.2 +++ b/trans-types.h 4 Apr 2004 16:23:13 -0000 @@ -91,6 +91,7 @@ extern GTY(()) tree pchar_type_node; #define gfc_character1_type_node gfc_type_nodes[F95_CHARACTER1_TYPE] +#define gfc_strlen_kind 4 #define gfc_strlen_type_node gfc_int4_type_node /* These C-specific types are used while building builtin function decls. @@ -136,4 +137,7 @@ void gfc_finish_type (tree); /* Some functions have an extra parameter for the return value. */ int gfc_return_by_reference (gfc_symbol *); +/* Returns true if the array sym does not require a descriptor. */ +int gfc_is_nodesc_array (gfc_symbol *); + #endif Index: trans.h =================================================================== RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/fortran/Attic/trans.h,v retrieving revision 1.1.2.14 diff -u -p -r1.1.2.14 trans.h --- a/trans.h 16 Feb 2004 12:36:08 -0000 1.1.2.14 +++ b/trans.h 4 Apr 2004 22:20:08 -0000 @@ -303,10 +303,8 @@ tree gfc_conv_expr_present (gfc_symbol * /* Generate code to allocate a string temporary. */ tree gfc_conv_string_tmp (gfc_se *, tree, tree); -/* Get the length of a string. */ -tree gfc_conv_string_length (tree); /* Initialize a string length variable. */ -tree gfc_conv_init_string_length (gfc_symbol *, stmtblock_t *); +void gfc_trans_init_string_length (gfc_charlen *, stmtblock_t *); /* Add an expression to the end of a block. */ void gfc_add_expr_to_block (stmtblock_t *, tree); @@ -485,19 +483,19 @@ struct lang_type GTY(()) struct lang_decl GTY(()) { - /* String nodes. */ - tree stringlength; + /* Dummy variables. */ tree saved_descriptor; /* Assigned integer nodes. Stringlength is the IO format string's length. Addr is the address of the string or the target label. Stringlength is initialized to -2 and assiged to -1 when addr is assigned to the address of target label. */ + tree stringlen; tree addr; }; #define GFC_DECL_ASSIGN_ADDR(node) DECL_LANG_SPECIFIC(node)->addr -#define GFC_DECL_STRING_LENGTH(node) (DECL_LANG_SPECIFIC(node)->stringlength) +#define GFC_DECL_STRING_LEN(node) DECL_LANG_SPECIFIC(node)->stringlen #define GFC_DECL_SAVED_DESCRIPTOR(node) \ (DECL_LANG_SPECIFIC(node)->saved_descriptor) #define GFC_DECL_STRING(node) DECL_LANG_FLAG_0(node) @@ -505,7 +503,6 @@ struct lang_decl GTY(()) #define GFC_DECL_PARTIAL_PACKED_ARRAY(node) DECL_LANG_FLAG_2(node) #define GFC_DECL_ASSIGN(node) DECL_LANG_FLAG_3(node) -#define GFC_KNOWN_SIZE_STRING_TYPE(node) TYPE_LANG_FLAG_0(node) /* An array descriptor. */ #define GFC_DESCRIPTOR_TYPE_P(node) TYPE_LANG_FLAG_1(node) /* An array without a descriptor. */
Attachment:
strarray_3.f90
Description: Text document
Attachment:
strarray_1.f90
Description: Text document
Attachment:
strcommon_1.f90
Description: Text document
Attachment:
strarray_2.f90
Description: Text document
Attachment:
strarray_4.f90
Description: Text document
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |