[gcc r14-10291] Fortran: fix ALLOCATE with SOURCE=, zero-length character [PR83865]

2024-06-08 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:c3e16edcf2c8429da2cb479d8941397f4300e0c4

commit r14-10291-gc3e16edcf2c8429da2cb479d8941397f4300e0c4
Author: Harald Anlauf 
Date:   Mon Jun 3 22:02:06 2024 +0200

Fortran: fix ALLOCATE with SOURCE=, zero-length character [PR83865]

gcc/fortran/ChangeLog:

PR fortran/83865
* trans-stmt.cc (gfc_trans_allocate): Restrict special case for
source-expression with zero-length character to rank 0, so that
the array shape is not discarded.

gcc/testsuite/ChangeLog:

PR fortran/83865
* gfortran.dg/allocate_with_source_32.f90: New test.

(cherry picked from commit 7f21aee0d4ef95eee7d9f7f42e9a056715836648)

Diff:
---
 gcc/fortran/trans-stmt.cc  |  3 +-
 .../gfortran.dg/allocate_with_source_32.f90| 33 ++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc
index d355009fa5e..87dd833872a 100644
--- a/gcc/fortran/trans-stmt.cc
+++ b/gcc/fortran/trans-stmt.cc
@@ -6449,8 +6449,9 @@ gfc_trans_allocate (gfc_code * code, gfc_omp_namelist 
*omp_allocate)
   else
gfc_add_block_to_block (, );
 
-  /* Special case when string in expr3 is zero.  */
+  /* Special case when string in expr3 is scalar and has length zero.  */
   if (code->expr3->ts.type == BT_CHARACTER
+ && code->expr3->rank == 0
  && integer_zerop (se.string_length))
{
  gfc_init_se (, NULL);
diff --git a/gcc/testsuite/gfortran.dg/allocate_with_source_32.f90 
b/gcc/testsuite/gfortran.dg/allocate_with_source_32.f90
new file mode 100644
index 000..4a9bd46da4d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/allocate_with_source_32.f90
@@ -0,0 +1,33 @@
+! { dg-do run }
+!
+! PR fortran/83865
+!
+! Test ALLOCATE with SOURCE= of deferred length character, where
+! the source-expression is an array of character with length 0.
+
+program p
+  implicit none
+  character(:), allocatable :: z(:)
+  character(1) :: cc(4) = ""
+  allocate (z, source=[''])
+  if (len (z) /= 0 .or. size (z) /= 1) stop 1
+  deallocate (z)
+  allocate (z, source=['',''])
+  if (len (z) /= 0 .or. size (z) /= 2) stop 2
+  deallocate (z)
+  allocate (z, source=[ character(0) :: 'a','b','c'])
+  if (len (z) /= 0 .or. size (z) /= 3) stop 3
+  deallocate (z)
+  allocate (z, source=[ character(0) :: cc ])
+  if (len (z) /= 0 .or. size (z) /= 4) stop 4
+  deallocate (z)
+  associate (x => f())
+if (len (x) /= 0 .or. size (x) /= 1) stop 5
+if (x(1) /= '') stop 6
+  end associate
+contains
+  function f() result(z)
+character(:), allocatable :: z(:)
+allocate (z, source=[''])
+  end function f
+end


[gcc r15-1018] Fortran: fix ALLOCATE with SOURCE=, zero-length character [PR83865]

2024-06-04 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:7f21aee0d4ef95eee7d9f7f42e9a056715836648

commit r15-1018-g7f21aee0d4ef95eee7d9f7f42e9a056715836648
Author: Harald Anlauf 
Date:   Mon Jun 3 22:02:06 2024 +0200

Fortran: fix ALLOCATE with SOURCE=, zero-length character [PR83865]

gcc/fortran/ChangeLog:

PR fortran/83865
* trans-stmt.cc (gfc_trans_allocate): Restrict special case for
source-expression with zero-length character to rank 0, so that
the array shape is not discarded.

gcc/testsuite/ChangeLog:

PR fortran/83865
* gfortran.dg/allocate_with_source_32.f90: New test.

Diff:
---
 gcc/fortran/trans-stmt.cc  |  3 +-
 .../gfortran.dg/allocate_with_source_32.f90| 33 ++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc
index 9b497d6bdc6..93b633e212e 100644
--- a/gcc/fortran/trans-stmt.cc
+++ b/gcc/fortran/trans-stmt.cc
@@ -6449,8 +6449,9 @@ gfc_trans_allocate (gfc_code * code, gfc_omp_namelist 
*omp_allocate)
   else
gfc_add_block_to_block (, );
 
-  /* Special case when string in expr3 is zero.  */
+  /* Special case when string in expr3 is scalar and has length zero.  */
   if (code->expr3->ts.type == BT_CHARACTER
+ && code->expr3->rank == 0
  && integer_zerop (se.string_length))
{
  gfc_init_se (, NULL);
diff --git a/gcc/testsuite/gfortran.dg/allocate_with_source_32.f90 
b/gcc/testsuite/gfortran.dg/allocate_with_source_32.f90
new file mode 100644
index 000..4a9bd46da4d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/allocate_with_source_32.f90
@@ -0,0 +1,33 @@
+! { dg-do run }
+!
+! PR fortran/83865
+!
+! Test ALLOCATE with SOURCE= of deferred length character, where
+! the source-expression is an array of character with length 0.
+
+program p
+  implicit none
+  character(:), allocatable :: z(:)
+  character(1) :: cc(4) = ""
+  allocate (z, source=[''])
+  if (len (z) /= 0 .or. size (z) /= 1) stop 1
+  deallocate (z)
+  allocate (z, source=['',''])
+  if (len (z) /= 0 .or. size (z) /= 2) stop 2
+  deallocate (z)
+  allocate (z, source=[ character(0) :: 'a','b','c'])
+  if (len (z) /= 0 .or. size (z) /= 3) stop 3
+  deallocate (z)
+  allocate (z, source=[ character(0) :: cc ])
+  if (len (z) /= 0 .or. size (z) /= 4) stop 4
+  deallocate (z)
+  associate (x => f())
+if (len (x) /= 0 .or. size (x) /= 1) stop 5
+if (x(1) /= '') stop 6
+  end associate
+contains
+  function f() result(z)
+character(:), allocatable :: z(:)
+allocate (z, source=[''])
+  end function f
+end


[gcc r14-10244] Fortran: fix bounds check for assignment, class component [PR86100]

2024-05-25 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:b0b21d5bdfbc7d417b70010a11354b44968bb184

commit r14-10244-gb0b21d5bdfbc7d417b70010a11354b44968bb184
Author: Harald Anlauf 
Date:   Mon May 13 22:06:33 2024 +0200

Fortran: fix bounds check for assignment, class component [PR86100]

gcc/fortran/ChangeLog:

PR fortran/86100
* trans-array.cc (gfc_conv_ss_startstride): Use abridged_ref_name
to generate a more user-friendly name for bounds-check messages.
* trans-expr.cc (gfc_copy_class_to_class): Fix bounds check for
rank>1 by looping over the dimensions.

gcc/testsuite/ChangeLog:

PR fortran/86100
* gfortran.dg/bounds_check_25.f90: New test.

(cherry picked from commit 93765736815a049e14d985b758a213cfe60c1e1c)

Diff:
---
 gcc/fortran/trans-array.cc|  7 -
 gcc/fortran/trans-expr.cc | 40 +++
 gcc/testsuite/gfortran.dg/bounds_check_25.f90 | 32 +
 3 files changed, 60 insertions(+), 19 deletions(-)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 7ec33fb1598..a15ff30e8f4 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -4911,6 +4911,7 @@ done:
  gfc_expr *expr;
  locus *expr_loc;
  const char *expr_name;
+ char *ref_name = NULL;
 
  ss_info = ss->info;
  if (ss_info->type != GFC_SS_SECTION)
@@ -4922,7 +4923,10 @@ done:
 
  expr = ss_info->expr;
  expr_loc = >where;
- expr_name = expr->symtree->name;
+ if (expr->ref)
+   expr_name = ref_name = abridged_ref_name (expr, NULL);
+ else
+   expr_name = expr->symtree->name;
 
  gfc_start_block ();
 
@@ -5134,6 +5138,7 @@ done:
 
  gfc_add_expr_to_block (, tmp);
 
+ free (ref_name);
}
 
   tmp = gfc_finish_block ();
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index bc8eb419cff..d5fd6e39996 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -1518,7 +1518,6 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, 
bool unlimited)
   stmtblock_t body;
   stmtblock_t ifbody;
   gfc_loopinfo loop;
-  tree orig_nelems = nelems; /* Needed for bounds check.  */
 
   gfc_init_block ();
   tmp = fold_build2_loc (input_location, MINUS_EXPR,
@@ -1550,27 +1549,32 @@ gfc_copy_class_to_class (tree from, tree to, tree 
nelems, bool unlimited)
   /* Add bounds check.  */
   if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS) > 0 && is_from_desc)
{
- char *msg;
  const char *name = "<>";
- tree from_len;
+ int dim, rank;
 
  if (DECL_P (to))
-   name = (const char *)(DECL_NAME (to)->identifier.id.str);
-
- from_len = gfc_conv_descriptor_size (from_data, 1);
- from_len = fold_convert (TREE_TYPE (orig_nelems), from_len);
- tmp = fold_build2_loc (input_location, NE_EXPR,
- logical_type_node, from_len, orig_nelems);
- msg = xasprintf ("Array bound mismatch for dimension %d "
-  "of array '%s' (%%ld/%%ld)",
-  1, name);
-
- gfc_trans_runtime_check (true, false, tmp, ,
-  _current_locus, msg,
-fold_convert (long_integer_type_node, orig_nelems),
-  fold_convert (long_integer_type_node, from_len));
+   name = IDENTIFIER_POINTER (DECL_NAME (to));
 
- free (msg);
+ rank = GFC_TYPE_ARRAY_RANK (TREE_TYPE (from_data));
+ for (dim = 1; dim <= rank; dim++)
+   {
+ tree from_len, to_len, cond;
+ char *msg;
+
+ from_len = gfc_conv_descriptor_size (from_data, dim);
+ from_len = fold_convert (long_integer_type_node, from_len);
+ to_len = gfc_conv_descriptor_size (to_data, dim);
+ to_len = fold_convert (long_integer_type_node, to_len);
+ msg = xasprintf ("Array bound mismatch for dimension %d "
+  "of array '%s' (%%ld/%%ld)",
+  dim, name);
+ cond = fold_build2_loc (input_location, NE_EXPR,
+ logical_type_node, from_len, to_len);
+ gfc_trans_runtime_check (true, false, cond, ,
+  _current_locus, msg,
+  to_len, from_len);
+ free (msg);
+   }
}
 
   tmp = build_call_vec (fcn_type, fcn, args);
diff --git a/gcc/testsuite/gfortran.dg/bounds_check_25.f90 
b/gcc/testsuite/gfortran.dg/bounds_check_25.f90
new file mode 100644
index 000..cc2247597f9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/bounds_check_25.f90
@@ -0,0 +1,32 @@
+! { dg-do run }
+! { 

[gcc r15-828] Fortran: improve attribute conflict checking [PR93635]

2024-05-24 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:9561cf550a66a89e7c8d31202a03c4fddf82a3f2

commit r15-828-g9561cf550a66a89e7c8d31202a03c4fddf82a3f2
Author: Harald Anlauf 
Date:   Thu May 23 21:13:00 2024 +0200

Fortran: improve attribute conflict checking [PR93635]

gcc/fortran/ChangeLog:

PR fortran/93635
* symbol.cc (conflict_std): Helper function for reporting attribute
conflicts depending on the Fortran standard version.
(conf_std): Helper macro for checking standard-dependent conflicts.
(gfc_check_conflict): Use it.

gcc/testsuite/ChangeLog:

PR fortran/93635
* gfortran.dg/c-interop/c1255-2.f90: Adjust pattern.
* gfortran.dg/pr87907.f90: Likewise.
* gfortran.dg/pr93635.f90: New test.

Co-authored-by: Steven G. Kargl 

Diff:
---
 gcc/fortran/symbol.cc   | 63 +++--
 gcc/testsuite/gfortran.dg/c-interop/c1255-2.f90 |  4 +-
 gcc/testsuite/gfortran.dg/pr87907.f90   |  8 ++--
 gcc/testsuite/gfortran.dg/pr93635.f90   | 19 
 4 files changed, 54 insertions(+), 40 deletions(-)

diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc
index 0a1646def67..5db3c887127 100644
--- a/gcc/fortran/symbol.cc
+++ b/gcc/fortran/symbol.cc
@@ -407,18 +407,36 @@ gfc_check_function_type (gfc_namespace *ns)
 
 / Symbol attribute stuff */
 
+/* Older standards produced conflicts for some attributes that are allowed
+   in newer standards.  Check for the conflict and issue an error depending
+   on the standard in play.  */
+
+static bool
+conflict_std (int standard, const char *a1, const char *a2, const char *name,
+ locus *where)
+{
+  if (name == NULL)
+{
+  return gfc_notify_std (standard, "%s attribute conflicts "
+"with %s attribute at %L", a1, a2,
+where);
+}
+  else
+{
+  return gfc_notify_std (standard, "%s attribute conflicts "
+"with %s attribute in %qs at %L",
+a1, a2, name, where);
+}
+}
+
 /* This is a generic conflict-checker.  We do this to avoid having a
single conflict in two places.  */
 
 #define conf(a, b) if (attr->a && attr->b) { a1 = a; a2 = b; goto conflict; }
 #define conf2(a) if (attr->a) { a2 = a; goto conflict; }
-#define conf_std(a, b, std) if (attr->a && attr->b)\
-  {\
-a1 = a;\
-a2 = b;\
-standard = std;\
-goto conflict_std;\
-  }
+#define conf_std(a, b, std) if (attr->a && attr->b \
+   && !conflict_std (std, a, b, name, where)) \
+   return false;
 
 bool
 gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
@@ -451,7 +469,6 @@ gfc_check_conflict (symbol_attribute *attr, const char 
*name, locus *where)
"OACC DECLARE DEVICE_RESIDENT";
 
   const char *a1, *a2;
-  int standard;
 
   if (attr->artificial)
 return true;
@@ -460,20 +477,10 @@ gfc_check_conflict (symbol_attribute *attr, const char 
*name, locus *where)
 where = _current_locus;
 
   if (attr->pointer && attr->intent != INTENT_UNKNOWN)
-{
-  a1 = pointer;
-  a2 = intent;
-  standard = GFC_STD_F2003;
-  goto conflict_std;
-}
+conf_std (pointer, intent, GFC_STD_F2003);
 
-  if (attr->in_namelist && (attr->allocatable || attr->pointer))
-{
-  a1 = in_namelist;
-  a2 = attr->allocatable ? allocatable : pointer;
-  standard = GFC_STD_F2003;
-  goto conflict_std;
-}
+  conf_std (in_namelist, allocatable, GFC_STD_F2003);
+  conf_std (in_namelist, pointer, GFC_STD_F2003);
 
   /* Check for attributes not allowed in a BLOCK DATA.  */
   if (gfc_current_state () == COMP_BLOCK_DATA)
@@ -922,20 +929,6 @@ conflict:
   a1, a2, name, where);
 
   return false;
-
-conflict_std:
-  if (name == NULL)
-{
-  return gfc_notify_std (standard, "%s attribute conflicts "
- "with %s attribute at %L", a1, a2,
- where);
-}
-  else
-{
-  return gfc_notify_std (standard, "%s attribute conflicts "
-"with %s attribute in %qs at %L",
- a1, a2, name, where);
-}
 }
 
 #undef conf
diff --git a/gcc/testsuite/gfortran.dg/c-interop/c1255-2.f90 
b/gcc/testsuite/gfortran.dg/c-interop/c1255-2.f90
index 0e5505a0183..feed2e7645f 100644
--- a/gcc/testsuite/gfortran.dg/c-interop/c1255-2.f90
+++ b/gcc/testsuite/gfortran.dg/c-interop/c1255-2.f90
@@ -92,12 +92,12 @@ module m2
 end function
 
 ! function result is a type that is not interoperable
-function g (x) bind (c)  ! { dg-error 

[gcc r15-827] Fortran: fix bounds check for assignment, class component [PR86100]

2024-05-24 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:93765736815a049e14d985b758a213cfe60c1e1c

commit r15-827-g93765736815a049e14d985b758a213cfe60c1e1c
Author: Harald Anlauf 
Date:   Mon May 13 22:06:33 2024 +0200

Fortran: fix bounds check for assignment, class component [PR86100]

gcc/fortran/ChangeLog:

PR fortran/86100
* trans-array.cc (gfc_conv_ss_startstride): Use abridged_ref_name
to generate a more user-friendly name for bounds-check messages.
* trans-expr.cc (gfc_copy_class_to_class): Fix bounds check for
rank>1 by looping over the dimensions.

gcc/testsuite/ChangeLog:

PR fortran/86100
* gfortran.dg/bounds_check_25.f90: New test.

Diff:
---
 gcc/fortran/trans-array.cc|  7 -
 gcc/fortran/trans-expr.cc | 40 +++
 gcc/testsuite/gfortran.dg/bounds_check_25.f90 | 32 +
 3 files changed, 60 insertions(+), 19 deletions(-)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index c5b56f4e273..eec62c296ff 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -4911,6 +4911,7 @@ done:
  gfc_expr *expr;
  locus *expr_loc;
  const char *expr_name;
+ char *ref_name = NULL;
 
  ss_info = ss->info;
  if (ss_info->type != GFC_SS_SECTION)
@@ -4922,7 +4923,10 @@ done:
 
  expr = ss_info->expr;
  expr_loc = >where;
- expr_name = expr->symtree->name;
+ if (expr->ref)
+   expr_name = ref_name = abridged_ref_name (expr, NULL);
+ else
+   expr_name = expr->symtree->name;
 
  gfc_start_block ();
 
@@ -5134,6 +5138,7 @@ done:
 
  gfc_add_expr_to_block (, tmp);
 
+ free (ref_name);
}
 
   tmp = gfc_finish_block ();
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index e315e2d3370..dfc5b8e9b4a 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -1520,7 +1520,6 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, 
bool unlimited)
   stmtblock_t body;
   stmtblock_t ifbody;
   gfc_loopinfo loop;
-  tree orig_nelems = nelems; /* Needed for bounds check.  */
 
   gfc_init_block ();
   tmp = fold_build2_loc (input_location, MINUS_EXPR,
@@ -1552,27 +1551,32 @@ gfc_copy_class_to_class (tree from, tree to, tree 
nelems, bool unlimited)
   /* Add bounds check.  */
   if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS) > 0 && is_from_desc)
{
- char *msg;
  const char *name = "<>";
- tree from_len;
+ int dim, rank;
 
  if (DECL_P (to))
-   name = (const char *)(DECL_NAME (to)->identifier.id.str);
-
- from_len = gfc_conv_descriptor_size (from_data, 1);
- from_len = fold_convert (TREE_TYPE (orig_nelems), from_len);
- tmp = fold_build2_loc (input_location, NE_EXPR,
- logical_type_node, from_len, orig_nelems);
- msg = xasprintf ("Array bound mismatch for dimension %d "
-  "of array '%s' (%%ld/%%ld)",
-  1, name);
-
- gfc_trans_runtime_check (true, false, tmp, ,
-  _current_locus, msg,
-fold_convert (long_integer_type_node, orig_nelems),
-  fold_convert (long_integer_type_node, from_len));
+   name = IDENTIFIER_POINTER (DECL_NAME (to));
 
- free (msg);
+ rank = GFC_TYPE_ARRAY_RANK (TREE_TYPE (from_data));
+ for (dim = 1; dim <= rank; dim++)
+   {
+ tree from_len, to_len, cond;
+ char *msg;
+
+ from_len = gfc_conv_descriptor_size (from_data, dim);
+ from_len = fold_convert (long_integer_type_node, from_len);
+ to_len = gfc_conv_descriptor_size (to_data, dim);
+ to_len = fold_convert (long_integer_type_node, to_len);
+ msg = xasprintf ("Array bound mismatch for dimension %d "
+  "of array '%s' (%%ld/%%ld)",
+  dim, name);
+ cond = fold_build2_loc (input_location, NE_EXPR,
+ logical_type_node, from_len, to_len);
+ gfc_trans_runtime_check (true, false, cond, ,
+  _current_locus, msg,
+  to_len, from_len);
+ free (msg);
+   }
}
 
   tmp = build_call_vec (fcn_type, fcn, args);
diff --git a/gcc/testsuite/gfortran.dg/bounds_check_25.f90 
b/gcc/testsuite/gfortran.dg/bounds_check_25.f90
new file mode 100644
index 000..cc2247597f9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/bounds_check_25.f90
@@ -0,0 +1,32 @@
+! { dg-do run }
+! { dg-additional-options "-fcheck=bounds -fdump-tree-original" }
+!
+! PR fortran/86100 - bogus bounds 

[gcc r13-8794] Fortran: fix issues with class(*) assignment [PR114827]

2024-05-22 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:f0b88ec4ae829798cb533618f781ca467bab6b9b

commit r13-8794-gf0b88ec4ae829798cb533618f781ca467bab6b9b
Author: Harald Anlauf 
Date:   Mon Apr 29 19:52:52 2024 +0200

Fortran: fix issues with class(*) assignment [PR114827]

gcc/fortran/ChangeLog:

PR fortran/114827
* trans-array.cc (gfc_alloc_allocatable_for_assignment): Take into
account _len of unlimited polymorphic entities when calculating
the effective element size for allocation size and array span.
Set _len of lhs to _len of rhs.
* trans-expr.cc (trans_class_assignment): Take into account _len
of unlimited polymorphic entities for allocation size.

gcc/testsuite/ChangeLog:

PR fortran/114827
* gfortran.dg/asan/unlimited_polymorphic_34.f90: New test.

(cherry picked from commit 21e7aa5f3ea44ca2fef8deb8788edffc04901b5c)

Diff:
---
 gcc/fortran/trans-array.cc |  16 +++
 gcc/fortran/trans-expr.cc  |  13 ++
 .../gfortran.dg/asan/unlimited_polymorphic_34.f90  | 135 +
 3 files changed, 164 insertions(+)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 5eef4b4ec87..f38e872f5d9 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -11008,6 +11008,19 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo 
*loop,
gfc_add_modify (, linfo->delta[dim], tmp);
 }
 
+  /* Take into account _len of unlimited polymorphic entities, so that span
+ for array descriptors and allocation sizes are computed correctly.  */
+  if (UNLIMITED_POLY (expr2))
+{
+  tree len = gfc_class_len_get (TREE_OPERAND (desc2, 0));
+  len = fold_build2_loc (input_location, MAX_EXPR, size_type_node,
+fold_convert (size_type_node, len),
+size_one_node);
+  elemsize2 = fold_build2_loc (input_location, MULT_EXPR,
+  gfc_array_index_type, elemsize2,
+  fold_convert (gfc_array_index_type, len));
+}
+
   if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
 gfc_conv_descriptor_span_set (, desc, elemsize2);
 
@@ -11054,6 +11067,9 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo 
*loop,
gfc_add_modify (, tmp,
fold_convert (TREE_TYPE (tmp),
  TYPE_SIZE_UNIT (type)));
+ else if (UNLIMITED_POLY (expr2))
+   gfc_add_modify (, tmp,
+   gfc_class_len_get (TREE_OPERAND (desc2, 0)));
  else
gfc_add_modify (, tmp,
build_int_cst (TREE_TYPE (tmp), 0));
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 2b2dceb8d0f..5946aa81391 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -11668,6 +11668,19 @@ trans_class_assignment (stmtblock_t *block, gfc_expr 
*lhs, gfc_expr *rhs,
old_vptr = build_int_cst (TREE_TYPE (vptr), 0);
 
   size = gfc_vptr_size_get (rhs_vptr);
+
+  /* Take into account _len of unlimited polymorphic entities.
+TODO: handle class(*) allocatable function results on rhs.  */
+  if (UNLIMITED_POLY (rhs) && rhs->expr_type == EXPR_VARIABLE)
+   {
+ tree len = trans_get_upoly_len (block, rhs);
+ len = fold_build2_loc (input_location, MAX_EXPR, size_type_node,
+fold_convert (size_type_node, len),
+size_one_node);
+ size = fold_build2_loc (input_location, MULT_EXPR, TREE_TYPE (size),
+ size, fold_convert (TREE_TYPE (size), len));
+   }
+
   tmp = lse->expr;
   class_han = GFC_CLASS_TYPE_P (TREE_TYPE (tmp))
  ? gfc_class_data_get (tmp) : tmp;
diff --git a/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90 
b/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90
new file mode 100644
index 000..c69158a1b55
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90
@@ -0,0 +1,135 @@
+! { dg-do run }
+! PR fortran/114827 - issues with class(*) assignment found by valgrind
+!
+! Contributed by Neil Carlson 
+
+program main
+  implicit none
+  call run
+  call run1
+  call run2
+contains
+  ! Scalar tests
+  subroutine run ()
+character(*),parameter :: c = 'fubarfubarfubarfubarfubarfu'
+character(*,kind=4), parameter :: d = 4_"abcdef"
+complex, parameter :: z = (1.,2.)
+class(*),  allocatable :: y
+
+call foo (c, y)
+select type (y)
+type is (character(*))
+!  print *, y(5:6)  ! ICE (-> pr114874)
+   if (y /= c) stop 1
+class default
+   stop 2
+end select
+
+call foo (z, y)
+select type (y)
+type is (complex)
+   if (y /= z) stop 3
+class default
+  

[gcc r13-8793] Fortran: fix reallocation on assignment of polymorphic variables [PR110415]

2024-05-22 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:2ebf3af1f84d54fbda172eff105a8842c685d11d

commit r13-8793-g2ebf3af1f84d54fbda172eff105a8842c685d11d
Author: Andrew Jenner 
Date:   Tue Nov 28 15:27:05 2023 +

Fortran: fix reallocation on assignment of polymorphic variables [PR110415]

This patch fixes two bugs related to polymorphic class assignment in the
Fortran front-end. One (described in PR110415) is an issue with the malloc
and realloc calls using the size from the old vptr rather than the new one.
The other is caused by the return value from the realloc call being ignored.
Testcases are added for these issues.

2023-11-28  Andrew Jenner  

gcc/fortran/
PR fortran/110415
* trans-expr.cc (trans_class_vptr_len_assignment): Add
from_vptrp parameter. Populate it. Don't check for DECL_P
when deciding whether to create temporary.
(trans_class_pointer_fcn, gfc_trans_pointer_assignment): Add
NULL argument to trans_class_vptr_len_assignment calls.
(trans_class_assignment): Get rhs_vptr from
trans_class_vptr_len_assignment and use it for determining size
for allocation/reallocation. Use return value from realloc.

gcc/testsuite/
PR fortran/110415
* gfortran.dg/pr110415.f90: New test.
* gfortran.dg/asan/pr110415-2.f90: New test.
* gfortran.dg/asan/pr110415-3.f90: New test.

Co-Authored-By: Tobias Burnus  
(cherry picked from commit b247e917ff13328298c1eecf8563b12edd7ade04)

Diff:
---
 gcc/fortran/trans-expr.cc | 39 +
 gcc/testsuite/gfortran.dg/asan/pr110415-2.f90 | 45 
 gcc/testsuite/gfortran.dg/asan/pr110415-3.f90 | 49 +++
 gcc/testsuite/gfortran.dg/pr110415.f90| 20 +++
 4 files changed, 139 insertions(+), 14 deletions(-)

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index cfe03252582..2b2dceb8d0f 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -9748,7 +9748,8 @@ trans_get_upoly_len (stmtblock_t *block, gfc_expr *expr)
 static tree
 trans_class_vptr_len_assignment (stmtblock_t *block, gfc_expr * le,
 gfc_expr * re, gfc_se *rse,
-tree * to_lenp, tree * from_lenp)
+tree * to_lenp, tree * from_lenp,
+tree * from_vptrp)
 {
   gfc_se se;
   gfc_expr * vptr_expr;
@@ -9756,10 +9757,11 @@ trans_class_vptr_len_assignment (stmtblock_t *block, 
gfc_expr * le,
   bool set_vptr = false, temp_rhs = false;
   stmtblock_t *pre = block;
   tree class_expr = NULL_TREE;
+  tree from_vptr = NULL_TREE;
 
   /* Create a temporary for complicated expressions.  */
   if (re->expr_type != EXPR_VARIABLE && re->expr_type != EXPR_NULL
-  && rse->expr != NULL_TREE && !DECL_P (rse->expr))
+  && rse->expr != NULL_TREE)
 {
   if (re->ts.type == BT_CLASS && !GFC_CLASS_TYPE_P (TREE_TYPE (rse->expr)))
class_expr = gfc_get_class_from_expr (rse->expr);
@@ -9856,6 +9858,7 @@ trans_class_vptr_len_assignment (stmtblock_t *block, 
gfc_expr * le,
tmp = rse->expr;
 
  se.expr = gfc_class_vptr_get (tmp);
+ from_vptr = se.expr;
  if (UNLIMITED_POLY (re))
from_len = gfc_class_len_get (tmp);
 
@@ -9877,6 +9880,7 @@ trans_class_vptr_len_assignment (stmtblock_t *block, 
gfc_expr * le,
  gfc_free_expr (vptr_expr);
  gfc_add_block_to_block (block, );
  gcc_assert (se.post.head == NULL_TREE);
+ from_vptr = se.expr;
}
   gfc_add_modify (pre, lhs_vptr, fold_convert (TREE_TYPE (lhs_vptr),
se.expr));
@@ -9905,11 +9909,13 @@ trans_class_vptr_len_assignment (stmtblock_t *block, 
gfc_expr * le,
}
 }
 
-  /* Return the _len trees only, when requested.  */
+  /* Return the _len and _vptr trees only, when requested.  */
   if (to_lenp)
 *to_lenp = to_len;
   if (from_lenp)
 *from_lenp = from_len;
+  if (from_vptrp)
+*from_vptrp = from_vptr;
   return lhs_vptr;
 }
 
@@ -9978,7 +9984,7 @@ trans_class_pointer_fcn (stmtblock_t *block, gfc_se *lse, 
gfc_se *rse,
 {
   expr1_vptr = trans_class_vptr_len_assignment (block, expr1,
expr2, rse,
-   NULL, NULL);
+   NULL, NULL, NULL);
   gfc_add_block_to_block (block, >pre);
   tmp = gfc_create_var (TREE_TYPE (rse->expr), "ptrtemp");
   gfc_add_modify (>pre, tmp, rse->expr);
@@ -10054,7 +10060,7 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, 
gfc_expr * expr2)
   if (non_proc_ptr_assign && expr1->ts.type == BT_CLASS)
{
  trans_class_vptr_len_assignment (, expr1, expr2, , 

[gcc r13-8786] Fortran: fix dependency checks for inquiry refs [PR115039]

2024-05-21 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:5ed32d00a7b408baa48d85e841740e73c8504d7a

commit r13-8786-g5ed32d00a7b408baa48d85e841740e73c8504d7a
Author: Harald Anlauf 
Date:   Fri May 10 21:18:03 2024 +0200

Fortran: fix dependency checks for inquiry refs [PR115039]

gcc/fortran/ChangeLog:

PR fortran/115039
* expr.cc (gfc_traverse_expr): An inquiry ref does not constitute
a dependency and cannot collide with a symbol.

gcc/testsuite/ChangeLog:

PR fortran/115039
* gfortran.dg/statement_function_5.f90: New test.

(cherry picked from commit d4974fd22730014e337fd7ec2471945ba8afb00e)

Diff:
---
 gcc/fortran/expr.cc|  2 +-
 gcc/testsuite/gfortran.dg/statement_function_5.f90 | 20 
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index a6c4dccb125..4a9b29c7e9d 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -5483,7 +5483,7 @@ gfc_traverse_expr (gfc_expr *expr, gfc_symbol *sym,
  break;
 
case REF_INQUIRY:
- return true;
+ return false;
 
default:
  gcc_unreachable ();
diff --git a/gcc/testsuite/gfortran.dg/statement_function_5.f90 
b/gcc/testsuite/gfortran.dg/statement_function_5.f90
new file mode 100644
index 000..bc5a5dba7a0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/statement_function_5.f90
@@ -0,0 +1,20 @@
+! { dg-do compile }
+! PR fortran/115039
+!
+! Check that inquiry refs work with statement functions
+!
+! { dg-additional-options "-std=legacy -fdump-tree-optimized" }
+! { dg-prune-output " Obsolescent feature" }
+! { dg-final { scan-tree-dump-not "_gfortran_stop_numeric" "optimized" } }
+
+program testit
+  implicit none
+  complex :: x
+  real:: im
+  integer :: slen
+  character(5) :: s
+  im(x)   = x%im + x%re + x%kind
+  slen(s) = s%len
+  if (im((1.0,3.0) + (2.0,4.0)) /= 14.) stop 1
+  if (slen('abcdef') /= 5)  stop 2
+end program testit


[gcc r14-10225] Fortran: fix dependency checks for inquiry refs [PR115039]

2024-05-21 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:edde60a53c7d4ee5a58c9835c8e1e1758ba636f7

commit r14-10225-gedde60a53c7d4ee5a58c9835c8e1e1758ba636f7
Author: Harald Anlauf 
Date:   Fri May 10 21:18:03 2024 +0200

Fortran: fix dependency checks for inquiry refs [PR115039]

gcc/fortran/ChangeLog:

PR fortran/115039
* expr.cc (gfc_traverse_expr): An inquiry ref does not constitute
a dependency and cannot collide with a symbol.

gcc/testsuite/ChangeLog:

PR fortran/115039
* gfortran.dg/statement_function_5.f90: New test.

(cherry picked from commit d4974fd22730014e337fd7ec2471945ba8afb00e)

Diff:
---
 gcc/fortran/expr.cc|  2 +-
 gcc/testsuite/gfortran.dg/statement_function_5.f90 | 20 
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 09d1ebd95d2..50e32a7a3b7 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -5491,7 +5491,7 @@ gfc_traverse_expr (gfc_expr *expr, gfc_symbol *sym,
  break;
 
case REF_INQUIRY:
- return true;
+ return false;
 
default:
  gcc_unreachable ();
diff --git a/gcc/testsuite/gfortran.dg/statement_function_5.f90 
b/gcc/testsuite/gfortran.dg/statement_function_5.f90
new file mode 100644
index 000..bc5a5dba7a0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/statement_function_5.f90
@@ -0,0 +1,20 @@
+! { dg-do compile }
+! PR fortran/115039
+!
+! Check that inquiry refs work with statement functions
+!
+! { dg-additional-options "-std=legacy -fdump-tree-optimized" }
+! { dg-prune-output " Obsolescent feature" }
+! { dg-final { scan-tree-dump-not "_gfortran_stop_numeric" "optimized" } }
+
+program testit
+  implicit none
+  complex :: x
+  real:: im
+  integer :: slen
+  character(5) :: s
+  im(x)   = x%im + x%re + x%kind
+  slen(s) = s%len
+  if (im((1.0,3.0) + (2.0,4.0)) /= 14.) stop 1
+  if (slen('abcdef') /= 5)  stop 2
+end program testit


[gcc r15-391] Fortran: fix frontend memleak

2024-05-12 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:13b6ac4ebd04f0703d92828c9268b0b216890b0d

commit r15-391-g13b6ac4ebd04f0703d92828c9268b0b216890b0d
Author: Harald Anlauf 
Date:   Sun May 12 21:48:03 2024 +0200

Fortran: fix frontend memleak

gcc/fortran/ChangeLog:

* primary.cc (gfc_match_varspec): Replace 'ref' argument to
is_inquiry_ref() by NULL when the result is not needed to avoid
a memleak.

Diff:
---
 gcc/fortran/primary.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index 606e84432be6..8e7833769a8f 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -2250,7 +2250,7 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, 
bool sub_flag,
 can be found.  If this was an inquiry reference with the same name
 as a derived component and the associate-name type is not derived
 or class, this is fixed up in 'gfc_fixup_inferred_type_refs'.  */
-  if (mm == MATCH_YES && is_inquiry_ref (name, )
+  if (mm == MATCH_YES && is_inquiry_ref (name, NULL)
  && !(sym->ts.type == BT_UNKNOWN
&& gfc_find_derived_types (sym, gfc_current_ns, name)))
inquiry = true;


[gcc r15-385] Fortran: fix dependency checks for inquiry refs [PR115039]

2024-05-11 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:d4974fd22730014e337fd7ec2471945ba8afb00e

commit r15-385-gd4974fd22730014e337fd7ec2471945ba8afb00e
Author: Harald Anlauf 
Date:   Fri May 10 21:18:03 2024 +0200

Fortran: fix dependency checks for inquiry refs [PR115039]

gcc/fortran/ChangeLog:

PR fortran/115039
* expr.cc (gfc_traverse_expr): An inquiry ref does not constitute
a dependency and cannot collide with a symbol.

gcc/testsuite/ChangeLog:

PR fortran/115039
* gfortran.dg/statement_function_5.f90: New test.

Diff:
---
 gcc/fortran/expr.cc|  2 +-
 gcc/testsuite/gfortran.dg/statement_function_5.f90 | 20 
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 66edad58278a..c883966646cb 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -5500,7 +5500,7 @@ gfc_traverse_expr (gfc_expr *expr, gfc_symbol *sym,
  break;
 
case REF_INQUIRY:
- return true;
+ return false;
 
default:
  gcc_unreachable ();
diff --git a/gcc/testsuite/gfortran.dg/statement_function_5.f90 
b/gcc/testsuite/gfortran.dg/statement_function_5.f90
new file mode 100644
index ..bc5a5dba7a0f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/statement_function_5.f90
@@ -0,0 +1,20 @@
+! { dg-do compile }
+! PR fortran/115039
+!
+! Check that inquiry refs work with statement functions
+!
+! { dg-additional-options "-std=legacy -fdump-tree-optimized" }
+! { dg-prune-output " Obsolescent feature" }
+! { dg-final { scan-tree-dump-not "_gfortran_stop_numeric" "optimized" } }
+
+program testit
+  implicit none
+  complex :: x
+  real:: im
+  integer :: slen
+  character(5) :: s
+  im(x)   = x%im + x%re + x%kind
+  slen(s) = s%len
+  if (im((1.0,3.0) + (2.0,4.0)) /= 14.) stop 1
+  if (slen('abcdef') /= 5)  stop 2
+end program testit


[gcc r14-10191] Fortran: fix issues with class(*) assignment [PR114827]

2024-05-09 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:a5046235509caa10a4dc309ca0a8e67892b27750

commit r14-10191-ga5046235509caa10a4dc309ca0a8e67892b27750
Author: Harald Anlauf 
Date:   Mon Apr 29 19:52:52 2024 +0200

Fortran: fix issues with class(*) assignment [PR114827]

gcc/fortran/ChangeLog:

PR fortran/114827
* trans-array.cc (gfc_alloc_allocatable_for_assignment): Take into
account _len of unlimited polymorphic entities when calculating
the effective element size for allocation size and array span.
Set _len of lhs to _len of rhs.
* trans-expr.cc (trans_class_assignment): Take into account _len
of unlimited polymorphic entities for allocation size.

gcc/testsuite/ChangeLog:

PR fortran/114827
* gfortran.dg/asan/unlimited_polymorphic_34.f90: New test.

(cherry picked from commit 21e7aa5f3ea44ca2fef8deb8788edffc04901b5c)

Diff:
---
 gcc/fortran/trans-array.cc |  16 +++
 gcc/fortran/trans-expr.cc  |  13 ++
 .../gfortran.dg/asan/unlimited_polymorphic_34.f90  | 135 +
 3 files changed, 164 insertions(+)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 30b84762346d..7ec33fb15986 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -11278,6 +11278,19 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo 
*loop,
gfc_add_modify (, linfo->delta[dim], tmp);
 }
 
+  /* Take into account _len of unlimited polymorphic entities, so that span
+ for array descriptors and allocation sizes are computed correctly.  */
+  if (UNLIMITED_POLY (expr2))
+{
+  tree len = gfc_class_len_get (TREE_OPERAND (desc2, 0));
+  len = fold_build2_loc (input_location, MAX_EXPR, size_type_node,
+fold_convert (size_type_node, len),
+size_one_node);
+  elemsize2 = fold_build2_loc (input_location, MULT_EXPR,
+  gfc_array_index_type, elemsize2,
+  fold_convert (gfc_array_index_type, len));
+}
+
   if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
 gfc_conv_descriptor_span_set (, desc, elemsize2);
 
@@ -11324,6 +11337,9 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo 
*loop,
gfc_add_modify (, tmp,
fold_convert (TREE_TYPE (tmp),
  TYPE_SIZE_UNIT (type)));
+ else if (UNLIMITED_POLY (expr2))
+   gfc_add_modify (, tmp,
+   gfc_class_len_get (TREE_OPERAND (desc2, 0)));
  else
gfc_add_modify (, tmp,
build_int_cst (TREE_TYPE (tmp), 0));
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 0280c441ced3..bc8eb419cffe 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -11991,6 +11991,19 @@ trans_class_assignment (stmtblock_t *block, gfc_expr 
*lhs, gfc_expr *rhs,
old_vptr = build_int_cst (TREE_TYPE (vptr), 0);
 
   size = gfc_vptr_size_get (rhs_vptr);
+
+  /* Take into account _len of unlimited polymorphic entities.
+TODO: handle class(*) allocatable function results on rhs.  */
+  if (UNLIMITED_POLY (rhs) && rhs->expr_type == EXPR_VARIABLE)
+   {
+ tree len = trans_get_upoly_len (block, rhs);
+ len = fold_build2_loc (input_location, MAX_EXPR, size_type_node,
+fold_convert (size_type_node, len),
+size_one_node);
+ size = fold_build2_loc (input_location, MULT_EXPR, TREE_TYPE (size),
+ size, fold_convert (TREE_TYPE (size), len));
+   }
+
   tmp = lse->expr;
   class_han = GFC_CLASS_TYPE_P (TREE_TYPE (tmp))
  ? gfc_class_data_get (tmp) : tmp;
diff --git a/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90 
b/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90
new file mode 100644
index ..c69158a1b55f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90
@@ -0,0 +1,135 @@
+! { dg-do run }
+! PR fortran/114827 - issues with class(*) assignment found by valgrind
+!
+! Contributed by Neil Carlson 
+
+program main
+  implicit none
+  call run
+  call run1
+  call run2
+contains
+  ! Scalar tests
+  subroutine run ()
+character(*),parameter :: c = 'fubarfubarfubarfubarfubarfu'
+character(*,kind=4), parameter :: d = 4_"abcdef"
+complex, parameter :: z = (1.,2.)
+class(*),  allocatable :: y
+
+call foo (c, y)
+select type (y)
+type is (character(*))
+!  print *, y(5:6)  ! ICE (-> pr114874)
+   if (y /= c) stop 1
+class default
+   stop 2
+end select
+
+call foo (z, y)
+select type (y)
+type is (complex)
+   if (y /= z) stop 3
+class default

[gcc r15-168] Fortran: fix issues with class(*) assignment [PR114827]

2024-05-05 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:21e7aa5f3ea44ca2fef8deb8788edffc04901b5c

commit r15-168-g21e7aa5f3ea44ca2fef8deb8788edffc04901b5c
Author: Harald Anlauf 
Date:   Mon Apr 29 19:52:52 2024 +0200

Fortran: fix issues with class(*) assignment [PR114827]

gcc/fortran/ChangeLog:

PR fortran/114827
* trans-array.cc (gfc_alloc_allocatable_for_assignment): Take into
account _len of unlimited polymorphic entities when calculating
the effective element size for allocation size and array span.
Set _len of lhs to _len of rhs.
* trans-expr.cc (trans_class_assignment): Take into account _len
of unlimited polymorphic entities for allocation size.

gcc/testsuite/ChangeLog:

PR fortran/114827
* gfortran.dg/asan/unlimited_polymorphic_34.f90: New test.

Diff:
---
 gcc/fortran/trans-array.cc |  16 +++
 gcc/fortran/trans-expr.cc  |  13 ++
 .../gfortran.dg/asan/unlimited_polymorphic_34.f90  | 135 +
 3 files changed, 164 insertions(+)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 30b84762346..7ec33fb1598 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -11278,6 +11278,19 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo 
*loop,
gfc_add_modify (, linfo->delta[dim], tmp);
 }
 
+  /* Take into account _len of unlimited polymorphic entities, so that span
+ for array descriptors and allocation sizes are computed correctly.  */
+  if (UNLIMITED_POLY (expr2))
+{
+  tree len = gfc_class_len_get (TREE_OPERAND (desc2, 0));
+  len = fold_build2_loc (input_location, MAX_EXPR, size_type_node,
+fold_convert (size_type_node, len),
+size_one_node);
+  elemsize2 = fold_build2_loc (input_location, MULT_EXPR,
+  gfc_array_index_type, elemsize2,
+  fold_convert (gfc_array_index_type, len));
+}
+
   if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
 gfc_conv_descriptor_span_set (, desc, elemsize2);
 
@@ -11324,6 +11337,9 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo 
*loop,
gfc_add_modify (, tmp,
fold_convert (TREE_TYPE (tmp),
  TYPE_SIZE_UNIT (type)));
+ else if (UNLIMITED_POLY (expr2))
+   gfc_add_modify (, tmp,
+   gfc_class_len_get (TREE_OPERAND (desc2, 0)));
  else
gfc_add_modify (, tmp,
build_int_cst (TREE_TYPE (tmp), 0));
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 0280c441ced..bc8eb419cff 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -11991,6 +11991,19 @@ trans_class_assignment (stmtblock_t *block, gfc_expr 
*lhs, gfc_expr *rhs,
old_vptr = build_int_cst (TREE_TYPE (vptr), 0);
 
   size = gfc_vptr_size_get (rhs_vptr);
+
+  /* Take into account _len of unlimited polymorphic entities.
+TODO: handle class(*) allocatable function results on rhs.  */
+  if (UNLIMITED_POLY (rhs) && rhs->expr_type == EXPR_VARIABLE)
+   {
+ tree len = trans_get_upoly_len (block, rhs);
+ len = fold_build2_loc (input_location, MAX_EXPR, size_type_node,
+fold_convert (size_type_node, len),
+size_one_node);
+ size = fold_build2_loc (input_location, MULT_EXPR, TREE_TYPE (size),
+ size, fold_convert (TREE_TYPE (size), len));
+   }
+
   tmp = lse->expr;
   class_han = GFC_CLASS_TYPE_P (TREE_TYPE (tmp))
  ? gfc_class_data_get (tmp) : tmp;
diff --git a/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90 
b/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90
new file mode 100644
index 000..c69158a1b55
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/asan/unlimited_polymorphic_34.f90
@@ -0,0 +1,135 @@
+! { dg-do run }
+! PR fortran/114827 - issues with class(*) assignment found by valgrind
+!
+! Contributed by Neil Carlson 
+
+program main
+  implicit none
+  call run
+  call run1
+  call run2
+contains
+  ! Scalar tests
+  subroutine run ()
+character(*),parameter :: c = 'fubarfubarfubarfubarfubarfu'
+character(*,kind=4), parameter :: d = 4_"abcdef"
+complex, parameter :: z = (1.,2.)
+class(*),  allocatable :: y
+
+call foo (c, y)
+select type (y)
+type is (character(*))
+!  print *, y(5:6)  ! ICE (-> pr114874)
+   if (y /= c) stop 1
+class default
+   stop 2
+end select
+
+call foo (z, y)
+select type (y)
+type is (complex)
+   if (y /= z) stop 3
+class default
+   stop 4
+end select
+
+call foo (d, y)
+select type (y)
+type 

[gcc r12-10398] Fortran: Fix assumed length chars and len inquiry [PR103716]

2024-04-26 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:b482968801158116dd8ba3b15a4c29143b2a423a

commit r12-10398-gb482968801158116dd8ba3b15a4c29143b2a423a
Author: Paul Thomas 
Date:   Tue May 23 06:46:37 2023 +0100

Fortran: Fix assumed length chars and len inquiry [PR103716]

2023-05-23  Paul Thomas  

gcc/fortran
PR fortran/103716
* resolve.cc (gfc_resolve_ref): Conversion of array_ref into an
element should be done for all characters without a len expr,
not just deferred lens, and for integer expressions.
* trans-expr.cc (conv_inquiry): For len and kind inquiry refs,
set the se string_length to NULL_TREE.

gcc/testsuite/
PR fortran/103716
* gfortran.dg/pr103716.f90 : New test.

(cherry picked from commit 842a432b02238361ecc601d301ac400a7f30f4fa)

Diff:
---
 gcc/fortran/resolve.cc |  4 +++-
 gcc/fortran/trans-expr.cc  |  2 ++
 gcc/testsuite/gfortran.dg/pr103716.f90 | 15 +++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 9264322f671..6a7325e15e7 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -5461,7 +5461,9 @@ gfc_resolve_ref (gfc_expr *expr)
case REF_INQUIRY:
  /* Implement requirement in note 9.7 of F2018 that the result of the
 LEN inquiry be a scalar.  */
- if (ref->u.i == INQUIRY_LEN && array_ref && expr->ts.deferred)
+ if (ref->u.i == INQUIRY_LEN && array_ref
+ && ((expr->ts.type == BT_CHARACTER && !expr->ts.u.cl->length)
+ || expr->ts.type == BT_INTEGER))
{
  array_ref->u.ar.type = AR_ELEMENT;
  expr->rank = 0;
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 11ee1931b8e..e78a01003c9 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -2854,11 +2854,13 @@ conv_inquiry (gfc_se * se, gfc_ref * ref, gfc_expr 
*expr, gfc_typespec *ts)
 case INQUIRY_KIND:
   res = build_int_cst (gfc_typenode_for_spec (>ts),
   ts->kind);
+  se->string_length = NULL_TREE;
   break;
 
 case INQUIRY_LEN:
   res = fold_convert (gfc_typenode_for_spec (>ts),
  se->string_length);
+  se->string_length = NULL_TREE;
   break;
 
 default:
diff --git a/gcc/testsuite/gfortran.dg/pr103716.f90 
b/gcc/testsuite/gfortran.dg/pr103716.f90
new file mode 100644
index 000..4f78900839e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr103716.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+!
+! The gimplifier used to throw a fit on thes two functions.
+!
+! Contributed by Gerhard Steinmetz  
+!
+function f1(x)
+   character(*) :: x(*)
+   print *, g(x%len)
+end
+
+function f2(x)
+   character(*) :: x(3)
+   print *, g(x%len)
+end


[gcc r12-10396] gfortran: Allow ref'ing PDT's len() in parameter-initializer.

2024-04-26 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:8ad460ca8824f7e29e38a63f9cb4a9a3b96d506f

commit r12-10396-g8ad460ca8824f7e29e38a63f9cb4a9a3b96d506f
Author: Andre Vehreschild 
Date:   Wed Jul 12 12:51:30 2023 +0200

gfortran: Allow ref'ing PDT's len() in parameter-initializer.

Fix declaring a parameter initialized using a pdt_len reference
not simplifying the reference to a constant.

2023-07-12  Andre Vehreschild  

gcc/fortran/ChangeLog:

PR fortran/102003
* expr.cc (find_inquiry_ref): Replace len of pdt_string by
constant.
(simplify_ref_chain): Ensure input to find_inquiry_ref is
NULL.
(gfc_match_init_expr): Prevent PDT analysis for function calls.
(gfc_pdt_find_component_copy_initializer): Get the initializer
value for given component.
* gfortran.h (gfc_pdt_find_component_copy_initializer): New
function.
* simplify.cc (gfc_simplify_len): Replace len() of PDT with pdt
component ref or constant.

gcc/testsuite/ChangeLog:

* gfortran.dg/pdt_33.f03: New test.

(cherry picked from commit f9182da3213aa57c16dd0b52862126de4a259f6a)

Diff:
---
 gcc/fortran/expr.cc  | 31 ++--
 gcc/fortran/gfortran.h   |  1 +
 gcc/fortran/simplify.cc  | 57 
 gcc/testsuite/gfortran.dg/pdt_33.f03 | 21 +
 4 files changed, 94 insertions(+), 16 deletions(-)

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index c04403a2b89..5640d215925 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -1850,6 +1850,13 @@ find_inquiry_ref (gfc_expr *p, gfc_expr **newp)
  else if (tmp->expr_type == EXPR_CONSTANT)
*newp = gfc_get_int_expr (gfc_default_integer_kind,
  NULL, tmp->value.character.length);
+ else if (gfc_init_expr_flag
+  && tmp->ts.u.cl->length->symtree->n.sym->attr.pdt_len)
+   *newp = gfc_pdt_find_component_copy_initializer (tmp->symtree->n
+.sym,
+tmp->ts.u.cl
+->length->symtree
+->n.sym->name);
  else
goto cleanup;
 
@@ -1890,7 +1897,9 @@ find_inquiry_ref (gfc_expr *p, gfc_expr **newp)
mpc_imagref (tmp->value.complex), GFC_RND_MODE);
  break;
}
-  tmp = gfc_copy_expr (*newp);
+  // TODO: Fix leaking expr tmp, when simplify is done twice.
+  if (inquiry->next)
+   gfc_replace_expr (tmp, *newp);
 }
 
   if (!(*newp))
@@ -2055,7 +2064,7 @@ static bool
 simplify_ref_chain (gfc_ref *ref, int type, gfc_expr **p)
 {
   int n;
-  gfc_expr *newp;
+  gfc_expr *newp = NULL;
 
   for (; ref; ref = ref->next)
 {
@@ -3217,7 +3226,7 @@ gfc_match_init_expr (gfc_expr **result)
   return m;
 }
 
-  if (gfc_derived_parameter_expr (expr))
+  if (expr->expr_type != EXPR_FUNCTION && gfc_derived_parameter_expr (expr))
 {
   *result = expr;
   gfc_init_expr_flag = false;
@@ -6530,3 +6539,19 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, 
bool alloc_obj,
 
   return true;
 }
+
+gfc_expr*
+gfc_pdt_find_component_copy_initializer (gfc_symbol *sym, const char *name)
+{
+  /* The actual length of a pdt is in its components.  In the
+ initializer of the current ref is only the default value.
+ Therefore traverse the chain of components and pick the correct
+ one's initializer expressions.  */
+  for (gfc_component *comp = sym->ts.u.derived->components; comp != NULL;
+   comp = comp->next)
+{
+  if (!strcmp (comp->name, name))
+   return gfc_copy_expr (comp->initializer);
+}
+  return NULL;
+}
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 98c0cd39503..0b0a8fe7118 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3667,6 +3667,7 @@ gfc_expr* gfc_find_stat_co (gfc_expr *);
 gfc_expr* gfc_build_intrinsic_call (gfc_namespace *, gfc_isym_id, const char*,
locus, unsigned, ...);
 bool gfc_check_vardef_context (gfc_expr*, bool, bool, bool, const char*);
+gfc_expr* gfc_pdt_find_component_copy_initializer (gfc_symbol *, const char *);
 
 
 /* st.cc */
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index 83b4e7d3493..a10f79c4a93 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -4525,19 +4525,50 @@ gfc_simplify_len (gfc_expr *e, gfc_expr *kind)
   return range_check (result, "LEN");
 }
   else if (e->expr_type == EXPR_VARIABLE && e->ts.type == BT_CHARACTER
-  && e->symtree->n.sym
-  && e->symtree->n.sym->ts.type != BT_DERIVED
-  && e->symtree->n.sym->assoc && 

[gcc r13-8651] gfortran: Allow ref'ing PDT's len() in parameter-initializer.

2024-04-26 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:e207b67fcde224f2be0c79bf2a24f7fc75b6f481

commit r13-8651-ge207b67fcde224f2be0c79bf2a24f7fc75b6f481
Author: Andre Vehreschild 
Date:   Wed Jul 12 12:51:30 2023 +0200

gfortran: Allow ref'ing PDT's len() in parameter-initializer.

Fix declaring a parameter initialized using a pdt_len reference
not simplifying the reference to a constant.

2023-07-12  Andre Vehreschild  

gcc/fortran/ChangeLog:

PR fortran/102003
* expr.cc (find_inquiry_ref): Replace len of pdt_string by
constant.
(simplify_ref_chain): Ensure input to find_inquiry_ref is
NULL.
(gfc_match_init_expr): Prevent PDT analysis for function calls.
(gfc_pdt_find_component_copy_initializer): Get the initializer
value for given component.
* gfortran.h (gfc_pdt_find_component_copy_initializer): New
function.
* simplify.cc (gfc_simplify_len): Replace len() of PDT with pdt
component ref or constant.

gcc/testsuite/ChangeLog:

* gfortran.dg/pdt_33.f03: New test.

(cherry picked from commit f9182da3213aa57c16dd0b52862126de4a259f6a)

Diff:
---
 gcc/fortran/expr.cc  | 31 ++--
 gcc/fortran/gfortran.h   |  1 +
 gcc/fortran/simplify.cc  | 57 
 gcc/testsuite/gfortran.dg/pdt_33.f03 | 21 +
 4 files changed, 94 insertions(+), 16 deletions(-)

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 8b9c93940c8..a6c4dccb125 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -1854,6 +1854,13 @@ find_inquiry_ref (gfc_expr *p, gfc_expr **newp)
  else if (tmp->expr_type == EXPR_CONSTANT)
*newp = gfc_get_int_expr (gfc_default_integer_kind,
  NULL, tmp->value.character.length);
+ else if (gfc_init_expr_flag
+  && tmp->ts.u.cl->length->symtree->n.sym->attr.pdt_len)
+   *newp = gfc_pdt_find_component_copy_initializer (tmp->symtree->n
+.sym,
+tmp->ts.u.cl
+->length->symtree
+->n.sym->name);
  else
goto cleanup;
 
@@ -1894,7 +1901,9 @@ find_inquiry_ref (gfc_expr *p, gfc_expr **newp)
mpc_imagref (tmp->value.complex), GFC_RND_MODE);
  break;
}
-  tmp = gfc_copy_expr (*newp);
+  // TODO: Fix leaking expr tmp, when simplify is done twice.
+  if (inquiry->next)
+   gfc_replace_expr (tmp, *newp);
 }
 
   if (!(*newp))
@@ -2059,7 +2068,7 @@ static bool
 simplify_ref_chain (gfc_ref *ref, int type, gfc_expr **p)
 {
   int n;
-  gfc_expr *newp;
+  gfc_expr *newp = NULL;
 
   for (; ref; ref = ref->next)
 {
@@ -3221,7 +3230,7 @@ gfc_match_init_expr (gfc_expr **result)
   return m;
 }
 
-  if (gfc_derived_parameter_expr (expr))
+  if (expr->expr_type != EXPR_FUNCTION && gfc_derived_parameter_expr (expr))
 {
   *result = expr;
   gfc_init_expr_flag = false;
@@ -6533,3 +6542,19 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, 
bool alloc_obj,
 
   return true;
 }
+
+gfc_expr*
+gfc_pdt_find_component_copy_initializer (gfc_symbol *sym, const char *name)
+{
+  /* The actual length of a pdt is in its components.  In the
+ initializer of the current ref is only the default value.
+ Therefore traverse the chain of components and pick the correct
+ one's initializer expressions.  */
+  for (gfc_component *comp = sym->ts.u.derived->components; comp != NULL;
+   comp = comp->next)
+{
+  if (!strcmp (comp->name, name))
+   return gfc_copy_expr (comp->initializer);
+}
+  return NULL;
+}
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 47414f73254..c1430f7dfec 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3716,6 +3716,7 @@ gfc_expr* gfc_find_stat_co (gfc_expr *);
 gfc_expr* gfc_build_intrinsic_call (gfc_namespace *, gfc_isym_id, const char*,
locus, unsigned, ...);
 bool gfc_check_vardef_context (gfc_expr*, bool, bool, bool, const char*);
+gfc_expr* gfc_pdt_find_component_copy_initializer (gfc_symbol *, const char *);
 
 
 /* st.cc */
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index b65854c1021..fe700097b7b 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -4566,19 +4566,50 @@ gfc_simplify_len (gfc_expr *e, gfc_expr *kind)
   return range_check (result, "LEN");
 }
   else if (e->expr_type == EXPR_VARIABLE && e->ts.type == BT_CHARACTER
-  && e->symtree->n.sym
-  && e->symtree->n.sym->ts.type != BT_DERIVED
-  && e->symtree->n.sym->assoc && 

[gcc r14-10097] Fortran: check C_SIZEOF on additions from TS29113/F2018 [PR103496]

2024-04-23 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:0bf94da59feab2c72a02c91df310a36d33dfd1f7

commit r14-10097-g0bf94da59feab2c72a02c91df310a36d33dfd1f7
Author: Harald Anlauf 
Date:   Tue Apr 23 20:21:43 2024 +0200

Fortran: check C_SIZEOF on additions from TS29113/F2018 [PR103496]

gcc/testsuite/ChangeLog:

PR fortran/103496
* gfortran.dg/c_sizeof_8.f90: New test.

Diff:
---
 gcc/testsuite/gfortran.dg/c_sizeof_8.f90 | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/gcc/testsuite/gfortran.dg/c_sizeof_8.f90 
b/gcc/testsuite/gfortran.dg/c_sizeof_8.f90
new file mode 100644
index 000..0ae284436d0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c_sizeof_8.f90
@@ -0,0 +1,23 @@
+! { dg-do run }
+!
+! PR fortran/103496
+!
+! Test that C_SIZEOF returns the expected results
+
+program pr103496
+  use iso_c_binding
+  implicit none
+  integer :: a(6)
+  integer, pointer :: p(:)
+
+  if (c_sizeof(a)   /= 6*4) stop 1
+  if (c_sizeof(a(1))/=   4) stop 2
+  if (c_sizeof(a(:))/= 6*4) stop 3
+  if (c_sizeof(a(2::2)) /= 3*4) stop 4
+
+  allocate(p(5))
+  if (c_sizeof(p)   /= 5*4) stop 5
+  if (c_sizeof(p(1))/=   4) stop 6
+  if (c_sizeof(p(:))/= 5*4) stop 7
+  if (c_sizeof(p(2::2)) /= 2*4) stop 8
+end


[gcc r14-9996] Fortran: ALLOCATE of fixed-length CHARACTER with SOURCE/MOLD [PR113793]

2024-04-16 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:48024a99e3c2ae522d0026eedd591390506b68ca

commit r14-9996-g48024a99e3c2ae522d0026eedd591390506b68ca
Author: Harald Anlauf 
Date:   Sat Apr 13 19:09:24 2024 +0200

Fortran: ALLOCATE of fixed-length CHARACTER with SOURCE/MOLD [PR113793]

F2008 requires for ALLOCATE with SOURCE= or MOLD= specifier that the kind
type parameters of allocate-object and source-expr have the same values.
Add compile-time diagnostics for different character length and a runtime
check (under -fcheck=bounds).  Use length from allocate-object to prevent
heap corruption and to allow string padding or truncation on assignment.

gcc/fortran/ChangeLog:

PR fortran/113793
* resolve.cc (resolve_allocate_expr): Reject ALLOCATE with SOURCE=
or MOLD= specifier for unequal length.
* trans-stmt.cc (gfc_trans_allocate): If an allocatable character
variable has fixed length, use it and do not use the source length.
With bounds-checking enabled, add a runtime check for same length.

gcc/testsuite/ChangeLog:

PR fortran/113793
* gfortran.dg/allocate_with_source_29.f90: New test.
* gfortran.dg/allocate_with_source_30.f90: New test.
* gfortran.dg/allocate_with_source_31.f90: New test.

Diff:
---
 gcc/fortran/resolve.cc | 10 +
 gcc/fortran/trans-stmt.cc  | 36 +--
 .../gfortran.dg/allocate_with_source_29.f90| 48 
 .../gfortran.dg/allocate_with_source_30.f90| 51 ++
 .../gfortran.dg/allocate_with_source_31.f90| 38 
 5 files changed, 179 insertions(+), 4 deletions(-)

diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 4cbf7186119..6b3e5ba4fcb 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -8278,6 +8278,16 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code, bool 
*array_alloc_wo_spec)
  goto failure;
}
 
+  /* Check F2008:C639: "Corresponding kind type parameters of
+allocate-object and source-expr shall have the same values."  */
+  if (e->ts.type == BT_CHARACTER
+ && !e->ts.deferred
+ && e->ts.u.cl->length
+ && code->expr3->ts.type == BT_CHARACTER
+ && !gfc_check_same_strlen (e, code->expr3, "ALLOCATE with "
+"SOURCE= or MOLD= specifier"))
+   goto failure;
+
   /* Check TS18508, C702/C703.  */
   if (code->expr3->ts.type == BT_DERIVED
  && ((codimension && gfc_expr_attr (code->expr3).event_comp)
diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc
index 7997c167bae..c34e0b4c0cd 100644
--- a/gcc/fortran/trans-stmt.cc
+++ b/gcc/fortran/trans-stmt.cc
@@ -6829,10 +6829,26 @@ gfc_trans_allocate (gfc_code * code, gfc_omp_namelist 
*omp_allocate)
 in the array is needed, which is the product of the len and
 esize for char arrays.  For unlimited polymorphics len can be
 zero, therefore take the maximum of len and one.  */
+ tree lhs_len;
+
+ /* If an allocatable character variable has fixed length, use it.
+Otherwise use source length.  As different lengths are not
+allowed by the standard, generate a runtime check.  */
+ if (expr->ts.type == BT_CHARACTER && !expr->ts.deferred)
+   {
+ gfc_trans_same_strlen_check ("ALLOCATE with SOURCE= or MOLD=",
+  >expr3->where,
+  se.string_length, expr3_len,
+  );
+ lhs_len = fold_convert (TREE_TYPE (expr3_len), se.string_length);
+   }
+ else
+   lhs_len = expr3_len;
+
  tmp = fold_build2_loc (input_location, MAX_EXPR,
 TREE_TYPE (expr3_len),
-expr3_len, fold_convert (TREE_TYPE (expr3_len),
- integer_one_node));
+lhs_len, fold_convert (TREE_TYPE (expr3_len),
+   integer_one_node));
  tmp = fold_build2_loc (input_location, MULT_EXPR,
 TREE_TYPE (expr3_esize), expr3_esize,
 fold_convert (TREE_TYPE (expr3_esize), tmp));
@@ -6877,10 +6893,22 @@ gfc_trans_allocate (gfc_code * code, gfc_omp_namelist 
*omp_allocate)
 allocate.
 
 expr3_len is set when expr3 is an unlimited polymorphic
-object or a deferred length string.  */
+object or a deferred length string.
+
+If an allocatable character variable has fixed length, use it.
+Otherwise use source length.  As different lengths are not
+allowed by the 

[gcc r14-9893] Fortran: fix argument checking of intrinsics C_SIZEOF, C_F_POINTER [PR106500]

2024-04-10 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:ded646c91d2c0fb908faf6fa8fe1df0d7df49d16

commit r14-9893-gded646c91d2c0fb908faf6fa8fe1df0d7df49d16
Author: Harald Anlauf 
Date:   Tue Apr 9 23:07:59 2024 +0200

Fortran: fix argument checking of intrinsics C_SIZEOF, C_F_POINTER 
[PR106500]

The interpretation of the F2018 standard regarding valid arguments to the
intrinsic C_SIZEOF(X) was clarified in an edit to 18-007r1:

  https://j3-fortran.org/doc/year/22/22-101r1.txt

loosening restrictions and giving examples.  The F2023 text has:

! F2023:18.2.3.8  C_SIZEOF (X)
!
!   X shall be a data entity with interoperable type and type parameters,
!   and shall not be an assumed-size array, an assumed-rank array that
!   is associated with an assumed-size array, an unallocated allocatable
!   variable, or a pointer that is not associated.

where

! 3.41 data entity
!   data object, result of the evaluation of an expression, or the
!   result of the execution of a function reference

Update the checking code for interoperable arguments accordingly, and extend
to reject functions returning pointer as FPTR argument to C_F_POINTER.

gcc/fortran/ChangeLog:

PR fortran/106500
* check.cc (is_c_interoperable): Fix checks for C_SIZEOF.
(gfc_check_c_f_pointer): Reject function returning a pointer as 
FPTR,
and improve an error message.

gcc/testsuite/ChangeLog:

PR fortran/106500
* gfortran.dg/c_sizeof_6.f90: Remove wrong dg-error.
* gfortran.dg/sizeof_2.f90: Adjust pattern.
* gfortran.dg/c_f_pointer_tests_9.f90: New test.
* gfortran.dg/c_sizeof_7.f90: New test.

Diff:
---
 gcc/fortran/check.cc  | 26 --
 gcc/testsuite/gfortran.dg/c_f_pointer_tests_9.f90 | 37 
 gcc/testsuite/gfortran.dg/c_sizeof_6.f90  |  2 +-
 gcc/testsuite/gfortran.dg/c_sizeof_7.f90  | 42 +++
 gcc/testsuite/gfortran.dg/sizeof_2.f90|  2 +-
 5 files changed, 96 insertions(+), 13 deletions(-)

diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
index db74dcf3f40..2f50d84b876 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -5299,18 +5299,14 @@ is_c_interoperable (gfc_expr *expr, const char **msg, 
bool c_loc, bool c_f_ptr)
   return false;
 }
 
-  if (!c_loc && expr->rank > 0 && expr->expr_type != EXPR_ARRAY)
+  /* Checks for C_SIZEOF need to take into account edits to 18-007r1, see
+ https://j3-fortran.org/doc/year/22/22-101r1.txt .  */
+  if (!c_loc && !c_f_ptr && expr->rank > 0 && expr->expr_type == EXPR_VARIABLE)
 {
   gfc_array_ref *ar = gfc_find_array_ref (expr);
-  if (ar->type != AR_FULL)
+  if (ar->type == AR_FULL && ar->as->type == AS_ASSUMED_SIZE)
{
- *msg = "Only whole-arrays are interoperable";
- return false;
-   }
-  if (!c_f_ptr && ar->as->type != AS_EXPLICIT
- && ar->as->type != AS_ASSUMED_SIZE)
-   {
- *msg = "Only explicit-size and assumed-size arrays are interoperable";
+ *msg = "Assumed-size arrays are not interoperable";
  return false;
}
 }
@@ -5475,9 +5471,17 @@ gfc_check_c_f_pointer (gfc_expr *cptr, gfc_expr *fptr, 
gfc_expr *shape)
   return false;
 }
 
+  if (fptr->ts.type == BT_PROCEDURE && attr.function)
+{
+  gfc_error ("FPTR argument to C_F_POINTER at %L is a function "
+"returning a pointer", >where);
+  return false;
+}
+
   if (fptr->rank > 0 && !is_c_interoperable (fptr, , false, true))
-return gfc_notify_std (GFC_STD_F2018, "Noninteroperable array FPTR "
-  "at %L to C_F_POINTER: %s", >where, msg);
+return gfc_notify_std (GFC_STD_F2018,
+  "Noninteroperable array FPTR argument to "
+  "C_F_POINTER at %L: %s", >where, msg);
 
   return true;
 }
diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_tests_9.f90 
b/gcc/testsuite/gfortran.dg/c_f_pointer_tests_9.f90
new file mode 100644
index 000..8c8b4a713a4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c_f_pointer_tests_9.f90
@@ -0,0 +1,37 @@
+! { dg-do compile }
+!
+! A function returning a pointer cannot be interoperable
+! and cannot be used as FPTR argument to C_F_POINTER.
+
+subroutine s ()
+  use, intrinsic :: iso_c_binding
+  implicit none
+  type(c_ptr) :: cPtr
+  call c_f_pointer (cPtr, p0)! { dg-error "function returning a 
pointer" }
+  call c_f_pointer (cPtr, p1, shape=[2]) ! { dg-error "function returning a 
pointer" }
+contains
+  function p0 ()
+integer, pointer :: p0
+nullify (p0)
+  end
+  function p1 ()
+integer, pointer :: p1(:)
+nullify (p1)
+  end
+  function fp0 ()
+integer, pointer :: fp0
+call c_f_pointer (cPtr, fp0)! valid here
+  end
+  function fp1 

[gcc r11-11311] Fortran: fix DATA and derived types with pointer components [PR114474]

2024-04-07 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:619fc13043c86d616ef57cb31f8ac5d29b059ade

commit r11-11311-g619fc13043c86d616ef57cb31f8ac5d29b059ade
Author: Harald Anlauf 
Date:   Wed Mar 27 21:18:04 2024 +0100

Fortran: fix DATA and derived types with pointer components [PR114474]

When matching actual arguments in match_actual_arg, these are initially
treated as a possible dummy procedure, assuming that the correct type is
determined later.  This resolution could fail when the procedure is a
derived type constructor with a pointer component and appears in a DATA
statement, where the pointer shall be associated with an initial data
target.  Check for those cases where the type obviously has not been
resolved yet, and which were missed because there was no component
reference.

gcc/fortran/ChangeLog:

PR fortran/114474
* primary.c (gfc_variable_attr): Catch variables used in structure
constructors within DATA statements that are still tagged with a
temporary type BT_PROCEDURE from match_actual_arg and which have the
target attribute, and fix their typespec.

gcc/testsuite/ChangeLog:

PR fortran/114474
* gfortran.dg/data_pointer_3.f90: New test.

(cherry picked from commit bbb7c513dddc5c9b2d5e9b78bc1c2f85a0cfe07e)

Diff:
---
 gcc/fortran/primary.c| 12 +
 gcc/testsuite/gfortran.dg/data_pointer_3.f90 | 77 
 2 files changed, 89 insertions(+)

diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c
index 5cad2d2682b..79a2201c812 100644
--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -2663,6 +2663,18 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts)
   if (ts != NULL && expr->ts.type == BT_UNKNOWN)
 *ts = sym->ts;
 
+  /* Catch left-overs from match_actual_arg, where an actual argument of a
+ procedure is given a temporary ts.type == BT_PROCEDURE.  The fixup is
+ needed for structure constructors in DATA statements, where a pointer
+ is associated with a data target, and the argument has not been fully
+ resolved yet.  Components references are dealt with further below.  */
+  if (ts != NULL
+  && expr->ts.type == BT_PROCEDURE
+  && expr->ref == NULL
+  && attr.flavor != FL_PROCEDURE
+  && attr.target)
+*ts = sym->ts;
+
   has_inquiry_part = false;
   for (ref = expr->ref; ref; ref = ref->next)
 if (ref->type == REF_INQUIRY)
diff --git a/gcc/testsuite/gfortran.dg/data_pointer_3.f90 
b/gcc/testsuite/gfortran.dg/data_pointer_3.f90
new file mode 100644
index 000..49c288e93b9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_pointer_3.f90
@@ -0,0 +1,77 @@
+! { dg-do compile }
+! PR fortran/114474 - DATA and derived types with pointer components
+
+program pr114474
+  implicit none
+  integer, target :: ii = 42! initial data target
+
+  integer, target :: jj = 24
+  integer, pointer:: qq => jj
+  ! ii and jj resolve slightly differently when the data statement below
+  ! is reached, as jj is resolved outside the structure constructor first
+
+  type t
+ integer, pointer :: h
+  end type t
+
+  integer, target :: kk(7) =  23
+  integer, pointer:: ll(:) => kk
+
+  type t1
+ integer  :: m(7)
+  end type t1
+
+  type(t) :: x1, x2, x3, x4, x5
+  type(t), parameter  :: z1 = t(null())
+
+  type(t1), target:: tt = t1([1,2,3,4,5,6,7])
+  type(t1), parameter :: vv = t1(22)
+  type(t1):: w1, w2
+  integer,  pointer   :: p1(:) => tt% m
+
+  data x1 / t(null())  /
+  data x2 / t(ii)  / ! ii is initial data target
+  data x3 / t(jj)  / ! jj is resolved differently...
+  data x4 / t(tt%m(3)) / ! pointer association with 3rd element
+
+  data w1 / t1(12) /
+  data w2 / t1(vv%m)   /
+
+  if (  associated (x1% h)) stop 1
+  if (.not. associated (x2% h)) stop 2
+  if (.not. associated (x3% h)) stop 3
+  if (.not. associated (x4% h)) stop 4
+  if (x2% h /= 42) stop 5
+  if (x3% h /= 24) stop 6
+  if (x4% h /=  3) stop 7
+ 
+  if (any (w1%m /= 12  )) stop 8
+  if (any (w2%m /= vv%m)) stop 9
+end
+
+
+subroutine sub
+  implicit none
+
+  interface
+ real function myfun (x)
+   real, intent(in) :: x
+ end function myfun
+  end interface
+
+  type u
+ procedure(myfun), pointer, nopass :: p
+  end type u
+
+  type(u):: u3 = u(null())
+  type(u), parameter :: u4 = u(null())
+  type(u):: u1, u2
+
+  data u1 / u(null()) /
+  data u2 / u(myfun)  /
+end
+
+real function myfun (x)
+  real, intent(in) :: x
+  myfun = x
+end function myfun


[gcc r12-10314] Fortran: fix DATA and derived types with pointer components [PR114474]

2024-04-07 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:88abe04de2f16f773126f3908632a27568330cc9

commit r12-10314-g88abe04de2f16f773126f3908632a27568330cc9
Author: Harald Anlauf 
Date:   Wed Mar 27 21:18:04 2024 +0100

Fortran: fix DATA and derived types with pointer components [PR114474]

When matching actual arguments in match_actual_arg, these are initially
treated as a possible dummy procedure, assuming that the correct type is
determined later.  This resolution could fail when the procedure is a
derived type constructor with a pointer component and appears in a DATA
statement, where the pointer shall be associated with an initial data
target.  Check for those cases where the type obviously has not been
resolved yet, and which were missed because there was no component
reference.

gcc/fortran/ChangeLog:

PR fortran/114474
* primary.cc (gfc_variable_attr): Catch variables used in structure
constructors within DATA statements that are still tagged with a
temporary type BT_PROCEDURE from match_actual_arg and which have the
target attribute, and fix their typespec.

gcc/testsuite/ChangeLog:

PR fortran/114474
* gfortran.dg/data_pointer_3.f90: New test.

(cherry picked from commit bbb7c513dddc5c9b2d5e9b78bc1c2f85a0cfe07e)

Diff:
---
 gcc/fortran/primary.cc   | 12 +
 gcc/testsuite/gfortran.dg/data_pointer_3.f90 | 77 
 2 files changed, 89 insertions(+)

diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index 1ae6a12e0b7..78295c54b6c 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -2664,6 +2664,18 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts)
   if (ts != NULL && expr->ts.type == BT_UNKNOWN)
 *ts = sym->ts;
 
+  /* Catch left-overs from match_actual_arg, where an actual argument of a
+ procedure is given a temporary ts.type == BT_PROCEDURE.  The fixup is
+ needed for structure constructors in DATA statements, where a pointer
+ is associated with a data target, and the argument has not been fully
+ resolved yet.  Components references are dealt with further below.  */
+  if (ts != NULL
+  && expr->ts.type == BT_PROCEDURE
+  && expr->ref == NULL
+  && attr.flavor != FL_PROCEDURE
+  && attr.target)
+*ts = sym->ts;
+
   has_inquiry_part = false;
   for (ref = expr->ref; ref; ref = ref->next)
 if (ref->type == REF_INQUIRY)
diff --git a/gcc/testsuite/gfortran.dg/data_pointer_3.f90 
b/gcc/testsuite/gfortran.dg/data_pointer_3.f90
new file mode 100644
index 000..49c288e93b9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_pointer_3.f90
@@ -0,0 +1,77 @@
+! { dg-do compile }
+! PR fortran/114474 - DATA and derived types with pointer components
+
+program pr114474
+  implicit none
+  integer, target :: ii = 42! initial data target
+
+  integer, target :: jj = 24
+  integer, pointer:: qq => jj
+  ! ii and jj resolve slightly differently when the data statement below
+  ! is reached, as jj is resolved outside the structure constructor first
+
+  type t
+ integer, pointer :: h
+  end type t
+
+  integer, target :: kk(7) =  23
+  integer, pointer:: ll(:) => kk
+
+  type t1
+ integer  :: m(7)
+  end type t1
+
+  type(t) :: x1, x2, x3, x4, x5
+  type(t), parameter  :: z1 = t(null())
+
+  type(t1), target:: tt = t1([1,2,3,4,5,6,7])
+  type(t1), parameter :: vv = t1(22)
+  type(t1):: w1, w2
+  integer,  pointer   :: p1(:) => tt% m
+
+  data x1 / t(null())  /
+  data x2 / t(ii)  / ! ii is initial data target
+  data x3 / t(jj)  / ! jj is resolved differently...
+  data x4 / t(tt%m(3)) / ! pointer association with 3rd element
+
+  data w1 / t1(12) /
+  data w2 / t1(vv%m)   /
+
+  if (  associated (x1% h)) stop 1
+  if (.not. associated (x2% h)) stop 2
+  if (.not. associated (x3% h)) stop 3
+  if (.not. associated (x4% h)) stop 4
+  if (x2% h /= 42) stop 5
+  if (x3% h /= 24) stop 6
+  if (x4% h /=  3) stop 7
+ 
+  if (any (w1%m /= 12  )) stop 8
+  if (any (w2%m /= vv%m)) stop 9
+end
+
+
+subroutine sub
+  implicit none
+
+  interface
+ real function myfun (x)
+   real, intent(in) :: x
+ end function myfun
+  end interface
+
+  type u
+ procedure(myfun), pointer, nopass :: p
+  end type u
+
+  type(u):: u3 = u(null())
+  type(u), parameter :: u4 = u(null())
+  type(u):: u1, u2
+
+  data u1 / u(null()) /
+  data u2 / u(myfun)  /
+end
+
+real function myfun (x)
+  real, intent(in) :: x
+  myfun = x
+end function myfun


[gcc r13-8592] Fortran: fix DATA and derived types with pointer components [PR114474]

2024-04-07 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:0d4862691d2b58f7bd2d58de0e78bc574c313d39

commit r13-8592-g0d4862691d2b58f7bd2d58de0e78bc574c313d39
Author: Harald Anlauf 
Date:   Wed Mar 27 21:18:04 2024 +0100

Fortran: fix DATA and derived types with pointer components [PR114474]

When matching actual arguments in match_actual_arg, these are initially
treated as a possible dummy procedure, assuming that the correct type is
determined later.  This resolution could fail when the procedure is a
derived type constructor with a pointer component and appears in a DATA
statement, where the pointer shall be associated with an initial data
target.  Check for those cases where the type obviously has not been
resolved yet, and which were missed because there was no component
reference.

gcc/fortran/ChangeLog:

PR fortran/114474
* primary.cc (gfc_variable_attr): Catch variables used in structure
constructors within DATA statements that are still tagged with a
temporary type BT_PROCEDURE from match_actual_arg and which have the
target attribute, and fix their typespec.

gcc/testsuite/ChangeLog:

PR fortran/114474
* gfortran.dg/data_pointer_3.f90: New test.

(cherry picked from commit bbb7c513dddc5c9b2d5e9b78bc1c2f85a0cfe07e)

Diff:
---
 gcc/fortran/primary.cc   | 12 +
 gcc/testsuite/gfortran.dg/data_pointer_3.f90 | 77 
 2 files changed, 89 insertions(+)

diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index c6a119c73cb..edbd162ed13 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -2672,6 +2672,18 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts)
   if (ts != NULL && expr->ts.type == BT_UNKNOWN)
 *ts = sym->ts;
 
+  /* Catch left-overs from match_actual_arg, where an actual argument of a
+ procedure is given a temporary ts.type == BT_PROCEDURE.  The fixup is
+ needed for structure constructors in DATA statements, where a pointer
+ is associated with a data target, and the argument has not been fully
+ resolved yet.  Components references are dealt with further below.  */
+  if (ts != NULL
+  && expr->ts.type == BT_PROCEDURE
+  && expr->ref == NULL
+  && attr.flavor != FL_PROCEDURE
+  && attr.target)
+*ts = sym->ts;
+
   has_inquiry_part = false;
   for (ref = expr->ref; ref; ref = ref->next)
 if (ref->type == REF_INQUIRY)
diff --git a/gcc/testsuite/gfortran.dg/data_pointer_3.f90 
b/gcc/testsuite/gfortran.dg/data_pointer_3.f90
new file mode 100644
index 000..49c288e93b9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_pointer_3.f90
@@ -0,0 +1,77 @@
+! { dg-do compile }
+! PR fortran/114474 - DATA and derived types with pointer components
+
+program pr114474
+  implicit none
+  integer, target :: ii = 42! initial data target
+
+  integer, target :: jj = 24
+  integer, pointer:: qq => jj
+  ! ii and jj resolve slightly differently when the data statement below
+  ! is reached, as jj is resolved outside the structure constructor first
+
+  type t
+ integer, pointer :: h
+  end type t
+
+  integer, target :: kk(7) =  23
+  integer, pointer:: ll(:) => kk
+
+  type t1
+ integer  :: m(7)
+  end type t1
+
+  type(t) :: x1, x2, x3, x4, x5
+  type(t), parameter  :: z1 = t(null())
+
+  type(t1), target:: tt = t1([1,2,3,4,5,6,7])
+  type(t1), parameter :: vv = t1(22)
+  type(t1):: w1, w2
+  integer,  pointer   :: p1(:) => tt% m
+
+  data x1 / t(null())  /
+  data x2 / t(ii)  / ! ii is initial data target
+  data x3 / t(jj)  / ! jj is resolved differently...
+  data x4 / t(tt%m(3)) / ! pointer association with 3rd element
+
+  data w1 / t1(12) /
+  data w2 / t1(vv%m)   /
+
+  if (  associated (x1% h)) stop 1
+  if (.not. associated (x2% h)) stop 2
+  if (.not. associated (x3% h)) stop 3
+  if (.not. associated (x4% h)) stop 4
+  if (x2% h /= 42) stop 5
+  if (x3% h /= 24) stop 6
+  if (x4% h /=  3) stop 7
+ 
+  if (any (w1%m /= 12  )) stop 8
+  if (any (w2%m /= vv%m)) stop 9
+end
+
+
+subroutine sub
+  implicit none
+
+  interface
+ real function myfun (x)
+   real, intent(in) :: x
+ end function myfun
+  end interface
+
+  type u
+ procedure(myfun), pointer, nopass :: p
+  end type u
+
+  type(u):: u3 = u(null())
+  type(u), parameter :: u4 = u(null())
+  type(u):: u1, u2
+
+  data u1 / u(null()) /
+  data u2 / u(myfun)  /
+end
+
+real function myfun (x)
+  real, intent(in) :: x
+  myfun = x
+end function myfun


[gcc r11-11310] fortran: Fix setting of array lower bound for named arrays

2024-04-06 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:b755a7af1f2ef1f5348d04db20f751e898abcd9d

commit r11-11310-gb755a7af1f2ef1f5348d04db20f751e898abcd9d
Author: Chung-Lin Tang 
Date:   Fri Dec 3 17:27:17 2021 +0800

fortran: Fix setting of array lower bound for named arrays

This patch fixes a case of setting array low-bounds, found for particular 
uses
of SOURCE=/MOLD=. This adjusts the relevant part in gfc_trans_allocate() to
set e3_has_nodescriptor only for non-named arrays.

2021-12-03  Tobias Burnus  

gcc/fortran/ChangeLog:

* trans-stmt.c (gfc_trans_allocate): Set e3_has_nodescriptor to true
only for non-named arrays.

gcc/testsuite/ChangeLog:

* gfortran.dg/allocate_with_source_26.f90: Adjust testcase.
* gfortran.dg/allocate_with_mold_4.f90: New testcase.

(cherry picked from commit 6262e3a22b3d86afc116480bc59a7bb30b0cfd40)

Diff:
---
 gcc/fortran/trans-stmt.c   | 17 +++
 gcc/testsuite/gfortran.dg/allocate_with_mold_4.f90 | 24 ++
 .../gfortran.dg/allocate_with_source_26.f90|  8 
 3 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index 0e387bbb4e6..0f920c496a0 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -6661,16 +6661,13 @@ gfc_trans_allocate (gfc_code * code)
   else
e3rhs = gfc_copy_expr (code->expr3);
 
-  // We need to propagate the bounds of the expr3 for source=/mold=;
-  // however, for nondescriptor arrays, we use internally a lower bound
-  // of zero instead of one, which needs to be corrected for the allocate 
obj
-  if (e3_is == E3_DESC)
-   {
- symbol_attribute attr = gfc_expr_attr (code->expr3);
- if (code->expr3->expr_type == EXPR_ARRAY ||
- (!attr.allocatable && !attr.pointer))
-   e3_has_nodescriptor = true;
-   }
+  // We need to propagate the bounds of the expr3 for source=/mold=.
+  // However, for non-named arrays, the lbound has to be 1 and neither the
+  // bound used inside the called function even when returning an
+  // allocatable/pointer nor the zero used internally.
+  if (e3_is == E3_DESC
+ && code->expr3->expr_type != EXPR_VARIABLE)
+   e3_has_nodescriptor = true;
 }
 
   /* Loop over all objects to allocate.  */
diff --git a/gcc/testsuite/gfortran.dg/allocate_with_mold_4.f90 
b/gcc/testsuite/gfortran.dg/allocate_with_mold_4.f90
new file mode 100644
index 000..d545fe1249f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/allocate_with_mold_4.f90
@@ -0,0 +1,24 @@
+program A_M
+  implicit none
+  real, parameter :: C(5:10) = 5.0
+  real, dimension (:), allocatable :: A, B
+  allocate (A(6))
+  call Init (A)
+contains
+  subroutine Init ( A )
+real, dimension ( -1 : ), intent ( in ) :: A
+integer, dimension ( 1 ) :: lb_B
+
+allocate (B, mold = A)
+if (any (lbound (B) /= lbound (A))) stop 1
+if (any (ubound (B) /= ubound (A))) stop 2
+if (any (shape (B) /= shape (A))) stop 3
+if (size (B) /= size (A)) stop 4
+deallocate (B)
+allocate (B, mold = C)
+if (any (lbound (B) /= lbound (C))) stop 5
+if (any (ubound (B) /= ubound (C))) stop 6
+if (any (shape (B) /= shape (C))) stop 7
+if (size (B) /= size (C)) stop 8
+end
+end 
diff --git a/gcc/testsuite/gfortran.dg/allocate_with_source_26.f90 
b/gcc/testsuite/gfortran.dg/allocate_with_source_26.f90
index 28f24fc1e10..323c8a30b9e 100644
--- a/gcc/testsuite/gfortran.dg/allocate_with_source_26.f90
+++ b/gcc/testsuite/gfortran.dg/allocate_with_source_26.f90
@@ -34,23 +34,23 @@ program p
  if (lbound(p1, 1) /= 3 .or. ubound(p1, 1) /= 4 &
  .or. lbound(p2, 1) /= 3 .or. ubound(p2, 1) /= 4 &
  .or. lbound(p3, 1) /= 1 .or. ubound(p3, 1) /= 2 &
- .or. lbound(p4, 1) /= 7 .or. ubound(p4, 1) /= 8 &
+ .or. lbound(p4, 1) /= 1 .or. ubound(p4, 1) /= 2 &
  .or. p1(3)%i /= 43 .or. p1(4)%i /= 56 &
  .or. p2(3)%i /= 43 .or. p2(4)%i /= 56 &
  .or. p3(1)%i /= 43 .or. p3(2)%i /= 56 &
- .or. p4(7)%i /= 11 .or. p4(8)%i /= 12) then
+ .or. p4(1)%i /= 11 .or. p4(2)%i /= 12) then
call abort()
  endif
 
  !write(*,*) lbound(a,1), ubound(a,1) ! prints 1 3
  !write(*,*) lbound(b,1), ubound(b,1) ! prints 1 3
- !write(*,*) lbound(c,1), ubound(c,1) ! prints 3 5
+ !write(*,*) lbound(c,1), ubound(c,1) ! prints 1 3
  !write(*,*) lbound(d,1), ubound(d,1) ! prints 1 5
  !write(*,*) lbound(e,1), ubound(e,1) ! prints 1 6
 
  if (lbound(a,1) /= 1 .or. ubound(a,1) /= 3 &
  .or. lbound(b,1) /= 1 .or. ubound(b,1) /= 3 &
- .or. lbound(c,1) /= 3 .or. ubound(c,1) /= 5 &
+ .or. lbound(c,1) /= 1 .or. ubound(c,1) /= 3 & 
  .or. lbound(d,1) /= 1 .or. ubound(d,1) /= 5 &
  .or. lbound(e,1) /= 1 .or. ubound(e,1) /= 6) then
call abort()


[gcc r13-8559] Fortran: error recovery while simplifying expressions [PR103707, PR106987]

2024-04-02 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:2808797fc4da7cc455803e2b69368b52db857b4c

commit r13-8559-g2808797fc4da7cc455803e2b69368b52db857b4c
Author: Harald Anlauf 
Date:   Tue Mar 5 21:54:26 2024 +0100

Fortran: error recovery while simplifying expressions [PR103707,PR106987]

When an exception is encountered during simplification of arithmetic
expressions, the result may depend on whether range-checking is active
(-frange-check) or not.  However, the code path in the front-end should
stay the same for "soft" errors for which the exception is triggered by the
check, while "hard" errors should always terminate the simplification, so
that error recovery is independent of the flag.  Separation of arithmetic
error codes into "hard" and "soft" errors shall be done consistently via
is_hard_arith_error().

PR fortran/103707
PR fortran/106987

gcc/fortran/ChangeLog:

* arith.cc (is_hard_arith_error): New helper function to determine
whether an arithmetic error is "hard" or not.
(check_result): Use it.
(gfc_arith_divide): Set "Division by zero" only for regular
numerators of real and complex divisions.
(reduce_unary): Use is_hard_arith_error to determine whether a hard
or (recoverable) soft error was encountered.  Terminate immediately
on hard error, otherwise remember code of first soft error.
(reduce_binary_ac): Likewise.
(reduce_binary_ca): Likewise.
(reduce_binary_aa): Likewise.

gcc/testsuite/ChangeLog:

* gfortran.dg/arithmetic_overflow_3.f90: New test.

(cherry picked from commit 93e1d4d24ed014387da97e2ce11556d68fe98e66)

Diff:
---
 gcc/fortran/arith.cc   | 134 +++--
 .../gfortran.dg/arithmetic_overflow_3.f90  |  48 
 2 files changed, 142 insertions(+), 40 deletions(-)

diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc
index 5673c76823a..fade085450c 100644
--- a/gcc/fortran/arith.cc
+++ b/gcc/fortran/arith.cc
@@ -130,6 +130,30 @@ gfc_arith_error (arith code)
 }
 
 
+/* Check if a certain arithmetic error code is severe enough to prevent
+   further simplification, as opposed to errors thrown by the range check
+   (e.g. overflow) or arithmetic exceptions that are tolerated with
+   -fno-range-check.  */
+
+static bool
+is_hard_arith_error (arith code)
+{
+  switch (code)
+{
+case ARITH_OK:
+case ARITH_OVERFLOW:
+case ARITH_UNDERFLOW:
+case ARITH_NAN:
+case ARITH_DIV0:
+case ARITH_ASYMMETRIC:
+  return false;
+
+default:
+  return true;
+}
+}
+
+
 /* Get things ready to do math.  */
 
 void
@@ -579,10 +603,10 @@ check_result (arith rc, gfc_expr *x, gfc_expr *r, 
gfc_expr **rp)
   val = ARITH_OK;
 }
 
-  if (val == ARITH_OK || val == ARITH_OVERFLOW)
-*rp = r;
-  else
+  if (is_hard_arith_error (val))
 gfc_free_expr (r);
+  else
+*rp = r;
 
   return val;
 }
@@ -792,23 +816,26 @@ gfc_arith_divide (gfc_expr *op1, gfc_expr *op2, gfc_expr 
**resultp)
   break;
 
 case BT_REAL:
-  if (mpfr_sgn (op2->value.real) == 0 && flag_range_check == 1)
-   {
- rc = ARITH_DIV0;
- break;
-   }
+  /* Set "Division by zero" only for regular numerator.  */
+  if (flag_range_check == 1
+ && mpfr_zero_p (op2->value.real)
+ && mpfr_regular_p (op1->value.real))
+   rc = ARITH_DIV0;
 
   mpfr_div (result->value.real, op1->value.real, op2->value.real,
   GFC_RND_MODE);
   break;
 
 case BT_COMPLEX:
-  if (mpc_cmp_si_si (op2->value.complex, 0, 0) == 0
- && flag_range_check == 1)
-   {
- rc = ARITH_DIV0;
- break;
-   }
+  /* Set "Division by zero" only for regular numerator.  */
+  if (flag_range_check == 1
+ && mpfr_zero_p (mpc_realref (op2->value.complex))
+ && mpfr_zero_p (mpc_imagref (op2->value.complex))
+ && ((mpfr_regular_p (mpc_realref (op1->value.complex))
+  && mpfr_number_p (mpc_imagref (op1->value.complex)))
+ || (mpfr_regular_p (mpc_imagref (op1->value.complex))
+ && mpfr_number_p (mpc_realref (op1->value.complex)
+   rc = ARITH_DIV0;
 
   gfc_set_model (mpc_realref (op1->value.complex));
   if (mpc_cmp_si_si (op2->value.complex, 0, 0) == 0)
@@ -1323,7 +1350,6 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), 
gfc_expr *op,
   gfc_constructor *c;
   gfc_expr *r;
   arith rc;
-  bool ov = false;
 
   if (op->expr_type == EXPR_CONSTANT)
 return eval (op, result);
@@ -1335,19 +1361,22 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), 
gfc_expr *op,
   head = gfc_constructor_copy (op->value.constructor);
   for (c = gfc_constructor_first (head); c; c = gfc_constructor_next (c))
 {
-  rc = reduce_unary (eval, c->expr, );
+  arith rc_tmp = 

[gcc r13-8558] Fortran: error recovery on arithmetic overflow on unary operations [PR113799]

2024-04-02 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:ec8303dea72ed4f9ae9fdf3c996a0deef6809351

commit r13-8558-gec8303dea72ed4f9ae9fdf3c996a0deef6809351
Author: Harald Anlauf 
Date:   Thu Feb 8 21:51:38 2024 +0100

Fortran: error recovery on arithmetic overflow on unary operations 
[PR113799]

PR fortran/113799

gcc/fortran/ChangeLog:

* arith.cc (reduce_unary): Remember any overflow encountered during
reduction of unary arithmetic operations on array constructors and
continue, and return error status, but terminate on serious errors.

gcc/testsuite/ChangeLog:

* gfortran.dg/arithmetic_overflow_2.f90: New test.

(cherry picked from commit b3d622d70ba209b63471fc1b0970870046e55745)

Diff:
---
 gcc/fortran/arith.cc| 11 ---
 gcc/testsuite/gfortran.dg/arithmetic_overflow_2.f90 | 12 
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc
index fcf37d48bfc..5673c76823a 100644
--- a/gcc/fortran/arith.cc
+++ b/gcc/fortran/arith.cc
@@ -1323,6 +1323,7 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), 
gfc_expr *op,
   gfc_constructor *c;
   gfc_expr *r;
   arith rc;
+  bool ov = false;
 
   if (op->expr_type == EXPR_CONSTANT)
 return eval (op, result);
@@ -1336,13 +1337,17 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), 
gfc_expr *op,
 {
   rc = reduce_unary (eval, c->expr, );
 
-  if (rc != ARITH_OK)
+  /* Remember any overflow encountered during reduction and continue,
+but terminate on serious errors.  */
+  if (rc == ARITH_OVERFLOW)
+   ov = true;
+  else if (rc != ARITH_OK)
break;
 
   gfc_replace_expr (c->expr, r);
 }
 
-  if (rc != ARITH_OK)
+  if (rc != ARITH_OK && rc != ARITH_OVERFLOW)
 gfc_constructor_free (head);
   else
 {
@@ -1363,7 +1368,7 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), 
gfc_expr *op,
   *result = r;
 }
 
-  return rc;
+  return ov ? ARITH_OVERFLOW : rc;
 }
 
 
diff --git a/gcc/testsuite/gfortran.dg/arithmetic_overflow_2.f90 
b/gcc/testsuite/gfortran.dg/arithmetic_overflow_2.f90
new file mode 100644
index 000..6ca27f74215
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/arithmetic_overflow_2.f90
@@ -0,0 +1,12 @@
+! { dg-do compile }
+! { dg-additional-options "-frange-check" }
+!
+! PR fortran/113799 - handle arithmetic overflow on unary minus
+
+program p
+  implicit none
+  real, parameter :: inf = real(z'7F80')
+  real, parameter :: someInf(*) = [inf, 0.]
+  print *, -someInf ! { dg-error "Arithmetic overflow" }
+  print *, minval(-someInf) ! { dg-error "Arithmetic overflow" }
+end


[gcc r13-8557] Fortran: set shape of initializers of zero-sized arrays [PR95374, PR104352]

2024-04-02 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:0dd82c0fba660775ff76ae27077a67f2f1358920

commit r13-8557-g0dd82c0fba660775ff76ae27077a67f2f1358920
Author: Harald Anlauf 
Date:   Wed May 17 20:39:18 2023 +0200

Fortran: set shape of initializers of zero-sized arrays [PR95374,PR104352]

gcc/fortran/ChangeLog:

PR fortran/95374
PR fortran/104352
* decl.cc (add_init_expr_to_sym): Set shape of initializer also for
zero-sized arrays, so that bounds violations can be detected later.

gcc/testsuite/ChangeLog:

PR fortran/95374
PR fortran/104352
* gfortran.dg/zero_sized_13.f90: New test.

(cherry picked from commit 7bafe652dba9167b65e7b5ef24e77eceb49709ba)

Diff:
---
 gcc/fortran/decl.cc |  3 +--
 gcc/testsuite/gfortran.dg/zero_sized_13.f90 | 28 
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 03e993eb0ff..527e84ad763 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -2248,8 +2248,7 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, 
locus *var_locus)
  && gfc_is_constant_expr (init)
  && (init->expr_type == EXPR_CONSTANT
  || init->expr_type == EXPR_STRUCTURE)
- && spec_size (sym->as, )
- && mpz_cmp_si (size, 0) > 0)
+ && spec_size (sym->as, ))
{
  array = gfc_get_array_expr (init->ts.type, init->ts.kind,
  >where);
diff --git a/gcc/testsuite/gfortran.dg/zero_sized_13.f90 
b/gcc/testsuite/gfortran.dg/zero_sized_13.f90
new file mode 100644
index 000..4035d458b32
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/zero_sized_13.f90
@@ -0,0 +1,28 @@
+! { dg-do compile }
+! { dg-options "-w" }
+!
+! PR fortran/95374
+! PR fortran/104352 - Various ICEs for bounds violation with zero-sized arrays
+!
+! Contributed by G. Steinmetz
+
+program p
+  implicit none
+  integer :: i
+  integer, parameter :: a(0)= 0
+  integer, parameter :: b(0:-5) = 0
+  integer, parameter :: c(*) = [(a(i:i), i=0,0)] ! { dg-error "out of bounds" }
+  integer, parameter :: d(*) = [(b(i:i), i=1,1)] ! { dg-error "out of bounds" }
+  integer, parameter :: e(1) = [(a(i)  , i=1,1)] ! { dg-error "out of bounds" }
+  integer, parameter :: f(1) = [(a(i:i), i=1,1)] ! { dg-error "out of bounds" }
+  integer:: g(1) = [(a(i:i), i=0,0)] ! { dg-error "out of bounds" }
+  integer:: h(1) = [(a(i:i), i=1,1)] ! { dg-error "out of bounds" }
+  print *, [(a(i:i), i=0,0)] ! { dg-error "out of bounds" }
+  print *, [(a(i:i), i=1,1)] ! { dg-error "out of bounds" }
+  print *, any (a(1:1) == 1) ! { dg-error "out of bounds" }
+  print *, all (a(0:0) == 1) ! { dg-error "out of bounds" }
+  print *, sum (a(1:1))  ! { dg-error "out of bounds" }
+  print *, iall (a(0:0)) ! { dg-error "out of bounds" }
+  print *, minloc (a(0:0),1) ! { dg-error "out of bounds" }
+  print *, dot_product(a(1:1),a(1:1)) ! { dg-error "out of bounds" }
+end


[gcc r11-11299] Fortran: fix NULL pointer dereference on overlapping initialization [PR50410]

2024-03-29 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:1611acc1f72cad30c7ecccb5c85246836c1d0299

commit r11-11299-g1611acc1f72cad30c7ecccb5c85246836c1d0299
Author: Harald Anlauf 
Date:   Thu Mar 28 22:34:40 2024 +0100

Fortran: fix NULL pointer dereference on overlapping initialization 
[PR50410]

gcc/fortran/ChangeLog:

PR fortran/50410
* trans-expr.c (gfc_conv_structure): Check for NULL pointer.

gcc/testsuite/ChangeLog:

PR fortran/50410
* gfortran.dg/data_initialized_4.f90: New test.

(cherry picked from commit 6fb253a25dff13253d63553f02e0fe72c5e3ab4e)

Diff:
---
 gcc/fortran/trans-expr.c |  2 +-
 gcc/testsuite/gfortran.dg/data_initialized_4.f90 | 16 
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 5adee114157..37f16f37e12 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -8879,7 +8879,7 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int 
init)
   cm = expr->ts.u.derived->components;
 
   for (c = gfc_constructor_first (expr->value.constructor);
-   c; c = gfc_constructor_next (c), cm = cm->next)
+   c && cm; c = gfc_constructor_next (c), cm = cm->next)
 {
   /* Skip absent members in default initializers and allocatable
 components.  Although the latter have a default initializer
diff --git a/gcc/testsuite/gfortran.dg/data_initialized_4.f90 
b/gcc/testsuite/gfortran.dg/data_initialized_4.f90
new file mode 100644
index 000..156b6607edf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_initialized_4.f90
@@ -0,0 +1,16 @@
+! { dg-do compile }
+! { dg-additional-options "-std=legacy" }
+!
+! PR fortran/50410
+!
+! Silently allow overlapping initialization in legacy mode (used to ICE)
+
+program p
+  implicit none
+  type t
+ integer :: g = 1
+  end type t
+  type(t) :: u = t(2)
+  data u%g /3/
+  print *, u! this might print "2"
+end


[gcc r12-10299] Fortran: fix NULL pointer dereference on overlapping initialization [PR50410]

2024-03-29 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:cb72fbd49e1f0c1cbdf8a9e97860063b19b1f95e

commit r12-10299-gcb72fbd49e1f0c1cbdf8a9e97860063b19b1f95e
Author: Harald Anlauf 
Date:   Thu Mar 28 22:34:40 2024 +0100

Fortran: fix NULL pointer dereference on overlapping initialization 
[PR50410]

gcc/fortran/ChangeLog:

PR fortran/50410
* trans-expr.cc (gfc_conv_structure): Check for NULL pointer.

gcc/testsuite/ChangeLog:

PR fortran/50410
* gfortran.dg/data_initialized_4.f90: New test.

(cherry picked from commit 6fb253a25dff13253d63553f02e0fe72c5e3ab4e)

Diff:
---
 gcc/fortran/trans-expr.cc|  2 +-
 gcc/testsuite/gfortran.dg/data_initialized_4.f90 | 16 
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 27b34984705..11ee1931b8e 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -9298,7 +9298,7 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int 
init)
   cm = expr->ts.u.derived->components;
 
   for (c = gfc_constructor_first (expr->value.constructor);
-   c; c = gfc_constructor_next (c), cm = cm->next)
+   c && cm; c = gfc_constructor_next (c), cm = cm->next)
 {
   /* Skip absent members in default initializers and allocatable
 components.  Although the latter have a default initializer
diff --git a/gcc/testsuite/gfortran.dg/data_initialized_4.f90 
b/gcc/testsuite/gfortran.dg/data_initialized_4.f90
new file mode 100644
index 000..156b6607edf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_initialized_4.f90
@@ -0,0 +1,16 @@
+! { dg-do compile }
+! { dg-additional-options "-std=legacy" }
+!
+! PR fortran/50410
+!
+! Silently allow overlapping initialization in legacy mode (used to ICE)
+
+program p
+  implicit none
+  type t
+ integer :: g = 1
+  end type t
+  type(t) :: u = t(2)
+  data u%g /3/
+  print *, u! this might print "2"
+end


[gcc r13-8506] Fortran: fix passing of optional dummies to bind(c) procedures [PR113866]

2024-03-29 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:5f9144021615f24d038890dab7db2a0b9e84f6d3

commit r13-8506-g5f9144021615f24d038890dab7db2a0b9e84f6d3
Author: Harald Anlauf 
Date:   Tue Feb 13 20:19:10 2024 +0100

Fortran: fix passing of optional dummies to bind(c) procedures [PR113866]

PR fortran/113866

gcc/fortran/ChangeLog:

* trans-expr.cc (gfc_conv_procedure_call): When passing an optional
dummy argument to an optional dummy argument of a bind(c) procedure
and the dummy argument is passed via a CFI descriptor, no special
presence check and passing of a default NULL pointer is needed.

gcc/testsuite/ChangeLog:

* gfortran.dg/bind_c_optional-2.f90: New test.

(cherry picked from commit f4935df217ad89f884f908f39086b322e80123d0)

Diff:
---
 gcc/fortran/trans-expr.cc   |   6 +-
 gcc/testsuite/gfortran.dg/bind_c_optional-2.f90 | 105 
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index d9de93260a6..c3f02c83b3f 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -7052,8 +7052,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 with an interface indicating an optional argument.  When we call
 an intrinsic subroutine, however, fsym is NULL, but we might still
 have an optional argument, so we proceed to the substitution
-just in case.  */
-  if (e && (fsym == NULL || fsym->attr.optional))
+just in case.  Arguments passed to bind(c) procedures via CFI
+descriptors are handled elsewhere.  */
+  if (e && (fsym == NULL || fsym->attr.optional)
+ && !(sym->attr.is_bind_c && is_CFI_desc (fsym, NULL)))
{
  /* If an optional argument is itself an optional dummy argument,
 check its presence and substitute a null if absent.  This is
diff --git a/gcc/testsuite/gfortran.dg/bind_c_optional-2.f90 
b/gcc/testsuite/gfortran.dg/bind_c_optional-2.f90
new file mode 100644
index 000..ceedef7f006
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/bind_c_optional-2.f90
@@ -0,0 +1,105 @@
+! { dg-do run }
+! PR fortran/113866
+!
+! Check interoperability of assumed-length character (optional and
+! non-optional) dummies between bind(c) and non-bind(c) procedures
+
+module bindcchar
+  implicit none
+  integer, parameter :: n = 100, l = 10
+contains
+  subroutine bindc_optional (c2, c4) bind(c)
+character(*), optional :: c2, c4(n)
+!   print *, c2(1:3)
+!   print *, c4(5)(1:3) 
+if (.not. present (c2) .or. .not. present (c4)) stop 8
+if (len (c2) /= l .or. len (c4) /= l) stop 81
+if (c2(1:3)/= "a23") stop 1
+if (c4(5)(1:3) /= "bcd") stop 2
+  end
+
+  subroutine bindc (c2, c4) bind(c)
+character(*) :: c2, c4(n)
+if (len (c2) /= l .or. len (c4) /= l) stop 82
+if (c2(1:3)/= "a23") stop 3
+if (c4(5)(1:3) /= "bcd") stop 4
+call bindc_optional (c2, c4)
+  end
+
+  subroutine not_bindc_optional (c1, c3)
+character(*), optional :: c1, c3(n)
+if (.not. present (c1) .or. .not. present (c3)) stop 5
+if (len (c1) /= l .or. len (c3) /= l) stop 83
+call bindc_optional (c1, c3)
+call bindc  (c1, c3)
+  end
+
+  subroutine not_bindc_optional_deferred (c5, c6)
+character(:), allocatable, optional :: c5, c6(:)
+if (.not. present (c5) .or. .not. present (c6)) stop 6
+if (len (c5) /= l .or. len (c6) /= l) stop 84
+call not_bindc_optional (c5, c6)
+call bindc_optional (c5, c6)
+call bindc  (c5, c6)
+  end
+
+  subroutine not_bindc_optional2 (c7, c8)
+character(*), optional :: c7, c8(:)
+if (.not. present (c7) .or. .not. present (c8)) stop 7
+if (len (c7) /= l .or. len (c8) /= l) stop 85
+call bindc_optional (c7, c8)
+call bindc  (c7, c8)
+  end
+
+  subroutine bindc_optional2 (c2, c4) bind(c)
+character(*), optional :: c2, c4(n)
+if (.not. present (c2) .or. .not. present (c4)) stop 8
+if (len (c2) /= l .or. len (c4) /= l) stop 86
+if (c2(1:3)/= "a23") stop 9
+if (c4(5)(1:3) /= "bcd") stop 10
+call bindc_optional (c2, c4)
+call not_bindc_optional (c2, c4)
+  end
+
+  subroutine bindc_optional_missing (c1, c2, c3, c4, c5) bind(c)
+character(*), optional :: c1, c2(n), c3(:), c4(..), c5(*)
+if (present (c1)) stop 11
+if (present (c2)) stop 12
+if (present (c3)) stop 13
+if (present (c4)) stop 14
+if (present (c5)) stop 15
+  end
+
+  subroutine non_bindc_optional_missing (c1, c2, c3, c4, c5)
+character(*), optional :: c1, c2(n), c3(:), c4(..), c5(*)
+if (present (c1)) stop 21
+if (present (c2)) stop 22
+if (present (c3)) stop 23
+if (present (c4)) stop 24
+if (present (c5)) stop 25
+  end
+end module
+
+program p
+  use bindcchar
+  implicit none
+  character(l) :: a, b(n)
+  character(:), allocatable :: d, 

[gcc r13-8505] Fortran: fix NULL pointer dereference on overlapping initialization [PR50410]

2024-03-29 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:250990298fb792635d9895e7642ccedbc2dd39d4

commit r13-8505-g250990298fb792635d9895e7642ccedbc2dd39d4
Author: Harald Anlauf 
Date:   Thu Mar 28 22:34:40 2024 +0100

Fortran: fix NULL pointer dereference on overlapping initialization 
[PR50410]

gcc/fortran/ChangeLog:

PR fortran/50410
* trans-expr.cc (gfc_conv_structure): Check for NULL pointer.

gcc/testsuite/ChangeLog:

PR fortran/50410
* gfortran.dg/data_initialized_4.f90: New test.

(cherry picked from commit 6fb253a25dff13253d63553f02e0fe72c5e3ab4e)

Diff:
---
 gcc/fortran/trans-expr.cc|  2 +-
 gcc/testsuite/gfortran.dg/data_initialized_4.f90 | 16 
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 3f3f0123dc3..d9de93260a6 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -9364,7 +9364,7 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int 
init)
   cm = expr->ts.u.derived->components;
 
   for (c = gfc_constructor_first (expr->value.constructor);
-   c; c = gfc_constructor_next (c), cm = cm->next)
+   c && cm; c = gfc_constructor_next (c), cm = cm->next)
 {
   /* Skip absent members in default initializers and allocatable
 components.  Although the latter have a default initializer
diff --git a/gcc/testsuite/gfortran.dg/data_initialized_4.f90 
b/gcc/testsuite/gfortran.dg/data_initialized_4.f90
new file mode 100644
index 000..156b6607edf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_initialized_4.f90
@@ -0,0 +1,16 @@
+! { dg-do compile }
+! { dg-additional-options "-std=legacy" }
+!
+! PR fortran/50410
+!
+! Silently allow overlapping initialization in legacy mode (used to ICE)
+
+program p
+  implicit none
+  type t
+ integer :: g = 1
+  end type t
+  type(t) :: u = t(2)
+  data u%g /3/
+  print *, u! this might print "2"
+end


[gcc r14-9720] Fortran: fix NULL pointer dereference on overlapping initialization [PR50410]

2024-03-29 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:6fb253a25dff13253d63553f02e0fe72c5e3ab4e

commit r14-9720-g6fb253a25dff13253d63553f02e0fe72c5e3ab4e
Author: Harald Anlauf 
Date:   Thu Mar 28 22:34:40 2024 +0100

Fortran: fix NULL pointer dereference on overlapping initialization 
[PR50410]

gcc/fortran/ChangeLog:

PR fortran/50410
* trans-expr.cc (gfc_conv_structure): Check for NULL pointer.

gcc/testsuite/ChangeLog:

PR fortran/50410
* gfortran.dg/data_initialized_4.f90: New test.

Diff:
---
 gcc/fortran/trans-expr.cc|  2 +-
 gcc/testsuite/gfortran.dg/data_initialized_4.f90 | 16 
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 079ac93aa8a..d21e3956d6e 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -9650,7 +9650,7 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int 
init)
   cm = expr->ts.u.derived->components;
 
   for (c = gfc_constructor_first (expr->value.constructor);
-   c; c = gfc_constructor_next (c), cm = cm->next)
+   c && cm; c = gfc_constructor_next (c), cm = cm->next)
 {
   /* Skip absent members in default initializers and allocatable
 components.  Although the latter have a default initializer
diff --git a/gcc/testsuite/gfortran.dg/data_initialized_4.f90 
b/gcc/testsuite/gfortran.dg/data_initialized_4.f90
new file mode 100644
index 000..156b6607edf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_initialized_4.f90
@@ -0,0 +1,16 @@
+! { dg-do compile }
+! { dg-additional-options "-std=legacy" }
+!
+! PR fortran/50410
+!
+! Silently allow overlapping initialization in legacy mode (used to ICE)
+
+program p
+  implicit none
+  type t
+ integer :: g = 1
+  end type t
+  type(t) :: u = t(2)
+  data u%g /3/
+  print *, u! this might print "2"
+end


[gcc r14-9712] Fortran: fix DATA and derived types with pointer components [PR114474]

2024-03-28 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:bbb7c513dddc5c9b2d5e9b78bc1c2f85a0cfe07e

commit r14-9712-gbbb7c513dddc5c9b2d5e9b78bc1c2f85a0cfe07e
Author: Harald Anlauf 
Date:   Wed Mar 27 21:18:04 2024 +0100

Fortran: fix DATA and derived types with pointer components [PR114474]

When matching actual arguments in match_actual_arg, these are initially
treated as a possible dummy procedure, assuming that the correct type is
determined later.  This resolution could fail when the procedure is a
derived type constructor with a pointer component and appears in a DATA
statement, where the pointer shall be associated with an initial data
target.  Check for those cases where the type obviously has not been
resolved yet, and which were missed because there was no component
reference.

gcc/fortran/ChangeLog:

PR fortran/114474
* primary.cc (gfc_variable_attr): Catch variables used in structure
constructors within DATA statements that are still tagged with a
temporary type BT_PROCEDURE from match_actual_arg and which have the
target attribute, and fix their typespec.

gcc/testsuite/ChangeLog:

PR fortran/114474
* gfortran.dg/data_pointer_3.f90: New test.

Diff:
---
 gcc/fortran/primary.cc   | 12 +
 gcc/testsuite/gfortran.dg/data_pointer_3.f90 | 77 
 2 files changed, 89 insertions(+)

diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index 0ab69bb9dce..5dd6875a4a6 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -2804,6 +2804,18 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts)
   if (ts != NULL && expr->ts.type == BT_UNKNOWN)
 *ts = sym->ts;
 
+  /* Catch left-overs from match_actual_arg, where an actual argument of a
+ procedure is given a temporary ts.type == BT_PROCEDURE.  The fixup is
+ needed for structure constructors in DATA statements, where a pointer
+ is associated with a data target, and the argument has not been fully
+ resolved yet.  Components references are dealt with further below.  */
+  if (ts != NULL
+  && expr->ts.type == BT_PROCEDURE
+  && expr->ref == NULL
+  && attr.flavor != FL_PROCEDURE
+  && attr.target)
+*ts = sym->ts;
+
   has_inquiry_part = false;
   for (ref = expr->ref; ref; ref = ref->next)
 if (ref->type == REF_INQUIRY)
diff --git a/gcc/testsuite/gfortran.dg/data_pointer_3.f90 
b/gcc/testsuite/gfortran.dg/data_pointer_3.f90
new file mode 100644
index 000..49c288e93b9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_pointer_3.f90
@@ -0,0 +1,77 @@
+! { dg-do compile }
+! PR fortran/114474 - DATA and derived types with pointer components
+
+program pr114474
+  implicit none
+  integer, target :: ii = 42! initial data target
+
+  integer, target :: jj = 24
+  integer, pointer:: qq => jj
+  ! ii and jj resolve slightly differently when the data statement below
+  ! is reached, as jj is resolved outside the structure constructor first
+
+  type t
+ integer, pointer :: h
+  end type t
+
+  integer, target :: kk(7) =  23
+  integer, pointer:: ll(:) => kk
+
+  type t1
+ integer  :: m(7)
+  end type t1
+
+  type(t) :: x1, x2, x3, x4, x5
+  type(t), parameter  :: z1 = t(null())
+
+  type(t1), target:: tt = t1([1,2,3,4,5,6,7])
+  type(t1), parameter :: vv = t1(22)
+  type(t1):: w1, w2
+  integer,  pointer   :: p1(:) => tt% m
+
+  data x1 / t(null())  /
+  data x2 / t(ii)  / ! ii is initial data target
+  data x3 / t(jj)  / ! jj is resolved differently...
+  data x4 / t(tt%m(3)) / ! pointer association with 3rd element
+
+  data w1 / t1(12) /
+  data w2 / t1(vv%m)   /
+
+  if (  associated (x1% h)) stop 1
+  if (.not. associated (x2% h)) stop 2
+  if (.not. associated (x3% h)) stop 3
+  if (.not. associated (x4% h)) stop 4
+  if (x2% h /= 42) stop 5
+  if (x3% h /= 24) stop 6
+  if (x4% h /=  3) stop 7
+ 
+  if (any (w1%m /= 12  )) stop 8
+  if (any (w2%m /= vv%m)) stop 9
+end
+
+
+subroutine sub
+  implicit none
+
+  interface
+ real function myfun (x)
+   real, intent(in) :: x
+ end function myfun
+  end interface
+
+  type u
+ procedure(myfun), pointer, nopass :: p
+  end type u
+
+  type(u):: u3 = u(null())
+  type(u), parameter :: u4 = u(null())
+  type(u):: u1, u2
+
+  data u1 / u(null()) /
+  data u2 / u(myfun)  /
+end
+
+real function myfun (x)
+  real, intent(in) :: x
+  myfun = x
+end function myfun


[gcc r13-8492] Fortran: fix for absent array argument passed to optional dummy [PR101135]

2024-03-23 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:344b60addb79278c95b7a5712aaf38721a27

commit r13-8492-g344b60addb79278c95b7a5712aaf38721a27
Author: Harald Anlauf 
Date:   Fri Mar 15 20:14:07 2024 +0100

Fortran: fix for absent array argument passed to optional dummy [PR101135]

gcc/fortran/ChangeLog:

PR fortran/101135
* trans-array.cc (gfc_get_dataptr_offset): Check for optional
arguments being present before dereferencing data pointer.

gcc/testsuite/ChangeLog:

PR fortran/101135
* gfortran.dg/missing_optional_dummy_6a.f90: Adjust diagnostic 
pattern.
* gfortran.dg/ubsan/missing_optional_dummy_8.f90: New test.

Diff:
---
 gcc/fortran/trans-array.cc |  11 +++
 .../gfortran.dg/missing_optional_dummy_6a.f90  |   2 +-
 .../gfortran.dg/ubsan/missing_optional_dummy_8.f90 | 108 +
 3 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 074ea2f2384..5eef4b4ec87 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -7326,6 +7326,17 @@ gfc_get_dataptr_offset (stmtblock_t *block, tree parm, 
tree desc, tree offset,
 
   /* Set the target data pointer.  */
   offset = gfc_build_addr_expr (gfc_array_dataptr_type (desc), tmp);
+
+  /* Check for optional dummy argument being present.  Arguments of BIND(C)
+ procedures are excepted here since they are handled differently.  */
+  if (expr->expr_type == EXPR_VARIABLE
+  && expr->symtree->n.sym->attr.dummy
+  && expr->symtree->n.sym->attr.optional
+  && !is_CFI_desc (NULL, expr))
+offset = build3_loc (input_location, COND_EXPR, TREE_TYPE (offset),
+gfc_conv_expr_present (expr->symtree->n.sym), offset,
+fold_convert (TREE_TYPE (offset), 
gfc_index_zero_node));
+
   gfc_conv_descriptor_data_set (block, parm, offset);
 }
 
diff --git a/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90 
b/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90
index c6a79059a91..b5e1726d74d 100644
--- a/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90
+++ b/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90
@@ -49,7 +49,7 @@ end program test
 
 ! { dg-final { scan-tree-dump-times "scalar2 \\(.* slr1" 1 "original" } }
 
-! { dg-final { scan-tree-dump-times "= es1 != 0B" 1 "original" } }
+! { dg-final { scan-tree-dump-times "= es1 != 0B" 2 "original" } }
 ! { dg-final { scan-tree-dump-times "assumed_shape2 \\(es1" 0 "original" } }
 ! { dg-final { scan-tree-dump-times "explicit_shape2 \\(es1" 1 "original" } }
 
diff --git a/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90 
b/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90
new file mode 100644
index 000..fd3914934aa
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90
@@ -0,0 +1,108 @@
+! { dg-do run }
+! { dg-additional-options "-fdump-tree-original -fsanitize=undefined" }
+!
+! PR fortran/101135 - Load of null pointer when passing absent
+! assumed-shape array argument for an optional dummy argument
+!
+! Based on testcase by Marcel Jacobse
+
+program main
+  implicit none
+  character(len=3) :: a(6) = ['abc', 'def', 'ghi', 'jlm', 'nop', 'qrs']
+  call as ()
+  call as (a(::2))
+  call as_c ()
+  call as_c (a(2::2))
+  call test_wrapper
+  call test_wrapper_c
+  call test_ar_wrapper
+  call test_ar_wrapper_c
+contains
+  subroutine as (xx)
+character(len=*), optional, intent(in) :: xx(*)
+if (.not. present (xx)) return
+print *, xx(1:3)
+  end subroutine as
+
+  subroutine as_c (zz) bind(c)
+character(len=*), optional, intent(in) :: zz(*)
+if (.not. present (zz)) return
+print *, zz(1:3)
+  end subroutine as_c
+
+  subroutine test_wrapper (x)
+real, dimension(1), intent(out), optional :: x
+call test (x)
+call test1 (x)
+call test_c (x)
+call test1_c (x)
+  end subroutine test_wrapper
+
+  subroutine test_wrapper_c (w) bind(c)
+real, dimension(1), intent(out), optional :: w
+call test (w)
+call test1 (w)
+call test_c (w)
+call test1_c (w)
+  end subroutine test_wrapper_c
+
+  subroutine test (y)
+real, dimension(:), intent(out), optional :: y
+if (present (y)) y=0.
+  end subroutine test
+
+  subroutine test_c (y) bind(c)
+real, dimension(:), intent(out), optional :: y
+if (present (y)) y=0.
+  end subroutine test_c
+
+  subroutine test1 (y)
+real, dimension(1), intent(out), optional :: y
+if (present (y)) y=0.
+  end subroutine test1
+
+  subroutine test1_c (y) bind(c)
+real, dimension(1), intent(out), optional :: y
+if (present (y)) y=0.
+  end subroutine test1_c
+
+  subroutine test_ar_wrapper (p, q, r)
+real,   intent(out), optional :: p
+real, dimension(1), intent(out), optional :: q
+real, dimension(:), intent(out), optional :: r
+call test_ar (p)
+

[gcc r13-8491] Fortran: no size check passing NULL() without MOLD argument [PR55978]

2024-03-23 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:57062bc355aece623c6a38c5e813ed24f8b775f1

commit r13-8491-g57062bc355aece623c6a38c5e813ed24f8b775f1
Author: Harald Anlauf 
Date:   Fri Mar 22 18:17:15 2024 +0100

Fortran: no size check passing NULL() without MOLD argument [PR55978]

gcc/fortran/ChangeLog:

PR fortran/55978
* interface.cc (gfc_compare_actual_formal): Skip size check for
NULL() actual without MOLD argument.

gcc/testsuite/ChangeLog:

PR fortran/55978
* gfortran.dg/null_actual_5.f90: New test.

Diff:
---
 gcc/fortran/interface.cc|  4 ++
 gcc/testsuite/gfortran.dg/null_actual_5.f90 | 76 +
 2 files changed, 80 insertions(+)

diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc
index 5cda94753d8..dc384ad9323 100644
--- a/gcc/fortran/interface.cc
+++ b/gcc/fortran/interface.cc
@@ -3392,6 +3392,10 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, 
gfc_formal_arglist *formal,
   if (f->sym->ts.type == BT_CLASS)
goto skip_size_check;
 
+  /* Skip size check for NULL() actual without MOLD argument.  */
+  if (a->expr->expr_type == EXPR_NULL && a->expr->ts.type == BT_UNKNOWN)
+   goto skip_size_check;
+
   actual_size = get_expr_storage_size (a->expr);
   formal_size = get_sym_storage_size (f->sym);
   if (actual_size != 0 && actual_size < formal_size
diff --git a/gcc/testsuite/gfortran.dg/null_actual_5.f90 
b/gcc/testsuite/gfortran.dg/null_actual_5.f90
new file mode 100644
index 000..1198715b7c8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/null_actual_5.f90
@@ -0,0 +1,76 @@
+! { dg-do compile }
+! PR fortran/55978
+!
+! Passing of NULL() with and without MOLD as actual argument
+!
+! Testcase derived from pr55978 comment#16
+
+program pr55978_c16
+  implicit none
+
+  integer, pointer   :: p(:)
+  integer, allocatable   :: a(:)
+  character(10), pointer :: c
+  character(10), pointer :: cp(:)
+
+  type t
+integer, pointer :: p(:)
+integer, allocatable :: a(:)
+  end type
+
+  type(t) :: d
+
+  ! (1) pointer
+  p => null()
+  call sub (p)
+
+  ! (2) allocatable
+  call sub (a)
+  call sub (d%a)
+
+  ! (3) pointer component
+  d%p => null ()
+  call sub (d%p)
+
+  ! (4) NULL
+  call sub (null (a))   ! OK
+  call sub (null (p))   ! OK
+  call sub (null (d%a)) ! OK
+  call sub (null (d%p)) ! OK
+  call sub (null ())! was erroneously rejected with:
+  ! Actual argument contains too few elements for dummy argument 'x' (1/4)
+
+  call bla (null(c))
+  call bla (null()) ! was erroneously rejected with:
+  ! Actual argument contains too few elements for dummy argument 'x' (1/10)
+
+  call foo (null(cp))
+  call foo (null())
+
+  call bar (null(cp))
+  call bar (null()) ! was erroneously rejected with:
+  ! Actual argument contains too few elements for dummy argument 'x' (1/70)
+
+contains
+
+  subroutine sub(x)
+integer, intent(in), optional :: x(4)
+if (present (x)) stop 1
+  end
+
+  subroutine bla(x)
+character(len=10), intent(in), optional :: x
+if (present (x)) stop 2
+  end
+
+  subroutine foo(x)
+character(len=10), intent(in), optional :: x(:)
+if (present (x)) stop 3
+  end
+
+  subroutine bar(x)
+character(len=10), intent(in), optional :: x(7)
+if (present (x)) stop 4
+  end
+
+end


[gcc r13-8490] Fortran: fix FE memleak

2024-03-23 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:c65c4c6af5b5321f1a517dd045ab1344e849135a

commit r13-8490-gc65c4c6af5b5321f1a517dd045ab1344e849135a
Author: Harald Anlauf 
Date:   Wed Jan 3 20:21:00 2024 +0100

Fortran: fix FE memleak

gcc/fortran/ChangeLog:

* trans-types.cc (gfc_get_nodesc_array_type): Clear used gmp
variables.

Diff:
---
 gcc/fortran/trans-types.cc | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc
index b514d8e5a57..b2a3000da1f 100644
--- a/gcc/fortran/trans-types.cc
+++ b/gcc/fortran/trans-types.cc
@@ -1791,7 +1791,7 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * 
as, gfc_packed packed,
  TYPE_LANG_SPECIFIC (type) = TYPE_LANG_SPECIFIC (TREE_TYPE (type));
}
 
-  return type;
+  goto array_type_done;
 }
 
   if (known_stride)
@@ -1810,10 +1810,6 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * 
as, gfc_packed packed,
 
   layout_type (type);
 
-  mpz_clear (offset);
-  mpz_clear (stride);
-  mpz_clear (delta);
-
   /* Represent packed arrays as multi-dimensional if they have rank >
  1 and with proper bounds, instead of flat arrays.  This makes for
  better debug info.  */
@@ -1844,6 +1840,12 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * 
as, gfc_packed packed,
   GFC_ARRAY_TYPE_P (type) = 1;
   TYPE_LANG_SPECIFIC (type) = TYPE_LANG_SPECIFIC (TREE_TYPE (type));
 }
+
+array_type_done:
+  mpz_clear (offset);
+  mpz_clear (stride);
+  mpz_clear (delta);
+
   return type;
 }


[gcc r14-9631] Fortran: no size check passing NULL() without MOLD argument [PR55978]

2024-03-22 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:c083a453dbe51853e26e02edd8b9346fb8618292

commit r14-9631-gc083a453dbe51853e26e02edd8b9346fb8618292
Author: Harald Anlauf 
Date:   Fri Mar 22 18:17:15 2024 +0100

Fortran: no size check passing NULL() without MOLD argument [PR55978]

gcc/fortran/ChangeLog:

PR fortran/55978
* interface.cc (gfc_compare_actual_formal): Skip size check for
NULL() actual without MOLD argument.

gcc/testsuite/ChangeLog:

PR fortran/55978
* gfortran.dg/null_actual_5.f90: New test.

Diff:
---
 gcc/fortran/interface.cc|  4 ++
 gcc/testsuite/gfortran.dg/null_actual_5.f90 | 76 +
 2 files changed, 80 insertions(+)

diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc
index 64b90550be2..7b86a338bc1 100644
--- a/gcc/fortran/interface.cc
+++ b/gcc/fortran/interface.cc
@@ -3439,6 +3439,10 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, 
gfc_formal_arglist *formal,
   if (f->sym->ts.type == BT_CLASS)
goto skip_size_check;
 
+  /* Skip size check for NULL() actual without MOLD argument.  */
+  if (a->expr->expr_type == EXPR_NULL && a->expr->ts.type == BT_UNKNOWN)
+   goto skip_size_check;
+
   actual_size = get_expr_storage_size (a->expr);
   formal_size = get_sym_storage_size (f->sym);
   if (actual_size != 0 && actual_size < formal_size
diff --git a/gcc/testsuite/gfortran.dg/null_actual_5.f90 
b/gcc/testsuite/gfortran.dg/null_actual_5.f90
new file mode 100644
index 000..1198715b7c8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/null_actual_5.f90
@@ -0,0 +1,76 @@
+! { dg-do compile }
+! PR fortran/55978
+!
+! Passing of NULL() with and without MOLD as actual argument
+!
+! Testcase derived from pr55978 comment#16
+
+program pr55978_c16
+  implicit none
+
+  integer, pointer   :: p(:)
+  integer, allocatable   :: a(:)
+  character(10), pointer :: c
+  character(10), pointer :: cp(:)
+
+  type t
+integer, pointer :: p(:)
+integer, allocatable :: a(:)
+  end type
+
+  type(t) :: d
+
+  ! (1) pointer
+  p => null()
+  call sub (p)
+
+  ! (2) allocatable
+  call sub (a)
+  call sub (d%a)
+
+  ! (3) pointer component
+  d%p => null ()
+  call sub (d%p)
+
+  ! (4) NULL
+  call sub (null (a))   ! OK
+  call sub (null (p))   ! OK
+  call sub (null (d%a)) ! OK
+  call sub (null (d%p)) ! OK
+  call sub (null ())! was erroneously rejected with:
+  ! Actual argument contains too few elements for dummy argument 'x' (1/4)
+
+  call bla (null(c))
+  call bla (null()) ! was erroneously rejected with:
+  ! Actual argument contains too few elements for dummy argument 'x' (1/10)
+
+  call foo (null(cp))
+  call foo (null())
+
+  call bar (null(cp))
+  call bar (null()) ! was erroneously rejected with:
+  ! Actual argument contains too few elements for dummy argument 'x' (1/70)
+
+contains
+
+  subroutine sub(x)
+integer, intent(in), optional :: x(4)
+if (present (x)) stop 1
+  end
+
+  subroutine bla(x)
+character(len=10), intent(in), optional :: x
+if (present (x)) stop 2
+  end
+
+  subroutine foo(x)
+character(len=10), intent(in), optional :: x(:)
+if (present (x)) stop 3
+  end
+
+  subroutine bar(x)
+character(len=10), intent(in), optional :: x(7)
+if (present (x)) stop 4
+  end
+
+end


[gcc r14-9597] Fortran: improve array component description in runtime error message [PR30802]

2024-03-21 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:509352069d6f166d396f4b4a86e71ea521f2ca78

commit r14-9597-g509352069d6f166d396f4b4a86e71ea521f2ca78
Author: Harald Anlauf 
Date:   Wed Mar 20 20:59:24 2024 +0100

Fortran: improve array component description in runtime error message 
[PR30802]

Runtime error messages for array bounds violation shall use the following
scheme for a coherent, abridged description of arrays or array components
of derived types:
(1) If x is an ordinary array variable, use "x"
(2) if z is a DT scalar and x an array component at level 1, use "z%x"
(3) if z is a DT scalar and x an array component at level > 1, or
if z is a DT array and x an array (at any level), use "z...%x"
Use a new helper function abridged_ref_name for construction of that name.

gcc/fortran/ChangeLog:

PR fortran/30802
* trans-array.cc (abridged_ref_name): New helper function.
(trans_array_bound_check): Use it.
(array_bound_check_elemental): Likewise.
(gfc_conv_array_ref): Likewise.

gcc/testsuite/ChangeLog:

PR fortran/30802
* gfortran.dg/bounds_check_17.f90: Adjust pattern.
* gfortran.dg/bounds_check_fail_8.f90: New test.

Diff:
---
 gcc/fortran/trans-array.cc| 132 ++
 gcc/testsuite/gfortran.dg/bounds_check_17.f90 |   2 +-
 gcc/testsuite/gfortran.dg/bounds_check_fail_8.f90 |  56 +
 3 files changed, 142 insertions(+), 48 deletions(-)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 0a453828bad..30b84762346 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -3485,6 +3485,78 @@ gfc_conv_array_ubound (tree descriptor, int dim)
 }
 
 
+/* Generate abridged name of a part-ref for use in bounds-check message.
+   Cases:
+   (1) for an ordinary array variable x return "x"
+   (2) for z a DT scalar and array component x (at level 1) return "z%%x"
+   (3) for z a DT scalar and array component x (at level > 1) or
+   for z a DT array and array x (at any number of levels): "z...%%x"
+ */
+
+static char *
+abridged_ref_name (gfc_expr * expr, gfc_array_ref * ar)
+{
+  gfc_ref *ref;
+  gfc_symbol *sym;
+  char *ref_name = NULL;
+  const char *comp_name = NULL;
+  int len_sym, last_len = 0, level = 0;
+  bool sym_is_array;
+
+  gcc_assert (expr->expr_type == EXPR_VARIABLE && expr->ref != NULL);
+
+  sym = expr->symtree->n.sym;
+  sym_is_array = (sym->ts.type != BT_CLASS
+ ? sym->as != NULL
+ : IS_CLASS_ARRAY (sym));
+  len_sym = strlen (sym->name);
+
+  /* Scan ref chain to get name of the array component (when ar != NULL) or
+ array section, determine depth and remember its component name.  */
+  for (ref = expr->ref; ref; ref = ref->next)
+{
+  if (ref->type == REF_COMPONENT
+ && strcmp (ref->u.c.component->name, "_data") != 0)
+   {
+ level++;
+ comp_name = ref->u.c.component->name;
+ continue;
+   }
+
+  if (ref->type != REF_ARRAY)
+   continue;
+
+  if (ar)
+   {
+ if (>u.ar == ar)
+   break;
+   }
+  else if (ref->u.ar.type == AR_SECTION)
+   break;
+}
+
+  if (level > 0)
+last_len = strlen (comp_name);
+
+  /* Provide a buffer sufficiently large to hold "x...%%z".  */
+  ref_name = XNEWVEC (char, len_sym + last_len + 6);
+  strcpy (ref_name, sym->name);
+
+  if (level == 1 && !sym_is_array)
+{
+  strcat (ref_name, "%%");
+  strcat (ref_name, comp_name);
+}
+  else if (level > 0)
+{
+  strcat (ref_name, "...%%");
+  strcat (ref_name, comp_name);
+}
+
+  return ref_name;
+}
+
+
 /* Generate code to perform an array index bound check.  */
 
 static tree
@@ -3496,7 +3568,9 @@ trans_array_bound_check (gfc_se * se, gfc_ss *ss, tree 
index, int n,
   tree tmp_lo, tmp_up;
   tree descriptor;
   char *msg;
+  char *ref_name = NULL;
   const char * name = NULL;
+  gfc_expr *expr;
 
   if (!(gfc_option.rtcheck & GFC_RTCHECK_BOUNDS))
 return index;
@@ -3509,6 +3583,12 @@ trans_array_bound_check (gfc_se * se, gfc_ss *ss, tree 
index, int n,
   name = ss->info->expr->symtree->n.sym->name;
   gcc_assert (name != NULL);
 
+  /* When we have a component ref, get name of the array section.
+ Note that there can only be one part ref.  */
+  expr = ss->info->expr;
+  if (expr->ref && !compname)
+name = ref_name = abridged_ref_name (expr, NULL);
+
   if (VAR_P (descriptor))
 name = IDENTIFIER_POINTER (DECL_NAME (descriptor));
 
@@ -3562,6 +3642,7 @@ trans_array_bound_check (gfc_se * se, gfc_ss *ss, tree 
index, int n,
   free (msg);
 }
 
+  free (ref_name);
   return index;
 }
 
@@ -3573,36 +3654,17 @@ array_bound_check_elemental (gfc_se * se, gfc_ss * ss, 
gfc_expr * expr)
 {
   gfc_array_ref *ar;
   gfc_ref *ref;
-  gfc_symbol *sym;
   char *var_name = NULL;
-  size_t len;
   int dim;
 
   if 

[gcc r11-11287] Fortran: error recovery in frontend optimization [PR103715]

2024-03-20 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:7294f1a7aa457fe24d11270f06fd15c2b3ffd4ab

commit r11-11287-g7294f1a7aa457fe24d11270f06fd15c2b3ffd4ab
Author: Harald Anlauf 
Date:   Mon Mar 18 19:36:59 2024 +0100

Fortran: error recovery in frontend optimization [PR103715]

gcc/fortran/ChangeLog:

PR fortran/103715
* frontend-passes.c (check_externals_expr): Prevent invalid read
in case of mismatch of external subroutine with function.

gcc/testsuite/ChangeLog:

PR fortran/103715
* gfortran.dg/pr103715.f90: New test.

(cherry picked from commit 3be2b8f475f22c531d6cef1b041c0573b3ea5133)

Diff:
---
 gcc/fortran/frontend-passes.c  |  3 +++
 gcc/testsuite/gfortran.dg/pr103715.f90 | 12 
 2 files changed, 15 insertions(+)

diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index ebc5a7f3699..439a311e4a5 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -5782,6 +5782,9 @@ check_externals_expr (gfc_expr **ep, int *walk_subtrees 
ATTRIBUTE_UNUSED,
   if (e->expr_type != EXPR_FUNCTION)
 return 0;
 
+  if (e->symtree && e->symtree->n.sym->attr.subroutine)
+return 0;
+
   sym = e->value.function.esym;
   if (sym == NULL)
 return 0;
diff --git a/gcc/testsuite/gfortran.dg/pr103715.f90 
b/gcc/testsuite/gfortran.dg/pr103715.f90
new file mode 100644
index 000..72c5a31fb21
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr103715.f90
@@ -0,0 +1,12 @@
+! { dg-do compile }
+! PR fortran/103715 - ICE in gfc_find_gsymbol
+!
+! valgrind did report an invalid read in check_externals_procedure
+
+program p
+  select type (y => g()) ! { dg-error "Selector shall be polymorphic" }
+  end select
+  call g()
+end
+
+! { dg-prune-output "already being used as a FUNCTION" }


[gcc r12-10286] Fortran: error recovery in frontend optimization [PR103715]

2024-03-20 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:811145b10ff30608bb5ea459ea277219ada4f13d

commit r12-10286-g811145b10ff30608bb5ea459ea277219ada4f13d
Author: Harald Anlauf 
Date:   Mon Mar 18 19:36:59 2024 +0100

Fortran: error recovery in frontend optimization [PR103715]

gcc/fortran/ChangeLog:

PR fortran/103715
* frontend-passes.cc (check_externals_expr): Prevent invalid read
in case of mismatch of external subroutine with function.

gcc/testsuite/ChangeLog:

PR fortran/103715
* gfortran.dg/pr103715.f90: New test.

(cherry picked from commit 3be2b8f475f22c531d6cef1b041c0573b3ea5133)

Diff:
---
 gcc/fortran/frontend-passes.cc |  3 +++
 gcc/testsuite/gfortran.dg/pr103715.f90 | 12 
 2 files changed, 15 insertions(+)

diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc
index 53567307cec..de8cb5a2204 100644
--- a/gcc/fortran/frontend-passes.cc
+++ b/gcc/fortran/frontend-passes.cc
@@ -5794,6 +5794,9 @@ check_externals_expr (gfc_expr **ep, int *walk_subtrees 
ATTRIBUTE_UNUSED,
   if (e->expr_type != EXPR_FUNCTION)
 return 0;
 
+  if (e->symtree && e->symtree->n.sym->attr.subroutine)
+return 0;
+
   sym = e->value.function.esym;
   if (sym == NULL)
 return 0;
diff --git a/gcc/testsuite/gfortran.dg/pr103715.f90 
b/gcc/testsuite/gfortran.dg/pr103715.f90
new file mode 100644
index 000..72c5a31fb21
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr103715.f90
@@ -0,0 +1,12 @@
+! { dg-do compile }
+! PR fortran/103715 - ICE in gfc_find_gsymbol
+!
+! valgrind did report an invalid read in check_externals_procedure
+
+program p
+  select type (y => g()) ! { dg-error "Selector shall be polymorphic" }
+  end select
+  call g()
+end
+
+! { dg-prune-output "already being used as a FUNCTION" }


[gcc r13-8468] Fortran: fix IS_CONTIGUOUS for polymorphic dummy arguments [PR114001]

2024-03-19 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:5b928badac560ad48e0e9fc480096ff396d9d9c6

commit r13-8468-g5b928badac560ad48e0e9fc480096ff396d9d9c6
Author: Harald Anlauf 
Date:   Tue Mar 12 22:58:39 2024 +0100

Fortran: fix IS_CONTIGUOUS for polymorphic dummy arguments [PR114001]

gcc/fortran/ChangeLog:

PR fortran/114001
* expr.cc (gfc_is_simply_contiguous): Adjust logic so that CLASS
symbols are also handled.

gcc/testsuite/ChangeLog:

PR fortran/114001
* gfortran.dg/is_contiguous_4.f90: New test.

(cherry picked from commit 11caf47b599568c6c6f5a12cf8e21f50778176d3)

Diff:
---
 gcc/fortran/expr.cc   | 19 ---
 gcc/testsuite/gfortran.dg/is_contiguous_4.f90 | 81 +++
 2 files changed, 91 insertions(+), 9 deletions(-)

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 9fdbe7a84c5..8b9c93940c8 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -5994,15 +5994,16 @@ gfc_is_simply_contiguous (gfc_expr *expr, bool strict, 
bool permit_element)
 }
 
   sym = expr->symtree->n.sym;
-  if (expr->ts.type != BT_CLASS
-  && ((part_ref
-  && !part_ref->u.c.component->attr.contiguous
-  && part_ref->u.c.component->attr.pointer)
- || (!part_ref
- && !sym->attr.contiguous
- && (sym->attr.pointer
- || (sym->as && sym->as->type == AS_ASSUMED_RANK)
- || (sym->as && sym->as->type == AS_ASSUMED_SHAPE)
+  if ((part_ref
+   && part_ref->u.c.component
+   && !part_ref->u.c.component->attr.contiguous
+   && IS_POINTER (part_ref->u.c.component))
+  || (!part_ref
+ && expr->ts.type != BT_CLASS
+ && !sym->attr.contiguous
+ && (sym->attr.pointer
+ || (sym->as && sym->as->type == AS_ASSUMED_RANK)
+ || (sym->as && sym->as->type == AS_ASSUMED_SHAPE
 return false;
 
   if (!ar || ar->type == AR_FULL)
diff --git a/gcc/testsuite/gfortran.dg/is_contiguous_4.f90 
b/gcc/testsuite/gfortran.dg/is_contiguous_4.f90
new file mode 100644
index 000..cb066f8836b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/is_contiguous_4.f90
@@ -0,0 +1,81 @@
+! { dg-do run }
+! PR fortran/114001 - IS_CONTIGUOUS and polymorphic dummy
+
+program main
+  implicit none
+  integer :: i, cnt = 0
+  logical :: expect
+  integer, target  :: m(10) = [(i,i=1,size(m))]
+  integer, pointer :: p(:)
+  type t
+ integer :: j
+  end type t
+  type(t),  pointer :: tt(:), tp(:) ! Type pointer
+  class(t), pointer :: ct(:), cp(:) ! Class pointer
+
+  p => m(1:3)
+  expect = is_contiguous (p)
+  print *, "is_contiguous (p)=", expect
+  if (.not. expect) stop 91
+  call sub_star (p, expect)
+  p => m(1::3)
+  expect = is_contiguous (p)
+  print *, "is_contiguous (p)=", expect
+  if (expect) stop 92
+  call sub_star (p, expect)
+
+  allocate (tt(10))
+  tt(:)% j = m
+  tp => tt(4:6)
+  expect = is_contiguous (tp)
+  if (.not. expect) stop 96
+  print *, "is_contiguous (tp)=", expect
+  call sub_t (tp, expect)
+  tp => tt(4::3)
+  expect = is_contiguous (tp)
+  if (expect) stop 97
+  print *, "is_contiguous (tp)=", expect
+  call sub_t (tp, expect)
+
+  allocate (ct(10))
+  ct(:)% j = m
+  cp => ct(7:9)
+  expect = is_contiguous (cp)
+  print *, "is_contiguous (cp)=", expect
+  if (.not. expect) stop 98
+  call sub_t (cp, expect)
+  cp => ct(4::3)
+  expect = is_contiguous (cp)
+  print *, "is_contiguous (cp)=", expect
+  if (expect) stop 99
+  call sub_t (cp, expect)
+
+contains
+
+  subroutine sub_star (x, expect)
+class(*), intent(in) :: x(:)
+logical,  intent(in) :: expect
+cnt = cnt + 10
+if (is_contiguous (x) .neqv. expect) then
+   print *, "sub_star(1): is_contiguous (x)=", is_contiguous (x), expect
+   stop (cnt + 1)
+end if
+select type (x)
+type is (integer)
+   if (is_contiguous (x) .neqv. expect) then
+  print *, "sub_star(2): is_contiguous (x)=", is_contiguous (x), expect
+  stop (cnt + 2)
+   end if
+end select
+  end
+
+  subroutine sub_t (x, expect)
+class(t), intent(in) :: x(:)
+logical,  intent(in) :: expect
+cnt = cnt + 10
+if (is_contiguous (x) .neqv. expect) then
+   print *, "sub_t: is_contiguous (x)=", is_contiguous (x), expect
+   stop (cnt + 3)
+end if
+  end
+end


[gcc r13-8467] Fortran: error recovery in frontend optimization [PR103715]

2024-03-19 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:9623e5dd70b0d8334ebe093459721d0d447ce4f2

commit r13-8467-g9623e5dd70b0d8334ebe093459721d0d447ce4f2
Author: Harald Anlauf 
Date:   Mon Mar 18 19:36:59 2024 +0100

Fortran: error recovery in frontend optimization [PR103715]

gcc/fortran/ChangeLog:

PR fortran/103715
* frontend-passes.cc (check_externals_expr): Prevent invalid read
in case of mismatch of external subroutine with function.

gcc/testsuite/ChangeLog:

PR fortran/103715
* gfortran.dg/pr103715.f90: New test.

(cherry picked from commit 3be2b8f475f22c531d6cef1b041c0573b3ea5133)

Diff:
---
 gcc/fortran/frontend-passes.cc |  3 +++
 gcc/testsuite/gfortran.dg/pr103715.f90 | 12 
 2 files changed, 15 insertions(+)

diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc
index 85ebca56a69..349d26ec29a 100644
--- a/gcc/fortran/frontend-passes.cc
+++ b/gcc/fortran/frontend-passes.cc
@@ -5807,6 +5807,9 @@ check_externals_expr (gfc_expr **ep, int *walk_subtrees 
ATTRIBUTE_UNUSED,
   if (e->expr_type != EXPR_FUNCTION)
 return 0;
 
+  if (e->symtree && e->symtree->n.sym->attr.subroutine)
+return 0;
+
   sym = e->value.function.esym;
   if (sym == NULL)
 return 0;
diff --git a/gcc/testsuite/gfortran.dg/pr103715.f90 
b/gcc/testsuite/gfortran.dg/pr103715.f90
new file mode 100644
index 000..72c5a31fb21
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr103715.f90
@@ -0,0 +1,12 @@
+! { dg-do compile }
+! PR fortran/103715 - ICE in gfc_find_gsymbol
+!
+! valgrind did report an invalid read in check_externals_procedure
+
+program p
+  select type (y => g()) ! { dg-error "Selector shall be polymorphic" }
+  end select
+  call g()
+end
+
+! { dg-prune-output "already being used as a FUNCTION" }


[gcc r14-9522] Fortran: error recovery in frontend optimization [PR103715]

2024-03-18 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:3be2b8f475f22c531d6cef1b041c0573b3ea5133

commit r14-9522-g3be2b8f475f22c531d6cef1b041c0573b3ea5133
Author: Harald Anlauf 
Date:   Mon Mar 18 19:36:59 2024 +0100

Fortran: error recovery in frontend optimization [PR103715]

gcc/fortran/ChangeLog:

PR fortran/103715
* frontend-passes.cc (check_externals_expr): Prevent invalid read
in case of mismatch of external subroutine with function.

gcc/testsuite/ChangeLog:

PR fortran/103715
* gfortran.dg/pr103715.f90: New test.

Diff:
---
 gcc/fortran/frontend-passes.cc |  3 +++
 gcc/testsuite/gfortran.dg/pr103715.f90 | 12 
 2 files changed, 15 insertions(+)

diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc
index 06dfa1a3232..3c06018fdbb 100644
--- a/gcc/fortran/frontend-passes.cc
+++ b/gcc/fortran/frontend-passes.cc
@@ -5807,6 +5807,9 @@ check_externals_expr (gfc_expr **ep, int *walk_subtrees 
ATTRIBUTE_UNUSED,
   if (e->expr_type != EXPR_FUNCTION)
 return 0;
 
+  if (e->symtree && e->symtree->n.sym->attr.subroutine)
+return 0;
+
   sym = e->value.function.esym;
   if (sym == NULL)
 return 0;
diff --git a/gcc/testsuite/gfortran.dg/pr103715.f90 
b/gcc/testsuite/gfortran.dg/pr103715.f90
new file mode 100644
index 000..72c5a31fb21
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr103715.f90
@@ -0,0 +1,12 @@
+! { dg-do compile }
+! PR fortran/103715 - ICE in gfc_find_gsymbol
+!
+! valgrind did report an invalid read in check_externals_procedure
+
+program p
+  select type (y => g()) ! { dg-error "Selector shall be polymorphic" }
+  end select
+  call g()
+end
+
+! { dg-prune-output "already being used as a FUNCTION" }


[gcc r14-9509] Fortran: fix for absent array argument passed to optional dummy [PR101135]

2024-03-17 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:3f3f0b7ee8022776d69ecaed1375e1559716f226

commit r14-9509-g3f3f0b7ee8022776d69ecaed1375e1559716f226
Author: Harald Anlauf 
Date:   Fri Mar 15 20:14:07 2024 +0100

Fortran: fix for absent array argument passed to optional dummy [PR101135]

gcc/fortran/ChangeLog:

PR fortran/101135
* trans-array.cc (gfc_get_dataptr_offset): Check for optional
arguments being present before dereferencing data pointer.

gcc/testsuite/ChangeLog:

PR fortran/101135
* gfortran.dg/missing_optional_dummy_6a.f90: Adjust diagnostic 
pattern.
* gfortran.dg/ubsan/missing_optional_dummy_8.f90: New test.

Diff:
---
 gcc/fortran/trans-array.cc |  11 +++
 .../gfortran.dg/missing_optional_dummy_6a.f90  |   2 +-
 .../gfortran.dg/ubsan/missing_optional_dummy_8.f90 | 108 +
 3 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 3673fa40720..a7717a8107e 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -7526,6 +7526,17 @@ gfc_get_dataptr_offset (stmtblock_t *block, tree parm, 
tree desc, tree offset,
 
   /* Set the target data pointer.  */
   offset = gfc_build_addr_expr (gfc_array_dataptr_type (desc), tmp);
+
+  /* Check for optional dummy argument being present.  Arguments of BIND(C)
+ procedures are excepted here since they are handled differently.  */
+  if (expr->expr_type == EXPR_VARIABLE
+  && expr->symtree->n.sym->attr.dummy
+  && expr->symtree->n.sym->attr.optional
+  && !is_CFI_desc (NULL, expr))
+offset = build3_loc (input_location, COND_EXPR, TREE_TYPE (offset),
+gfc_conv_expr_present (expr->symtree->n.sym), offset,
+fold_convert (TREE_TYPE (offset), 
gfc_index_zero_node));
+
   gfc_conv_descriptor_data_set (block, parm, offset);
 }
 
diff --git a/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90 
b/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90
index c6a79059a91..b5e1726d74d 100644
--- a/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90
+++ b/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90
@@ -49,7 +49,7 @@ end program test
 
 ! { dg-final { scan-tree-dump-times "scalar2 \\(.* slr1" 1 "original" } }
 
-! { dg-final { scan-tree-dump-times "= es1 != 0B" 1 "original" } }
+! { dg-final { scan-tree-dump-times "= es1 != 0B" 2 "original" } }
 ! { dg-final { scan-tree-dump-times "assumed_shape2 \\(es1" 0 "original" } }
 ! { dg-final { scan-tree-dump-times "explicit_shape2 \\(es1" 1 "original" } }
 
diff --git a/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90 
b/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90
new file mode 100644
index 000..fd3914934aa
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90
@@ -0,0 +1,108 @@
+! { dg-do run }
+! { dg-additional-options "-fdump-tree-original -fsanitize=undefined" }
+!
+! PR fortran/101135 - Load of null pointer when passing absent
+! assumed-shape array argument for an optional dummy argument
+!
+! Based on testcase by Marcel Jacobse
+
+program main
+  implicit none
+  character(len=3) :: a(6) = ['abc', 'def', 'ghi', 'jlm', 'nop', 'qrs']
+  call as ()
+  call as (a(::2))
+  call as_c ()
+  call as_c (a(2::2))
+  call test_wrapper
+  call test_wrapper_c
+  call test_ar_wrapper
+  call test_ar_wrapper_c
+contains
+  subroutine as (xx)
+character(len=*), optional, intent(in) :: xx(*)
+if (.not. present (xx)) return
+print *, xx(1:3)
+  end subroutine as
+
+  subroutine as_c (zz) bind(c)
+character(len=*), optional, intent(in) :: zz(*)
+if (.not. present (zz)) return
+print *, zz(1:3)
+  end subroutine as_c
+
+  subroutine test_wrapper (x)
+real, dimension(1), intent(out), optional :: x
+call test (x)
+call test1 (x)
+call test_c (x)
+call test1_c (x)
+  end subroutine test_wrapper
+
+  subroutine test_wrapper_c (w) bind(c)
+real, dimension(1), intent(out), optional :: w
+call test (w)
+call test1 (w)
+call test_c (w)
+call test1_c (w)
+  end subroutine test_wrapper_c
+
+  subroutine test (y)
+real, dimension(:), intent(out), optional :: y
+if (present (y)) y=0.
+  end subroutine test
+
+  subroutine test_c (y) bind(c)
+real, dimension(:), intent(out), optional :: y
+if (present (y)) y=0.
+  end subroutine test_c
+
+  subroutine test1 (y)
+real, dimension(1), intent(out), optional :: y
+if (present (y)) y=0.
+  end subroutine test1
+
+  subroutine test1_c (y) bind(c)
+real, dimension(1), intent(out), optional :: y
+if (present (y)) y=0.
+  end subroutine test1_c
+
+  subroutine test_ar_wrapper (p, q, r)
+real,   intent(out), optional :: p
+real, dimension(1), intent(out), optional :: q
+real, dimension(:), intent(out), optional :: r
+call test_ar (p)
+

[gcc r13-8443] Fortran: improve checks of NULL without MOLD as actual argument [PR104819]

2024-03-15 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:90442fb421823153c4f762a2d26a0d700af2e6c3

commit r13-8443-g90442fb421823153c4f762a2d26a0d700af2e6c3
Author: Harald Anlauf 
Date:   Fri Mar 1 19:21:27 2024 +0100

Fortran: improve checks of NULL without MOLD as actual argument [PR104819]

gcc/fortran/ChangeLog:

PR fortran/104819
* check.cc (gfc_check_null): Handle nested NULL()s.
(is_c_interoperable): Check for MOLD argument of NULL() as part of
the interoperability check.
* interface.cc (gfc_compare_actual_formal): Extend checks for NULL()
actual arguments for presence of MOLD argument when required by
Interp J3/22-146.

gcc/testsuite/ChangeLog:

PR fortran/104819
* gfortran.dg/assumed_rank_9.f90: Adjust testcase use of NULL().
* gfortran.dg/pr101329.f90: Adjust testcase to conform to interp.
* gfortran.dg/null_actual_4.f90: New test.

(cherry picked from commit db0b6746be075e43c8142585968483e125bb52d0)

Diff:
---
 gcc/fortran/check.cc |  5 +++-
 gcc/fortran/interface.cc | 30 
 gcc/testsuite/gfortran.dg/assumed_rank_9.f90 | 13 +++
 gcc/testsuite/gfortran.dg/null_actual_4.f90  | 35 
 gcc/testsuite/gfortran.dg/pr101329.f90   |  4 ++--
 5 files changed, 79 insertions(+), 8 deletions(-)

diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
index 8c1ae8c2f00..f39a7610073 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -4357,6 +4357,9 @@ gfc_check_null (gfc_expr *mold)
   if (mold == NULL)
 return true;
 
+  if (mold->expr_type == EXPR_NULL)
+return true;
+
   if (!variable_check (mold, 0, true))
 return false;
 
@@ -5187,7 +5190,7 @@ is_c_interoperable (gfc_expr *expr, const char **msg, 
bool c_loc, bool c_f_ptr)
 {
   *msg = NULL;
 
-  if (expr->expr_type == EXPR_NULL)
+  if (expr->expr_type == EXPR_NULL && expr->ts.type == BT_UNKNOWN)
 {
   *msg = "NULL() is not interoperable";
   return false;
diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc
index e9843e9549c..5cda94753d8 100644
--- a/gcc/fortran/interface.cc
+++ b/gcc/fortran/interface.cc
@@ -3259,6 +3259,36 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, 
gfc_formal_arglist *formal,
  && a->expr->ts.type != BT_ASSUMED)
gfc_find_vtab (>expr->ts);
 
+  /* Interp J3/22-146:
+"If the context of the reference to NULL is an 
+corresponding to an  dummy argument, MOLD shall be
+present."  */
+  if (a->expr->expr_type == EXPR_NULL
+ && a->expr->ts.type == BT_UNKNOWN
+ && f->sym->as
+ && f->sym->as->type == AS_ASSUMED_RANK)
+   {
+ gfc_error ("Intrinsic % without % argument at %L "
+"passed to assumed-rank dummy %qs",
+>expr->where, f->sym->name);
+ ok = false;
+ goto match;
+   }
+
+  if (a->expr->expr_type == EXPR_NULL
+ && a->expr->ts.type == BT_UNKNOWN
+ && f->sym->ts.type == BT_CHARACTER
+ && !f->sym->ts.deferred
+ && f->sym->ts.u.cl
+ && f->sym->ts.u.cl->length == NULL)
+   {
+ gfc_error ("Intrinsic % without % argument at %L "
+"passed to assumed-length dummy %qs",
+>expr->where, f->sym->name);
+ ok = false;
+ goto match;
+   }
+
   if (a->expr->expr_type == EXPR_NULL
  && ((f->sym->ts.type != BT_CLASS && !f->sym->attr.pointer
   && (f->sym->attr.allocatable || !f->sym->attr.optional
diff --git a/gcc/testsuite/gfortran.dg/assumed_rank_9.f90 
b/gcc/testsuite/gfortran.dg/assumed_rank_9.f90
index 1296d068959..5e59ec136c9 100644
--- a/gcc/testsuite/gfortran.dg/assumed_rank_9.f90
+++ b/gcc/testsuite/gfortran.dg/assumed_rank_9.f90
@@ -26,19 +26,20 @@ program main
 
   type(t), target :: y
   class(t), allocatable, target :: yac
-  
+  type(t),  pointer :: ypt
+
   y%i = 489
   allocate (yac)
   yac%i = 489
   j = 0
   call fc()
-  call fc(null())
+  call fc(null(yac))
   call fc(y)
   call fc(yac)
   if (j /= 2) STOP 1
 
   j = 0
-  call gc(null())
+! call gc(null(yac)) ! ICE
   call gc(y)
   call gc(yac)
   deallocate (yac)
@@ -54,13 +55,14 @@ program main
 
   j = 0
   call ft()
-  call ft(null())
+  call ft(null(yac))
   call ft(y)
   call ft(yac)
   if (j /= 2) STOP 4
 
   j = 0
-  call gt(null())
+  call gt(null(ypt))
+! call gt(null(yac)) ! ICE
   call gt(y)
   call gt(yac)
   deallocate (yac)
@@ -73,6 +75,7 @@ program main
   yac%i = 489
   call ht(yac)
   if (j /= 1) STOP 6
+  deallocate (yac)
 
 contains
 
diff --git a/gcc/testsuite/gfortran.dg/null_actual_4.f90 
b/gcc/testsuite/gfortran.dg/null_actual_4.f90
new file mode 100644
index 000..e03d5c8f7de
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/null_actual_4.f90
@@ -0,0 +1,35 @@
+! { dg-do 

[gcc r13-8445] Fortran: handle procedure pointer component in DT array [PR110826]

2024-03-15 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:4e9f475cdc8617f94c903656faaf28910c21c29b

commit r13-8445-g4e9f475cdc8617f94c903656faaf28910c21c29b
Author: Harald Anlauf 
Date:   Mon Mar 11 22:05:51 2024 +0100

Fortran: handle procedure pointer component in DT array [PR110826]

gcc/fortran/ChangeLog:

PR fortran/110826
* array.cc (gfc_array_dimen_size): When walking the ref chain of an
array and the ultimate component is a procedure pointer, do not try
to figure out its dimension even if it is a array-valued function.

gcc/testsuite/ChangeLog:

PR fortran/110826
* gfortran.dg/proc_ptr_comp_53.f90: New test.

(cherry picked from commit 81ee1298b47d3f3b3712ef3f3b2929ca26c4bcd2)

Diff:
---
 gcc/fortran/array.cc   |  7 +
 gcc/testsuite/gfortran.dg/proc_ptr_comp_53.f90 | 43 ++
 2 files changed, 50 insertions(+)

diff --git a/gcc/fortran/array.cc b/gcc/fortran/array.cc
index be5eb8b6a0f..936f774353e 100644
--- a/gcc/fortran/array.cc
+++ b/gcc/fortran/array.cc
@@ -2600,6 +2600,13 @@ gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t 
*result)
 case EXPR_FUNCTION:
   for (ref = array->ref; ref; ref = ref->next)
{
+ /* Ultimate component is a procedure pointer.  */
+ if (ref->type == REF_COMPONENT
+ && !ref->next
+ && ref->u.c.component->attr.function
+ && IS_PROC_POINTER (ref->u.c.component))
+   return false;
+
  if (ref->type != REF_ARRAY)
continue;
 
diff --git a/gcc/testsuite/gfortran.dg/proc_ptr_comp_53.f90 
b/gcc/testsuite/gfortran.dg/proc_ptr_comp_53.f90
new file mode 100644
index 000..affb5922235
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/proc_ptr_comp_53.f90
@@ -0,0 +1,43 @@
+! { dg-do compile }
+! PR fortran/110826 - procedure pointer component in DT array
+
+module m
+  implicit none
+
+  type pp
+procedure(func_template), pointer, nopass :: f =>null()
+  end type pp
+
+  abstract interface
+ function func_template(state) result(dstate)
+   implicit none
+   real, dimension(:,:), intent(in)  :: state
+   real, dimension(size(state,1), size(state,2)) :: dstate
+ end function
+  end interface
+
+contains
+
+  function zero_state(state) result(dstate)
+real, dimension(:,:), intent(in)  :: state
+real, dimension(size(state,1), size(state,2)) :: dstate
+dstate = 0.
+  end function zero_state
+
+end module m
+
+program test_func_array
+  use m
+  implicit none
+
+  real, dimension(4,6) :: state
+  type(pp) :: func_scalar
+  type(pp) :: func_array(4)
+
+  func_scalar  %f => zero_state
+  func_array(1)%f => zero_state
+  print *, func_scalar  %f(state)
+  print *, func_array(1)%f(state)
+  if (.not. all (shape (func_scalar  %f(state)) == shape (state))) stop 1
+  if (.not. all (shape (func_array(1)%f(state)) == shape (state))) stop 2
+end program test_func_array


[gcc r13-8444] Fortran: allow RESTRICT qualifier also for optional arguments [PR100988]

2024-03-15 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:337dc58139595bd9ab4101b988078c5d54d8506a

commit r13-8444-g337dc58139595bd9ab4101b988078c5d54d8506a
Author: Harald Anlauf 
Date:   Mon Dec 4 22:44:53 2023 +0100

Fortran: allow RESTRICT qualifier also for optional arguments [PR100988]

gcc/fortran/ChangeLog:

PR fortran/100988
* gfortran.h (IS_PROC_POINTER): New macro.
* trans-types.cc (gfc_sym_type): Use macro in determination if the
restrict qualifier can be used for a dummy variable.  Fix logic to
allow the restrict qualifier also for optional arguments, and to
not apply it to pointer or proc_pointer arguments.

gcc/testsuite/ChangeLog:

PR fortran/100988
* gfortran.dg/coarray_poly_6.f90: Adjust pattern.
* gfortran.dg/coarray_poly_7.f90: Likewise.
* gfortran.dg/coarray_poly_8.f90: Likewise.
* gfortran.dg/missing_optional_dummy_6a.f90: Likewise.
* gfortran.dg/pr100988.f90: New test.

Co-authored-by: Tobias Burnus  
(cherry picked from commit 9c3a880feecf81c310b4ade210fbd7004c9aece7)

Diff:
---
 gcc/fortran/gfortran.h |  3 ++
 gcc/fortran/trans-types.cc | 13 +++--
 gcc/testsuite/gfortran.dg/coarray_poly_6.f90   |  2 +-
 gcc/testsuite/gfortran.dg/coarray_poly_7.f90   |  2 +-
 gcc/testsuite/gfortran.dg/coarray_poly_8.f90   |  2 +-
 .../gfortran.dg/missing_optional_dummy_6a.f90  |  2 +-
 gcc/testsuite/gfortran.dg/pr100988.f90 | 61 ++
 7 files changed, 74 insertions(+), 11 deletions(-)

diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index aba16cf998b..e6939056a7c 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3951,6 +3951,9 @@ bool gfc_may_be_finalized (gfc_typespec);
 #define IS_POINTER(sym) \
(sym->ts.type == BT_CLASS && sym->attr.class_ok && CLASS_DATA (sym) \
 ? CLASS_DATA (sym)->attr.class_pointer : sym->attr.pointer)
+#define IS_PROC_POINTER(sym) \
+   (sym->ts.type == BT_CLASS && sym->attr.class_ok && CLASS_DATA (sym) \
+? CLASS_DATA (sym)->attr.proc_pointer : sym->attr.proc_pointer)
 
 /* frontend-passes.cc */
 
diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc
index fc5c221a301..b514d8e5a57 100644
--- a/gcc/fortran/trans-types.cc
+++ b/gcc/fortran/trans-types.cc
@@ -2324,8 +2324,8 @@ gfc_sym_type (gfc_symbol * sym, bool is_bind_c)
   else
 byref = 0;
 
-  restricted = !sym->attr.target && !sym->attr.pointer
-   && !sym->attr.proc_pointer && !sym->attr.cray_pointee;
+  restricted = (!sym->attr.target && !IS_POINTER (sym)
+   && !IS_PROC_POINTER (sym) && !sym->attr.cray_pointee);
   if (!restricted)
 type = gfc_nonrestricted_type (type);
 
@@ -2381,11 +2381,10 @@ gfc_sym_type (gfc_symbol * sym, bool is_bind_c)
  || (sym->ns->proc_name && sym->ns->proc_name->attr.entry_master))
type = build_pointer_type (type);
   else
-   {
- type = build_reference_type (type);
- if (restricted)
-   type = build_qualified_type (type, TYPE_QUAL_RESTRICT);
-   }
+   type = build_reference_type (type);
+
+  if (restricted)
+   type = build_qualified_type (type, TYPE_QUAL_RESTRICT);
 }
 
   return (type);
diff --git a/gcc/testsuite/gfortran.dg/coarray_poly_6.f90 
b/gcc/testsuite/gfortran.dg/coarray_poly_6.f90
index 53b80e442d3..344e12b4eff 100644
--- a/gcc/testsuite/gfortran.dg/coarray_poly_6.f90
+++ b/gcc/testsuite/gfortran.dg/coarray_poly_6.f90
@@ -16,6 +16,6 @@ contains
   end subroutine foo
 end
 ! { dg-final { scan-tree-dump-times "foo \\(struct __class_MAIN___T_0_1t & 
restrict x, void \\* restrict caf_token.., integer\\(kind=\[48\]\\) 
caf_offset..\\)" 1 "original" } }
-! { dg-final { scan-tree-dump-times "bar \\(struct __class_MAIN___T_0_1t \\* 
x, void \\* restrict caf_token.., integer\\(kind=\[48\]\\) caf_offset..\\)" 1 
"original" } }
+! { dg-final { scan-tree-dump-times "bar \\(struct __class_MAIN___T_0_1t \\* 
restrict x, void \\* restrict caf_token.., integer\\(kind=\[48\]\\) 
caf_offset..\\)" 1 "original" } }
 ! { dg-final { scan-tree-dump-times "bar \\(0B, 0B, 0\\);" 1 "original" } }
 ! { dg-final { scan-tree-dump-times "foo \\(, y._data.token, 
\\(integer\\(kind=\[48\]\\)\\) class..._data.data - 
\\(integer\\(kind=\[48\]\\)\\) y._data.data\\);" 1 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/coarray_poly_7.f90 
b/gcc/testsuite/gfortran.dg/coarray_poly_7.f90
index 44f98e16e09..d8d83aea39b 100644
--- a/gcc/testsuite/gfortran.dg/coarray_poly_7.f90
+++ b/gcc/testsuite/gfortran.dg/coarray_poly_7.f90
@@ -16,6 +16,6 @@ contains
   end subroutine foo
 end
 ! { dg-final { scan-tree-dump-times "foo \\(struct __class_MAIN___T_1_1t & 
restrict x, void \\* restrict caf_token.., integer\\(kind=\[48\]\\) 
caf_offset..\\)" 1 "original" } }
-! { dg-final { scan-tree-dump-times "bar 

[gcc r13-8442] testsuite: fortran: fix invalid testcases (missing MOLD argument to NULL)

2024-03-15 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:ba4b4b3864d426835ea10e900a4e1dd466d06e51

commit r13-8442-gba4b4b3864d426835ea10e900a4e1dd466d06e51
Author: Harald Anlauf 
Date:   Wed Nov 22 21:45:46 2023 +0100

testsuite: fortran: fix invalid testcases (missing MOLD argument to NULL)

The Fortran standard requires that NULL() passed to an assumed-rank
dummy argument has a MOLD argument.

gcc/testsuite/ChangeLog:

PR fortran/104819
* gfortran.dg/assumed_rank_10.f90: Add MOLD argument to NULL().
* gfortran.dg/assumed_rank_8.f90: Likewise.

(cherry picked from commit 7646b5d88056cf269ff555afe95bc361dcf5e5c0)

Diff:
---
 gcc/testsuite/gfortran.dg/assumed_rank_10.f90 | 6 +++---
 gcc/testsuite/gfortran.dg/assumed_rank_8.f90  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/gcc/testsuite/gfortran.dg/assumed_rank_10.f90 
b/gcc/testsuite/gfortran.dg/assumed_rank_10.f90
index 6a3cc94483e..f22d43ab955 100644
--- a/gcc/testsuite/gfortran.dg/assumed_rank_10.f90
+++ b/gcc/testsuite/gfortran.dg/assumed_rank_10.f90
@@ -50,9 +50,9 @@ program test
 
  is_present = .false.
 
- call fpa(null(), null()) ! No copy back
- call fpi(null(), null()) ! No copy back
- call fno(null(), null()) ! No copy back
+ call fpa(null(iip), null(jjp)) ! No copy back
+ call fpi(null(iip), null(jjp)) ! No copy back
+ call fno(null(iip), null(jjp)) ! No copy back
 
  call fno() ! No copy back
 
diff --git a/gcc/testsuite/gfortran.dg/assumed_rank_8.f90 
b/gcc/testsuite/gfortran.dg/assumed_rank_8.f90
index 5873296a7a5..34ff42c0be2 100644
--- a/gcc/testsuite/gfortran.dg/assumed_rank_8.f90
+++ b/gcc/testsuite/gfortran.dg/assumed_rank_8.f90
@@ -22,13 +22,13 @@ program main
   call f (ii)
   call f (489)
   call f ()
-  call f (null())
+  call f (null(kk))
   call f (kk)
   if (j /= 2) STOP 1
 
   j = 0
   nullify (ll)
-  call g (null())
+  call g (null(ll))
   call g (ll)
   call g (ii)
   if (j /= 1) STOP 2


[gcc r14-9454] Fortran: fix IS_CONTIGUOUS for polymorphic dummy arguments [PR114001]

2024-03-13 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:11caf47b599568c6c6f5a12cf8e21f50778176d3

commit r14-9454-g11caf47b599568c6c6f5a12cf8e21f50778176d3
Author: Harald Anlauf 
Date:   Tue Mar 12 22:58:39 2024 +0100

Fortran: fix IS_CONTIGUOUS for polymorphic dummy arguments [PR114001]

gcc/fortran/ChangeLog:

PR fortran/114001
* expr.cc (gfc_is_simply_contiguous): Adjust logic so that CLASS
symbols are also handled.

gcc/testsuite/ChangeLog:

PR fortran/114001
* gfortran.dg/is_contiguous_4.f90: New test.

Diff:
---
 gcc/fortran/expr.cc   | 19 ---
 gcc/testsuite/gfortran.dg/is_contiguous_4.f90 | 81 +++
 2 files changed, 91 insertions(+), 9 deletions(-)

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 37ea95d0185..82a642b01f7 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -6025,15 +6025,16 @@ gfc_is_simply_contiguous (gfc_expr *expr, bool strict, 
bool permit_element)
 }
 
   sym = expr->symtree->n.sym;
-  if (expr->ts.type != BT_CLASS
-  && ((part_ref
-  && !part_ref->u.c.component->attr.contiguous
-  && part_ref->u.c.component->attr.pointer)
- || (!part_ref
- && !sym->attr.contiguous
- && (sym->attr.pointer
- || (sym->as && sym->as->type == AS_ASSUMED_RANK)
- || (sym->as && sym->as->type == AS_ASSUMED_SHAPE)
+  if ((part_ref
+   && part_ref->u.c.component
+   && !part_ref->u.c.component->attr.contiguous
+   && IS_POINTER (part_ref->u.c.component))
+  || (!part_ref
+ && expr->ts.type != BT_CLASS
+ && !sym->attr.contiguous
+ && (sym->attr.pointer
+ || (sym->as && sym->as->type == AS_ASSUMED_RANK)
+ || (sym->as && sym->as->type == AS_ASSUMED_SHAPE
 return false;
 
   if (!ar || ar->type == AR_FULL)
diff --git a/gcc/testsuite/gfortran.dg/is_contiguous_4.f90 
b/gcc/testsuite/gfortran.dg/is_contiguous_4.f90
new file mode 100644
index 000..cb066f8836b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/is_contiguous_4.f90
@@ -0,0 +1,81 @@
+! { dg-do run }
+! PR fortran/114001 - IS_CONTIGUOUS and polymorphic dummy
+
+program main
+  implicit none
+  integer :: i, cnt = 0
+  logical :: expect
+  integer, target  :: m(10) = [(i,i=1,size(m))]
+  integer, pointer :: p(:)
+  type t
+ integer :: j
+  end type t
+  type(t),  pointer :: tt(:), tp(:) ! Type pointer
+  class(t), pointer :: ct(:), cp(:) ! Class pointer
+
+  p => m(1:3)
+  expect = is_contiguous (p)
+  print *, "is_contiguous (p)=", expect
+  if (.not. expect) stop 91
+  call sub_star (p, expect)
+  p => m(1::3)
+  expect = is_contiguous (p)
+  print *, "is_contiguous (p)=", expect
+  if (expect) stop 92
+  call sub_star (p, expect)
+
+  allocate (tt(10))
+  tt(:)% j = m
+  tp => tt(4:6)
+  expect = is_contiguous (tp)
+  if (.not. expect) stop 96
+  print *, "is_contiguous (tp)=", expect
+  call sub_t (tp, expect)
+  tp => tt(4::3)
+  expect = is_contiguous (tp)
+  if (expect) stop 97
+  print *, "is_contiguous (tp)=", expect
+  call sub_t (tp, expect)
+
+  allocate (ct(10))
+  ct(:)% j = m
+  cp => ct(7:9)
+  expect = is_contiguous (cp)
+  print *, "is_contiguous (cp)=", expect
+  if (.not. expect) stop 98
+  call sub_t (cp, expect)
+  cp => ct(4::3)
+  expect = is_contiguous (cp)
+  print *, "is_contiguous (cp)=", expect
+  if (expect) stop 99
+  call sub_t (cp, expect)
+
+contains
+
+  subroutine sub_star (x, expect)
+class(*), intent(in) :: x(:)
+logical,  intent(in) :: expect
+cnt = cnt + 10
+if (is_contiguous (x) .neqv. expect) then
+   print *, "sub_star(1): is_contiguous (x)=", is_contiguous (x), expect
+   stop (cnt + 1)
+end if
+select type (x)
+type is (integer)
+   if (is_contiguous (x) .neqv. expect) then
+  print *, "sub_star(2): is_contiguous (x)=", is_contiguous (x), expect
+  stop (cnt + 2)
+   end if
+end select
+  end
+
+  subroutine sub_t (x, expect)
+class(t), intent(in) :: x(:)
+logical,  intent(in) :: expect
+cnt = cnt + 10
+if (is_contiguous (x) .neqv. expect) then
+   print *, "sub_t: is_contiguous (x)=", is_contiguous (x), expect
+   stop (cnt + 3)
+end if
+  end
+end


[gcc r14-9442] Fortran: handle procedure pointer component in DT array [PR110826]

2024-03-12 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:81ee1298b47d3f3b3712ef3f3b2929ca26c4bcd2

commit r14-9442-g81ee1298b47d3f3b3712ef3f3b2929ca26c4bcd2
Author: Harald Anlauf 
Date:   Mon Mar 11 22:05:51 2024 +0100

Fortran: handle procedure pointer component in DT array [PR110826]

gcc/fortran/ChangeLog:

PR fortran/110826
* array.cc (gfc_array_dimen_size): When walking the ref chain of an
array and the ultimate component is a procedure pointer, do not try
to figure out its dimension even if it is a array-valued function.

gcc/testsuite/ChangeLog:

PR fortran/110826
* gfortran.dg/proc_ptr_comp_53.f90: New test.

Diff:
---
 gcc/fortran/array.cc   |  7 +
 gcc/testsuite/gfortran.dg/proc_ptr_comp_53.f90 | 43 ++
 2 files changed, 50 insertions(+)

diff --git a/gcc/fortran/array.cc b/gcc/fortran/array.cc
index 3a6e3a7c95b..e9934f1491b 100644
--- a/gcc/fortran/array.cc
+++ b/gcc/fortran/array.cc
@@ -2597,6 +2597,13 @@ gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t 
*result)
 case EXPR_FUNCTION:
   for (ref = array->ref; ref; ref = ref->next)
{
+ /* Ultimate component is a procedure pointer.  */
+ if (ref->type == REF_COMPONENT
+ && !ref->next
+ && ref->u.c.component->attr.function
+ && IS_PROC_POINTER (ref->u.c.component))
+   return false;
+
  if (ref->type != REF_ARRAY)
continue;
 
diff --git a/gcc/testsuite/gfortran.dg/proc_ptr_comp_53.f90 
b/gcc/testsuite/gfortran.dg/proc_ptr_comp_53.f90
new file mode 100644
index 000..affb5922235
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/proc_ptr_comp_53.f90
@@ -0,0 +1,43 @@
+! { dg-do compile }
+! PR fortran/110826 - procedure pointer component in DT array
+
+module m
+  implicit none
+
+  type pp
+procedure(func_template), pointer, nopass :: f =>null()
+  end type pp
+
+  abstract interface
+ function func_template(state) result(dstate)
+   implicit none
+   real, dimension(:,:), intent(in)  :: state
+   real, dimension(size(state,1), size(state,2)) :: dstate
+ end function
+  end interface
+
+contains
+
+  function zero_state(state) result(dstate)
+real, dimension(:,:), intent(in)  :: state
+real, dimension(size(state,1), size(state,2)) :: dstate
+dstate = 0.
+  end function zero_state
+
+end module m
+
+program test_func_array
+  use m
+  implicit none
+
+  real, dimension(4,6) :: state
+  type(pp) :: func_scalar
+  type(pp) :: func_array(4)
+
+  func_scalar  %f => zero_state
+  func_array(1)%f => zero_state
+  print *, func_scalar  %f(state)
+  print *, func_array(1)%f(state)
+  if (.not. all (shape (func_scalar  %f(state)) == shape (state))) stop 1
+  if (.not. all (shape (func_array(1)%f(state)) == shape (state))) stop 2
+end program test_func_array


[gcc r13-8407] Fortran: do not evaluate polymorphic functions twice in assignment [PR114012]

2024-03-06 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:1f5787e4b803a4294eeb80e048f56ccdb99c1b3b

commit r13-8407-g1f5787e4b803a4294eeb80e048f56ccdb99c1b3b
Author: Harald Anlauf 
Date:   Sun Feb 25 21:18:23 2024 +0100

Fortran: do not evaluate polymorphic functions twice in assignment 
[PR114012]

PR fortran/114012

gcc/fortran/ChangeLog:

* trans-expr.cc (gfc_conv_procedure_call): Evaluate non-trivial
arguments just once before assigning to an unlimited polymorphic
dummy variable.

gcc/testsuite/ChangeLog:

* gfortran.dg/pr114012.f90: New test.

(cherry picked from commit 2f71e801ad0bb1f620334aadbd7c99cc4efe6309)

Diff:
---
 gcc/fortran/trans-expr.cc  |  4 ++
 gcc/testsuite/gfortran.dg/pr114012.f90 | 81 ++
 2 files changed, 85 insertions(+)

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 48af30740fe..316ad684a64 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6518,6 +6518,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
{
  tree efield;
 
+ /* Evaluate arguments just once.  */
+ if (e->expr_type != EXPR_VARIABLE)
+   parmse.expr = save_expr (parmse.expr);
+
  /* Set the _data field.  */
  tmp = gfc_class_data_get (var);
  efield = fold_convert (TREE_TYPE (tmp),
diff --git a/gcc/testsuite/gfortran.dg/pr114012.f90 
b/gcc/testsuite/gfortran.dg/pr114012.f90
new file mode 100644
index 000..9dbb031c664
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr114012.f90
@@ -0,0 +1,81 @@
+! { dg-do run }
+! PR fortran/114012
+!
+! Polymorphic functions were evaluated twice in assignment
+
+program test
+  implicit none
+
+  type :: custom_int
+ integer :: val = 2
+  end type
+
+  interface assignment(=)
+ procedure assign
+  end interface
+  interface operator(-)
+ procedure neg
+  end interface
+
+  type(custom_int) :: i
+  integer  :: count_assign, count_neg
+
+  count_assign = 0
+  count_neg= 0
+
+  i = 1
+  if (count_assign /= 1 .or. count_neg /= 0) stop 1
+
+  i = -i
+  if (count_assign /= 2 .or. count_neg /= 1) stop 2
+  if (i% val /= -1) stop 3
+
+  i = neg(i)
+  if (count_assign /= 3 .or. count_neg /= 2) stop 4
+  if (i% val /=  1) stop 5
+
+  i = (neg(i))
+  if (count_assign /= 4 .or. count_neg /= 3) stop 6
+  if (i% val /= -1) stop 7
+
+  i = - neg(i)
+  if (count_assign /= 5 .or. count_neg /= 5) stop 8
+  if (i% val /= -1) stop 9
+
+contains
+
+  subroutine assign (field, val)
+type(custom_int), intent(out) :: field
+class(*), intent(in) :: val
+
+count_assign = count_assign + 1
+
+select type (val)
+type is (integer)
+!  print *, " in assign(integer)", field%val, val
+   field%val = val
+type is (custom_int)
+!  print *, " in assign(custom)", field%val, val%val
+   field%val = val%val
+class default
+   error stop
+end select
+
+  end subroutine assign
+
+  function neg (input_field) result(output_field)
+type(custom_int), intent(in), target :: input_field
+class(custom_int), allocatable :: output_field
+allocate (custom_int :: output_field)
+
+count_neg = count_neg + 1
+
+select type (output_field)
+type is (custom_int)
+!  print *, " in neg", output_field%val, input_field%val
+   output_field%val = -input_field%val
+class default
+   error stop
+end select
+  end function neg
+end program test


[gcc r13-8406] Fortran: ALLOCATE statement, SOURCE/MOLD expressions with subrefs [PR114024]

2024-03-06 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:77cf842869ddda8cfcdbb7db6e65ecfb9ac432fc

commit r13-8406-g77cf842869ddda8cfcdbb7db6e65ecfb9ac432fc
Author: Steve Kargl 
Date:   Fri Feb 23 22:05:04 2024 +0100

Fortran: ALLOCATE statement, SOURCE/MOLD expressions with subrefs [PR114024]

PR fortran/114024

gcc/fortran/ChangeLog:

* trans-stmt.cc (gfc_trans_allocate): When a source expression has
substring references, part-refs, or %re/%im inquiries, wrap the
entity in parentheses to force evaluation of the expression.

gcc/testsuite/ChangeLog:

* gfortran.dg/allocate_with_source_27.f90: New test.
* gfortran.dg/allocate_with_source_28.f90: New test.

Co-Authored-By: Harald Anlauf 
(cherry picked from commit 80d126ba99f4b9bc64d4861b3c4bae666497f2d4)

Diff:
---
 gcc/fortran/trans-stmt.cc  | 10 ++-
 .../gfortran.dg/allocate_with_source_27.f90| 20 +
 .../gfortran.dg/allocate_with_source_28.f90| 90 ++
 3 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc
index 776f98d08d9..35eb1880539 100644
--- a/gcc/fortran/trans-stmt.cc
+++ b/gcc/fortran/trans-stmt.cc
@@ -6318,8 +6318,14 @@ gfc_trans_allocate (gfc_code * code)
vtab_needed = (al->expr->ts.type == BT_CLASS);
 
   gfc_init_se (, NULL);
-  /* When expr3 is a variable, i.e., a very simple expression,
-then convert it once here.  */
+  /* When expr3 is a variable, i.e., a very simple expression, then
+convert it once here.  If one has a source expression that has
+substring references, part-refs, or %re/%im inquiries, wrap the
+entity in parentheses to force evaluation of the expression.  */
+  if (code->expr3->expr_type == EXPR_VARIABLE
+ && is_subref_array (code->expr3))
+   code->expr3 = gfc_get_parentheses (code->expr3);
+
   if (code->expr3->expr_type == EXPR_VARIABLE
  || code->expr3->expr_type == EXPR_ARRAY
  || code->expr3->expr_type == EXPR_CONSTANT)
diff --git a/gcc/testsuite/gfortran.dg/allocate_with_source_27.f90 
b/gcc/testsuite/gfortran.dg/allocate_with_source_27.f90
new file mode 100644
index 000..d0f0f3c4a84
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/allocate_with_source_27.f90
@@ -0,0 +1,20 @@
+!
+! { dg-do run }
+!
+! fortran/PR114024
+! https://github.com/fujitsu/compiler-test-suite
+! Modified from Fortran/0093/0093_0130.f90
+!
+program foo
+   implicit none
+   complex :: cmp(3)
+   real, allocatable :: xx(:), yy(:), zz(:)
+   cmp = (3., 6.78)
+   allocate(xx, source = cmp%re)  ! This caused an ICE.
+   allocate(yy, source = cmp(1:3)%re) ! This caused an ICE.
+   allocate(zz, source = (cmp%re))
+   if (any(xx /= [3., 3., 3.])) stop 1
+   if (any(yy /= [3., 3., 3.])) stop 2
+   if (any(zz /= [3., 3., 3.])) stop 3
+end program foo
+
diff --git a/gcc/testsuite/gfortran.dg/allocate_with_source_28.f90 
b/gcc/testsuite/gfortran.dg/allocate_with_source_28.f90
new file mode 100644
index 000..8548ccb34e2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/allocate_with_source_28.f90
@@ -0,0 +1,90 @@
+! { dg-do run }
+!
+! PR fortran/114024
+
+program foo
+  implicit none
+  complex :: cmp(3) = (3.,4.)
+  type ci   ! pseudo "complex integer" type
+ integer :: re
+ integer :: im
+  end type ci
+  type cr   ! pseudo "complex" type
+ real :: re
+ real :: im
+  end type cr
+  type u
+ type(ci) :: ii(3)
+ type(cr) :: rr(3)
+  end type u
+  type(u) :: cc
+
+  cc% ii% re = nint (cmp% re)
+  cc% ii% im = nint (cmp% im)
+  cc% rr% re = cmp% re
+  cc% rr% im = cmp% im
+ 
+  call test_substring ()
+  call test_int_real ()
+  call test_poly ()
+
+contains
+
+  subroutine test_substring ()
+character(4)  :: str(3) = ["abcd","efgh","ijkl"]
+character(:), allocatable :: ac(:)
+allocate (ac, source=str(1::2)(2:4))
+if (size (ac) /= 2 .or. len (ac) /= 3) stop 11
+if (ac(2) /= "jkl")stop 12
+deallocate (ac)
+allocate (ac, mold=str(1::2)(2:4))
+if (size (ac) /= 2 .or. len (ac) /= 3) stop 13
+deallocate (ac)
+  end
+
+  subroutine test_int_real ()
+integer, allocatable  :: aa(:)
+real, pointer :: pp(:)
+allocate (aa, source = cc% ii% im)
+if (size (aa) /= 3)  stop 21
+if (any (aa /= cmp% im)) stop 22
+allocate (pp, source = cc% rr% re)
+if (size (pp) /= 3)  stop 23
+if (any (pp /= cmp% re)) stop 24
+deallocate (aa, pp)
+  end
+
+  subroutine test_poly ()
+class(*), allocatable :: uu(:), vv(:)
+allocate (uu, source = cc% ii% im)
+allocate (vv, source = cc% rr% re)
+if (size (uu) /= 3) stop 31
+if (size (vv) /= 3) stop 32
+call check (uu)
+call check (vv)
+deallocate (uu, vv)
+allocate (uu, mold = cc% ii% im)
+allocate (vv, mold = cc% rr% re)
+if 

[gcc r14-9340] Fortran: error recovery while simplifying expressions [PR103707, PR106987]

2024-03-06 Thread Harald Anlauf via Gcc-cvs
https://gcc.gnu.org/g:93e1d4d24ed014387da97e2ce11556d68fe98e66

commit r14-9340-g93e1d4d24ed014387da97e2ce11556d68fe98e66
Author: Harald Anlauf 
Date:   Tue Mar 5 21:54:26 2024 +0100

Fortran: error recovery while simplifying expressions [PR103707,PR106987]

When an exception is encountered during simplification of arithmetic
expressions, the result may depend on whether range-checking is active
(-frange-check) or not.  However, the code path in the front-end should
stay the same for "soft" errors for which the exception is triggered by the
check, while "hard" errors should always terminate the simplification, so
that error recovery is independent of the flag.  Separation of arithmetic
error codes into "hard" and "soft" errors shall be done consistently via
is_hard_arith_error().

PR fortran/103707
PR fortran/106987

gcc/fortran/ChangeLog:

* arith.cc (is_hard_arith_error): New helper function to determine
whether an arithmetic error is "hard" or not.
(check_result): Use it.
(gfc_arith_divide): Set "Division by zero" only for regular
numerators of real and complex divisions.
(reduce_unary): Use is_hard_arith_error to determine whether a hard
or (recoverable) soft error was encountered.  Terminate immediately
on hard error, otherwise remember code of first soft error.
(reduce_binary_ac): Likewise.
(reduce_binary_ca): Likewise.
(reduce_binary_aa): Likewise.

gcc/testsuite/ChangeLog:

* gfortran.dg/pr99350.f90:
* gfortran.dg/arithmetic_overflow_3.f90: New test.

Diff:
---
 gcc/fortran/arith.cc   | 134 +++--
 .../gfortran.dg/arithmetic_overflow_3.f90  |  48 
 gcc/testsuite/gfortran.dg/pr99350.f90  |   2 +-
 3 files changed, 143 insertions(+), 41 deletions(-)

diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc
index d17d1aaa1d9..b373c25e5e1 100644
--- a/gcc/fortran/arith.cc
+++ b/gcc/fortran/arith.cc
@@ -130,6 +130,30 @@ gfc_arith_error (arith code)
 }
 
 
+/* Check if a certain arithmetic error code is severe enough to prevent
+   further simplification, as opposed to errors thrown by the range check
+   (e.g. overflow) or arithmetic exceptions that are tolerated with
+   -fno-range-check.  */
+
+static bool
+is_hard_arith_error (arith code)
+{
+  switch (code)
+{
+case ARITH_OK:
+case ARITH_OVERFLOW:
+case ARITH_UNDERFLOW:
+case ARITH_NAN:
+case ARITH_DIV0:
+case ARITH_ASYMMETRIC:
+  return false;
+
+default:
+  return true;
+}
+}
+
+
 /* Get things ready to do math.  */
 
 void
@@ -579,10 +603,10 @@ check_result (arith rc, gfc_expr *x, gfc_expr *r, 
gfc_expr **rp)
   val = ARITH_OK;
 }
 
-  if (val == ARITH_OK || val == ARITH_OVERFLOW)
-*rp = r;
-  else
+  if (is_hard_arith_error (val))
 gfc_free_expr (r);
+  else
+*rp = r;
 
   return val;
 }
@@ -792,23 +816,26 @@ gfc_arith_divide (gfc_expr *op1, gfc_expr *op2, gfc_expr 
**resultp)
   break;
 
 case BT_REAL:
-  if (mpfr_sgn (op2->value.real) == 0 && flag_range_check == 1)
-   {
- rc = ARITH_DIV0;
- break;
-   }
+  /* Set "Division by zero" only for regular numerator.  */
+  if (flag_range_check == 1
+ && mpfr_zero_p (op2->value.real)
+ && mpfr_regular_p (op1->value.real))
+   rc = ARITH_DIV0;
 
   mpfr_div (result->value.real, op1->value.real, op2->value.real,
   GFC_RND_MODE);
   break;
 
 case BT_COMPLEX:
-  if (mpc_cmp_si_si (op2->value.complex, 0, 0) == 0
- && flag_range_check == 1)
-   {
- rc = ARITH_DIV0;
- break;
-   }
+  /* Set "Division by zero" only for regular numerator.  */
+  if (flag_range_check == 1
+ && mpfr_zero_p (mpc_realref (op2->value.complex))
+ && mpfr_zero_p (mpc_imagref (op2->value.complex))
+ && ((mpfr_regular_p (mpc_realref (op1->value.complex))
+  && mpfr_number_p (mpc_imagref (op1->value.complex)))
+ || (mpfr_regular_p (mpc_imagref (op1->value.complex))
+ && mpfr_number_p (mpc_realref (op1->value.complex)
+   rc = ARITH_DIV0;
 
   gfc_set_model (mpc_realref (op1->value.complex));
   if (mpc_cmp_si_si (op2->value.complex, 0, 0) == 0)
@@ -1323,7 +1350,6 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), 
gfc_expr *op,
   gfc_constructor *c;
   gfc_expr *r;
   arith rc;
-  bool ov = false;
 
   if (op->expr_type == EXPR_CONSTANT)
 return eval (op, result);
@@ -1335,19 +1361,22 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), 
gfc_expr *op,
   head = gfc_constructor_copy (op->value.constructor);
   for (c = gfc_constructor_first (head); c; c = gfc_constructor_next (c))
 {
-  rc = reduce_unary (eval, c->expr, );
+