Commit 7b5b57b7 by Paul Brook Committed by Paul Brook

re PR fortran/15620 (Statement functions and optimization cause IC)

	PR fortran/15620
	* trans-decl.c (gfc_shadow_sym, gfc_restore_sym): New functions.
	* trans-expr.c (gfc_trans_string_copy): New function.
	(gfc_conv_statement_function): Use them.  Create temp vars.  Enforce
	character lengths.
	(gfc_conv_string_parameter): Use gfc_trans_string_copy.
	* trans-stmt.c (gfc_trans_forall_1): Use gfc_{shadow,restore}_sym.
	* trans.h (struct gfc_saved_var): Define.
	(gfc_shadow_sym, gfc_restore_sym): Add prototypes.
testsuite/
	* gfortran.fortran-torture/execute/st_function_1.f90: New test.
	* gfortran.fortran-torture/execute/st_function_2.f90: New test.

From-SVN: r82452
parent 7a70d70c
2004-05-30 Paul Brook <paul@codesourcery.com>
PR fortran/15620
* trans-decl.c (gfc_shadow_sym, gfc_restore_sym): New functions.
* trans-expr.c (gfc_trans_string_copy): New function.
(gfc_conv_statement_function): Use them. Create temp vars. Enforce
character lengths.
(gfc_conv_string_parameter): Use gfc_trans_string_copy.
* trans-stmt.c (gfc_trans_forall_1): Use gfc_{shadow,restore}_sym.
* trans.h (struct gfc_saved_var): Define.
(gfc_shadow_sym, gfc_restore_sym): Add prototypes.
2004-05-30 Steven G. Kargl <kargls@comcast.net> 2004-05-30 Steven G. Kargl <kargls@comcast.net>
* iresolve.c (gfc_resolve_random_number): Clean up conditional. * iresolve.c (gfc_resolve_random_number): Clean up conditional.
......
...@@ -866,6 +866,32 @@ gfc_get_symbol_decl (gfc_symbol * sym) ...@@ -866,6 +866,32 @@ gfc_get_symbol_decl (gfc_symbol * sym)
} }
/* Substitute a temporary variable in place of the real one. */
void
gfc_shadow_sym (gfc_symbol * sym, tree decl, gfc_saved_var * save)
{
save->attr = sym->attr;
save->decl = sym->backend_decl;
gfc_clear_attr (&sym->attr);
sym->attr.referenced = 1;
sym->attr.flavor = FL_VARIABLE;
sym->backend_decl = decl;
}
/* Restore the original variable. */
void
gfc_restore_sym (gfc_symbol * sym, gfc_saved_var * save)
{
sym->attr = save->attr;
sym->backend_decl = save->decl;
}
/* Get a basic decl for an external function. */ /* Get a basic decl for an external function. */
tree tree
......
...@@ -1182,6 +1182,24 @@ gfc_conv_function_call (gfc_se * se, gfc_symbol * sym, ...@@ -1182,6 +1182,24 @@ gfc_conv_function_call (gfc_se * se, gfc_symbol * sym,
} }
/* Generate code to copy a string. */
static void
gfc_trans_string_copy (stmtblock_t * block, tree dlen, tree dest,
tree slen, tree src)
{
tree tmp;
tmp = NULL_TREE;
tmp = gfc_chainon_list (tmp, dlen);
tmp = gfc_chainon_list (tmp, dest);
tmp = gfc_chainon_list (tmp, slen);
tmp = gfc_chainon_list (tmp, src);
tmp = gfc_build_function_call (gfor_fndecl_copy_string, tmp);
gfc_add_expr_to_block (block, tmp);
}
/* Translate a statement function. /* Translate a statement function.
The value of a statement function reference is obtained by evaluating the The value of a statement function reference is obtained by evaluating the
expression using the values of the actual arguments for the values of the expression using the values of the actual arguments for the values of the
...@@ -1196,69 +1214,98 @@ gfc_conv_statement_function (gfc_se * se, gfc_expr * expr) ...@@ -1196,69 +1214,98 @@ gfc_conv_statement_function (gfc_se * se, gfc_expr * expr)
gfc_actual_arglist *args; gfc_actual_arglist *args;
gfc_se lse; gfc_se lse;
gfc_se rse; gfc_se rse;
gfc_saved_var *saved_vars;
tree *temp_vars;
tree type;
tree tmp;
int n;
sym = expr->symtree->n.sym; sym = expr->symtree->n.sym;
args = expr->value.function.actual; args = expr->value.function.actual;
gfc_init_se (&lse, NULL); gfc_init_se (&lse, NULL);
gfc_init_se (&rse, NULL); gfc_init_se (&rse, NULL);
n = 0;
for (fargs = sym->formal; fargs; fargs = fargs->next) for (fargs = sym->formal; fargs; fargs = fargs->next)
n++;
saved_vars = (gfc_saved_var *)gfc_getmem (n * sizeof (gfc_saved_var));
temp_vars = (tree *)gfc_getmem (n * sizeof (tree));
for (fargs = sym->formal, n = 0; fargs; fargs = fargs->next, n++)
{ {
/* Each dummy shall be specified, explicitly or implicitly, to be /* Each dummy shall be specified, explicitly or implicitly, to be
scalar. */ scalar. */
assert (fargs->sym->attr.dimension == 0); assert (fargs->sym->attr.dimension == 0);
fsym = fargs->sym; fsym = fargs->sym;
assert (fsym->backend_decl);
/* Convert non-pointer string dummy. */ /* Create a temporary to hold the value. */
if (fsym->ts.type == BT_CHARACTER && !fsym->attr.pointer) type = gfc_typenode_for_spec (&fsym->ts);
temp_vars[n] = gfc_create_var (type, fsym->name);
if (fsym->ts.type == BT_CHARACTER)
{ {
tree len1; /* Copy string arguments. */
tree len2; tree arglen;
tree arg;
tree tmp;
tree type;
tree var;
assert (fsym->ts.cl && fsym->ts.cl->length assert (fsym->ts.cl && fsym->ts.cl->length
&& fsym->ts.cl->length->expr_type == EXPR_CONSTANT); && fsym->ts.cl->length->expr_type == EXPR_CONSTANT);
type = gfc_get_character_type (fsym->ts.kind, fsym->ts.cl); arglen = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
len1 = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); tmp = gfc_build_addr_expr (build_pointer_type (type),
var = gfc_build_addr_expr (build_pointer_type (type), temp_vars[n]);
fsym->backend_decl);
gfc_conv_expr (&rse, args->expr); gfc_conv_expr (&rse, args->expr);
gfc_conv_string_parameter (&rse); gfc_conv_string_parameter (&rse);
len2 = rse.string_length;
gfc_add_block_to_block (&se->pre, &lse.pre); gfc_add_block_to_block (&se->pre, &lse.pre);
gfc_add_block_to_block (&se->pre, &rse.pre); gfc_add_block_to_block (&se->pre, &rse.pre);
arg = NULL_TREE; gfc_trans_string_copy (&se->pre, arglen, tmp, rse.string_length,
arg = gfc_chainon_list (arg, len1); rse.expr);
arg = gfc_chainon_list (arg, var);
arg = gfc_chainon_list (arg, len2);
arg = gfc_chainon_list (arg, rse.expr);
tmp = gfc_build_function_call (gfor_fndecl_copy_string, arg);
gfc_add_expr_to_block (&se->pre, tmp);
gfc_add_block_to_block (&se->pre, &lse.post); gfc_add_block_to_block (&se->pre, &lse.post);
gfc_add_block_to_block (&se->pre, &rse.post); gfc_add_block_to_block (&se->pre, &rse.post);
} }
else else
{ {
/* For everything else, just evaluate the expression. */ /* For everything else, just evaluate the expression. */
if (fsym->attr.pointer == 1)
lse.want_pointer = 1;
gfc_conv_expr (&lse, args->expr); gfc_conv_expr (&lse, args->expr);
gfc_add_block_to_block (&se->pre, &lse.pre); gfc_add_block_to_block (&se->pre, &lse.pre);
gfc_add_modify_expr (&se->pre, fsym->backend_decl, lse.expr); gfc_add_modify_expr (&se->pre, temp_vars[n], lse.expr);
gfc_add_block_to_block (&se->pre, &lse.post); gfc_add_block_to_block (&se->pre, &lse.post);
} }
args = args->next; args = args->next;
} }
/* Use the temporary variables in place of the real ones. */
for (fargs = sym->formal, n = 0; fargs; fargs = fargs->next, n++)
gfc_shadow_sym (fargs->sym, temp_vars[n], &saved_vars[n]);
gfc_conv_expr (se, sym->value); gfc_conv_expr (se, sym->value);
if (sym->ts.type == BT_CHARACTER)
{
gfc_conv_const_charlen (sym->ts.cl);
/* Force the expression to the correct length. */
if (!INTEGER_CST_P (se->string_length)
|| tree_int_cst_lt (se->string_length,
sym->ts.cl->backend_decl))
{
type = gfc_get_character_type (sym->ts.kind, sym->ts.cl);
tmp = gfc_create_var (type, sym->name);
tmp = gfc_build_addr_expr (build_pointer_type (type), tmp);
gfc_trans_string_copy (&se->pre, sym->ts.cl->backend_decl, tmp,
se->string_length, se->expr);
se->expr = tmp;
}
se->string_length = sym->ts.cl->backend_decl;
}
/* Resore the original variables. */
for (fargs = sym->formal, n = 0; fargs; fargs = fargs->next, n++)
gfc_restore_sym (fargs->sym, &saved_vars[n]);
gfc_free (saved_vars);
} }
...@@ -1617,17 +1664,12 @@ gfc_conv_string_parameter (gfc_se * se) ...@@ -1617,17 +1664,12 @@ gfc_conv_string_parameter (gfc_se * se)
tree tree
gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, bt type) gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, bt type)
{ {
tree tmp;
tree args;
stmtblock_t block; stmtblock_t block;
gfc_init_block (&block); gfc_init_block (&block);
if (type == BT_CHARACTER) if (type == BT_CHARACTER)
{ {
args = NULL_TREE;
assert (lse->string_length != NULL_TREE assert (lse->string_length != NULL_TREE
&& rse->string_length != NULL_TREE); && rse->string_length != NULL_TREE);
...@@ -1637,13 +1679,8 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, bt type) ...@@ -1637,13 +1679,8 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, bt type)
gfc_add_block_to_block (&block, &lse->pre); gfc_add_block_to_block (&block, &lse->pre);
gfc_add_block_to_block (&block, &rse->pre); gfc_add_block_to_block (&block, &rse->pre);
args = gfc_chainon_list (args, lse->string_length); gfc_trans_string_copy (&block, lse->string_length, lse->expr,
args = gfc_chainon_list (args, lse->expr); rse->string_length, rse->expr);
args = gfc_chainon_list (args, rse->string_length);
args = gfc_chainon_list (args, rse->expr);
tmp = gfc_build_function_call (gfor_fndecl_copy_string, args);
gfc_add_expr_to_block (&block, tmp);
} }
else else
{ {
......
...@@ -2121,8 +2121,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) ...@@ -2121,8 +2121,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
gfc_forall_iterator *fa; gfc_forall_iterator *fa;
gfc_se se; gfc_se se;
gfc_code *c; gfc_code *c;
tree *saved_var_decl; gfc_saved_var *saved_vars;
symbol_attribute *saved_var_attr;
iter_info *this_forall, *iter_tmp; iter_info *this_forall, *iter_tmp;
forall_info *info, *forall_tmp; forall_info *info, *forall_tmp;
temporary_list *temp; temporary_list *temp;
...@@ -2141,9 +2140,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) ...@@ -2141,9 +2140,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
end = (tree *) gfc_getmem (nvar * sizeof (tree)); end = (tree *) gfc_getmem (nvar * sizeof (tree));
step = (tree *) gfc_getmem (nvar * sizeof (tree)); step = (tree *) gfc_getmem (nvar * sizeof (tree));
varexpr = (gfc_expr **) gfc_getmem (nvar * sizeof (gfc_expr *)); varexpr = (gfc_expr **) gfc_getmem (nvar * sizeof (gfc_expr *));
saved_var_decl = (tree *) gfc_getmem (nvar * sizeof (tree)); saved_vars = (gfc_saved_var *) gfc_getmem (nvar * sizeof (gfc_saved_var));
saved_var_attr = (symbol_attribute *)
gfc_getmem (nvar * sizeof (symbol_attribute));
/* Allocate the space for info. */ /* Allocate the space for info. */
info = (forall_info *) gfc_getmem (sizeof (forall_info)); info = (forall_info *) gfc_getmem (sizeof (forall_info));
...@@ -2155,20 +2152,11 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) ...@@ -2155,20 +2152,11 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
/* allocate space for this_forall. */ /* allocate space for this_forall. */
this_forall = (iter_info *) gfc_getmem (sizeof (iter_info)); this_forall = (iter_info *) gfc_getmem (sizeof (iter_info));
/* Save the FORALL index's backend_decl. */
saved_var_decl[n] = sym->backend_decl;
/* Save the attribute. */
saved_var_attr[n] = sym->attr;
/* Set the proper attributes. */
gfc_clear_attr (&sym->attr);
sym->attr.referenced = 1;
sym->attr.flavor = FL_VARIABLE;
/* Create a temporary variable for the FORALL index. */ /* Create a temporary variable for the FORALL index. */
tmp = gfc_typenode_for_spec (&sym->ts); tmp = gfc_typenode_for_spec (&sym->ts);
var[n] = gfc_create_var (tmp, sym->name); var[n] = gfc_create_var (tmp, sym->name);
gfc_shadow_sym (sym, var[n], &saved_vars[n]);
/* Record it in this_forall. */ /* Record it in this_forall. */
this_forall->var = var[n]; this_forall->var = var[n];
...@@ -2396,13 +2384,9 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) ...@@ -2396,13 +2384,9 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
c = c->next; c = c->next;
} }
/* Restore the index original backend_decl and the attribute. */ /* Restore the original index variables. */
for (fa = code->ext.forall_iterator, n=0; fa; fa = fa->next, n++) for (fa = code->ext.forall_iterator, n = 0; fa; fa = fa->next, n++)
{ gfc_restore_sym (fa->var->symtree->n.sym, &saved_vars[n]);
gfc_symbol *sym = fa->var->symtree->n.sym;
sym->backend_decl = saved_var_decl[n];
sym->attr = saved_var_attr[n];
}
/* Free the space for var, start, end, step, varexpr. */ /* Free the space for var, start, end, step, varexpr. */
gfc_free (var); gfc_free (var);
...@@ -2410,8 +2394,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) ...@@ -2410,8 +2394,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
gfc_free (end); gfc_free (end);
gfc_free (step); gfc_free (step);
gfc_free (varexpr); gfc_free (varexpr);
gfc_free (saved_var_decl); gfc_free (saved_vars);
gfc_free (saved_var_attr);
if (pmask) if (pmask)
{ {
......
...@@ -235,6 +235,16 @@ typedef struct gfc_loopinfo ...@@ -235,6 +235,16 @@ typedef struct gfc_loopinfo
} }
gfc_loopinfo; gfc_loopinfo;
/* Information about a symbol that has been shadowed by a temporary. */
typedef struct
{
symbol_attribute attr;
tree decl;
}
gfc_saved_var;
/* Advance the SS chain to the next term. */ /* Advance the SS chain to the next term. */
void gfc_advance_se_ss_chain (gfc_se *); void gfc_advance_se_ss_chain (gfc_se *);
...@@ -364,6 +374,12 @@ void gfc_build_builtin_function_decls (void); ...@@ -364,6 +374,12 @@ void gfc_build_builtin_function_decls (void);
/* Return the variable decl for a symbol. */ /* Return the variable decl for a symbol. */
tree gfc_get_symbol_decl (gfc_symbol *); tree gfc_get_symbol_decl (gfc_symbol *);
/* Substitute a temporary variable in place of the real one. */
void gfc_shadow_sym (gfc_symbol *, tree, gfc_saved_var *);
/* Restore the original variable. */
void gfc_restore_sym (gfc_symbol *, gfc_saved_var *);
/* Allocate the lang-spcific part of a decl node. */ /* Allocate the lang-spcific part of a decl node. */
void gfc_allocate_lang_decl (tree); void gfc_allocate_lang_decl (tree);
......
2004-05-30 Paul Brook <paul@codesourcery.com>
PR fortran/15620
* gfortran.fortran-torture/execute/st_function_1.f90: New test.
* gfortran.fortran-torture/execute/st_function_2.f90: New test.
2004-05-30 Steven G. Kargl <kargls@comcast.net> 2004-05-30 Steven G. Kargl <kargls@comcast.net>
* gfortran.fortran-torture/execute/random_1.f90: New test. * gfortran.fortran-torture/execute/random_1.f90: New test.
......
! Check that character valued statement functions honour length parameters
program st_function_1
character(8) :: foo
character(15) :: bar
character(6) :: p
character (7) :: s
foo(p) = p // "World"
bar(p) = p // "World"
! Expression longer than function, actual arg shorter than dummy.
call check (foo("Hello"), "Hello Wo")
! Expression shorter than function, actual arg longer than dummy.
! Result shorter than type
s = "Hello"
call check (bar(s), "Hello World ")
contains
subroutine check(a, b)
character (len=*) :: a, b
if ((a .ne. b) .or. (len(a) .ne. len(b))) call abort ()
end subroutine
end program
! PR15620
! Check that evaluating a statement function doesn't affect the value of
! its dummy argument variables.
program st_function_2
integer fn, a, b
fn(a, b) = a + b
if (foo(1) .ne. 43) call abort
! Check that values aren't modified when avaluating the arguments.
a = 1
b = 5
if (fn (b + 2, a + 3) .ne. 11) call abort
contains
function foo (x)
integer z, y, foo, x
bar(z) = z*z
z = 42
t = bar(x)
foo = t + z
end function
end program
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment