nested forall constructs. This is used to allocate the needed memory
in gfc_resolve_forall. */
+static int gfc_count_forall_iterators (gfc_code *code);
+
+/* Return the deepest nested FORALL/DO CONCURRENT iterator count in CODE's
+ next-chain, descending into block arms such as IF/ELSE branches. */
+
+static int
+gfc_max_forall_iterators_in_chain (gfc_code *code)
+{
+ int max_iters = 0;
+
+ for (gfc_code *c = code; c; c = c->next)
+ {
+ int sub_iters = 0;
+
+ if (c->op == EXEC_FORALL || c->op == EXEC_DO_CONCURRENT)
+ sub_iters = gfc_count_forall_iterators (c);
+ else if (c->block)
+ for (gfc_code *b = c->block; b; b = b->block)
+ {
+ int arm_iters = gfc_max_forall_iterators_in_chain (b->next);
+ if (arm_iters > sub_iters)
+ sub_iters = arm_iters;
+ }
+
+ if (sub_iters > max_iters)
+ max_iters = sub_iters;
+ }
+
+ return max_iters;
+}
+
+
static int
gfc_count_forall_iterators (gfc_code *code)
{
- int max_iters, sub_iters, current_iters;
+ int current_iters = 0;
gfc_forall_iterator *fa;
gcc_assert (code->op == EXEC_FORALL || code->op == EXEC_DO_CONCURRENT);
- max_iters = 0;
- current_iters = 0;
for (fa = code->ext.concur.forall_iterator; fa; fa = fa->next)
- current_iters ++;
-
- code = code->block->next;
-
- while (code)
- {
- if (code->op == EXEC_FORALL || code->op == EXEC_DO_CONCURRENT)
- {
- sub_iters = gfc_count_forall_iterators (code);
- if (sub_iters > max_iters)
- max_iters = sub_iters;
- }
- code = code->next;
- }
+ current_iters++;
- return current_iters + max_iters;
+ return current_iters + gfc_max_forall_iterators_in_chain (code->block->next);
}
--- /dev/null
+! { dg-do compile }
+! PR fortran/123943
+!
+! Nested DO CONCURRENT in block constructs must not ICE in gfc_resolve_forall.
+! Reduced testcase by Harald Anlauf <anlauf@gcc.gnu.org>
+
+subroutine nested_in_if
+ implicit none
+ integer :: k, l
+
+ do concurrent (k = 1:5)
+ if (k == 3) then
+ do concurrent (l = 1:4)
+ end do
+ end if
+ end do
+end subroutine nested_in_if
+
+
+subroutine nested_in_if_else
+ implicit none
+ integer :: k, l
+
+ do concurrent (k = 1:5)
+ if (k == 3) then
+ do concurrent (l = 1:4)
+ end do
+ else
+ do concurrent (l = 1:2)
+ end do
+ end if
+ end do
+end subroutine nested_in_if_else
+
+
+subroutine nested_in_select_case
+ implicit none
+ integer :: k, l
+
+ do concurrent (k = 1:5)
+ select case (k)
+ case (3)
+ do concurrent (l = 1:4)
+ end do
+ case default
+ end select
+ end do
+end subroutine nested_in_select_case