As permitted by OpenMP 6, accept an 'omp nothing' directive as intervening code.
Also handle the special case where a metadirective can be resolved at parse time
to 'omp nothing'.
This fixes a build issue that affects 10 out 12 SPECaccel benchmarks.

        PR c/120180

gcc/c/ChangeLog:

        * c-parser.cc (c_parser_pragma): Do not emit an error for 'omp nothing'
        and metadirectives as intervening code.
        (c_parser_omp_metadirective): Return early if only one selector matches
        and it resolves to 'omp nothing'.

gcc/cp/ChangeLog:

        * parser.cc (cp_parser_omp_metadirective): Return early if only one
        selector matches and it resolves to 'omp nothing'.
        (cp_parser_pragma): Do not emit an error for 'omp nothing' and
        metadirectives as intervening code.

gcc/fortran/ChangeLog:

        * openmp.cc (match_omp_metadirective): Skip variants with a
        user-condition selector that statically resolves to false.
        * parse.cc (parse_omp_metadirective_body): Return early if there is only
        one variant and it resolves to 'omp nothing'.

gcc/testsuite/ChangeLog:

        * c-c++-common/gomp/imperfect1.c: Adjust dg-error.
        * c-c++-common/gomp/imperfect4.c: Likewise.
        * c-c++-common/gomp/pr120180.c: Move to...
        * c-c++-common/gomp/pr120180-1.c: ...here. Remove dg-error.
        * g++.dg/gomp/attrs-imperfect1.C: Adjust dg-error.
        * g++.dg/gomp/attrs-imperfect4.C: Likewise.
        * c-c++-common/gomp/pr120180-2.c: New test.
        * g++.dg/gomp/pr120180-1.C: New test.
        * g++.dg/gomp/pr120180-2.C: New test.
        * gfortran.dg/gomp/pr120180-1.f90: New test.
        * gfortran.dg/gomp/pr120180-2.f90: New test.
---
 gcc/c/c-parser.cc                             | 22 ++++++++++---
 gcc/cp/parser.cc                              | 21 ++++++++++---
 gcc/fortran/openmp.cc                         | 10 ++++++
 gcc/fortran/parse.cc                          | 11 ++++++-
 gcc/testsuite/c-c++-common/gomp/imperfect1.c  |  2 +-
 gcc/testsuite/c-c++-common/gomp/imperfect4.c  |  2 +-
 .../gomp/{pr120180.c => pr120180-1.c}         |  6 ++--
 gcc/testsuite/c-c++-common/gomp/pr120180-2.c  | 19 ++++++++++++
 gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C  |  2 +-
 gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C  |  2 +-
 gcc/testsuite/g++.dg/gomp/pr120180-1.C        | 26 ++++++++++++++++
 gcc/testsuite/g++.dg/gomp/pr120180-2.C        | 19 ++++++++++++
 gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90 | 31 +++++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90 | 31 +++++++++++++++++++
 14 files changed, 187 insertions(+), 17 deletions(-)
 rename gcc/testsuite/c-c++-common/gomp/{pr120180.c => pr120180-1.c} (79%)
 create mode 100644 gcc/testsuite/c-c++-common/gomp/pr120180-2.c
 create mode 100644 gcc/testsuite/g++.dg/gomp/pr120180-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/pr120180-2.C
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 7c2452644bd..7b2990062aa 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -15761,11 +15761,12 @@ c_parser_pragma (c_parser *parser, enum 
pragma_context context, bool *if_p,
   gcc_assert (id != PRAGMA_NONE);
   if (parser->omp_for_parse_state
       && parser->omp_for_parse_state->in_intervening_code
-      && id >= PRAGMA_OMP__START_
-      && id <= PRAGMA_OMP__LAST_)
+      && id >= PRAGMA_OMP__START_ && id <= PRAGMA_OMP__LAST_
+      && id != PRAGMA_OMP_METADIRECTIVE && id != PRAGMA_OMP_NOTHING)
     {
-      error_at (input_location,
-               "intervening code must not contain OpenMP directives");
+      error_at (
+       input_location,
+       "intervening code must not contain executable OpenMP directives");
       parser->omp_for_parse_state->fail = true;
       c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
       return false;
@@ -29837,6 +29838,17 @@ c_parser_omp_metadirective (c_parser *parser, bool 
*if_p)
     }
   c_parser_skip_to_pragma_eol (parser);
 
+  /* If only one selector matches and it evaluates to 'omp nothing', no need to
+   * proceed.  */
+  if (ctxs.length () == 1)
+    {
+      tree ctx = ctxs[0];
+      if (ctx == NULL_TREE
+         || (omp_context_selector_matches (ctx, NULL_TREE, false) == 1
+             && directive_tokens[0].pragma_kind == PRAGMA_OMP_NOTHING))
+       return;
+    }
+
   if (!default_seen)
     {
       /* Add a default clause that evaluates to 'omp nothing'.  */
@@ -29917,7 +29929,7 @@ c_parser_omp_metadirective (c_parser *parser, bool 
*if_p)
          if (standalone_body == NULL_TREE)
            {
              standalone_body = push_stmt_list ();
-             c_parser_statement (parser, if_p);
+             c_parser_statement (parser, if_p); // TODO skip this
              standalone_body = pop_stmt_list (standalone_body);
            }
          else
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 362cddbaf69..1e1fe65dce8 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -52609,6 +52609,18 @@ cp_parser_omp_metadirective (cp_parser *parser, 
cp_token *pragma_tok,
     }
   cp_parser_skip_to_pragma_eol (parser, pragma_tok);
 
+  /* If only one selector matches and it evaluates to 'omp nothing', no need to
+   * proceed.  */
+  if (ctxs.length () == 1)
+    {
+      tree ctx = ctxs[0];
+      if (ctx == NULL_TREE
+         || (omp_context_selector_matches (ctx, NULL_TREE, false) == 1
+             && cp_parser_pragma_kind (&directive_tokens[0])
+                  == PRAGMA_OMP_NOTHING))
+       return;
+    }
+
   if (!default_seen)
     {
       /* Add a default clause that evaluates to 'omp nothing'.  */
@@ -54638,11 +54650,12 @@ cp_parser_pragma (cp_parser *parser, enum 
pragma_context context, bool *if_p)
   id = cp_parser_pragma_kind (pragma_tok);
   if (parser->omp_for_parse_state
       && parser->omp_for_parse_state->in_intervening_code
-      && id >= PRAGMA_OMP__START_
-      && id <= PRAGMA_OMP__LAST_)
+      && id >= PRAGMA_OMP__START_ && id <= PRAGMA_OMP__LAST_
+      && id != PRAGMA_OMP_METADIRECTIVE && id != PRAGMA_OMP_NOTHING)
     {
-      error_at (pragma_tok->location,
-               "intervening code must not contain OpenMP directives");
+      error_at (
+       pragma_tok->location,
+       "intervening code must not contain executable OpenMP directives");
       parser->omp_for_parse_state->fail = true;
       cp_parser_skip_to_pragma_eol (parser, pragma_tok);
       return false;
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 9e282c7b9f1..cb6ff2262cd 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -7089,6 +7089,16 @@ match_omp_metadirective (bool begin_p)
          return MATCH_ERROR;
        }
 
+      /* Don't record the variant if the selector is a false user condition.  
*/
+      if (selectors != NULL && selectors->code == OMP_TRAIT_SET_USER
+         && selectors->trait_selectors->code == OMP_TRAIT_USER_CONDITION
+         && selectors->trait_selectors->properties->property_kind
+              == OMP_TRAIT_PROPERTY_BOOL_EXPR
+         && selectors->trait_selectors->properties->expr->expr_type
+              == EXPR_CONSTANT
+         && selectors->trait_selectors->properties->expr->value.logical == 0)
+       continue;
+
       if (default_p)
        default_seen = true;
 
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index b29f6900841..e16030f0ec4 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -6518,7 +6518,16 @@ parse_omp_metadirective_body (gfc_statement omp_st)
   locus body_locus = gfc_current_locus;
   bool saw_error = false;
 
-  accept_statement (omp_st);
+  /* If there is only one variant and it evaluates to 'omp nothing', no need to
+  proceed.  */
+  if (variant->selectors == NULL && variant->stmt == ST_NONE
+      && variant->next == NULL)
+    {
+      reject_statement ();
+      return next_statement ();
+    }
+  else
+    accept_statement (omp_st);
 
   gfc_statement next_st = ST_NONE;
   locus next_loc;
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect1.c 
b/gcc/testsuite/c-c++-common/gomp/imperfect1.c
index 705626ad169..bef783bb907 100644
--- a/gcc/testsuite/c-c++-common/gomp/imperfect1.c
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect1.c
@@ -15,7 +15,7 @@ void s1 (int a1, int a2, int a3)
       f1 (0, i);
       for (j = 0; j < a2; j++)
        {
-#pragma omp barrier    /* { dg-error "intervening code must not contain OpenMP 
directives" } */
+#pragma omp barrier    /* { dg-error "intervening code must not contain 
executable OpenMP directives" } */
          f1 (1, j);
          if (i == 2)
            continue;   /* { dg-error "invalid exit" } */
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect4.c 
b/gcc/testsuite/c-c++-common/gomp/imperfect4.c
index 1a0c07cd48e..30d1cc66235 100644
--- a/gcc/testsuite/c-c++-common/gomp/imperfect4.c
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect4.c
@@ -21,7 +21,7 @@ void s1 (int a1, int a2, int a3)
              /* According to the grammar, this is intervening code; we
                 don't know that we are also missing a nested for loop
                 until we have parsed this whole compound expression.  */
-#pragma omp barrier    /* { dg-error "intervening code must not contain OpenMP 
directives" } */
+#pragma omp barrier    /* { dg-error "intervening code must not contain 
executable OpenMP directives" } */
              f1 (2, k);
              f2 (2, k);
            }
diff --git a/gcc/testsuite/c-c++-common/gomp/pr120180.c 
b/gcc/testsuite/c-c++-common/gomp/pr120180-1.c
similarity index 79%
rename from gcc/testsuite/c-c++-common/gomp/pr120180.c
rename to gcc/testsuite/c-c++-common/gomp/pr120180-1.c
index cb5a0d5a819..52b5082b4e7 100644
--- a/gcc/testsuite/c-c++-common/gomp/pr120180.c
+++ b/gcc/testsuite/c-c++-common/gomp/pr120180-1.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 
-/* This test used to ICE after erroring on the metadirective in the
-   loop nest.  */
+/* This test case checks that the inner metadirective is accepted as 
intervening
+   code since it resolves to 'omp nothing'.  */
 
 int main()
 {
@@ -14,7 +14,7 @@ int main()
                             when(user={condition(1)}: target teams loop 
collapse(2) map(qq[:0]) private(i))
   for(k=0; k<blksize; k++)
     {
-#pragma omp metadirective when(user={condition(0)}: simd) default() // { 
dg-error "intervening code must not contain OpenMP directives" }
+#pragma omp metadirective when(user={condition(0)}: simd) default()
       for (i=0; i<nq; i++)
         qq[k*nq + i] = 0.0;
     }
diff --git a/gcc/testsuite/c-c++-common/gomp/pr120180-2.c 
b/gcc/testsuite/c-c++-common/gomp/pr120180-2.c
new file mode 100644
index 00000000000..6c52e6c3dcb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/pr120180-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+
+/* This test case checks that a non-executable OpenMP directive is accepted 
+   as intervening code.  */
+
+int main()
+{
+  int blksize = 15000;
+  double *qq;
+  int i, k, nq;
+#pragma omp target parallel for collapse(2) map(qq[:0]) private(i)
+  for(k=0; k<blksize; k++)
+    { 
+      #pragma omp nothing
+      for (i=0; i<nq; i++)
+      qq[k*nq + i] = 0.0;
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C 
b/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
index cf293b5081c..b43139c8968 100644
--- a/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
+++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
@@ -15,7 +15,7 @@ void s1 (int a1, int a2, int a3)
       f1 (0, i);
       for (j = 0; j < a2; j++)
        {
-         [[ omp :: directive (barrier) ]] ;    /* { dg-error "intervening code 
must not contain OpenMP directives" } */
+         [[ omp :: directive (barrier) ]] ;    /* { dg-error "intervening code 
must not contain executable OpenMP directives" } */
          f1 (1, j);
          if (i == 2)
            continue;   /* { dg-error "invalid exit" } */
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C 
b/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
index 16636ab3eb6..94b4db856a9 100644
--- a/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
+++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
@@ -21,7 +21,7 @@ void s1 (int a1, int a2, int a3)
              /* According to the grammar, this is intervening code; we
                 don't know that we are also missing a nested for loop
                 until we have parsed this whole compound expression.  */
-             [[ omp :: directive (barrier) ]] ;        /* { dg-error 
"intervening code must not contain OpenMP directives" } */
+             [[ omp :: directive (barrier) ]] ;        /* { dg-error 
"intervening code must not contain executable OpenMP directives" } */
              f1 (2, k);
              f2 (2, k);
            }
diff --git a/gcc/testsuite/g++.dg/gomp/pr120180-1.C 
b/gcc/testsuite/g++.dg/gomp/pr120180-1.C
new file mode 100644
index 00000000000..819b3ee9045
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr120180-1.C
@@ -0,0 +1,26 @@
+// { dg-do compile }
+// { dg-additional-options "-std=c++11" }
+
+// This test case checks that the inner metadirective is accepted as 
intervening
+// code since it resolves to 'omp nothing'.
+
+int main()
+{
+  constexpr int use_teams = 1;
+  constexpr int use_simd = 0;
+  
+  int blksize = 15000;
+  double *qq;
+  int i, k, nq;
+
+  #pragma omp metadirective when(user={condition(use_teams)}: teams distribute 
parallel for collapse(2)) \
+                            otherwise(parallel for collapse(1))
+  for(k=0; k<blksize; k++)
+    {
+      #pragma omp metadirective when(user={condition(use_simd)}: simd) \
+                                otherwise(nothing)
+      for (i=0; i<nq; i++)
+        qq[k*nq + i] = 0.0;
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/pr120180-2.C 
b/gcc/testsuite/g++.dg/gomp/pr120180-2.C
new file mode 100644
index 00000000000..2a74ad6b94a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr120180-2.C
@@ -0,0 +1,19 @@
+// { dg-do compile }
+
+// This test case checks that a non-executable OpenMP directive is accepted 
+// as intervening code.
+
+int main()
+{
+  int blksize = 15000;
+  double *qq;
+  int i, k, nq;
+#pragma omp target parallel for collapse(2) map(qq[:0]) private(i)
+  for(k=0; k<blksize; k++)
+    { 
+      #pragma omp nothing
+      for (i=0; i<nq; i++)
+      qq[k*nq + i] = 0.0;
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90 
b/gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90
new file mode 100644
index 00000000000..a6dd68d3d36
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+
+! This test case checks that the inner metadirective is accepted as intervening
+! code since it resolves to 'omp nothing'.
+
+SUBROUTINE test(x_min, x_max, y_min, y_max, xarea, vol_flux_x)
+
+  IMPLICIT NONE
+
+  INTEGER, INTENT(IN) :: x_min, x_max, y_min, y_max
+
+  REAL(KIND=8), DIMENSION(x_min:x_max,y_min:y_max) :: xarea
+  REAL(KIND=8), DIMENSION(x_min:x_max,y_min:y_max) :: vol_flux_x
+
+  INTEGER :: j,k
+
+!$omp metadirective                                                          &
+!$omp  when(user={condition(.false.)}:                              &
+!$omp      target teams distribute parallel do simd collapse(2))             &
+!$omp  when(user={condition(.false.)}:                          &
+!$omp      target teams distribute parallel do)                              &
+!$omp  default(                                                              &
+!$omp      target teams loop collapse(2))
+  DO k=y_min,y_max
+!$omp metadirective when(user={condition(.false.)}: simd)
+    DO j=x_min,x_max
+      vol_flux_x(j,k)=0.25_8*xarea(j,k)
+    ENDDO
+  ENDDO
+
+END SUBROUTINE test
diff --git a/gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90 
b/gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90
new file mode 100644
index 00000000000..9f3389b4987
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+
+! This test case checks that a non-executable OpenMP directive is accepted 
+! as intervening code.
+
+SUBROUTINE test(x_min, x_max, y_min, y_max, xarea, vol_flux_x)
+
+  IMPLICIT NONE
+
+  INTEGER, INTENT(IN) :: x_min, x_max, y_min, y_max
+
+  REAL(KIND=8), DIMENSION(x_min:x_max,y_min:y_max) :: xarea
+  REAL(KIND=8), DIMENSION(x_min:x_max,y_min:y_max) :: vol_flux_x
+
+  INTEGER :: j,k
+
+!$omp metadirective                                                          &
+!$omp  when(user={condition(.false.)}:                              &
+!$omp      target teams distribute parallel do simd collapse(2))             &
+!$omp  when(user={condition(.false.)}:                          &
+!$omp      target teams distribute parallel do)                              &
+!$omp  default(                                                              &
+!$omp      target teams loop collapse(2))
+  DO k=y_min,y_max
+!$omp nothing
+    DO j=x_min,x_max
+      vol_flux_x(j,k)=0.25_8*xarea(j,k)
+    ENDDO
+  ENDDO
+
+END SUBROUTINE test
-- 
2.51.0

Reply via email to