Hi Andre,

Thanks for all these comments, aka early review:


>
> +  if (formal->sym->attr.allocatable || formal->sym->attr.allocatable
> +      || formal->sym->attr.pointer || formal->sym->attr.pointer
> +      || formal->sym->attr.optional || formal->sym->attr.optional
> +      || formal->sym->ts.type == BT_CLASS || formal->sym->ts.type ==
> BT_CLASS)
> +    {
> +      gfc_error ("Each argument of OPERATION at %L shall be a scalar, "
> +                "non-allocatable, non-pointer, non-polymorphic and "
> +                "nonoptional", &operation->where);
> +      return false;
> +    }
>
> and then again (in the third next if) in:
>
> +  if (formal->sym->attr.optional || formal->next->sym->attr.optional)
> +    {
> +      gfc_error ("The function passed as OPERATION at %L shall not have
> the "
> +                "OPTIONAL attribute for either of the arguments",
> +                &operation->where);
> +      return false;
> +    }
>
> Testing ones should be enough, right?
>

Good spot - thanks.


> I don't like the code repetition in
>
> +  if (array->ts.type == BT_CHARACTER)
> +    {
> +      gfc_charlen *cl;
> +      unsigned long actual_size, formal_size1, formal_size2, result_size;
> +
> +      cl = array->ts.u.cl;
> +      actual_size = cl && cl->length && cl->length->expr_type ==
> EXPR_CONSTANT
> +                    ? mpz_get_ui (cl->length->value.integer) : 0;
> +
> +      cl = formal->sym->ts.u.cl;
> +      formal_size1 = cl && cl->length && cl->length->expr_type ==
> EXPR_CONSTANT
> +                    ? mpz_get_ui (cl->length->value.integer) : 0;
> +
> +      cl = formal->next->sym->ts.u.cl;
> +      formal_size2 = cl && cl->length && cl->length->expr_type ==
> EXPR_CONSTANT
> +                    ? mpz_get_ui (cl->length->value.integer) : 0;
> +
> +      cl = sym->ts.u.cl;
> +      result_size = cl && cl->length && cl->length->expr_type ==
> EXPR_CONSTANT
> +                   ? mpz_get_ui (cl->length->value.integer) : 0;
> +
>

Copied and pasted directly from elsewhere in check.cc :-)


>
> either use function for evaluating the constant cl or how about this
> modern C++:
>
> +  if (array->ts.type == BT_CHARACTER)
> +    {
> +      unsigned long actual_size, formal_size1, formal_size2, result_size;
> +      auto get_cst_cl = [](const gfc_charlen *cl) -> unsigned log {
> +          return cl && cl->length && cl->length->expr_type ==
> EXPR_CONSTANT
> +                    ? mpz_get_ui (cl->length->value.integer) : 0;
> +      };
> +
> +      actual_size = get_cst_cl (array->ts.u.cl);
> +
> +      formal_size1 = get_cst_cl (formal->sym->ts.u.cl);
> +
> +      formal_size2 = get_cst_cl (formal->next->sym->ts.u.cl);
> +
> +      result_size = get_cst_cl (sym->ts.u.cl);
>
> I think the above is easier to maintain and read. Whether you use the
> lambda or
> a dedicated function I leave to your liking.
>

Thanks for the suggestion - I'll do "elsewhere" as well!


> In
> +static gfc_symtree *
> +generate_reduce_op_wrapper (gfc_expr *op)
> +{
> +  gfc_symbol *operation = op->symtree->n.sym;
> +  gfc_symbol *wrapper, *a, *b, *c;
> +  gfc_symtree *st;
> +  char tname[GFC_MAX_SYMBOL_LEN+1];
> +  char *name;
> +  gfc_namespace *ns;
> +//  gfc_gsymbol *gsym = NULL;
>
> ^^^ Is this needed?
>

No, it's one of the commented out bits that I mentioned and will be
eliminated.


>
> @@ -8785,6 +8801,12 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol *
> sym,
>           gfc_add_expr_to_block (&se->pre, tmp);
>         }
>      }
> +  else if (scalar_reduce)
> +    {
> +      gfc_add_expr_to_block (&se->pre, se->expr);
> +      se->expr = result;
> +//      gfc_add_block_to_block (&se->post, &post);
>
> ^^^ I'd rather uncomment it to be safe in the future, if something is in
> post.
>

That is necessarily removed to deal with an 'array' type with allocatable
components. Adding post causes double frees because the wrapper already
does the job.


>
>
> --- a/gcc/fortran/trans-intrinsic.cc
> +++ b/gcc/fortran/trans-intrinsic.cc
> @@ -4250,6 +4250,20 @@ gfc_get_symbol_for_expr (gfc_expr * expr, bool
> ignore_optional) sym->attr.proc = PROC_INTRINSIC;
>    sym->attr.flavor = FL_PROCEDURE;
>    sym->result = sym;
> +#if 0
> +  if (expr->value.function.isym
> +      && expr->value.function.isym->id == GFC_ISYM_REDUCE)
> +    {
> +      if (expr->value.function.actual
> +         && expr->value.function.actual->next
> +         && expr->value.function.actual->next->next
> +         && expr->value.function.actual->next->next->expr == NULL)
> +       expr->rank = 0;
> +      else if (expr->value.function.actual
> +              && expr->value.function.actual->expr)
> +       expr->rank = expr->value.function.actual->expr->rank - 1;
> +    }
> +#endif
>

Also to be eliminated - was part of an earlier attempt at implementation.


>
> Er?
>
> Typo in Change.Logs
>
> s/discription/description/
>

:-)


>
> That Changelog looks non-standard.
>
> Ok, I hope this first feedback is valuable to you.
>
> One other question: How does REDUCE() relate to CO_REDUCE()?
>
> That's a good question. CO_REDUCE was already implemented by Tobias(?) but
I am not sure if it is complete, nor have I looked at the definition in the
standard.

Thanks a lot. It's very helpful to have another pair of eyes cast over the
patch at this stage.

Paul

Reply via email to