/* If handling a metadirective variant, treat 'omp end metadirective'
as the expected end statement for the current construct. */
- if (st == ST_OMP_END_METADIRECTIVE
- && gfc_state_stack->state == COMP_OMP_BEGIN_METADIRECTIVE)
- st = omp_end_st;
+ if (gfc_state_stack->state == COMP_OMP_BEGIN_METADIRECTIVE)
+ {
+ if (st == ST_OMP_END_METADIRECTIVE)
+ st = omp_end_st;
+ else
+ {
+ /* We have found some extra statements between the loop
+ and the "end metadirective" which is required in a
+ "begin metadirective" construct, or perhaps the
+ "end metadirective" is missing entirely. */
+ gfc_error_now ("Expected OMP END METADIRECTIVE at %C");
+ return st;
+ }
+ }
if (st == omp_end_st)
{
accept_statement (st);
st = next_statement ();
}
+ else if (omp_end_st == ST_OMP_END_METADIRECTIVE)
+ {
+ /* We have found some extra statements between the END BLOCK
+ and the "end metadirective" which is required in a
+ "begin metadirective" construct, or perhaps the
+ "end metadirective" is missing entirely. */
+ gfc_error_now ("Expected OMP END METADIRECTIVE at %C");
+ }
return st;
}
else if (st != omp_end_st || block_construct)
gfc_omp_variant *variant
= new_st.ext.omp_variants;
locus body_locus = gfc_current_locus;
+ bool saw_error = false;
accept_statement (omp_st);
gfc_statement next_st = ST_NONE;
+ locus next_loc;
while (variant)
{
reject_statement ();
st = next_statement ();
}
+
finish:
+ /* Sanity-check that each variant finishes parsing at the same place. */
+ if (next_st == ST_NONE)
+ {
+ next_st = st;
+ next_loc = gfc_current_locus;
+ }
+ else if (st != next_st
+ || next_loc.nextc != gfc_current_locus.nextc
+ || next_loc.u.lb != gfc_current_locus.u.lb)
+ {
+ saw_error = true;
+ next_st = st;
+ next_loc = gfc_current_locus;
+ }
+
gfc_in_omp_metadirective_body = old_in_metadirective_body;
if (gfc_state_stack->head)
if (variant->next)
gfc_clear_new_st ();
- /* Sanity-check that each variant finishes parsing at the same place. */
- if (next_st == ST_NONE)
- next_st = st;
- else
- gcc_assert (st == next_st);
-
variant = variant->next;
}
+ if (saw_error)
+ {
+ if (omp_st == ST_OMP_METADIRECTIVE)
+ gfc_error_now ("Variants in a metadirective at %L have "
+ "different associations; "
+ "consider using a BLOCK construct "
+ "or BEGIN/END METADIRECTIVE", &body_locus);
+ else
+ gfc_error_now ("Variants in a metadirective at %L have "
+ "different associations; "
+ "consider using a BLOCK construct", &body_locus);
+ }
+
return next_st;
}
! { dg-do compile }
-! { dg-ice "Statements following a block in a metadirective" }
! PR fortran/107067
program metadirectives
implicit none
logical :: UseDevice
+ integer :: n, v
!$OMP begin metadirective &
!$OMP when ( user = { condition ( UseDevice ) } &
!$OMP : nothing ) &
- !$OMP default ( parallel )
+ !$OMP default ( parallel ) ! { dg-error "Variants in a metadirective at .1. have different associations" }
block
call foo()
end block
- call bar() ! FIXME/XFAIL ICE in parse_omp_metadirective_body()
- !$omp end metadirective
+ call bar() ! { dg-error "Expected OMP END METADIRECTIVE" }
+ !$omp end metadirective ! { dg-error "Unexpected ..OMP END METADIRECTIVE statement" }
+ ! It's a quirk of the implementation that gfortran thinks the metadirective
+ ! ends where the *last* variant ends. If we reverse the order of the
+ ! variants from the previous case, the "unexpected OMP END METADIRECTIVE"
+ ! error disappears because the "nothing" variant eats it where the
+ ! "parallel" directive doesn't.
+
+ !$OMP begin metadirective &
+ !$OMP when ( user = { condition ( UseDevice ) } &
+ !$OMP : parallel ) &
+ !$OMP default ( nothing ) ! { dg-error "Variants in a metadirective at .1. have different associations" }
+ block
+ call foo()
+ end block
+ call bar() ! { dg-error "Expected OMP END METADIRECTIVE" }
+ !$omp end metadirective
!$OMP begin metadirective &
!$OMP when ( user = { condition ( UseDevice ) } &
!$OMP : nothing ) &
- !$OMP default ( parallel )
+ !$OMP default ( parallel ) ! { dg-error "Variants in a metadirective at .1. have different associations" }
block
call bar()
end block
- block ! FIXME/XFAIL ICE in parse_omp_metadirective_body()
+ block ! { dg-error "Expected OMP END METADIRECTIVE" }
call foo()
end block
+ !$omp end metadirective ! { dg-error "Unexpected ..OMP END METADIRECTIVE statement" }
+
+ ! This one depends on the locus comparison and not just the statement
+ ! code comparison to diagnose the "different associations" error, since
+ ! there are two call statements involved.
+ !$OMP begin metadirective &
+ !$OMP when ( user = { condition ( UseDevice ) } &
+ !$OMP : nothing ) &
+ !$OMP default ( parallel ) ! { dg-error "Variants in a metadirective at .1. have different associations" }
+ block
+ call foo()
+ end block
+ call bar() ! { dg-error "Expected OMP END METADIRECTIVE" }
+ !$omp end metadirective ! { dg-error "Unexpected ..OMP END METADIRECTIVE statement" }
+ call baz()
+
+ ! The "nothing" directive in a non-begin/end metadirective only applies to a
+ ! a single statement or block, while "atomic capture" permits multiple
+ ! assignment statements.
+ !$OMP metadirective &
+ !$OMP when ( user = { condition ( UseDevice ) } &
+ !$OMP : nothing ) &
+ !$OMP default (atomic capture) ! { dg-error "Variants in a metadirective at .1. have different associations" }
+ n = n + 1; v = n
+
+ ! Reverse order of the above.
+ !$OMP metadirective &
+ !$OMP when ( user = { condition ( UseDevice ) } &
+ !$OMP : atomic capture ) &
+ !$OMP default ( nothing ) ! { dg-error "Variants in a metadirective at .1. have different associations" }
+ n = n + 1; v = n
+
+ ! This one is correct because both variants are properly terminated
+ ! by the "end metadirective".
+ !$OMP begin metadirective &
+ !$OMP when ( user = { condition ( UseDevice ) } &
+ !$OMP : nothing ) &
+ !$OMP default (atomic capture)
+ n = n + 1; v = n
!$omp end metadirective
+
end program