[Patch, fortran, PR44672, v6] [F08] ALLOCATE with SOURCE and no array-spec

Mikael Morin mikael.morin@sfr.fr
Tue Jun 2 16:52:00 GMT 2015


Hello Andre,

comments below (out of order, sorry).

Le 29/05/2015 13:46, Andre Vehreschild a écrit :
> Hi Mikael,
> 
> comments inline below:
> 
> On Thu, 28 May 2015 20:06:57 +0200
> Mikael Morin <mikael.morin@sfr.fr> wrote:
> 
>> Le 28/05/2015 17:29, Andre Vehreschild a écrit :
>>> *************** resolve_allocate_expr (gfc_expr *e, gfc_
>>> *** 7103,7112 ****
>>> --- 7103,7123 ----
>>>     if (!ref2 || ref2->type != REF_ARRAY || ref2->u.ar.type == AR_FULL
>>>         || (dimension && ref2->u.ar.dimen == 0))
>>>       {
>>> +       /* F08:C633.  */
>>> +       if (code->expr3)
>>> + 	{
>>> + 	  if (!gfc_notify_std (GFC_STD_F2008, "Array specification
>>> required "
>>> + 			       "in ALLOCATE statement at %L", &e->where))
>>> + 	    goto failure;
>>> + 	  *array_alloc_wo_spec = true;
>>> + 	}
>>> +       else
>>> + 	{
>>>   	  gfc_error ("Array specification required in ALLOCATE statement "
>>>   		     "at %L", &e->where);
>>>   	  goto failure;
>>>   	}
>>> +     }
>>>   
>>>     /* Make sure that the array section reference makes sense in the
>>>        context of an ALLOCATE specification.  */
>> I think we can be a little be more user friendly with the gfc_notify_std
>> error message.
>> Something like:
>> ALLOCATE without array spec at %L
>> ALLOCATE with array bounds determined from SOURCE or MOLD at %L
> 
> I didn't want to mess with the error messages to prevent issues for
> translations. So how is the policy on this? 
> 
I'm not aware of any policy regarding translations.
With a message like:
	fortran 2008: array specification required ...
I don't see how the user can understand that the array specification is
_not_ required with fortran 2008, regardless of translations.
I'm rather in favour of not having misleading diagnostic, even if
correctly translated.

--------

>>> *************** gfc_array_init_size (tree descriptor, in
>>> *** 5076,5085 ****
>>>   
>>>         /* Set upper bound.  */
>>>         gfc_init_se (&se, NULL);
>>>         gcc_assert (ubound);
>>>         gfc_conv_expr_type (&se, ubound, gfc_array_index_type);
>>>         gfc_add_block_to_block (pblock, &se.pre);
>>> ! 
>>>         gfc_conv_descriptor_ubound_set (descriptor_block, descriptor,
>>>   				      gfc_rank_cst[n], se.expr);
>>>         conv_ubound = se.expr;
>>> --- 5087,5111 ----
>>>   
>>>         /* Set upper bound.  */
>>>         gfc_init_se (&se, NULL);
>>> +       if (expr3_desc != NULL_TREE)
>>> + 	{
>>> + 	  /* Set the upper bound to be (desc.ubound - desc.lbound)+ 1.  */
>>> + 	  tmp = fold_build2_loc (input_location, MINUS_EXPR,
>>> + 				 gfc_array_index_type,
>>> + 				 gfc_conv_descriptor_ubound_get (
>>> + 				   expr3_desc, gfc_rank_cst[n]),
>>> + 				 gfc_conv_descriptor_lbound_get (
>>> + 				   expr3_desc, gfc_rank_cst[n]));
>>> + 	  se.expr = fold_build2_loc (input_location, PLUS_EXPR,
>>> + 				     gfc_array_index_type, tmp,
>>> + 				     gfc_index_one_node);
>>> + 	}
>>> +       else
>>> + 	{
>>>   	  gcc_assert (ubound);
>>>   	  gfc_conv_expr_type (&se, ubound, gfc_array_index_type);
>>>   	  gfc_add_block_to_block (pblock, &se.pre);
>>> ! 	}
>>>         gfc_conv_descriptor_ubound_set (descriptor_block, descriptor,
>>>   				      gfc_rank_cst[n], se.expr);
>>>         conv_ubound = se.expr;
>> Your one-based-ness problem was here, wasn't it?
> 
> Correct.
> 
>> I would rather copy directly lbound and ubound from expr3_desc to
>> descriptor.
> 
> It was that way in the previous version of the patch, which does *not* work any
> longer. When gfc_trans_allocate () is responsible for the creating a temporary
> variable for the source=-expression, then it does so using zero based
> expressions. 
> 
>> If the source has non-one-based bounds, the above would produce wrong
>> bounds.
> 
> Counterexample? Note, the expr3_desc is guaranteed to be an artificial variable
> created by conv_expr_descriptor, aka zero-based.
> 
here is a counterexample.

	  integer, dimension(:), allocatable :: a, b

	  allocate (a(0:3))
	  allocate (b, source = a)
	  print *, lbound(a, 1), ubound(a, 1)
	  print *, lbound(b, 1), ubound(b, 1)
	end

output:
	0	3
	1	4


I think that if you set se.expr with
ubound with gfc_conv_descriptor_ubound_get(...) instead of what you do
above, and se.expr with gfc_conv_descriptor_lbound_get(...) instead of
gfc_index_one_node in the hunk before, it should work.

--------

> <snipp>
> 
>>> *************** gfc_trans_allocate (gfc_code * code)
>>> *** 5229,5235 ****
>>>   	    }
>>>   	  else
>>>   	    tmp = se.expr;
>>> ! 	  if (!code->expr3->mold)
>>>   	    expr3 = tmp;
>>>   	  else
>>>   	    expr3_tmp = tmp;
>>> --- 5240,5248 ----
>>>   	    }
>>>   	  else
>>>   	    tmp = se.expr;
>>> ! 	  if (code->ext.alloc.arr_spec_from_expr3)
>>> ! 	    expr3_desc = tmp;
>>> ! 	  else if (!code->expr3->mold)
>>>   	    expr3 = tmp;
>>>   	  else
>>>   	    expr3_tmp = tmp;
>> Couldn't expr3 be reused?
>> We had code->expr3, expr3, expr3rhs, and now this is adding expr3_desc,
>> and (below) inexpr3. :-(
> 
> Of course can we use just two variables for all expressions. I have removed the
> expr3_tmp, inexpr3 and expr3_desc and introduced a e3_is enumeration, which
> stores which kind the expr3 is, aka unset, source, mold, desc. This makes the
> code simpler at some places.
> 
I have thought some more about the code not distinguishing source vs mold.
It seems to me that it makes sense to _not_ distinguish, and what you do
with e3_is == E3_MOLD seems bogus to me.  For example:

> @@ -5391,6 +5398,12 @@ gfc_trans_allocate (gfc_code * code)
>  	}
>        gcc_assert (expr3_esize);
>        expr3_esize = fold_convert (sizetype, expr3_esize);
> +      if (e3_is == E3_MOLD)
> +	{
> +	  /* The expr3 is no longer valid after this point.  */
> +	  expr3 = NULL_TREE;
> +	  e3_is = E3_UNSET;
> +	}
>      }
>    else if (code->ext.alloc.ts.type != BT_UNKNOWN)
>      {
You forget about the descriptor you have just created?!?

--------

About e3_is, I'm not very fond of it, and I think it can be replaced
using...
> +      e3_is = expr3 != NULL_TREE ?
> +	    (code->ext.alloc.arr_spec_from_expr3 ?
> +	       E3_DESC
> +	     : (code->expr3->mold ? E3_MOLD : E3_SOURCE))
> +	  : E3_UNSET;
>  
... the conditions defining it above directly.
That is replace e3_is == E3_DESC with
code->ext.alloc.arr_spec_from_expr3, etc.

--------

> @@ -5035,6 +5036,11 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
>  
>    or_expr = boolean_false_node;
>  
> +  /* When expr3_desc is set, use its rank, because we want to allocate an
> +     array with the array_spec coming from source=.  */
> +  if (expr3_desc != NULL_TREE)
> +    rank = GFC_TYPE_ARRAY_RANK (TREE_TYPE (expr3_desc));
> +
>    for (n = 0; n < rank; n++)
>      {
>        tree conv_lbound;
This overrides the rank passed as argument.
Instead of this, calculate the correct rank...

> @@ -5338,10 +5392,11 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg,
>    overflow = integer_zero_node;
>  
>    gfc_init_block (&set_descriptor_block);
> -  size = gfc_array_init_size (se->expr, ref->u.ar.as->rank,
> +  size = gfc_array_init_size (se->expr, alloc_w_e3_arr_spec ? expr->rank
> +							   : ref->u.ar.as->rank,
... here.  Wasn't it correct already by the way?

--------

> @@ -5174,25 +5174,26 @@ gfc_trans_allocate (gfc_code * code)
>  	{
>  	  if (!code->expr3->mold
>  	      || code->expr3->ts.type == BT_CHARACTER
> -	      || vtab_needed)
> +	      || vtab_needed
> +	      || code->ext.alloc.arr_spec_from_expr3)
>  	    {
>  	      /* Convert expr3 to a tree.  */
>  	      gfc_init_se (&se, NULL);
> -	      /* For all "simple" expression just get the descriptor or the
> -		 reference, respectively, depending on the rank of the expr.  */
> -	      if (code->expr3->rank != 0)
> +	      /* For all "simple" expression just get the descriptor
> +		 or the reference, respectively, depending on the
> +		 rank of the expr.  */
> +	      if (code->ext.alloc.arr_spec_from_expr3 || code->expr3->rank != 0)
Hum, why this change?
Are there cases where arr_spec_from_expr3 is set and code->expr3->rank == 0?
And do you really want to call gfc_conv_expr_descriptor in such a case?

>  		gfc_conv_expr_descriptor (&se, code->expr3);
>  	      else
>  		gfc_conv_expr_reference (&se, code->expr3);
> -	      if (!code->expr3->mold)
> -		expr3 = se.expr;
> -	      else
> -		expr3_tmp = se.expr;
> +	      /* Create a temp variable only for component refs.  */
> +	      temp_var_needed = TREE_CODE (se.expr) == COMPONENT_REF;
Why only component refs?

>  	      expr3_len = se.string_length;
>  	      gfc_add_block_to_block (&block, &se.pre);
>  	      gfc_add_block_to_block (&post, &se.post);
>  	    }
> -	  /* else expr3 = NULL_TREE set above.  */
> +	  else
> +	    se.expr = NULL_TREE;
>  	}
>        else
>  	{

--------

> diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
> index 9be8a42..3916836 100644
> --- a/gcc/fortran/trans-expr.c
> +++ b/gcc/fortran/trans-expr.c
> @@ -5328,7 +5328,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
>        if (e && (e->ts.type == BT_DERIVED || e->ts.type == BT_CLASS)
>  	    && e->ts.u.derived->attr.alloc_comp
>  	    && !(e->symtree && e->symtree->n.sym->attr.pointer)
> -	    && (e->expr_type != EXPR_VARIABLE && !e->rank))
> +	    && e->expr_type != EXPR_VARIABLE && !e->rank)
>          {
>  	  int parm_rank;
>  	  tmp = build_fold_indirect_ref_loc (input_location,
You don't change it, so don't touch it.

> Attached is a new version of the patch. This one fails
> allocate_with_source_3.f90 on runtime, where I don't see the issue currently.
> May be you have some luck and time. If not I will investigate on Monday.
> 
I haven't looked at it yet.  Tomorrow maybe.

Thanks for your patience so far.

Mikael



More information about the Gcc-patches mailing list