diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc index 8c4571e0aa6..ba7fb5dfea5 100644 --- a/gcc/fortran/interface.cc +++ b/gcc/fortran/interface.cc @@ -4616,6 +4616,35 @@ build_compcall_for_operator (gfc_expr* e, gfc_actual_arglist* actual, } +/* Check if the type of an actual argument is OK to use with an + unlimited polymorphic formal argument in a defined operation. */ + +static bool +upoly_ok (bt type, gfc_intrinsic_op op) +{ + bool ok = false; + if (type == BT_DERIVED || type == BT_CLASS) + ok = true; + else if ((op >= INTRINSIC_UPLUS && op <= INTRINSIC_POWER) + && (type == BT_LOGICAL || type == BT_CHARACTER)) + ok = true; + else if ((op == INTRINSIC_CONCAT) && (type != BT_CHARACTER)) + ok = true; + else if ((op >= INTRINSIC_GT && op <= INTRINSIC_LE) + && (type == BT_COMPLEX)) + ok = true; + else if ((op >= INTRINSIC_GT_OS) && (op <= INTRINSIC_LE_OS) + && (type == BT_COMPLEX)) + ok = true; + else if ((op >= INTRINSIC_AND) && (op <= INTRINSIC_NEQV) + && (type != BT_LOGICAL)) + ok = true; + else if ((op == INTRINSIC_NOT) && (type != BT_LOGICAL)) + ok = true; + return ok; +} + + /* This subroutine is called when an expression is being resolved. The expression node in question is either a user defined operator or an intrinsic operator with arguments that aren't compatible @@ -4737,6 +4766,24 @@ gfc_extend_expr (gfc_expr *e) if (sym != NULL) break; } + + /* F2018(15.4.3.4.2): "If the operator is an intrinsic-operator (R608), + the number of dummy arguments shall be consistent with the intrinsic + uses of that operator, and the types, kind type parameters, or ranks + of the dummy arguments shall differ from those required for the + intrinsic operation (10.1.5)." ie. the use of unlimited polymorphic + formal arguments must not override the intrinsic uses. */ + if (sym && (UNLIMITED_POLY (sym->formal->sym) + || (sym->formal->next + && UNLIMITED_POLY (sym->formal->next->sym)))) + { + bool arg2 = (actual->next != NULL); + bool a1ok = upoly_ok (actual->expr->ts.type, e->value.op.op); + bool a2ok = arg2 && upoly_ok (actual->next->expr->ts.type, + e->value.op.op); + if ((!arg2 && !a1ok) || (arg2 && (!a1ok && !a2ok))) + sym = NULL; + } } /* TODO: Do an ambiguity-check and error if multiple matching interfaces are