Re: [PATCH] Fortran: error recovery for invalid types in array constructors [PR107000]
Hello Le 04/10/2022 à 23:19, Harald Anlauf via Fortran a écrit : Dear all, we did not recover well from bad expressions in array constructors, especially when there was a typespec and a unary '+' or '-', and when the array constructor was used in an arithmetic expression. The attached patch introduces an ARITH_INVALID_TYPE that is used when we try to recover from these errors, and tries to handle all unary and binary arithmetic expressions. In the PR, you noted an inconsistency in the error message reported, depending on the presence or lack of an operator. I'm not sure you saw the suggestion to do the following in the last message I posted: diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc index e6e35ef3c42..ed93ddb2882 100644 --- a/gcc/fortran/arith.cc +++ b/gcc/fortran/arith.cc @@ -1654,6 +1654,8 @@ eval_intrinsic (gfc_intrinsic_op op, else rc = reduce_binary (eval.f3, op1, op2, &result); + if (rc == ARITH_INVALID_TYPE) +goto runtime; /* Something went wrong. */ if (op == INTRINSIC_POWER && rc == ARITH_PROHIBIT) In the testcase, it improves the situation slightly. For example, from: 9 | x = (1.0, 2.0) * [complex :: +'1'] ! { dg-error "Invalid type" } |1 Error: Invalid type in arithmetic operation at (1) to: 9 | x = (1.0, 2.0) * [complex :: +'1'] ! { dg-error "Invalid type" } | 1 Error: Operand of unary numeric operator ‘+’ at (1) is UNKNOWN or from: 29 | print *, 2 * [real :: 0, 1+'1'] ! { dg-error "Invalid type" } |1 Error: Invalid type in arithmetic operation at (1) to: 29 | print *, 2 * [real :: 0, 1+'1'] ! { dg-error "Invalid type" } | 1 Error: Operands of binary numeric operator ‘+’ at (1) are INTEGER(4)/CHARACTER(1) Unfortunately, it doesn't fix the bogus incommensurate arrays errors.
Re: [PATCH] Fortran: error recovery for invalid types in array constructors [PR107000]
Le 05/10/2022 à 10:51, Mikael Morin a écrit : Unfortunately, it doesn't fix the bogus incommensurate arrays errors. The following does. diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc index e6e35ef3c42..2c57c796270 100644 --- a/gcc/fortran/arith.cc +++ b/gcc/fortran/arith.cc @@ -1443,7 +1443,7 @@ reduce_binary_aa (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), gfc_replace_expr (c->expr, r); } - if (c || d) + if (rc == ARITH_OK && (c || d)) rc = ARITH_INCOMMENSURATE; if (rc != ARITH_OK) There is one last thing that I'm dissatisfied with. The handling of unknown types should be moved to reduce_binary, because the dispatching in reduce_binary doesn't handle EXPR_OP, so even if either or both operands are scalar, they are handled by the (array vs array) reduce_binary_aa function. That's confusing.
Re: [PATCH] Fortran: reject procedures and procedure pointers as output item [PR107074]
Hello Le 04/10/2022 à 21:27, Harald Anlauf via Fortran a écrit : Dear all, when looking at output item lists we didn't catch procedures and procedure pointers and ran into a gfc_internal_error(). Such items are not allowed by the Fortran standard, e.g. for procedure pointers there is C1233 (R1217) An expression that is an output-item shall not have a value that is a procedure pointer. Attached patch generates an error instead. Regtested on x86_64-pc-linux-gnu. OK for mainline? Please move the check to resolve_transfer in resolve.cc. Strangely, the patch doesn't seem to fix the problem on the testcase here. There is an outer parenthese expression preventing the condition you added from triggering. Can you double check? If we take the standard to the letter, only output items are forbidden, so a check is missing for writing context. I don't know how it can work for input items though, so maybe not worth it. In any case, the error shouldn't mention output items in reading context. Here is a variant of the testcase with procedure pointer components, that fails differently but can probably be caught as well. program p implicit none type :: t procedure(f), pointer, nopass :: b end type t type(t) :: a interface real function f() end function f end interface print *, merge (a%b, a%b, .true.) end
Re: [Patch] Fortran: Add OpenMP's assume(s) directives
Hi Jakub, On 04.10.22 14:58, Jakub Jelinek via Gcc-patches wrote: On Tue, Oct 04, 2022 at 02:26:13PM +0200, Tobias Burnus wrote: On Sun, Oct 02, 2022 at 07:47:18PM +0200, Tobias Burnus wrote: --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi OK? Ok, thanks. Committed as https://gcc.gnu.org/r13-3063-g8792047470073df0da4a5b91997d6058193d7676 Wouldn't this be better table driven (like c_omp_directives in c-family, though guess for Fortran you can just use spaces in the name, don't need 3 strings for the separate tokens)? Because I think absent/contains isn't the only spot where you need directive names, metadirective is another. Now added. I noted that I have different kinds/categories than you used in c-family/c-omp.c; and my impression that standalone vs. block vs delimited is a different category than informational/meta/... Maybe – I think there are already way to many string repetitions. One problem is that metadirectives permit combined/composite constructs while 'assume(s)' does not. I on purpose did not parse them, but probably in light of Metadirectives, I should. I will take a look. It is true that metadirective supports combined/composite constructs, and so do we in the C++ attribute case, still we IMHO can use the C/C++ table as is.and it doesn't need to include combined/composite constructs. The thing is that for the metadirective/C++ attribute case, all we need to know is to discover the directive category (declarative, stand-alone, construct, informational, ...) and for that it is enough to parse the first directive-name in combined/composite constructs. ... else if (popcount (old_n_absent) == 1) absent = ... sizeof() * (old_n_absent) * 2) Yeah. Or for 0 allocate say 8 and use (pow2p_hwi (old_n_absent) && old_n_absent >= 8) in the else if. I used now pow2p_hwi as popcount did not exist (and I didn't want to add an #include or use __builtin_popcount), not that either variant is clearer and it is neither performance critical nor is neither of "(x & -x) == x" and "popcount(x) == 1" slow. I don't understand the point of preallocation of gfc_omp_clauses here, ... That's now gone. As I have to check the duplication right after parsing – but before merging, I can no longer do it during resolution. Instead of keeping track of the directives separately, I now moved the checking to the directive parsing itself. It is not equivalent to that, because while we have the restriction that the same list item can't appear multiple times on the same directive, it can appear multiple times on multiple directives. I am not sure the handling of nested/repeated informational/declarative directives is very clear, but that's a separate issue. (Namely, OpenMP spec issue 3362.) Updated patch enclosed. And thanks for your comments! OK? Tobias - Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955 Fortran: Add OpenMP's assume(s) directives libgomp/ChangeLog: * libgomp.texi (OpenMP 5.1 Impl. Status): Mark 'assume' as 'Y'. gcc/fortran/ChangeLog: * dump-parse-tree.cc (show_omp_assumes): New. (show_omp_clauses, show_namespace): Call it. (show_omp_node, show_code_node): Handle OpenMP ASSUME. * gfortran.h (enum gfc_statement): Add ST_OMP_ASSUME, ST_OMP_END_ASSUME, ST_OMP_ASSUMES and ST_NOTHING. (gfc_exec_op): Add EXEC_OMP_ASSUME. (gfc_omp_assumptions): New struct. (gfc_get_omp_assumptions): New XCNEW #define. (gfc_omp_clauses, gfc_namespace): Add assume member. (gfc_resolve_omp_assumptions): New prototype. * match.h (gfc_match_omp_assume, gfc_match_omp_assumes): New. * openmp.cc (omp_code_to_statement): Forward declare. (enum gfc_omp_directive_kind, struct gfc_omp_directive): New. (gfc_free_omp_clauses): Free assume member and its struct data. (enum omp_mask2): Add OMP_CLAUSE_ASSUMPTIONS. (gfc_omp_absent_contains_clause): New. (gfc_match_omp_clauses): Call it; optionally use passed omp_clauses argument. (omp_verify_merge_absent_contains, gfc_match_omp_assume, gfc_match_omp_assumes, gfc_resolve_omp_assumptions): New. (resolve_omp_clauses): Call the latter. (gfc_resolve_omp_directive, omp_code_to_statement): Handle EXEC_OMP_ASSUME. * parse.cc (decode_omp_directive): Parse OpenMP ASSUME(S). (next_statement, parse_executable, parse_omp_structured_block): Handle ST_OMP_ASSUME. (case_omp_decl): Add ST_OMP_ASSUMES. (gfc_ascii_statement): Handle Assumes, optional return string without '!$OMP '/'!$ACC ' prefix. * parse.h (gfc_ascii_statement): Add optional bool arg to prototype. * resolve.cc (gfc_resolve_blocks, gfc_resolve_code): Add EXEC_OMP_ASSUME. (gfc_resolve): Resolve ASSUMES directive. * symbol.cc (gfc_free_namespace): Free omp_assumes member. * st.cc (gfc_free_statement): Handle EXEC_OMP_ASSUME. * trans-openmp.cc (gfc_trans_omp_directive)
Re: [Patch] Fortran: Add OpenMP's assume(s) directives
Minor update to just posted patch: the table did not revert all strings where a substring directive name existed, i.e. 'target' vs. 'target update', 'assume' vs. 'assumes'. Now fixed. Otherwise unchanged: Tobias On 05.10.22 13:19, Tobias Burnus wrote: Hi Jakub, On 04.10.22 14:58, Jakub Jelinek via Gcc-patches wrote: On Tue, Oct 04, 2022 at 02:26:13PM +0200, Tobias Burnus wrote: On Sun, Oct 02, 2022 at 07:47:18PM +0200, Tobias Burnus wrote: --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi OK? Ok, thanks. Committed as https://gcc.gnu.org/r13-3063-g8792047470073df0da4a5b91997d6058193d7676 Wouldn't this be better table driven (like c_omp_directives in c-family, though guess for Fortran you can just use spaces in the name, don't need 3 strings for the separate tokens)? Because I think absent/contains isn't the only spot where you need directive names, metadirective is another. Now added. I noted that I have different kinds/categories than you used in c-family/c-omp.c; and my impression that standalone vs. block vs delimited is a different category than informational/meta/... Maybe – I think there are already way to many string repetitions. One problem is that metadirectives permit combined/composite constructs while 'assume(s)' does not. I on purpose did not parse them, but probably in light of Metadirectives, I should. I will take a look. It is true that metadirective supports combined/composite constructs, and so do we in the C++ attribute case, still we IMHO can use the C/C++ table as is.and it doesn't need to include combined/composite constructs. The thing is that for the metadirective/C++ attribute case, all we need to know is to discover the directive category (declarative, stand-alone, construct, informational, ...) and for that it is enough to parse the first directive-name in combined/composite constructs. ... else if (popcount (old_n_absent) == 1) absent = ... sizeof() * (old_n_absent) * 2) Yeah. Or for 0 allocate say 8 and use (pow2p_hwi (old_n_absent) && old_n_absent >= 8) in the else if. I used now pow2p_hwi as popcount did not exist (and I didn't want to add an #include or use __builtin_popcount), not that either variant is clearer and it is neither performance critical nor is neither of "(x & -x) == x" and "popcount(x) == 1" slow. I don't understand the point of preallocation of gfc_omp_clauses here, ... That's now gone. As I have to check the duplication right after parsing – but before merging, I can no longer do it during resolution. Instead of keeping track of the directives separately, I now moved the checking to the directive parsing itself. It is not equivalent to that, because while we have the restriction that the same list item can't appear multiple times on the same directive, it can appear multiple times on multiple directives. I am not sure the handling of nested/repeated informational/declarative directives is very clear, but that's a separate issue. (Namely, OpenMP spec issue 3362.) Updated patch enclosed. And thanks for your comments! OK? Tobias - Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955 Fortran: Add OpenMP's assume(s) directives libgomp/ChangeLog: * libgomp.texi (OpenMP 5.1 Impl. Status): Mark 'assume' as 'Y'. gcc/fortran/ChangeLog: * dump-parse-tree.cc (show_omp_assumes): New. (show_omp_clauses, show_namespace): Call it. (show_omp_node, show_code_node): Handle OpenMP ASSUME. * gfortran.h (enum gfc_statement): Add ST_OMP_ASSUME, ST_OMP_END_ASSUME, ST_OMP_ASSUMES and ST_NOTHING. (gfc_exec_op): Add EXEC_OMP_ASSUME. (gfc_omp_assumptions): New struct. (gfc_get_omp_assumptions): New XCNEW #define. (gfc_omp_clauses, gfc_namespace): Add assume member. (gfc_resolve_omp_assumptions): New prototype. * match.h (gfc_match_omp_assume, gfc_match_omp_assumes): New. * openmp.cc (omp_code_to_statement): Forward declare. (enum gfc_omp_directive_kind, struct gfc_omp_directive): New. (gfc_free_omp_clauses): Free assume member and its struct data. (enum omp_mask2): Add OMP_CLAUSE_ASSUMPTIONS. (gfc_omp_absent_contains_clause): New. (gfc_match_omp_clauses): Call it; optionally use passed omp_clauses argument. (omp_verify_merge_absent_contains, gfc_match_omp_assume, gfc_match_omp_assumes, gfc_resolve_omp_assumptions): New. (resolve_omp_clauses): Call the latter. (gfc_resolve_omp_directive, omp_code_to_statement): Handle EXEC_OMP_ASSUME. * parse.cc (decode_omp_directive): Parse OpenMP ASSUME(S). (next_statement, parse_executable, parse_omp_structured_block): Handle ST_OMP_ASSUME. (case_omp_decl): Add ST_OMP_ASSUMES. (gfc_ascii_statement): Handle Assumes, optional return string without '!$OMP '/'!$ACC ' prefix. * parse.h (gfc_ascii_statement): Add optional bool arg to prototype. * resolve.cc (gfc_re
Re: [Patch] Fortran: Add OpenMP's assume(s) directives
On Wed, Oct 05, 2022 at 02:29:56PM +0200, Tobias Burnus wrote: > + gfc_error ("!OMP ASSUMES at %C must be in the specification part of a " s/!OMP/!$OMP/ Otherwise LGTM. Jakub
Re: [PATCH, v2] Fortran: reject procedures and procedure pointers as IO element [PR107074]
Hi Mikael, > Gesendet: Mittwoch, 05. Oktober 2022 um 12:34 Uhr > Von: "Mikael Morin" > Please move the check to resolve_transfer in resolve.cc. I have done this, see attached updated patch. Regtests cleanly on x86_64-pc-linux-gnu. > Strangely, the patch doesn't seem to fix the problem on the testcase > here. There is an outer parenthese expression preventing the condition > you added from triggering. Can you double check? You are right: I had a one-liner in my worktree from PR105371 that fixes an issue with gfc_simplify_merge and that seems to help here. It is now included. > If we take the standard to the letter, only output items are forbidden, > so a check is missing for writing context. I don't know how it can work > for input items though, so maybe not worth it. In any case, the error > shouldn't mention output items in reading context. > > Here is a variant of the testcase with procedure pointer components, > that fails differently but can probably be caught as well. > > program p >implicit none >type :: t > procedure(f), pointer, nopass :: b >end type t >type(t) :: a > >interface > real function f() > end function f >end interface > >print *, merge (a%b, a%b, .true.) > end I hadn't thought about this, and found a solution that also fixes this one. Great example! This is now an additional test. OK for mainline? And thanks for your comments! Harald From 70cba7da18023282546b9a5d80e976fc3744d732 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Wed, 5 Oct 2022 22:25:14 +0200 Subject: [PATCH] Fortran: reject procedures and procedure pointers as IO element [PR107074] gcc/fortran/ChangeLog: PR fortran/107074 * resolve.cc (resolve_transfer): A procedure, type-bound procedure or a procedure pointer cannot be an element of an IO list. * simplify.cc (gfc_simplify_merge): Do not try to reset array lower bound for scalars. gcc/testsuite/ChangeLog: PR fortran/107074 * gfortran.dg/pr107074.f90: New test. * gfortran.dg/pr107074b.f90: New test. --- gcc/fortran/resolve.cc | 31 + gcc/fortran/simplify.cc | 3 ++- gcc/testsuite/gfortran.dg/pr107074.f90 | 11 + gcc/testsuite/gfortran.dg/pr107074b.f90 | 18 ++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/pr107074.f90 create mode 100644 gcc/testsuite/gfortran.dg/pr107074b.f90 diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index d133bc2d034..d9d101775f6 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -10137,6 +10137,37 @@ resolve_transfer (gfc_code *code) "an assumed-size array", &code->loc); return; } + + /* Check for procedures and procedure pointers. Fortran 2018 has: + + C1233 (R1217) An expression that is an output-item shall not have a + value that is a procedure pointer. + + There does not appear any reason to allow procedure pointers for + input, so we disallow them generally, and we reject procedures. */ + + if (exp->expr_type == EXPR_VARIABLE) +{ + /* Check for type-bound procedures. */ + for (ref = exp->ref; ref; ref = ref->next) + if (ref->type == REF_COMPONENT + && ref->u.c.component->attr.flavor == FL_PROCEDURE) + break; + + /* Procedure or procedure pointer? */ + if (exp->ts.type == BT_PROCEDURE + || (ref && ref->u.c.component->attr.flavor == FL_PROCEDURE)) + { + if (exp->symtree->n.sym->attr.proc_pointer + || (ref && ref->u.c.component->attr.proc_pointer)) + gfc_error ("Data transfer element at %L cannot be a procedure " + "pointer", &code->loc); + else + gfc_error ("Data transfer element at %L cannot be a procedure", + &code->loc); + return; + } +} } diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc index 6ac92cf9db8..f0482d349af 100644 --- a/gcc/fortran/simplify.cc +++ b/gcc/fortran/simplify.cc @@ -4915,7 +4915,8 @@ gfc_simplify_merge (gfc_expr *tsource, gfc_expr *fsource, gfc_expr *mask) { result = gfc_copy_expr (mask->value.logical ? tsource : fsource); /* Parenthesis is needed to get lower bounds of 1. */ - result = gfc_get_parentheses (result); + if (result->rank) + result = gfc_get_parentheses (result); gfc_simplify_expr (result, 1); return result; } diff --git a/gcc/testsuite/gfortran.dg/pr107074.f90 b/gcc/testsuite/gfortran.dg/pr107074.f90 new file mode 100644 index 000..1363c285912 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr107074.f90 @@ -0,0 +1,11 @@ +! { dg-do compile } +! PR fortran/107074 - ICE: Bad IO basetype (8) +! Contributed by G.Steinmetz + +program p + implicit none + integer, external:: a + procedure(real), pointer :: b + print *, merge (a, a, .true.) ! { dg-error "procedure" } + print *, merge (b, b, .true.) ! { dg-error "procedure pointer" } +end diff --git a/gcc/testsuite/gfortran.dg/pr107074b.f90
Re: [PATCH, v2] Fortran: error recovery for invalid types in array constructors [PR107000]
Hi Mikael, > Gesendet: Mittwoch, 05. Oktober 2022 um 11:23 Uhr > Von: "Mikael Morin" > An: "Harald Anlauf" , "fortran" , > "gcc-patches" > Betreff: Re: [PATCH] Fortran: error recovery for invalid types in array > constructors [PR107000] > The following does. > > > diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc > index e6e35ef3c42..2c57c796270 100644 > --- a/gcc/fortran/arith.cc > +++ b/gcc/fortran/arith.cc > @@ -1443,7 +1443,7 @@ reduce_binary_aa (arith (*eval) (gfc_expr *, > gfc_expr *, gfc_expr **), > gfc_replace_expr (c->expr, r); > } > > - if (c || d) > + if (rc == ARITH_OK && (c || d)) > rc = ARITH_INCOMMENSURATE; > > if (rc != ARITH_OK) that's great! It fixes several rather weird cases. (There is at least another PR on the incommensurate arrays, but we should not attempt to fix everything today.) > There is one last thing that I'm dissatisfied with. > The handling of unknown types should be moved to reduce_binary, because > the dispatching in reduce_binary doesn't handle EXPR_OP, so even if > either or both operands are scalar, they are handled by the (array vs > array) reduce_binary_aa function. That's confusing. Do you have an example? Anyway, please find attached an updated patch that incorporates your two changes and regtests fine on x86_64-pc-linux-gnu. Even if you disagree, I think this is really a significant step forwards... (error-recovery wise). OK for mainline? Thanks, Harald From 1b40214b2b538ec176ff6c118770e6e1cc8796ae Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Tue, 4 Oct 2022 23:04:06 +0200 Subject: [PATCH] Fortran: error recovery for invalid types in array constructors [PR107000] gcc/fortran/ChangeLog: PR fortran/107000 * arith.cc (gfc_arith_error): Define error message for ARITH_INVALID_TYPE. (reduce_unary): Catch arithmetic expressions with invalid type. (reduce_binary_ac): Likewise. (reduce_binary_ca): Likewise. (reduce_binary_aa): Likewise. (eval_intrinsic): Likewise. (gfc_real2complex): Source expression must be of type REAL. * gfortran.h (enum arith): Add ARITH_INVALID_TYPE. gcc/testsuite/ChangeLog: PR fortran/107000 * gfortran.dg/pr107000.f90: New test. Co-authored-by: Mikael Morin --- gcc/fortran/arith.cc | 23 +++- gcc/fortran/gfortran.h | 2 +- gcc/testsuite/gfortran.dg/pr107000.f90 | 50 ++ 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr107000.f90 diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc index d57059a375f..2c57c796270 100644 --- a/gcc/fortran/arith.cc +++ b/gcc/fortran/arith.cc @@ -118,6 +118,9 @@ gfc_arith_error (arith code) case ARITH_WRONGCONCAT: p = G_("Illegal type in character concatenation at %L"); break; +case ARITH_INVALID_TYPE: + p = G_("Invalid type in arithmetic operation at %L"); + break; default: gfc_internal_error ("gfc_arith_error(): Bad error code"); @@ -1261,6 +1264,9 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), gfc_expr *op, gfc_expr *r; arith rc; + if (op->expr_type == EXPR_OP && op->ts.type == BT_UNKNOWN) +return ARITH_INVALID_TYPE; + if (op->expr_type == EXPR_CONSTANT) return eval (op, result); @@ -1302,6 +1308,9 @@ reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), gfc_expr *r; arith rc = ARITH_OK; + if (op1->expr_type == EXPR_OP && op1->ts.type == BT_UNKNOWN) +return ARITH_INVALID_TYPE; + head = gfc_constructor_copy (op1->value.constructor); for (c = gfc_constructor_first (head); c; c = gfc_constructor_next (c)) { @@ -1354,6 +1363,9 @@ reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), gfc_expr *r; arith rc = ARITH_OK; + if (op2->expr_type == EXPR_OP && op2->ts.type == BT_UNKNOWN) +return ARITH_INVALID_TYPE; + head = gfc_constructor_copy (op2->value.constructor); for (c = gfc_constructor_first (head); c; c = gfc_constructor_next (c)) { @@ -1414,6 +1426,10 @@ reduce_binary_aa (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), if (!gfc_check_conformance (op1, op2, _("elemental binary operation"))) return ARITH_INCOMMENSURATE; + if ((op1->expr_type == EXPR_OP && op1->ts.type == BT_UNKNOWN) + || (op2->expr_type == EXPR_OP && op2->ts.type == BT_UNKNOWN)) +return ARITH_INVALID_TYPE; + head = gfc_constructor_copy (op1->value.constructor); for (c = gfc_constructor_first (head), d = gfc_constructor_first (op2->value.constructor); @@ -1427,7 +1443,7 @@ reduce_binary_aa (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), gfc_replace_expr (c->expr, r); } - if (c || d) + if (rc == ARITH_OK && (c || d)) rc = ARITH_INCOMMENSURATE; if (rc != ARITH_OK) @@ -1638,6 +1654,8 @@ eval_intrinsic (gfc_intrinsic_op op, else rc = reduce_binary (eval.f3, op1, op2, &result); + if (rc == ARITH_INVALID_TYPE) +goto runtime; /* Somet