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