Re: [PATCH] Fortran: error recovery for invalid types in array constructors [PR107000]

2022-10-05 Thread Mikael Morin

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]

2022-10-05 Thread Mikael Morin

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]

2022-10-05 Thread Mikael Morin

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

2022-10-05 Thread Tobias Burnus

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

2022-10-05 Thread Tobias Burnus

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

2022-10-05 Thread Jakub Jelinek via Fortran
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]

2022-10-05 Thread Harald Anlauf via Fortran
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]

2022-10-05 Thread Harald Anlauf via Fortran
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