public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-11] Fortran: Fixes and additional tests for shape/ubound/size [PR94070]
@ 2021-10-21  7:07 Tobias Burnus
  0 siblings, 0 replies; only message in thread
From: Tobias Burnus @ 2021-10-21  7:07 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:ce71cb796527be4ac326155aa7f348cabbe89009

commit ce71cb796527be4ac326155aa7f348cabbe89009
Author: Tobias Burnus <tobias@codesourcery.com>
Date:   Thu Oct 21 08:28:42 2021 +0200

    Fortran: Fixes and additional tests for shape/ubound/size [PR94070]
    
    This patch reimplements the SHAPE intrinsic to be inlined similarly to
    LBOUND and UBOUND, instead of as a library call, to avoid an
    unnecessary array copy.  Various bugs are also fixed.
    
    gcc/fortran/
            PR fortran/94070
    
            * expr.c (gfc_simplify_expr): Handle GFC_ISYM_SHAPE along with
            GFC_ISYM_LBOUND and GFC_ISYM_UBOUND.
            * trans-array.c (gfc_conv_ss_startstride): Likewise.
            (set_loop_bounds): Likewise.
            * trans-intrinsic.c (gfc_trans_intrinsic_bound): Extend to
            handle SHAPE.  Correct logic for zero-size special cases and
            detecting assumed-rank arrays associated with an assumed-size
            argument.
            (gfc_conv_intrinsic_shape): Deleted.
            (gfc_conv_intrinsic_function): Handle GFC_ISYM_SHAPE like
            GFC_ISYM_LBOUND and GFC_ISYM_UBOUND.
            (gfc_add_intrinsic_ss_code): Likewise.
            (gfc_walk_intrinsic_bound): Likewise.
    
    gcc/testsuite/
            PR fortran/94070
    
            * gfortran.dg/c-interop/shape-bindc.f90: New test.
            * gfortran.dg/c-interop/shape-poly.f90: New test.
            * gfortran.dg/c-interop/size-bindc.f90: New test.
            * gfortran.dg/c-interop/size-poly.f90: New test.
            * gfortran.dg/c-interop/ubound-bindc.f90: New test.
            * gfortran.dg/c-interop/ubound-poly.f90: New test.
    
    (cherry picked from commit 1af78e731feb9327a17c99ebaa19a4cca1125caf)

Diff:
---
 gcc/fortran/ChangeLog.omp                          |  20 ++
 gcc/fortran/expr.c                                 |   3 +-
 gcc/fortran/trans-array.c                          |  20 +-
 gcc/fortran/trans-intrinsic.c                      | 246 +++++++--------------
 gcc/testsuite/ChangeLog.omp                        |  13 ++
 .../gfortran.dg/c-interop/shape-bindc.f90          |  77 +++++++
 gcc/testsuite/gfortran.dg/c-interop/shape-poly.f90 |  89 ++++++++
 gcc/testsuite/gfortran.dg/c-interop/size-bindc.f90 | 106 +++++++++
 gcc/testsuite/gfortran.dg/c-interop/size-poly.f90  | 118 ++++++++++
 .../gfortran.dg/c-interop/ubound-bindc.f90         | 129 +++++++++++
 .../gfortran.dg/c-interop/ubound-poly.f90          | 145 ++++++++++++
 11 files changed, 788 insertions(+), 178 deletions(-)

diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp
index 14b01395814..4ca778c2135 100644
--- a/gcc/fortran/ChangeLog.omp
+++ b/gcc/fortran/ChangeLog.omp
@@ -1,3 +1,23 @@
+2021-10-21  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backport from master:
+	2021-10-20  Sandra Loosemore  <sandra@codesourcery.com>
+
+	PR fortran/94070
+	* expr.c (gfc_simplify_expr): Handle GFC_ISYM_SHAPE along with
+	GFC_ISYM_LBOUND and GFC_ISYM_UBOUND.
+	* trans-array.c (gfc_conv_ss_startstride): Likewise.
+	(set_loop_bounds): Likewise.
+	* trans-intrinsic.c (gfc_trans_intrinsic_bound): Extend to
+	handle SHAPE.  Correct logic for zero-size special cases and
+	detecting assumed-rank arrays associated with an assumed-size
+	argument.
+	(gfc_conv_intrinsic_shape): Deleted.
+	(gfc_conv_intrinsic_function): Handle GFC_ISYM_SHAPE like
+	GFC_ISYM_LBOUND and GFC_ISYM_UBOUND.
+	(gfc_add_intrinsic_ss_code): Likewise.
+	(gfc_walk_intrinsic_bound): Likewise.
+
 2021-10-19  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index 66f24c63823..b19d3a26c60 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -2205,7 +2205,8 @@ gfc_simplify_expr (gfc_expr *p, int type)
 	  (p->value.function.isym->id == GFC_ISYM_LBOUND
 	   || p->value.function.isym->id == GFC_ISYM_UBOUND
 	   || p->value.function.isym->id == GFC_ISYM_LCOBOUND
-	   || p->value.function.isym->id == GFC_ISYM_UCOBOUND))
+	   || p->value.function.isym->id == GFC_ISYM_UCOBOUND
+	   || p->value.function.isym->id == GFC_ISYM_SHAPE))
 	ap = ap->next;
 
       for ( ; ap; ap = ap->next)
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index ab37d53fbfa..b7d94992972 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -4507,6 +4507,7 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
 	    case GFC_ISYM_UBOUND:
 	    case GFC_ISYM_LCOBOUND:
 	    case GFC_ISYM_UCOBOUND:
+	    case GFC_ISYM_SHAPE:
 	    case GFC_ISYM_THIS_IMAGE:
 	      loop->dimen = ss->dimen;
 	      goto done;
@@ -4558,12 +4559,14 @@ done:
 	    /* Fall through to supply start and stride.  */
 	    case GFC_ISYM_LBOUND:
 	    case GFC_ISYM_UBOUND:
+	      /* This is the variant without DIM=...  */
+	      gcc_assert (expr->value.function.actual->next->expr == NULL);
+	      /* Fall through.  */
+
+	    case GFC_ISYM_SHAPE:
 	      {
 		gfc_expr *arg;
 
-		/* This is the variant without DIM=...  */
-		gcc_assert (expr->value.function.actual->next->expr == NULL);
-
 		arg = expr->value.function.actual->expr;
 		if (arg->rank == -1)
 		  {
@@ -5351,10 +5354,13 @@ set_loop_bounds (gfc_loopinfo *loop)
 		gfc_expr *expr = loopspec[n]->info->expr;
 
 		/* The {l,u}bound of an assumed rank.  */
-		gcc_assert ((expr->value.function.isym->id == GFC_ISYM_LBOUND
-			     || expr->value.function.isym->id == GFC_ISYM_UBOUND)
-			     && expr->value.function.actual->next->expr == NULL
-			     && expr->value.function.actual->expr->rank == -1);
+		if (expr->value.function.isym->id == GFC_ISYM_SHAPE)
+		  gcc_assert (expr->value.function.actual->expr->rank == -1);
+		else
+		  gcc_assert ((expr->value.function.isym->id == GFC_ISYM_LBOUND
+			       || expr->value.function.isym->id == GFC_ISYM_UBOUND)
+			      && expr->value.function.actual->next->expr == NULL
+			      && expr->value.function.actual->expr->rank == -1);
 
 		loop->to[n] = info->end[dim];
 		break;
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index fd0bc96ed1f..6bda0f82114 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -2922,7 +2922,7 @@ gfc_conv_is_contiguous_expr (gfc_se *se, gfc_expr *arg)
 /* TODO: bound intrinsic generates way too much unnecessary code.  */
 
 static void
-gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper)
+gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, enum gfc_isym_id op)
 {
   gfc_actual_arglist *arg;
   gfc_actual_arglist *arg2;
@@ -2930,9 +2930,10 @@ gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper)
   tree type;
   tree bound;
   tree tmp;
-  tree cond, cond1, cond3, cond4, size;
+  tree cond, cond1;
   tree ubound;
   tree lbound;
+  tree size;
   gfc_se argse;
   gfc_array_spec * as;
   bool assumed_rank_lb_one;
@@ -2943,7 +2944,7 @@ gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper)
   if (se->ss)
     {
       /* Create an implicit second parameter from the loop variable.  */
-      gcc_assert (!arg2->expr);
+      gcc_assert (!arg2->expr || op == GFC_ISYM_SHAPE);
       gcc_assert (se->loop->dimen == 1);
       gcc_assert (se->ss->info->expr == expr);
       gfc_advance_se_ss_chain (se);
@@ -2979,12 +2980,14 @@ gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper)
 
   if (INTEGER_CST_P (bound))
     {
+      gcc_assert (op != GFC_ISYM_SHAPE);
       if (((!as || as->type != AS_ASSUMED_RANK)
 	   && wi::geu_p (wi::to_wide (bound),
 			 GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc))))
 	  || wi::gtu_p (wi::to_wide (bound), GFC_MAX_DIMENSIONS))
 	gfc_error ("%<dim%> argument of %s intrinsic at %L is not a valid "
-		   "dimension index", upper ? "UBOUND" : "LBOUND",
+		   "dimension index",
+		   (op == GFC_ISYM_UBOUND) ? "UBOUND" : "LBOUND",
 		   &expr->where);
     }
 
@@ -3008,8 +3011,8 @@ gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper)
         }
     }
 
-  /* Take care of the lbound shift for assumed-rank arrays, which are
-     nonallocatable and nonpointers. Those has a lbound of 1.  */
+  /* Take care of the lbound shift for assumed-rank arrays that are
+     nonallocatable and nonpointers. Those have a lbound of 1.  */
   assumed_rank_lb_one = as && as->type == AS_ASSUMED_RANK
 			&& ((arg->expr->ts.type != BT_CLASS
 			     && !arg->expr->symtree->n.sym->attr.allocatable
@@ -3020,6 +3023,10 @@ gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper)
 
   ubound = gfc_conv_descriptor_ubound_get (desc, bound);
   lbound = gfc_conv_descriptor_lbound_get (desc, bound);
+  size = fold_build2_loc (input_location, MINUS_EXPR,
+			  gfc_array_index_type, ubound, lbound);
+  size = fold_build2_loc (input_location, PLUS_EXPR,
+			  gfc_array_index_type, size, gfc_index_one_node);
 
   /* 13.14.53: Result value for LBOUND
 
@@ -3042,106 +3049,82 @@ gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper)
                not have size zero and has value zero if dimension DIM has
                size zero.  */
 
-  if (!upper && assumed_rank_lb_one)
+  if (op == GFC_ISYM_LBOUND && assumed_rank_lb_one)
     se->expr = gfc_index_one_node;
   else if (as)
     {
-      tree stride = gfc_conv_descriptor_stride_get (desc, bound);
-
-      cond1 = fold_build2_loc (input_location, GE_EXPR, logical_type_node,
-			       ubound, lbound);
-      cond3 = fold_build2_loc (input_location, GE_EXPR, logical_type_node,
-			       stride, gfc_index_zero_node);
-      cond3 = fold_build2_loc (input_location, TRUTH_AND_EXPR,
-			       logical_type_node, cond3, cond1);
-      cond4 = fold_build2_loc (input_location, LT_EXPR, logical_type_node,
-			       stride, gfc_index_zero_node);
-
-      if (upper)
+      if (op == GFC_ISYM_UBOUND)
 	{
-	  tree cond5;
-	  cond = fold_build2_loc (input_location, TRUTH_OR_EXPR,
-				  logical_type_node, cond3, cond4);
-	  cond5 = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
-				   gfc_index_one_node, lbound);
-	  cond5 = fold_build2_loc (input_location, TRUTH_AND_EXPR,
-				   logical_type_node, cond4, cond5);
-
-	  cond = fold_build2_loc (input_location, TRUTH_OR_EXPR,
-				  logical_type_node, cond, cond5);
-
-	  if (assumed_rank_lb_one)
+	  cond = fold_build2_loc (input_location, GT_EXPR, logical_type_node,
+				  size, gfc_index_zero_node);
+	  se->expr = fold_build3_loc (input_location, COND_EXPR,
+				      gfc_array_index_type, cond,
+				      (assumed_rank_lb_one ? size : ubound),
+				      gfc_index_zero_node);
+	}
+      else if (op == GFC_ISYM_LBOUND)
+	{
+	  cond = fold_build2_loc (input_location, GT_EXPR, logical_type_node,
+				  size, gfc_index_zero_node);
+	  if (as->type == AS_ASSUMED_SIZE)
 	    {
-	      tmp = fold_build2_loc (input_location, MINUS_EXPR,
-			       gfc_array_index_type, ubound, lbound);
-	      tmp = fold_build2_loc (input_location, PLUS_EXPR,
-			       gfc_array_index_type, tmp, gfc_index_one_node);
+	      cond1 = fold_build2_loc (input_location, EQ_EXPR,
+				       logical_type_node, bound,
+				       build_int_cst (TREE_TYPE (bound),
+						      arg->expr->rank - 1));
+	      cond = fold_build2_loc (input_location, TRUTH_OR_EXPR,
+				      logical_type_node, cond, cond1);
 	    }
-          else
-            tmp = ubound;
-
 	  se->expr = fold_build3_loc (input_location, COND_EXPR,
 				      gfc_array_index_type, cond,
-				      tmp, gfc_index_zero_node);
+				      lbound, gfc_index_one_node);
 	}
+      else if (op == GFC_ISYM_SHAPE)
+	se->expr = size;
       else
-	{
-	  if (as->type == AS_ASSUMED_SIZE)
-	    cond = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
-				    bound, build_int_cst (TREE_TYPE (bound),
-							  arg->expr->rank - 1));
-	  else
-	    cond = logical_false_node;
+	gcc_unreachable ();
 
-	  cond1 = fold_build2_loc (input_location, TRUTH_OR_EXPR,
-				   logical_type_node, cond3, cond4);
-	  cond = fold_build2_loc (input_location, TRUTH_OR_EXPR,
+      /* According to F2018 16.9.172, para 5, an assumed rank object,
+	 argument associated with and assumed size array, has the ubound
+	 of the final dimension set to -1 and UBOUND must return this.
+	 Similarly for the SHAPE intrinsic.  */
+      if (op != GFC_ISYM_LBOUND && assumed_rank_lb_one)
+	{
+	  tree minus_one = build_int_cst (gfc_array_index_type, -1);
+	  tree rank = fold_convert (gfc_array_index_type,
+				    gfc_conv_descriptor_rank (desc));
+	  rank = fold_build2_loc (input_location, PLUS_EXPR,
+				  gfc_array_index_type, rank, minus_one);
+
+	  /* Fix the expression to stop it from becoming even more
+	     complicated.  */
+	  se->expr = gfc_evaluate_now (se->expr, &se->pre);
+
+	  /* Descriptors for assumed-size arrays have ubound = -1
+	     in the last dimension.  */
+	  cond1 = fold_build2_loc (input_location, EQ_EXPR,
+				   logical_type_node, ubound, minus_one);
+	  cond = fold_build2_loc (input_location, EQ_EXPR,
+				  logical_type_node, bound, rank);
+	  cond = fold_build2_loc (input_location, TRUTH_AND_EXPR,
 				  logical_type_node, cond, cond1);
-
 	  se->expr = fold_build3_loc (input_location, COND_EXPR,
 				      gfc_array_index_type, cond,
-				      lbound, gfc_index_one_node);
+				      minus_one, se->expr);
 	}
     }
-  else
+  else   /* as is null; this is an old-fashioned 1-based array.  */
     {
-      if (upper)
+      if (op != GFC_ISYM_LBOUND)
         {
-	  size = fold_build2_loc (input_location, MINUS_EXPR,
-				  gfc_array_index_type, ubound, lbound);
-	  se->expr = fold_build2_loc (input_location, PLUS_EXPR,
-				      gfc_array_index_type, size,
-				  gfc_index_one_node);
 	  se->expr = fold_build2_loc (input_location, MAX_EXPR,
-				      gfc_array_index_type, se->expr,
+				      gfc_array_index_type, size,
 				      gfc_index_zero_node);
 	}
       else
 	se->expr = gfc_index_one_node;
     }
 
-  /* According to F2018 16.9.172, para 5, an assumed rank object, argument
-     associated with and assumed size array, has the ubound of the final
-     dimension set to -1 and UBOUND must return this.  */
-  if (upper && as && as->type == AS_ASSUMED_RANK)
-    {
-      tree minus_one = build_int_cst (gfc_array_index_type, -1);
-      tree rank = fold_convert (gfc_array_index_type,
-				gfc_conv_descriptor_rank (desc));
-      rank = fold_build2_loc (input_location, PLUS_EXPR,
-			      gfc_array_index_type, rank, minus_one);
-      /* Fix the expression to stop it from becoming even more complicated.  */
-      se->expr = gfc_evaluate_now (se->expr, &se->pre);
-      cond = fold_build2_loc (input_location, NE_EXPR,
-			     logical_type_node, bound, rank);
-      cond1 = fold_build2_loc (input_location, NE_EXPR,
-			       logical_type_node, ubound, minus_one);
-      cond = fold_build2_loc (input_location, TRUTH_OR_EXPR,
-			      logical_type_node, cond, cond1);
-      se->expr = fold_build3_loc (input_location, COND_EXPR,
-				  gfc_array_index_type, cond,
-				  se->expr, minus_one);
-    }
 
   type = gfc_typenode_for_spec (&expr->ts);
   se->expr = convert (type, se->expr);
@@ -6690,85 +6673,6 @@ gfc_conv_intrinsic_ibits (gfc_se * se, gfc_expr * expr)
   se->expr = fold_build2_loc (input_location, BIT_AND_EXPR, type, tmp, mask);
 }
 
-static void
-gfc_conv_intrinsic_shape (gfc_se *se, gfc_expr *expr)
-{
-  gfc_actual_arglist *s, *k;
-  gfc_expr *e;
-  gfc_array_spec *as;
-  gfc_ss *ss;
-  symbol_attribute attr;
-  tree result_desc = se->expr;
-
-  /* Remove the KIND argument, if present. */
-  s = expr->value.function.actual;
-  k = s->next;
-  e = k->expr;
-  gfc_free_expr (e);
-  k->expr = NULL;
-
-  gfc_conv_intrinsic_funcall (se, expr);
-
-  /* According to F2018 16.9.172, para 5, an assumed rank entity, argument
-     associated with an assumed size array, has the ubound of the final
-     dimension set to -1 and SHAPE must return this.  */
-
-  as = gfc_get_full_arrayspec_from_expr (s->expr);
-  if (!as || as->type != AS_ASSUMED_RANK)
-    return;
-  attr = gfc_expr_attr (s->expr);
-  ss = gfc_walk_expr (s->expr);
-  if (attr.pointer || attr.allocatable
-      || !ss || ss->info->type != GFC_SS_SECTION)
-    return;
-  if (se->expr)
-    result_desc = se->expr;
-  if (POINTER_TYPE_P (TREE_TYPE (result_desc)))
-    result_desc = build_fold_indirect_ref_loc (input_location, result_desc);
-  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (result_desc)))
-    {
-      tree rank, minus_one, cond, ubound, tmp;
-      stmtblock_t block;
-      gfc_se ase;
-
-      minus_one = build_int_cst (gfc_array_index_type, -1);
-
-      /* Recover the descriptor for the array.  */
-      gfc_init_se (&ase, NULL);
-      ase.descriptor_only = 1;
-      gfc_conv_expr_lhs (&ase, ss->info->expr);
-
-      /* Obtain rank-1 so that we can address both descriptors.  */
-      rank = gfc_conv_descriptor_rank (ase.expr);
-      rank = fold_convert (gfc_array_index_type, rank);
-      rank = fold_build2_loc (input_location, PLUS_EXPR,
-			      gfc_array_index_type,
-			      rank, minus_one);
-      rank = gfc_evaluate_now (rank, &se->pre);
-
-      /* The ubound for the final dimension will be tested for being -1.  */
-      ubound = gfc_conv_descriptor_ubound_get (ase.expr, rank);
-      ubound = gfc_evaluate_now (ubound, &se->pre);
-      cond = fold_build2_loc (input_location, EQ_EXPR,
-			     logical_type_node,
-			     ubound, minus_one);
-
-      /* Obtain the last element of the result from the library shape
-	 intrinsic and set it to -1 if that is the value of ubound.  */
-      tmp = gfc_conv_array_data (result_desc);
-      tmp = build_fold_indirect_ref_loc (input_location, tmp);
-      tmp = gfc_build_array_ref (tmp, rank, NULL, NULL);
-
-      gfc_init_block (&block);
-      gfc_add_modify (&block, tmp, build_int_cst (TREE_TYPE (tmp), -1));
-
-      cond = build3_v (COND_EXPR, cond,
-		       gfc_finish_block (&block),
-		       build_empty_stmt (input_location));
-      gfc_add_expr_to_block (&se->pre, cond);
-    }
-}
-
 static void
 gfc_conv_intrinsic_shift (gfc_se * se, gfc_expr * expr, bool right_shift,
 			  bool arithmetic)
@@ -10165,10 +10069,6 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
 	      gfc_conv_intrinsic_minmaxloc (se, expr, GT_EXPR);
 	      break;
 
-	    case GFC_ISYM_SHAPE:
-	      gfc_conv_intrinsic_shape (se, expr);
-	      break;
-
 	    default:
 	      gfc_conv_intrinsic_funcall (se, expr);
 	      break;
@@ -10562,7 +10462,7 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
       break;
 
     case GFC_ISYM_LBOUND:
-      gfc_conv_intrinsic_bound (se, expr, 0);
+      gfc_conv_intrinsic_bound (se, expr, GFC_ISYM_LBOUND);
       break;
 
     case GFC_ISYM_LCOBOUND:
@@ -10697,6 +10597,10 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
       gfc_conv_intrinsic_scale (se, expr);
       break;
 
+    case GFC_ISYM_SHAPE:
+      gfc_conv_intrinsic_bound (se, expr, GFC_ISYM_SHAPE);
+      break;
+
     case GFC_ISYM_SIGN:
       gfc_conv_intrinsic_sign (se, expr);
       break;
@@ -10743,7 +10647,7 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
       break;
 
     case GFC_ISYM_UBOUND:
-      gfc_conv_intrinsic_bound (se, expr, 1);
+      gfc_conv_intrinsic_bound (se, expr, GFC_ISYM_UBOUND);
       break;
 
     case GFC_ISYM_UCOBOUND:
@@ -11017,6 +10921,7 @@ gfc_add_intrinsic_ss_code (gfc_loopinfo * loop ATTRIBUTE_UNUSED, gfc_ss * ss)
     case GFC_ISYM_UCOBOUND:
     case GFC_ISYM_LCOBOUND:
     case GFC_ISYM_THIS_IMAGE:
+    case GFC_ISYM_SHAPE:
       break;
 
     default:
@@ -11025,8 +10930,8 @@ gfc_add_intrinsic_ss_code (gfc_loopinfo * loop ATTRIBUTE_UNUSED, gfc_ss * ss)
 }
 
 
-/* The LBOUND, LCOBOUND, UBOUND and UCOBOUND intrinsics with one parameter
-   are expanded into code inside the scalarization loop.  */
+/* The LBOUND, LCOBOUND, UBOUND, UCOBOUND, and SHAPE intrinsics with
+   one parameter are expanded into code inside the scalarization loop.  */
 
 static gfc_ss *
 gfc_walk_intrinsic_bound (gfc_ss * ss, gfc_expr * expr)
@@ -11035,7 +10940,8 @@ gfc_walk_intrinsic_bound (gfc_ss * ss, gfc_expr * expr)
     gfc_add_class_array_ref (expr->value.function.actual->expr);
 
   /* The two argument version returns a scalar.  */
-  if (expr->value.function.actual->next->expr)
+  if (expr->value.function.isym->id != GFC_ISYM_SHAPE
+      && expr->value.function.actual->next->expr)
     return ss;
 
   return gfc_get_array_ss (ss, expr, 1, GFC_SS_INTRINSIC);
@@ -11135,7 +11041,6 @@ gfc_is_intrinsic_libcall (gfc_expr * expr)
     case GFC_ISYM_PARITY:
     case GFC_ISYM_PRODUCT:
     case GFC_ISYM_SUM:
-    case GFC_ISYM_SHAPE:
     case GFC_ISYM_SPREAD:
     case GFC_ISYM_YN2:
       /* Ignore absent optional parameters.  */
@@ -11185,6 +11090,7 @@ gfc_walk_intrinsic_function (gfc_ss * ss, gfc_expr * expr,
     case GFC_ISYM_UBOUND:
     case GFC_ISYM_UCOBOUND:
     case GFC_ISYM_THIS_IMAGE:
+    case GFC_ISYM_SHAPE:
       return gfc_walk_intrinsic_bound (ss, expr);
 
     case GFC_ISYM_TRANSFER:
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index cf6bd8de954..735c4105008 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,16 @@
+2021-10-21  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backport from master:
+	2021-10-20  Sandra Loosemore  <sandra@codesourcery.com>
+
+	PR fortran/94070
+	* gfortran.dg/c-interop/shape-bindc.f90: New test.
+	* gfortran.dg/c-interop/shape-poly.f90: New test.
+	* gfortran.dg/c-interop/size-bindc.f90: New test.
+	* gfortran.dg/c-interop/size-poly.f90: New test.
+	* gfortran.dg/c-interop/ubound-bindc.f90: New test.
+	* gfortran.dg/c-interop/ubound-poly.f90: New test.
+
 2021-10-20  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/testsuite/gfortran.dg/c-interop/shape-bindc.f90 b/gcc/testsuite/gfortran.dg/c-interop/shape-bindc.f90
new file mode 100644
index 00000000000..d9e193a6c3c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c-interop/shape-bindc.f90
@@ -0,0 +1,77 @@
+! { dg-do run }
+!
+! TS 29113
+! 6.4.1  SHAPE
+!
+! The description of the intrinsic function SHAPE in ISO/IEC 1539-1:2010
+! is changed for an assumed-rank array that is associated with an
+! assumed-size array; an assumed-size array has no shape, but in this
+! case the result has a value equal to 
+! [ (SIZE (ARRAY, I, KIND), I=1,RANK (ARRAY)) ] 
+! with KIND omitted from SIZE if it was omitted from SHAPE.
+!
+! The idea here is that the main program passes some arrays to a test
+! subroutine with an assumed-size dummy, which in turn passes that to a
+! subroutine with an assumed-rank dummy.
+
+program test 
+
+  ! Define some arrays for testing.
+  integer, target :: x1(5)
+  integer :: y1(0:9)
+  integer, pointer :: p1(:)
+  integer, allocatable :: a1(:)
+  integer, target :: x3(2,3,4)
+  integer :: y3(0:1,-3:-1,4)
+  integer, pointer :: p3(:,:,:)
+  integer, allocatable :: a3(:,:,:)
+
+  ! Test the 1-dimensional arrays.
+  call test1 (x1)
+  call test1 (y1)
+  p1 => x1
+  call test1 (p1)
+  allocate (a1(5))
+  call test1 (a1)
+
+  ! Test the multi-dimensional arrays.
+  call test3 (x3, 1, 2, 1, 3)
+  call test3 (y3, 0, 1, -3, -1)
+  p3 => x3
+  call test3 (p3, 1, 2, 1, 3)
+  allocate (a3(2,3,4))
+  call test3 (a3, 1, 2, 1, 3)
+
+contains
+
+  subroutine testit (a) bind(c)
+    integer :: a(..)
+    
+    integer :: r
+    r = rank(a)
+
+    block
+      integer :: s(r)
+      s = shape(a)
+      do i = 1, r
+        if (s(i) .ne. size(a,i)) stop 101
+      end do
+    end block
+
+  end subroutine
+
+  subroutine test1 (a) bind(c)
+    integer :: a(*)
+
+    call testit (a)
+  end subroutine
+
+  subroutine test3 (a, l1, u1, l2, u2) bind(c)
+    implicit none
+    integer :: l1, u1, l2, u2
+    integer :: a(l1:u1, l2:u2, *)
+
+    call testit (a)
+  end subroutine
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/c-interop/shape-poly.f90 b/gcc/testsuite/gfortran.dg/c-interop/shape-poly.f90
new file mode 100644
index 00000000000..e17ca889fe9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c-interop/shape-poly.f90
@@ -0,0 +1,89 @@
+! { dg-do run }
+!
+! TS 29113
+! 6.4.1  SHAPE
+!
+! The description of the intrinsic function SHAPE in ISO/IEC 1539-1:2010
+! is changed for an assumed-rank array that is associated with an
+! assumed-size array; an assumed-size array has no shape, but in this
+! case the result has a value equal to 
+! [ (SIZE (ARRAY, I, KIND), I=1,RANK (ARRAY)) ] 
+! with KIND omitted from SIZE if it was omitted from SHAPE.
+!
+! The idea here is that the main program passes some arrays to a test
+! subroutine with an assumed-size dummy, which in turn passes that to a
+! subroutine with an assumed-rank dummy.
+!
+! This is the polymorphic version of shape.f90.
+
+module m
+  type :: t
+    integer :: id
+    real :: xyz(3)
+  end type
+end module
+
+program test 
+  use m
+
+  ! Define some arrays for testing.
+  type(t), target :: x1(5)
+  type(t) :: y1(0:9)
+  class(t), pointer :: p1(:)
+  class(t), allocatable :: a1(:)
+  type(t), target :: x3(2,3,4)
+  type(t) :: y3(0:1,-3:-1,4)
+  class(t), pointer :: p3(:,:,:)
+  type(t), allocatable :: a3(:,:,:)
+
+  ! Test the 1-dimensional arrays.
+  call test1 (x1)
+  call test1 (y1)
+  p1 => x1
+  call test1 (p1)
+  allocate (a1(5))
+  call test1 (a1)
+
+  ! Test the multi-dimensional arrays.
+  call test3 (x3, 1, 2, 1, 3)
+  call test3 (y3, 0, 1, -3, -1)
+  p3 => x3
+  call test3 (p3, 1, 2, 1, 3)
+  allocate (a3(2,3,4))
+  call test3 (a3, 1, 2, 1, 3)
+
+contains
+
+  subroutine testit (a)
+    use m
+    class(t) :: a(..)
+    
+    integer :: r
+    r = rank(a)
+
+    block
+      integer :: s(r)
+      s = shape(a)
+      do i = 1, r
+        if (s(i) .ne. size(a,i)) stop 101
+      end do
+    end block
+
+  end subroutine
+
+  subroutine test1 (a)
+    use m
+    class(t) :: a(*)
+
+    call testit (a)
+  end subroutine
+
+  subroutine test3 (a, l1, u1, l2, u2)
+    use m
+    integer :: l1, u1, l2, u2
+    class(t) :: a(l1:u1, l2:u2, *)
+
+    call testit (a)
+  end subroutine
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/c-interop/size-bindc.f90 b/gcc/testsuite/gfortran.dg/c-interop/size-bindc.f90
new file mode 100644
index 00000000000..132ca509087
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c-interop/size-bindc.f90
@@ -0,0 +1,106 @@
+! Reported as pr94070.
+! { dg-do run }
+!
+! TS 29113
+! 6.4.2 SIZE
+!
+! The description of the intrinsic function SIZE in ISO/IEC 1539-1:2010
+! is changed in the following cases:
+!
+! (1) for an assumed-rank object that is associated with an assumed-size
+! array, the result has the value −1 if DIM is present and equal to the
+! rank of ARRAY, and a negative value that is equal to 
+! PRODUCT ( [ (SIZE (ARRAY, I, KIND), I=1, RANK (ARRAY)) ] ) 
+! if DIM is not present;
+!
+! (2) for an assumed-rank object that is associated with a scalar, the
+! result has the value 1.
+!
+! The idea here is that the main program passes some arrays to a test
+! subroutine with an assumed-size dummy, which in turn passes that to a
+! subroutine with an assumed-rank dummy.
+
+program test 
+
+  ! Define some arrays for testing.
+  integer, target :: x1(5)
+  integer :: y1(0:9)
+  integer, pointer :: p1(:)
+  integer, allocatable :: a1(:)
+  integer, target :: x3(2,3,4)
+  integer :: y3(0:1,-3:-1,4)
+  integer, pointer :: p3(:,:,:)
+  integer, allocatable :: a3(:,:,:)
+  integer :: x
+
+  ! Test the 1-dimensional arrays.
+  call test1 (x1)
+  call test1 (y1)
+  p1 => x1
+  call test1 (p1)
+  allocate (a1(5))
+  call test1 (a1)
+
+  ! Test the multi-dimensional arrays.
+  call test3 (x3, 1, 2, 1, 3)
+  call test3 (y3, 0, 1, -3, -1)
+  p3 => x3
+  call test3 (p3, 1, 2, 1, 3)
+  allocate (a3(2,3,4))
+  call test3 (a3, 1, 2, 1, 3)
+
+  ! Test scalars.
+  call test0 (x)
+  call test0 (-1)
+  call test0 (x1(1))
+
+contains
+
+  subroutine testit (a, r, sizes) bind(c)
+    integer :: a(..)
+    integer :: r
+    integer :: sizes(r)
+    
+    integer :: totalsize, thissize
+    totalsize = 1
+
+    if (r .ne. rank(a))  stop 101
+
+    do i = 1, r
+      thissize = size (a, i)
+      print *, 'got size ', thissize, ' expected ', sizes(i)
+      if (thissize .ne. sizes(i)) stop 102
+      totalsize = totalsize * thissize
+    end do
+
+    if (size(a) .ne. totalsize) stop 103
+  end subroutine
+
+  subroutine test0 (a) bind(c)
+    integer :: a(..)
+
+    if (size (a) .ne. 1) stop 103
+  end subroutine
+
+  subroutine test1 (a) bind(c)
+    integer :: a(*)
+
+    integer :: sizes(1)
+    sizes(1) = -1
+    call testit (a, 1, sizes)
+  end subroutine
+
+  subroutine test3 (a, l1, u1, l2, u2) bind(c)
+    implicit none
+    integer :: l1, u1, l2, u2
+    integer :: a(l1:u1, l2:u2, *)
+
+    integer :: sizes(3)
+    sizes(1) = u1 - l1 + 1
+    sizes(2) = u2 - l2 + 1
+    sizes(3) = -1
+
+    call testit (a, 3, sizes)
+  end subroutine
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/c-interop/size-poly.f90 b/gcc/testsuite/gfortran.dg/c-interop/size-poly.f90
new file mode 100644
index 00000000000..2241ab840bf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c-interop/size-poly.f90
@@ -0,0 +1,118 @@
+! Reported as pr94070.
+! { dg-do run }
+!
+! TS 29113
+! 6.4.2 SIZE
+!
+! The description of the intrinsic function SIZE in ISO/IEC 1539-1:2010
+! is changed in the following cases:
+!
+! (1) for an assumed-rank object that is associated with an assumed-size
+! array, the result has the value −1 if DIM is present and equal to the
+! rank of ARRAY, and a negative value that is equal to 
+! PRODUCT ( [ (SIZE (ARRAY, I, KIND), I=1, RANK (ARRAY)) ] ) 
+! if DIM is not present;
+!
+! (2) for an assumed-rank object that is associated with a scalar, the
+! result has the value 1.
+!
+! The idea here is that the main program passes some arrays to a test
+! subroutine with an assumed-size dummy, which in turn passes that to a
+! subroutine with an assumed-rank dummy.
+!
+! This is the polymorphic version of size.f90.
+
+module m
+  type :: t
+    integer :: id
+    real :: xyz(3)
+  end type
+end module
+
+program test
+  use m
+
+  ! Define some arrays for testing.
+  type(t), target :: x1(5)
+  type(t) :: y1(0:9)
+  class(t), pointer :: p1(:)
+  class(t), allocatable :: a1(:)
+  type(t), target :: x3(2,3,4)
+  type(t) :: y3(0:1,-3:-1,4)
+  class(t), pointer :: p3(:,:,:)
+  type(t), allocatable :: a3(:,:,:)
+  type(t) :: x
+
+  ! Test the 1-dimensional arrays.
+  call test1 (x1)
+  call test1 (y1)
+  p1 => x1
+  call test1 (p1)
+  allocate (a1(5))
+  call test1 (a1)
+
+  ! Test the multi-dimensional arrays.
+  call test3 (x3, 1, 2, 1, 3)
+  call test3 (y3, 0, 1, -3, -1)
+  p3 => x3
+  call test3 (p3, 1, 2, 1, 3)
+  allocate (a3(2,3,4))
+  call test3 (a3, 1, 2, 1, 3)
+
+  ! Test scalars.
+  call test0 (x)
+  call test0 (x1(1))
+
+contains
+
+  subroutine testit (a, r, sizes)
+    use m
+    class(t) :: a(..)
+    integer :: r
+    integer :: sizes(r)
+    
+    integer :: totalsize, thissize
+    totalsize = 1
+
+    if (r .ne. rank(a))  stop 101
+
+    do i = 1, r
+      thissize = size (a, i)
+      print *, 'got size ', thissize, ' expected ', sizes(i)
+      if (thissize .ne. sizes(i)) stop 102
+      totalsize = totalsize * thissize
+    end do
+
+    if (size(a) .ne. totalsize) stop 103
+  end subroutine
+
+  subroutine test0 (a)
+    use m
+    class(t) :: a(..)
+
+    if (size (a) .ne. 1) stop 103
+  end subroutine
+
+  subroutine test1 (a)
+    use m
+    class(t) :: a(*)
+
+    integer :: sizes(1)
+    sizes(1) = -1
+    call testit (a, 1, sizes)
+  end subroutine
+
+  subroutine test3 (a, l1, u1, l2, u2)
+    use m
+    integer :: l1, u1, l2, u2
+    class(t) :: a(l1:u1, l2:u2, *)
+
+    integer :: sizes(3)
+    sizes(1) = u1 - l1 + 1
+    sizes(2) = u2 - l2 + 1
+    sizes(3) = -1
+
+    call testit (a, 3, sizes)
+  end subroutine
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/c-interop/ubound-bindc.f90 b/gcc/testsuite/gfortran.dg/c-interop/ubound-bindc.f90
new file mode 100644
index 00000000000..e771836d11a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c-interop/ubound-bindc.f90
@@ -0,0 +1,129 @@
+! { dg-do run }
+!
+! TS 29113
+! 6.4.3  UBOUND
+!
+! The description of the intrinsic function UBOUND in ISO/IEC
+! 1539-1:2010 is changed for an assumed-rank object that is associated
+! with an assumed-size array; the result of UBOUND (ARRAY, RANK(ARRAY),
+! KIND) has a value equal to LBOUND (ARRAY, RANK (ARRAY), KIND) −2 with
+! KIND omitted from LBOUND if it was omitted from UBOUND.
+!
+! NOTE 6.2  
+! If LBOUND or UBOUND is invoked for an assumed-rank object that is
+! associated with a scalar and DIM is absent, the result is a zero-sized
+! array. LBOUND or UBOUND cannot be invoked for an assumed-rank object
+! that is associated with a scalar if DIM is present because the rank of
+! a scalar is zero and DIM must be ≥ 1.
+!
+! The idea here is that the main program passes some arrays to a test
+! subroutine with an assumed-size dummy, which in turn passes that to a
+! subroutine with an assumed-rank dummy.
+
+program test 
+
+  ! Define some arrays for testing.
+  integer, target :: x1(5)
+  integer :: y1(0:9)
+  integer, pointer :: p1(:)
+  integer, allocatable :: a1(:)
+  integer, target :: x3(2,3,4)
+  integer :: y3(0:1,-3:-1,4)
+  integer, pointer :: p3(:,:,:)
+  integer, allocatable :: a3(:,:,:)
+  integer :: x
+
+  ! Test the 1-dimensional arrays.
+  call test1 (x1)
+  call testit2(x1, shape(x1))
+  call test1 (y1)
+  call testit2(y1, shape(y1))
+  p1 => x1
+  call testit2(p1, shape(p1))
+  call testit2p(p1, lbound(p1), shape(p1))
+  call test1 (p1)
+  p1(77:) => x1
+  call testit2p(p1, [77], shape(p1))
+  allocate (a1(5))
+  call testit2(a1, shape(a1))
+  call testit2a(a1, lbound(a1), shape(a1))
+  call test1 (a1)
+  deallocate(a1)
+  allocate (a1(-38:5))
+  call test1 (a1)
+  call testit2(a1, shape(a1))
+  call testit2a(a1, [-38], shape(a1))
+
+  ! Test the multi-dimensional arrays.
+  call test3 (x3, 1, 2, 1, 3)
+  call test3 (y3, 0, 1, -3, -1)
+  p3 => x3
+  call test3 (p3, 1, 2, 1, 3)
+  allocate (a3(2,3,4))
+  call test3 (a3, 1, 2, 1, 3)
+
+  ! Test some scalars.
+  call test0 (x)
+  call test0 (-1)
+  call test0 (x1(1))
+
+contains
+
+  subroutine testit (a) bind(c)
+    integer :: a(..)
+    integer :: r
+    r = rank(a)
+    if (any (lbound (a) .ne. 1)) stop 101
+    if (ubound (a, r) .ne. -1) stop 102
+  end subroutine
+
+  subroutine testit2(a, shape) bind(c)
+    integer :: a(..)
+    integer :: shape(:)
+    if (rank(a) /= size(shape)) stop 111
+    if (any (lbound(a) /= 1)) stop 112
+    if (any (ubound(a) /= shape)) stop 113
+  end subroutine
+
+  subroutine testit2a(a,lbound2,  shape2) bind(c)
+    integer, allocatable :: a(..)
+    integer :: lbound2(:), shape2(:)
+    if (rank(a) /= size(shape2)) stop 121
+    if (any (lbound(a) /= lbound2)) stop 122
+    if (any (ubound(a) /= lbound2 + shape2 - 1)) stop 123
+    if (any (shape(a) /= shape2)) stop 124
+    if (sum (shape(a)) /= size(a)) stop 125
+  end subroutine
+
+  subroutine testit2p(a, lbound2, shape2) bind(c)
+    integer, pointer :: a(..)
+    integer :: lbound2(:), shape2(:)
+    if (rank(a) /= size(shape2)) stop 131
+    if (any (lbound(a) /= lbound2)) stop 132
+    if (any (ubound(a) /= lbound2 + shape2 - 1)) stop 133
+    if (any (shape(a) /= shape2)) stop 134
+    if (sum (shape(a)) /= size(a)) stop 135
+  end subroutine 
+
+  subroutine test0 (a) bind(c)
+    integer :: a(..)
+    if (rank (a) .ne. 0) stop 141
+    if (size (lbound (a)) .ne. 0) stop 142
+    if (size (ubound (a)) .ne. 0) stop 143
+  end subroutine
+
+  subroutine test1 (a) bind(c)
+    integer :: a(*)
+
+    call testit (a)
+  end subroutine
+
+  subroutine test3 (a, l1, u1, l2, u2) bind(c)
+    implicit none
+    integer :: l1, u1, l2, u2
+    integer :: a(l1:u1, l2:u2, *)
+
+    call testit (a)
+  end subroutine
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/c-interop/ubound-poly.f90 b/gcc/testsuite/gfortran.dg/c-interop/ubound-poly.f90
new file mode 100644
index 00000000000..333a253fc18
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c-interop/ubound-poly.f90
@@ -0,0 +1,145 @@
+! { dg-do run }
+!
+! TS 29113
+! 6.4.3  UBOUND
+!
+! The description of the intrinsic function UBOUND in ISO/IEC
+! 1539-1:2010 is changed for an assumed-rank object that is associated
+! with an assumed-size array; the result of UBOUND (ARRAY, RANK(ARRAY),
+! KIND) has a value equal to LBOUND (ARRAY, RANK (ARRAY), KIND) −2 with
+! KIND omitted from LBOUND if it was omitted from UBOUND.
+!
+! NOTE 6.2  
+! If LBOUND or UBOUND is invoked for an assumed-rank object that is
+! associated with a scalar and DIM is absent, the result is a zero-sized
+! array. LBOUND or UBOUND cannot be invoked for an assumed-rank object
+! that is associated with a scalar if DIM is present because the rank of
+! a scalar is zero and DIM must be ≥ 1.
+!
+! The idea here is that the main program passes some arrays to a test
+! subroutine with an assumed-size dummy, which in turn passes that to a
+! subroutine with an assumed-rank dummy.
+!
+! This is like ubound.f90, but using polymorphic arrays instead of integer
+! arrays.
+
+module m
+  type :: t
+    integer :: id
+    real :: xyz(3)
+  end type
+end module
+
+program test
+  use m
+
+  ! Define some arrays for testing.
+  type(t), target :: x1(5)
+  type(t) :: y1(0:9)
+  class(t), pointer :: p1(:)
+  class(t), allocatable :: a1(:)
+  type(t), target :: x3(2,3,4)
+  type(t) :: y3(0:1,-3:-1,4)
+  class(t), pointer :: p3(:,:,:)
+  type(t), allocatable :: a3(:,:,:)
+  type(t) :: x
+
+  ! Test the 1-dimensional arrays.
+  call test1 (x1)
+  call testit2(x1, shape(x1))
+  call test1 (y1)
+  call testit2(y1, shape(y1))
+  p1 => x1
+  call testit2(p1, shape(p1))
+  call testit2p(p1, lbound(p1), shape(p1))
+  call test1 (p1)
+  p1(77:) => x1
+  call testit2p(p1, [77], shape(p1))
+  allocate (a1(5))
+  call testit2(a1, shape(a1))
+  call testit2a(a1, lbound(a1), shape(a1))
+  call test1 (a1)
+  deallocate(a1)
+  allocate (a1(-38:5))
+  call test1 (a1)
+  call testit2(a1, shape(a1))
+  call testit2a(a1, [-38], shape(a1))
+
+  ! Test the multi-dimensional arrays.
+  call test3 (x3, 1, 2, 1, 3)
+  call test3 (y3, 0, 1, -3, -1)
+  p3 => x3
+  call test3 (p3, 1, 2, 1, 3)
+  allocate (a3(2,3,4))
+  call test3 (a3, 1, 2, 1, 3)
+
+  ! Test some scalars.
+  call test0 (x)
+  call test0 (x1(1))
+
+contains
+
+  subroutine testit (a)
+    use m
+    class(t) :: a(..)
+    integer :: r
+    r = rank(a)
+    if (any (lbound (a) .ne. 1)) stop 101
+    if (ubound (a, r) .ne. -1) stop 102
+  end subroutine
+
+  subroutine testit2(a, shape)
+    use m
+    class(t) :: a(..)
+    integer :: shape(:)
+    if (rank(a) /= size(shape)) stop 111
+    if (any (lbound(a) /= 1)) stop 112
+    if (any (ubound(a) /= shape)) stop 113
+  end subroutine
+
+  subroutine testit2a(a,lbound2,  shape2)
+    use m
+    class(t), allocatable :: a(..)
+    integer :: lbound2(:), shape2(:)
+    if (rank(a) /= size(shape2)) stop 121
+    if (any (lbound(a) /= lbound2)) stop 122
+    if (any (ubound(a) /= lbound2 + shape2 - 1)) stop 123
+    if (any (shape(a) /= shape2)) stop 124
+    if (sum (shape(a)) /= size(a)) stop 125
+  end subroutine
+
+  subroutine testit2p(a, lbound2, shape2)
+    use m
+    class(t), pointer :: a(..)
+    integer :: lbound2(:), shape2(:)
+    if (rank(a) /= size(shape2)) stop 131
+    if (any (lbound(a) /= lbound2)) stop 132
+    if (any (ubound(a) /= lbound2 + shape2 - 1)) stop 133
+    if (any (shape(a) /= shape2)) stop 134
+    if (sum (shape(a)) /= size(a)) stop 135
+  end subroutine 
+
+  subroutine test0 (a)
+    use m
+    class(t) :: a(..)
+    if (rank (a) .ne. 0) stop 141
+    if (size (lbound (a)) .ne. 0) stop 142
+    if (size (ubound (a)) .ne. 0) stop 143
+  end subroutine
+
+  subroutine test1 (a)
+    use m
+    class(t) :: a(*)
+
+    call testit (a)
+  end subroutine
+
+  subroutine test3 (a, l1, u1, l2, u2)
+    use m
+    integer :: l1, u1, l2, u2
+    class(t) :: a(l1:u1, l2:u2, *)
+
+    call testit (a)
+  end subroutine
+
+end program


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-10-21  7:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-21  7:07 [gcc/devel/omp/gcc-11] Fortran: Fixes and additional tests for shape/ubound/size [PR94070] Tobias Burnus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).