aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2006-02-06 18:15:51 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2006-02-06 18:15:51 +0100
commit417ab240ee902f214acc7f0d46966ba0bb9ab12e (patch)
tree4535fbfc82bc7b98cce85042940a2397426b81ec /gcc
parentf44013ae3f4d67e4c1cbbe6f28e2808fb2c34d0e (diff)
downloadgcc-417ab240ee902f214acc7f0d46966ba0bb9ab12e.zip
gcc-417ab240ee902f214acc7f0d46966ba0bb9ab12e.tar.gz
gcc-417ab240ee902f214acc7f0d46966ba0bb9ab12e.tar.bz2
backport: trans-decl.c (create_function_arglist): Handle dummy functions.
Backport from gomp-20050608-branch * trans-decl.c (create_function_arglist): Handle dummy functions. * trans-decl.c (gfc_get_symbol_decl): Revert explicit setting of TYPE_SIZE_UNIT. (gfc_trans_vla_type_sizes): Also "gimplify" GFC_TYPE_ARRAY_DATAPTR_TYPE for GFC_DESCRIPTOR_TYPE_P types. * trans-array.c (gfc_trans_deferred_array): Call gfc_trans_vla_type_sizes. * trans-decl.c (saved_function_decls, saved_parent_function_decls): Remove unnecessary initialization. (create_function_arglist): Make sure __result has complete type. (gfc_get_fake_result_decl): Change current_fake_result_decl into a tree chain. For entry master, create a separate variable for each result name. For BT_CHARACTER results, call gfc_finish_var_decl on length even if it has been already created, but not pushdecl'ed. (gfc_trans_vla_type_sizes): For function/entry result, adjust result value type, not the FUNCTION_TYPE. (gfc_generate_function_code): Adjust for current_fake_result_decl changes. (gfc_trans_deferred_vars): Likewise. Call gfc_trans_vla_type_sizes even on result if it is assumed-length character. * trans-decl.c (gfc_trans_dummy_character): Add SYM argument. Call gfc_trans_vla_type_sizes. (gfc_trans_auto_character_variable): Call gfc_trans_vla_type_sizes. (gfc_trans_vla_one_sizepos, gfc_trans_vla_type_sizes_1, gfc_trans_vla_type_sizes): New functions. (gfc_trans_deferred_vars): Adjust gfc_trans_dummy_character callers. Call gfc_trans_vla_type_sizes on assumed-length character parameters. * trans-array.c (gfc_trans_array_bounds, gfc_trans_auto_array_allocation, gfc_trans_dummy_array_bias): Call gfc_trans_vla_type_sizes. * trans.h (gfc_trans_vla_type_sizes): New prototype. * trans-decl.c (gfc_build_qualified_array): For non-assumed-size arrays without constant size, create also an index var for GFC_TYPE_ARRAY_SIZE (type). If the type is incomplete, complete it as 0..size-1. (gfc_create_string_length): Don't call gfc_defer_symbol_init if just creating DECL_ARGUMENTS. (gfc_get_symbol_decl): Call gfc_finish_var_decl and gfc_defer_symbol_init even if ts.cl->backend_decl is already set to a VAR_DECL that doesn't have DECL_CONTEXT yet. (create_function_arglist): Rework, so that hidden length arguments for CHARACTER parameters are created together with the parameters. Resolve ts.cl->backend_decl for CHARACTER parameters. If the argument is a non-constant length array or CHARACTER, ensure PARM_DECL has different type than its DECL_ARG_TYPE. (generate_local_decl): Call gfc_get_symbol_decl even for non-referenced non-constant length CHARACTER parameters after optionally issuing warnings. * trans-array.c (gfc_trans_array_bounds): Set last stride to GFC_TYPE_ARRAY_SIZE (type) to initialize it as well. (gfc_trans_dummy_array_bias): Initialize GFC_TYPE_ARRAY_SIZE (type) variable as well. * trans-expr.c (gfc_conv_expr_val): Fix comment typo. * trans-stmt.c (gfc_trans_simple_do): Fix comment. From-SVN: r110653
Diffstat (limited to 'gcc')
-rw-r--r--gcc/fortran/ChangeLog67
-rw-r--r--gcc/fortran/trans-array.c29
-rw-r--r--gcc/fortran/trans-decl.c481
-rw-r--r--gcc/fortran/trans-expr.c2
-rw-r--r--gcc/fortran/trans-stmt.c2
-rw-r--r--gcc/fortran/trans.h2
6 files changed, 452 insertions, 131 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index d2a51f4..baef826 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,70 @@
+2006-02-06 Jakub Jelinek <jakub@redhat.com>
+
+ Backport from gomp-20050608-branch
+ * trans-decl.c (create_function_arglist): Handle dummy functions.
+
+ * trans-decl.c (gfc_get_symbol_decl): Revert explicit setting of
+ TYPE_SIZE_UNIT.
+ (gfc_trans_vla_type_sizes): Also "gimplify"
+ GFC_TYPE_ARRAY_DATAPTR_TYPE for GFC_DESCRIPTOR_TYPE_P types.
+ * trans-array.c (gfc_trans_deferred_array): Call
+ gfc_trans_vla_type_sizes.
+
+ * trans-decl.c (saved_function_decls, saved_parent_function_decls):
+ Remove unnecessary initialization.
+ (create_function_arglist): Make sure __result has complete type.
+ (gfc_get_fake_result_decl): Change current_fake_result_decl into
+ a tree chain. For entry master, create a separate variable
+ for each result name. For BT_CHARACTER results, call
+ gfc_finish_var_decl on length even if it has been already created,
+ but not pushdecl'ed.
+ (gfc_trans_vla_type_sizes): For function/entry result, adjust
+ result value type, not the FUNCTION_TYPE.
+ (gfc_generate_function_code): Adjust for current_fake_result_decl
+ changes.
+ (gfc_trans_deferred_vars): Likewise. Call gfc_trans_vla_type_sizes
+ even on result if it is assumed-length character.
+
+ * trans-decl.c (gfc_trans_dummy_character): Add SYM argument.
+ Call gfc_trans_vla_type_sizes.
+ (gfc_trans_auto_character_variable): Call gfc_trans_vla_type_sizes.
+ (gfc_trans_vla_one_sizepos, gfc_trans_vla_type_sizes_1,
+ gfc_trans_vla_type_sizes): New functions.
+ (gfc_trans_deferred_vars): Adjust gfc_trans_dummy_character
+ callers. Call gfc_trans_vla_type_sizes on assumed-length
+ character parameters.
+ * trans-array.c (gfc_trans_array_bounds,
+ gfc_trans_auto_array_allocation, gfc_trans_dummy_array_bias): Call
+ gfc_trans_vla_type_sizes.
+ * trans.h (gfc_trans_vla_type_sizes): New prototype.
+
+ * trans-decl.c (gfc_build_qualified_array): For non-assumed-size
+ arrays without constant size, create also an index var for
+ GFC_TYPE_ARRAY_SIZE (type). If the type is incomplete, complete
+ it as 0..size-1.
+ (gfc_create_string_length): Don't call gfc_defer_symbol_init
+ if just creating DECL_ARGUMENTS.
+ (gfc_get_symbol_decl): Call gfc_finish_var_decl and
+ gfc_defer_symbol_init even if ts.cl->backend_decl is already
+ set to a VAR_DECL that doesn't have DECL_CONTEXT yet.
+ (create_function_arglist): Rework, so that hidden length
+ arguments for CHARACTER parameters are created together with
+ the parameters. Resolve ts.cl->backend_decl for CHARACTER
+ parameters. If the argument is a non-constant length array
+ or CHARACTER, ensure PARM_DECL has different type than
+ its DECL_ARG_TYPE.
+ (generate_local_decl): Call gfc_get_symbol_decl even
+ for non-referenced non-constant length CHARACTER parameters
+ after optionally issuing warnings.
+ * trans-array.c (gfc_trans_array_bounds): Set last stride
+ to GFC_TYPE_ARRAY_SIZE (type) to initialize it as well.
+ (gfc_trans_dummy_array_bias): Initialize GFC_TYPE_ARRAY_SIZE (type)
+ variable as well.
+
+ * trans-expr.c (gfc_conv_expr_val): Fix comment typo.
+
+ * trans-stmt.c (gfc_trans_simple_do): Fix comment.
+
2006-02-04 Roger Sayle <roger@eyesopen.com>
* dependency.c (gfc_check_dependency): Remove unused vars and nvars
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index cc8e97e..1edc7b7 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -3255,7 +3255,7 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset,
if (dim + 1 < as->rank)
stride = GFC_TYPE_ARRAY_STRIDE (type, dim + 1);
else
- stride = NULL_TREE;
+ stride = GFC_TYPE_ARRAY_SIZE (type);
if (ubound != NULL_TREE && !(stride && INTEGER_CST_P (stride)))
{
@@ -3273,6 +3273,8 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset,
size = stride;
}
+ gfc_trans_vla_type_sizes (sym, pblock);
+
*poffset = offset;
return size;
}
@@ -3309,6 +3311,8 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym, tree fnbody)
{
gfc_trans_init_string_length (sym->ts.cl, &block);
+ gfc_trans_vla_type_sizes (sym, &block);
+
/* Emit a DECL_EXPR for this variable, which will cause the
gimplifier to allocate storage, and all that good stuff. */
tmp = build1 (DECL_EXPR, TREE_TYPE (decl), decl);
@@ -3661,12 +3665,30 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, tree body)
gfc_add_modify_expr (&block, stride, tmp);
}
}
+ else
+ {
+ stride = GFC_TYPE_ARRAY_SIZE (type);
+
+ if (stride && !INTEGER_CST_P (stride))
+ {
+ /* Calculate size = stride * (ubound + 1 - lbound). */
+ tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+ gfc_index_one_node, lbound);
+ tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+ ubound, tmp);
+ tmp = fold_build2 (MULT_EXPR, gfc_array_index_type,
+ GFC_TYPE_ARRAY_STRIDE (type, n), tmp);
+ gfc_add_modify_expr (&block, stride, tmp);
+ }
+ }
}
/* Set the offset. */
if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL)
gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset);
+ gfc_trans_vla_type_sizes (sym, &block);
+
stmt = gfc_finish_block (&block);
gfc_start_block (&block);
@@ -4268,7 +4290,10 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body)
if (sym->ts.type == BT_CHARACTER
&& !INTEGER_CST_P (sym->ts.cl->backend_decl))
- gfc_trans_init_string_length (sym->ts.cl, &fnblock);
+ {
+ gfc_trans_init_string_length (sym->ts.cl, &fnblock);
+ gfc_trans_vla_type_sizes (sym, &fnblock);
+ }
/* Dummy and use associated variables don't need anything special. */
if (sym->attr.dummy || sym->attr.use_assoc)
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 2a92f5d..cdbb999 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -55,8 +55,8 @@ static GTY(()) tree current_function_return_label;
/* Holds the variable DECLs for the current function. */
-static GTY(()) tree saved_function_decls = NULL_TREE;
-static GTY(()) tree saved_parent_function_decls = NULL_TREE;
+static GTY(()) tree saved_function_decls;
+static GTY(()) tree saved_parent_function_decls;
/* The namespace of the module we're currently generating. Only used while
@@ -614,6 +614,30 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym)
else
gfc_add_decl_to_function (GFC_TYPE_ARRAY_OFFSET (type));
}
+
+ if (GFC_TYPE_ARRAY_SIZE (type) == NULL_TREE
+ && sym->as->type != AS_ASSUMED_SIZE)
+ GFC_TYPE_ARRAY_SIZE (type) = create_index_var ("size", nest);
+
+ if (POINTER_TYPE_P (type))
+ {
+ gcc_assert (GFC_ARRAY_TYPE_P (TREE_TYPE (type)));
+ gcc_assert (TYPE_LANG_SPECIFIC (type)
+ == TYPE_LANG_SPECIFIC (TREE_TYPE (type)));
+ type = TREE_TYPE (type);
+ }
+
+ if (! COMPLETE_TYPE_P (type) && GFC_TYPE_ARRAY_SIZE (type))
+ {
+ tree size, range;
+
+ size = build2 (MINUS_EXPR, gfc_array_index_type,
+ GFC_TYPE_ARRAY_SIZE (type), gfc_index_one_node);
+ range = build_range_type (gfc_array_index_type, gfc_index_zero_node,
+ size);
+ TYPE_DOMAIN (type) = range;
+ layout_type (type);
+ }
}
@@ -762,7 +786,8 @@ gfc_create_string_length (gfc_symbol * sym)
gfc_charlen_type_node);
DECL_ARTIFICIAL (length) = 1;
TREE_USED (length) = 1;
- gfc_defer_symbol_init (sym);
+ if (sym->ns->proc_name->tlink != NULL)
+ gfc_defer_symbol_init (sym);
sym->ts.cl->backend_decl = length;
}
@@ -810,9 +835,7 @@ tree
gfc_get_symbol_decl (gfc_symbol * sym)
{
tree decl;
- tree etype = NULL_TREE;
tree length = NULL_TREE;
- tree tmp = NULL_TREE;
int byref;
gcc_assert (sym->attr.referenced);
@@ -843,28 +866,14 @@ gfc_get_symbol_decl (gfc_symbol * sym)
if (sym->ts.type == BT_CHARACTER)
{
if (sym->ts.cl->backend_decl == NULL_TREE)
+ length = gfc_create_string_length (sym);
+ else
+ length = sym->ts.cl->backend_decl;
+ if (TREE_CODE (length) == VAR_DECL
+ && DECL_CONTEXT (length) == 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);
- }
- }
-
- /* Set the element size of automatic and assumed character length
- length, dummy, pointer arrays. */
- if (sym->attr.pointer && sym->attr.dummy
- && sym->attr.dimension)
- {
- tmp = build_fold_indirect_ref (sym->backend_decl);
- etype = gfc_get_element_type (TREE_TYPE (tmp));
- if (TYPE_SIZE_UNIT (etype) == NULL_TREE)
- {
- tmp = TYPE_SIZE_UNIT (gfc_character1_type_node);
- tmp = fold_convert (TREE_TYPE (tmp), sym->ts.cl->backend_decl);
- TYPE_SIZE_UNIT (etype) = tmp;
- }
+ gfc_finish_var_decl (length, sym);
+ gfc_defer_symbol_init (sym);
}
}
@@ -1241,9 +1250,8 @@ create_function_arglist (gfc_symbol * sym)
{
tree fndecl;
gfc_formal_arglist *f;
- tree typelist;
- tree arglist;
- tree length;
+ tree typelist, hidden_typelist;
+ tree arglist, hidden_arglist;
tree type;
tree parm;
@@ -1252,6 +1260,7 @@ create_function_arglist (gfc_symbol * sym)
/* Build formal argument list. Make sure that their TREE_CONTEXT is
the new FUNCTION_DECL node. */
arglist = NULL_TREE;
+ hidden_arglist = NULL_TREE;
typelist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
if (sym->attr.entry_master)
@@ -1270,131 +1279,186 @@ create_function_arglist (gfc_symbol * sym)
if (gfc_return_by_reference (sym))
{
- type = TREE_VALUE (typelist);
- parm = build_decl (PARM_DECL, get_identifier ("__result"), type);
-
- DECL_CONTEXT (parm) = fndecl;
- DECL_ARG_TYPE (parm) = type;
- TREE_READONLY (parm) = 1;
- DECL_ARTIFICIAL (parm) = 1;
- gfc_finish_decl (parm, NULL_TREE);
-
- arglist = chainon (arglist, parm);
- typelist = TREE_CHAIN (typelist);
+ tree type = TREE_VALUE (typelist), length = NULL;
if (sym->ts.type == BT_CHARACTER)
{
- gfc_allocate_lang_decl (parm);
-
/* Length of character result. */
- type = TREE_VALUE (typelist);
- gcc_assert (type == gfc_charlen_type_node);
+ tree len_type = TREE_VALUE (TREE_CHAIN (typelist));
+ gcc_assert (len_type == gfc_charlen_type_node);
length = build_decl (PARM_DECL,
get_identifier (".__result"),
- type);
+ len_type);
if (!sym->ts.cl->length)
{
sym->ts.cl->backend_decl = length;
TREE_USED (length) = 1;
}
gcc_assert (TREE_CODE (length) == PARM_DECL);
- arglist = chainon (arglist, length);
- typelist = TREE_CHAIN (typelist);
DECL_CONTEXT (length) = fndecl;
- DECL_ARG_TYPE (length) = type;
+ DECL_ARG_TYPE (length) = len_type;
TREE_READONLY (length) = 1;
DECL_ARTIFICIAL (length) = 1;
gfc_finish_decl (length, NULL_TREE);
- }
- }
-
- for (f = sym->formal; f; f = f->next)
- {
- if (f->sym != NULL) /* ignore alternate returns. */
- {
- length = NULL_TREE;
+ if (sym->ts.cl->backend_decl == NULL
+ || sym->ts.cl->backend_decl == length)
+ {
+ gfc_symbol *arg;
+ tree backend_decl;
- type = TREE_VALUE (typelist);
+ if (sym->ts.cl->backend_decl == NULL)
+ {
+ tree len = build_decl (VAR_DECL,
+ get_identifier ("..__result"),
+ gfc_charlen_type_node);
+ DECL_ARTIFICIAL (len) = 1;
+ TREE_USED (len) = 1;
+ sym->ts.cl->backend_decl = len;
+ }
- /* Build a the argument declaration. */
- parm = build_decl (PARM_DECL,
- gfc_sym_identifier (f->sym), type);
+ /* Make sure PARM_DECL type doesn't point to incomplete type. */
+ arg = sym->result ? sym->result : sym;
+ backend_decl = arg->backend_decl;
+ /* Temporary clear it, so that gfc_sym_type creates complete
+ type. */
+ arg->backend_decl = NULL;
+ type = gfc_sym_type (arg);
+ arg->backend_decl = backend_decl;
+ type = build_reference_type (type);
+ }
+ }
- /* Fill in arg stuff. */
- DECL_CONTEXT (parm) = fndecl;
- DECL_ARG_TYPE (parm) = type;
- /* All implementation args are read-only. */
- TREE_READONLY (parm) = 1;
+ parm = build_decl (PARM_DECL, get_identifier ("__result"), type);
- gfc_finish_decl (parm, NULL_TREE);
+ DECL_CONTEXT (parm) = fndecl;
+ DECL_ARG_TYPE (parm) = TREE_VALUE (typelist);
+ TREE_READONLY (parm) = 1;
+ DECL_ARTIFICIAL (parm) = 1;
+ gfc_finish_decl (parm, NULL_TREE);
- f->sym->backend_decl = parm;
+ arglist = chainon (arglist, parm);
+ typelist = TREE_CHAIN (typelist);
- arglist = chainon (arglist, parm);
+ if (sym->ts.type == BT_CHARACTER)
+ {
+ gfc_allocate_lang_decl (parm);
+ arglist = chainon (arglist, length);
typelist = TREE_CHAIN (typelist);
}
}
- /* Add the hidden string length parameters. */
- parm = arglist;
+ hidden_typelist = typelist;
+ for (f = sym->formal; f; f = f->next)
+ if (f->sym != NULL) /* Ignore alternate returns. */
+ hidden_typelist = TREE_CHAIN (hidden_typelist);
+
for (f = sym->formal; f; f = f->next)
{
char name[GFC_MAX_SYMBOL_LEN + 2];
+
/* Ignore alternate returns. */
if (f->sym == NULL)
continue;
- if (f->sym->ts.type != BT_CHARACTER)
- continue;
-
- parm = f->sym->backend_decl;
type = TREE_VALUE (typelist);
- gcc_assert (type == gfc_charlen_type_node);
- strcpy (&name[1], f->sym->name);
- name[0] = '_';
- length = build_decl (PARM_DECL, get_identifier (name), type);
+ if (f->sym->ts.type == BT_CHARACTER)
+ {
+ tree len_type = TREE_VALUE (hidden_typelist);
+ tree length = NULL_TREE;
+ gcc_assert (len_type == gfc_charlen_type_node);
- arglist = chainon (arglist, length);
- DECL_CONTEXT (length) = fndecl;
- DECL_ARTIFICIAL (length) = 1;
- DECL_ARG_TYPE (length) = type;
- TREE_READONLY (length) = 1;
- gfc_finish_decl (length, NULL_TREE);
+ strcpy (&name[1], f->sym->name);
+ name[0] = '_';
+ length = build_decl (PARM_DECL, get_identifier (name), len_type);
- /* TODO: Check string lengths when -fbounds-check. */
+ hidden_arglist = chainon (hidden_arglist, length);
+ DECL_CONTEXT (length) = fndecl;
+ DECL_ARTIFICIAL (length) = 1;
+ DECL_ARG_TYPE (length) = len_type;
+ TREE_READONLY (length) = 1;
+ gfc_finish_decl (length, NULL_TREE);
- /* Use the passed value for assumed length variables. */
- if (!f->sym->ts.cl->length)
- {
- TREE_USED (length) = 1;
- if (!f->sym->ts.cl->backend_decl)
- f->sym->ts.cl->backend_decl = length;
- else
+ /* TODO: Check string lengths when -fbounds-check. */
+
+ /* Use the passed value for assumed length variables. */
+ if (!f->sym->ts.cl->length)
{
- /* there is already another variable using this
- gfc_charlen node, build a new one for this variable
- and chain it into the list of gfc_charlens.
- This happens for e.g. in the case
- CHARACTER(*)::c1,c2
- since CHARACTER declarations on the same line share
- the same gfc_charlen node. */
- gfc_charlen *cl;
+ TREE_USED (length) = 1;
+ if (!f->sym->ts.cl->backend_decl)
+ f->sym->ts.cl->backend_decl = length;
+ else
+ {
+ /* there is already another variable using this
+ gfc_charlen node, build a new one for this variable
+ and chain it into the list of gfc_charlens.
+ This happens for e.g. in the case
+ CHARACTER(*)::c1,c2
+ since CHARACTER declarations on the same line share
+ the same gfc_charlen node. */
+ gfc_charlen *cl;
- cl = gfc_get_charlen ();
- cl->backend_decl = length;
- cl->next = f->sym->ts.cl->next;
- f->sym->ts.cl->next = cl;
- f->sym->ts.cl = cl;
+ cl = gfc_get_charlen ();
+ cl->backend_decl = length;
+ cl->next = f->sym->ts.cl->next;
+ f->sym->ts.cl->next = cl;
+ f->sym->ts.cl = cl;
+ }
+ }
+
+ hidden_typelist = TREE_CHAIN (hidden_typelist);
+
+ if (f->sym->ts.cl->backend_decl == NULL
+ || f->sym->ts.cl->backend_decl == length)
+ {
+ if (f->sym->ts.cl->backend_decl == NULL)
+ gfc_create_string_length (f->sym);
+
+ /* Make sure PARM_DECL type doesn't point to incomplete type. */
+ if (f->sym->attr.flavor == FL_PROCEDURE)
+ type = build_pointer_type (gfc_get_function_type (f->sym));
+ else
+ type = gfc_sym_type (f->sym);
}
}
- parm = TREE_CHAIN (parm);
+ /* For non-constant length array arguments, make sure they use
+ a different type node from TYPE_ARG_TYPES type. */
+ if (f->sym->attr.dimension
+ && type == TREE_VALUE (typelist)
+ && TREE_CODE (type) == POINTER_TYPE
+ && GFC_ARRAY_TYPE_P (type)
+ && f->sym->as->type != AS_ASSUMED_SIZE
+ && ! COMPLETE_TYPE_P (TREE_TYPE (type)))
+ {
+ if (f->sym->attr.flavor == FL_PROCEDURE)
+ type = build_pointer_type (gfc_get_function_type (f->sym));
+ else
+ type = gfc_sym_type (f->sym);
+ }
+
+ /* Build a the argument declaration. */
+ parm = build_decl (PARM_DECL, gfc_sym_identifier (f->sym), type);
+
+ /* Fill in arg stuff. */
+ DECL_CONTEXT (parm) = fndecl;
+ DECL_ARG_TYPE (parm) = TREE_VALUE (typelist);
+ /* All implementation args are read-only. */
+ TREE_READONLY (parm) = 1;
+
+ gfc_finish_decl (parm, NULL_TREE);
+
+ f->sym->backend_decl = parm;
+
+ arglist = chainon (arglist, parm);
typelist = TREE_CHAIN (typelist);
}
- gcc_assert (TREE_VALUE (typelist) == void_type_node);
+ /* Add the hidden string length parameters. */
+ arglist = chainon (arglist, hidden_arglist);
+
+ gcc_assert (TREE_VALUE (hidden_typelist) == void_type_node);
DECL_ARGUMENTS (fndecl) = arglist;
}
@@ -1658,18 +1722,24 @@ gfc_create_function_decl (gfc_namespace * ns)
tree
gfc_get_fake_result_decl (gfc_symbol * sym)
{
- tree decl;
- tree length;
+ tree decl, length;
char name[GFC_MAX_SYMBOL_LEN + 10];
if (sym
&& sym->ns->proc_name->backend_decl == current_function_decl
- && sym->ns->proc_name->attr.mixed_entry_master
+ && sym->ns->proc_name->attr.entry_master
&& sym != sym->ns->proc_name)
{
+ tree t = NULL, var;
+ if (current_fake_result_decl != NULL)
+ for (t = TREE_CHAIN (current_fake_result_decl); t; t = TREE_CHAIN (t))
+ if (strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t)), sym->name) == 0)
+ break;
+ if (t)
+ return TREE_VALUE (t);
decl = gfc_get_fake_result_decl (sym->ns->proc_name);
- if (decl)
+ if (decl && sym->ns->proc_name->attr.mixed_entry_master)
{
tree field;
@@ -1683,22 +1753,32 @@ gfc_get_fake_result_decl (gfc_symbol * sym)
decl = build3 (COMPONENT_REF, TREE_TYPE (field), decl, field,
NULL_TREE);
}
- return decl;
+ var = gfc_create_var (TREE_TYPE (decl), sym->name);
+ SET_DECL_VALUE_EXPR (var, decl);
+ DECL_HAS_VALUE_EXPR_P (var) = 1;
+ TREE_CHAIN (current_fake_result_decl)
+ = tree_cons (get_identifier (sym->name), var,
+ TREE_CHAIN (current_fake_result_decl));
+ return var;
}
if (current_fake_result_decl != NULL_TREE)
- return current_fake_result_decl;
+ return TREE_VALUE (current_fake_result_decl);
/* Only when gfc_get_fake_result_decl is called by gfc_trans_return,
sym is NULL. */
if (!sym)
return NULL_TREE;
- if (sym->ts.type == BT_CHARACTER
- && !sym->ts.cl->backend_decl)
+ if (sym->ts.type == BT_CHARACTER)
{
- length = gfc_create_string_length (sym);
- gfc_finish_var_decl (length, sym);
+ if (sym->ts.cl->backend_decl == NULL_TREE)
+ length = gfc_create_string_length (sym);
+ else
+ length = sym->ts.cl->backend_decl;
+ if (TREE_CODE (length) == VAR_DECL
+ && DECL_CONTEXT (length) == NULL_TREE)
+ gfc_finish_var_decl (length, sym);
}
if (gfc_return_by_reference (sym))
@@ -1731,7 +1811,7 @@ gfc_get_fake_result_decl (gfc_symbol * sym)
gfc_add_decl_to_function (decl);
}
- current_fake_result_decl = decl;
+ current_fake_result_decl = build_tree_list (NULL, decl);
return decl;
}
@@ -2174,7 +2254,7 @@ gfc_build_builtin_function_decls (void)
/* Evaluate the length of dummy character variables. */
static tree
-gfc_trans_dummy_character (gfc_charlen * cl, tree fnbody)
+gfc_trans_dummy_character (gfc_symbol *sym, gfc_charlen *cl, tree fnbody)
{
stmtblock_t body;
@@ -2184,7 +2264,9 @@ gfc_trans_dummy_character (gfc_charlen * cl, tree fnbody)
/* Evaluate the string length expression. */
gfc_trans_init_string_length (cl, &body);
-
+
+ gfc_trans_vla_type_sizes (sym, &body);
+
gfc_add_expr_to_block (&body, fnbody);
return gfc_finish_block (&body);
}
@@ -2207,6 +2289,8 @@ gfc_trans_auto_character_variable (gfc_symbol * sym, tree fnbody)
/* Evaluate the string length expression. */
gfc_trans_init_string_length (sym->ts.cl, &body);
+ gfc_trans_vla_type_sizes (sym, &body);
+
decl = sym->backend_decl;
/* Emit a DECL_EXPR for this variable, which will cause the
@@ -2237,6 +2321,112 @@ gfc_trans_assign_aux_var (gfc_symbol * sym, tree fnbody)
return gfc_finish_block (&body);
}
+static void
+gfc_trans_vla_one_sizepos (tree *tp, stmtblock_t *body)
+{
+ tree t = *tp, var, val;
+
+ if (t == NULL || t == error_mark_node)
+ return;
+ if (TREE_CONSTANT (t) || DECL_P (t))
+ return;
+
+ if (TREE_CODE (t) == SAVE_EXPR)
+ {
+ if (SAVE_EXPR_RESOLVED_P (t))
+ {
+ *tp = TREE_OPERAND (t, 0);
+ return;
+ }
+ val = TREE_OPERAND (t, 0);
+ }
+ else
+ val = t;
+
+ var = gfc_create_var_np (TREE_TYPE (t), NULL);
+ gfc_add_decl_to_function (var);
+ gfc_add_modify_expr (body, var, val);
+ if (TREE_CODE (t) == SAVE_EXPR)
+ TREE_OPERAND (t, 0) = var;
+ *tp = var;
+}
+
+static void
+gfc_trans_vla_type_sizes_1 (tree type, stmtblock_t *body)
+{
+ tree t;
+
+ if (type == NULL || type == error_mark_node)
+ return;
+
+ type = TYPE_MAIN_VARIANT (type);
+
+ if (TREE_CODE (type) == INTEGER_TYPE)
+ {
+ gfc_trans_vla_one_sizepos (&TYPE_MIN_VALUE (type), body);
+ gfc_trans_vla_one_sizepos (&TYPE_MAX_VALUE (type), body);
+
+ for (t = TYPE_NEXT_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ {
+ TYPE_MIN_VALUE (t) = TYPE_MIN_VALUE (type);
+ TYPE_MAX_VALUE (t) = TYPE_MAX_VALUE (type);
+ }
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ gfc_trans_vla_type_sizes_1 (TREE_TYPE (type), body);
+ gfc_trans_vla_type_sizes_1 (TYPE_DOMAIN (type), body);
+ gfc_trans_vla_one_sizepos (&TYPE_SIZE (type), body);
+ gfc_trans_vla_one_sizepos (&TYPE_SIZE_UNIT (type), body);
+
+ for (t = TYPE_NEXT_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ {
+ TYPE_SIZE (t) = TYPE_SIZE (type);
+ TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (type);
+ }
+ }
+}
+
+/* Make sure all type sizes and array domains are either constant,
+ or variable or parameter decls. This is a simplified variant
+ of gimplify_type_sizes, but we can't use it here, as none of the
+ variables in the expressions have been gimplified yet.
+ As type sizes and domains for various variable length arrays
+ contain VAR_DECLs that are only initialized at gfc_trans_deferred_vars
+ time, without this routine gimplify_type_sizes in the middle-end
+ could result in the type sizes being gimplified earlier than where
+ those variables are initialized. */
+
+void
+gfc_trans_vla_type_sizes (gfc_symbol *sym, stmtblock_t *body)
+{
+ tree type = TREE_TYPE (sym->backend_decl);
+
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ && (sym->attr.function || sym->attr.result || sym->attr.entry))
+ {
+ if (! current_fake_result_decl)
+ return;
+
+ type = TREE_TYPE (TREE_VALUE (current_fake_result_decl));
+ }
+
+ while (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ if (GFC_DESCRIPTOR_TYPE_P (type))
+ {
+ tree etype = GFC_TYPE_ARRAY_DATAPTR_TYPE (type);
+
+ while (POINTER_TYPE_P (etype))
+ etype = TREE_TYPE (etype);
+
+ gfc_trans_vla_type_sizes_1 (etype, body);
+ }
+
+ gfc_trans_vla_type_sizes_1 (type, body);
+}
+
/* Generate function entry and exit code, and add it to the function body.
This includes:
@@ -2250,6 +2440,8 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, tree fnbody)
{
locus loc;
gfc_symbol *sym;
+ gfc_formal_arglist *f;
+ stmtblock_t body;
/* Deal with implicit return variables. Explicit return variables will
already have been added. */
@@ -2269,14 +2461,14 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, tree fnbody)
}
else if (proc_sym->as)
{
- fnbody = gfc_trans_dummy_array_bias (proc_sym,
- current_fake_result_decl,
- fnbody);
+ tree result = TREE_VALUE (current_fake_result_decl);
+ fnbody = gfc_trans_dummy_array_bias (proc_sym, result, fnbody);
}
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);
+ fnbody = gfc_trans_dummy_character (proc_sym, proc_sym->ts.cl,
+ fnbody);
}
else
gcc_assert (gfc_option.flag_f2c
@@ -2339,7 +2531,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, tree fnbody)
gfc_get_backend_locus (&loc);
gfc_set_backend_locus (&sym->declared_at);
if (sym->attr.dummy || sym->attr.result)
- fnbody = gfc_trans_dummy_character (sym->ts.cl, fnbody);
+ fnbody = gfc_trans_dummy_character (sym, sym->ts.cl, fnbody);
else
fnbody = gfc_trans_auto_character_variable (sym, fnbody);
gfc_set_backend_locus (&loc);
@@ -2355,7 +2547,26 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, tree fnbody)
gcc_unreachable ();
}
- return fnbody;
+ gfc_init_block (&body);
+
+ for (f = proc_sym->formal; f; f = f->next)
+ if (f->sym && f->sym->tlink == NULL && f->sym->ts.type == BT_CHARACTER)
+ {
+ gcc_assert (f->sym->ts.cl->backend_decl != NULL);
+ if (TREE_CODE (f->sym->ts.cl->backend_decl) == PARM_DECL)
+ gfc_trans_vla_type_sizes (f->sym, &body);
+ }
+
+ if (gfc_return_by_reference (proc_sym) && proc_sym->ts.type == BT_CHARACTER
+ && current_fake_result_decl != NULL)
+ {
+ gcc_assert (proc_sym->ts.cl->backend_decl != NULL);
+ if (TREE_CODE (proc_sym->ts.cl->backend_decl) == PARM_DECL)
+ gfc_trans_vla_type_sizes (proc_sym, &body);
+ }
+
+ gfc_add_expr_to_block (&body, fnbody);
+ return gfc_finish_block (&body);
}
@@ -2477,6 +2688,19 @@ generate_local_decl (gfc_symbol * sym)
else if (warn_unused_variable
&& !(sym->attr.in_common || sym->attr.use_assoc))
warning (0, "unused variable %qs", sym->name);
+ /* For variable length CHARACTER parameters, the PARM_DECL already
+ references the length variable, so force gfc_get_symbol_decl
+ even when not referenced. If optimize > 0, it will be optimized
+ away anyway. But do this only after emitting -Wunused-parameter
+ warning if requested. */
+ if (sym->attr.dummy && ! sym->attr.referenced
+ && sym->ts.type == BT_CHARACTER
+ && sym->ts.cl->backend_decl != NULL
+ && TREE_CODE (sym->ts.cl->backend_decl) == VAR_DECL)
+ {
+ sym->attr.referenced = 1;
+ gfc_get_symbol_decl (sym);
+ }
}
}
@@ -2655,7 +2879,10 @@ gfc_generate_function_code (gfc_namespace * ns)
{
if (sym->attr.subroutine || sym == sym->result)
{
- result = current_fake_result_decl;
+ if (current_fake_result_decl != NULL)
+ result = TREE_VALUE (current_fake_result_decl);
+ else
+ result = NULL_TREE;
current_fake_result_decl = NULL_TREE;
}
else
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 2322705..2529fb7 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -2656,7 +2656,7 @@ gfc_conv_expr_lhs (gfc_se * se, gfc_expr * expr)
}
/* Like gfc_conv_expr, but the POST block is guaranteed to be empty for
- numeric expressions. Used for scalar values whee inserting cleanup code
+ numeric expressions. Used for scalar values where inserting cleanup code
is inconvenient. */
void
gfc_conv_expr_val (gfc_se * se, gfc_expr * expr)
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index b44774e..d6aa3d1 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -701,7 +701,7 @@ gfc_trans_simple_do (gfc_code * code, stmtblock_t *pblock, tree dovar,
to:
[evaluate loop bounds and step]
- count = to + step - from;
+ count = (to + step - from) / step;
dovar = from;
for (;;)
{
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index e4f998a..c7c2301 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -320,6 +320,8 @@ tree gfc_conv_string_tmp (gfc_se *, tree, tree);
tree gfc_get_expr_charlen (gfc_expr *);
/* Initialize a string length variable. */
void gfc_trans_init_string_length (gfc_charlen *, stmtblock_t *);
+/* Ensure type sizes can be gimplified. */
+void gfc_trans_vla_type_sizes (gfc_symbol *, stmtblock_t *);
/* Add an expression to the end of a block. */
void gfc_add_expr_to_block (stmtblock_t *, tree);