Fortran: Add OpenMP's error directive
authorTobias Burnus <tobias@codesourcery.com>
Fri, 20 Aug 2021 10:12:51 +0000 (12:12 +0200)
committerTobias Burnus <tobias@codesourcery.com>
Fri, 20 Aug 2021 10:12:51 +0000 (12:12 +0200)
Fortran part to the C/C++ implementation of
commit r12-3040-g0d973c0a0d90a0a302e7eda1a4d9709be3c5b102

gcc/fortran/ChangeLog:

* dump-parse-tree.c (show_omp_clauses): Handle 'at', 'severity'
and 'message' clauses.
(show_omp_node, show_code_node): Handle EXEC_OMP_ERROR.
* gfortran.h (gfc_statement): Add ST_OMP_ERROR.
(gfc_omp_severity_type, gfc_omp_at_type): New.
(gfc_omp_clauses): Add 'at', 'severity' and 'message' clause;
use more bitfields + ENUM_BITFIELD.
(gfc_exec_op): Add EXEC_OMP_ERROR.
* match.h (gfc_match_omp_error): New.
* openmp.c (enum omp_mask1): Add OMP_CLAUSE_(AT,SEVERITY,MESSAGE).
(gfc_match_omp_clauses): Handle new clauses.
(OMP_ERROR_CLAUSES, gfc_match_omp_error): New.
(resolve_omp_clauses): Resolve new clauses.
(omp_code_to_statement, gfc_resolve_omp_directive): Handle
EXEC_OMP_ERROR.
* parse.c (decode_omp_directive, next_statement,
gfc_ascii_statement): Handle 'omp error'.
* resolve.c (gfc_resolve_blocks): Likewise.
* st.c (gfc_free_statement): Likewise.
* trans-openmp.c (gfc_trans_omp_error): Likewise.
(gfc_trans_omp_directive): Likewise.
* trans.c (trans_code): Likewise.

libgomp/ChangeLog:

* testsuite/libgomp.fortran/error-1.f90: New test.

gcc/testsuite/ChangeLog:

* gfortran.dg/gomp/error-1.f90: New test.
* gfortran.dg/gomp/error-2.f90: New test.
* gfortran.dg/gomp/error-3.f90: New test.

13 files changed:
gcc/fortran/dump-parse-tree.c
gcc/fortran/gfortran.h
gcc/fortran/match.h
gcc/fortran/openmp.c
gcc/fortran/parse.c
gcc/fortran/resolve.c
gcc/fortran/st.c
gcc/fortran/trans-openmp.c
gcc/fortran/trans.c
gcc/testsuite/gfortran.dg/gomp/error-1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/error-2.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/error-3.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/error-1.f90 [new file with mode: 0644]

index 92d9f9e..c75a0a9 100644 (file)
@@ -1908,6 +1908,26 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
       fputc (' ', dumpfile);
       fputs (memorder, dumpfile);
     }
+  if (omp_clauses->at != OMP_AT_UNSET)
+    {
+      if (omp_clauses->at != OMP_AT_COMPILATION)
+       fputs (" AT (COMPILATION)", dumpfile);
+      else
+       fputs (" AT (EXECUTION)", dumpfile);
+    }
+  if (omp_clauses->severity != OMP_SEVERITY_UNSET)
+    {
+      if (omp_clauses->severity != OMP_SEVERITY_FATAL)
+       fputs (" SEVERITY (FATAL)", dumpfile);
+      else
+       fputs (" SEVERITY (WARNING)", dumpfile);
+    }
+  if (omp_clauses->message)
+    {
+      fputs (" ERROR (", dumpfile);
+      show_expr (omp_clauses->message);
+      fputc (')', dumpfile);
+    }
 }
 
 /* Show a single OpenMP or OpenACC directive node and everything underneath it
@@ -1950,8 +1970,9 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DISTRIBUTE_SIMD: name = "DISTRIBUTE SIMD"; break;
     case EXEC_OMP_DO: name = "DO"; break;
     case EXEC_OMP_DO_SIMD: name = "DO SIMD"; break;
-    case EXEC_OMP_LOOP: name = "LOOP"; break;
+    case EXEC_OMP_ERROR: name = "ERROR"; break;
     case EXEC_OMP_FLUSH: name = "FLUSH"; break;
+    case EXEC_OMP_LOOP: name = "LOOP"; break;
     case EXEC_OMP_MASKED: name = "MASKED"; break;
     case EXEC_OMP_MASKED_TASKLOOP: name = "MASKED TASKLOOP"; break;
     case EXEC_OMP_MASKED_TASKLOOP_SIMD: name = "MASKED TASKLOOP SIMD"; break;
@@ -2045,6 +2066,7 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DISTRIBUTE_SIMD:
     case EXEC_OMP_DO:
     case EXEC_OMP_DO_SIMD:
+    case EXEC_OMP_ERROR:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_ORDERED:
     case EXEC_OMP_MASKED:
@@ -2135,7 +2157,7 @@ show_omp_node (int level, gfc_code *c)
       || c->op == EXEC_OACC_ENTER_DATA || c->op == EXEC_OACC_EXIT_DATA
       || c->op == EXEC_OMP_TARGET_UPDATE || c->op == EXEC_OMP_TARGET_ENTER_DATA
       || c->op == EXEC_OMP_TARGET_EXIT_DATA || c->op == EXEC_OMP_SCAN
-      || c->op == EXEC_OMP_DEPOBJ
+      || c->op == EXEC_OMP_DEPOBJ || c->op == EXEC_OMP_ERROR
       || (c->op == EXEC_OMP_ORDERED && c->block == NULL))
     return;
   if (c->op == EXEC_OMP_SECTIONS || c->op == EXEC_OMP_PARALLEL_SECTIONS)
@@ -3268,6 +3290,7 @@ show_code_node (int level, gfc_code *c)
     case EXEC_OMP_DISTRIBUTE_SIMD:
     case EXEC_OMP_DO:
     case EXEC_OMP_DO_SIMD:
+    case EXEC_OMP_ERROR:
     case EXEC_OMP_FLUSH:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_MASKED:
index a7d82ae..4b26cb4 100644 (file)
@@ -281,7 +281,8 @@ enum gfc_statement
   ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
   ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD, ST_OMP_MASKED_TASKLOOP,
   ST_OMP_END_MASKED_TASKLOOP, ST_OMP_MASKED_TASKLOOP_SIMD,
-  ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_OMP_SCOPE, ST_OMP_END_SCOPE, ST_NONE
+  ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_OMP_SCOPE, ST_OMP_END_SCOPE,
+  ST_OMP_ERROR, ST_NONE
 };
 
 /* Types of interfaces that we can have.  Assignment interfaces are
@@ -776,6 +777,20 @@ enum gfc_omp_device_type
   OMP_DEVICE_TYPE_ANY
 };
 
+enum gfc_omp_severity_type
+{
+  OMP_SEVERITY_UNSET,
+  OMP_SEVERITY_WARNING,
+  OMP_SEVERITY_FATAL
+};
+
+enum gfc_omp_at_type
+{
+  OMP_AT_UNSET,
+  OMP_AT_COMPILATION,
+  OMP_AT_EXECUTION
+};
+
 /* Structure and list of supported extension attributes.  */
 typedef enum
 {
@@ -1446,26 +1461,11 @@ enum gfc_omp_bind_type
 
 typedef struct gfc_omp_clauses
 {
+  gfc_omp_namelist *lists[OMP_LIST_NUM];
   struct gfc_expr *if_expr;
   struct gfc_expr *final_expr;
   struct gfc_expr *num_threads;
-  gfc_omp_namelist *lists[OMP_LIST_NUM];
-  enum gfc_omp_sched_kind sched_kind;
-  enum gfc_omp_device_type device_type;
   struct gfc_expr *chunk_size;
-  enum gfc_omp_default_sharing default_sharing;
-  enum gfc_omp_defaultmap defaultmap[OMP_DEFAULTMAP_CAT_NUM];
-  int collapse, orderedc;
-  bool nowait, ordered, untied, mergeable;
-  bool inbranch, notinbranch, nogroup;
-  bool sched_simd, sched_monotonic, sched_nonmonotonic;
-  bool simd, threads, depend_source, destroy, order_concurrent, capture;
-  enum gfc_omp_atomic_op atomic_op;
-  enum gfc_omp_memorder memorder;
-  enum gfc_omp_cancel_kind cancel;
-  enum gfc_omp_proc_bind_kind proc_bind;
-  enum gfc_omp_depend_op depobj_update;
-  enum gfc_omp_bind_type bind;
   struct gfc_expr *safelen_expr;
   struct gfc_expr *simdlen_expr;
   struct gfc_expr *num_teams;
@@ -1479,9 +1479,28 @@ typedef struct gfc_omp_clauses
   struct gfc_expr *detach;
   struct gfc_expr *depobj;
   struct gfc_expr *if_exprs[OMP_IF_LAST];
-  enum gfc_omp_sched_kind dist_sched_kind;
   struct gfc_expr *dist_chunk_size;
+  struct gfc_expr *message;
   const char *critical_name;
+  enum gfc_omp_default_sharing default_sharing;
+  enum gfc_omp_atomic_op atomic_op;
+  enum gfc_omp_defaultmap defaultmap[OMP_DEFAULTMAP_CAT_NUM];
+  int collapse, orderedc;
+  unsigned nowait:1, ordered:1, untied:1, mergeable:1;
+  unsigned inbranch:1, notinbranch:1, nogroup:1;
+  unsigned sched_simd:1, sched_monotonic:1, sched_nonmonotonic:1;
+  unsigned simd:1, threads:1, depend_source:1, destroy:1, order_concurrent:1;
+  unsigned capture:1;
+  ENUM_BITFIELD (gfc_omp_sched_kind) sched_kind:3;
+  ENUM_BITFIELD (gfc_omp_device_type) device_type:2;
+  ENUM_BITFIELD (gfc_omp_memorder) memorder:3;
+  ENUM_BITFIELD (gfc_omp_cancel_kind) cancel:3;
+  ENUM_BITFIELD (gfc_omp_proc_bind_kind) proc_bind:3;
+  ENUM_BITFIELD (gfc_omp_depend_op) depobj_update:3;
+  ENUM_BITFIELD (gfc_omp_bind_type) bind:2;
+  ENUM_BITFIELD (gfc_omp_at_type) at:2;
+  ENUM_BITFIELD (gfc_omp_severity_type) severity:2;
+  ENUM_BITFIELD (gfc_omp_sched_kind) dist_sched_kind:3;
 
   /* OpenACC. */
   struct gfc_expr *async_expr;
@@ -2768,7 +2787,8 @@ enum gfc_exec_op
   EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP,
   EXEC_OMP_TARGET_TEAMS_LOOP, EXEC_OMP_MASKED, EXEC_OMP_PARALLEL_MASKED,
   EXEC_OMP_PARALLEL_MASKED_TASKLOOP, EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
-  EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD, EXEC_OMP_SCOPE
+  EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD, EXEC_OMP_SCOPE,
+  EXEC_OMP_ERROR
 };
 
 typedef struct gfc_code
index 5127b4b..92fd127 100644 (file)
@@ -168,6 +168,7 @@ match gfc_match_omp_distribute_simd (void);
 match gfc_match_omp_do (void);
 match gfc_match_omp_do_simd (void);
 match gfc_match_omp_loop (void);
+match gfc_match_omp_error (void);
 match gfc_match_omp_flush (void);
 match gfc_match_omp_masked (void);
 match gfc_match_omp_masked_taskloop (void);
index fd219dc..2380866 100644 (file)
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "constructor.h"
 #include "diagnostic.h"
 #include "gomp-constants.h"
+#include "target-memory.h"  /* For gfc_encode_character.  */
 
 /* Match an end of OpenMP directive.  End of OpenMP directive is optional
    whitespace, followed by '\n' or comment '!'.  */
@@ -848,6 +849,9 @@ enum omp_mask1
   OMP_CLAUSE_AFFINITY,  /* OpenMP 5.0.  */
   OMP_CLAUSE_BIND,  /* OpenMP 5.0.  */
   OMP_CLAUSE_FILTER,  /* OpenMP 5.1.  */
+  OMP_CLAUSE_AT,  /* OpenMP 5.1.  */
+  OMP_CLAUSE_MESSAGE,  /* OpenMP 5.1.  */
+  OMP_CLAUSE_SEVERITY,  /* OpenMP 5.1.  */
   OMP_CLAUSE_NOWAIT,
   /* This must come last.  */
   OMP_MASK1_LAST
@@ -1293,6 +1297,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                       bool first = true, bool needs_space = true,
                       bool openacc = false)
 {
+  bool error = false;
   gfc_omp_clauses *c = gfc_get_omp_clauses ();
   locus old_loc;
   /* Determine whether we're dealing with an OpenACC directive that permits
@@ -1392,6 +1397,22 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                }
              continue;
            }
+         if ((mask & OMP_CLAUSE_AT)
+             && c->at == OMP_AT_UNSET
+             && gfc_match ("at ( ") == MATCH_YES)
+           {
+             if (gfc_match ("compilation )") == MATCH_YES)
+               c->at = OMP_AT_COMPILATION;
+             else if (gfc_match ("execution )") == MATCH_YES)
+               c->at = OMP_AT_EXECUTION;
+             else
+               {
+                 gfc_error ("Expected COMPILATION or EXECUTION in AT clause "
+                            "at %C");
+                 goto error;
+               }
+             continue;
+           }
          if ((mask & OMP_CLAUSE_ASYNC)
              && !c->async
              && gfc_match ("async") == MATCH_YES)
@@ -1616,7 +1637,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                     else
                      gfc_error ("DEFAULTMAP at %C but prior DEFAULTMAP for "
                                 "category %s", pcategory);
-                    goto end;
+                    goto error;
                    }
                }
              c->defaultmap[category] = behavior;
@@ -2074,6 +2095,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
              c->mergeable = needs_space = true;
              continue;
            }
+         if ((mask & OMP_CLAUSE_MESSAGE)
+             && !c->message
+             && gfc_match ("message ( %e )", &c->message) == MATCH_YES)
+           continue;
          break;
        case 'n':
          if ((mask & OMP_CLAUSE_NO_CREATE)
@@ -2402,6 +2427,22 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
              c->simd = needs_space = true;
              continue;
            }
+         if ((mask & OMP_CLAUSE_SEVERITY)
+             && c->severity == OMP_SEVERITY_UNSET
+             && gfc_match ("severity ( ") == MATCH_YES)
+           {
+             if (gfc_match ("fatal )") == MATCH_YES)
+               c->severity = OMP_SEVERITY_FATAL;
+             else if (gfc_match ("warning )") == MATCH_YES)
+               c->severity = OMP_SEVERITY_WARNING;
+             else
+               {
+                 gfc_error ("Expected FATAL or WARNING in SEVERITY clause "
+                            "at %C");
+                 goto error;
+               }
+             continue;
+           }
          break;
        case 't':
          if ((mask & OMP_CLAUSE_TASK_REDUCTION)
@@ -2553,7 +2594,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
     }
 
 end:
-  if (gfc_match_omp_eos () != MATCH_YES)
+  if (error || gfc_match_omp_eos () != MATCH_YES)
     {
       if (!gfc_error_flag_test ())
        gfc_error ("Failed to match clause at %C");
@@ -2563,6 +2604,10 @@ end:
 
   *cp = c;
   return MATCH_YES;
+
+error:
+  error = true;
+  goto end;
 }
 
 
@@ -3208,6 +3253,9 @@ cleanup:
    | OMP_CLAUSE_MEMORDER)
 #define OMP_MASKED_CLAUSES \
   (omp_mask (OMP_CLAUSE_FILTER))
+#define OMP_ERROR_CLAUSES \
+  (omp_mask (OMP_CLAUSE_AT) | OMP_CLAUSE_MESSAGE | OMP_CLAUSE_SEVERITY)
+
 
 
 static match
@@ -3432,6 +3480,66 @@ gfc_match_omp_target_parallel_loop (void)
 
 
 match
+gfc_match_omp_error (void)
+{
+  locus loc = gfc_current_locus;
+  match m = match_omp (EXEC_OMP_ERROR, OMP_ERROR_CLAUSES);
+  if (m != MATCH_YES)
+    return m;
+
+  gfc_omp_clauses *c = new_st.ext.omp_clauses;
+  if (c->severity == OMP_SEVERITY_UNSET)
+    c->severity = OMP_SEVERITY_FATAL;
+  if (new_st.ext.omp_clauses->at == OMP_AT_EXECUTION)
+    return MATCH_YES;
+  if (c->message
+      && (!gfc_resolve_expr (c->message)
+         || c->message->ts.type != BT_CHARACTER
+         || c->message->ts.kind != gfc_default_character_kind
+         || c->message->rank != 0))
+    {
+      gfc_error ("MESSAGE clause at %L requires a scalar default-kind "
+                  "CHARACTER expression",
+                &new_st.ext.omp_clauses->message->where);
+      return MATCH_ERROR;
+    }
+  if (c->message && !gfc_is_constant_expr (c->message))
+    {
+      gfc_error ("Constant character expression required in MESSAGE clause "
+                "at %L", &new_st.ext.omp_clauses->message->where);
+      return MATCH_ERROR;
+    }
+  if (c->message)
+    {
+      const char *msg = G_("$OMP ERROR encountered at %L: %s");
+      gcc_assert (c->message->expr_type == EXPR_CONSTANT);
+      gfc_charlen_t slen = c->message->value.character.length;
+      int i = gfc_validate_kind (BT_CHARACTER, gfc_default_character_kind,
+                                false);
+      size_t size = slen * gfc_character_kinds[i].bit_size / 8;
+      unsigned char *s = XCNEWVAR (unsigned char, size + 1);
+      gfc_encode_character (gfc_default_character_kind, slen,
+                           c->message->value.character.string,
+                           (unsigned char *) s, size);
+      s[size] = '\0';
+      if (c->severity == OMP_SEVERITY_WARNING)
+       gfc_warning_now (0, msg, &loc, s);
+      else
+       gfc_error_now (msg, &loc, s);
+      free (s);
+    }
+  else
+    {
+      const char *msg = G_("$OMP ERROR encountered at %L");
+      if (c->severity == OMP_SEVERITY_WARNING)
+       gfc_warning_now (0, msg, &loc);
+      else
+       gfc_error_now (msg, &loc);
+    }
+  return MATCH_YES;
+}
+
+match
 gfc_match_omp_flush (void)
 {
   gfc_omp_namelist *list = NULL;
@@ -6463,6 +6571,15 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
   if (omp_clauses->depend_source && code->op != EXEC_OMP_ORDERED)
     gfc_error ("SOURCE dependence type only allowed "
               "on ORDERED directive at %L", &code->loc);
+  if (omp_clauses->message)
+    {
+      gfc_expr *expr = omp_clauses->message;
+      if (!gfc_resolve_expr (expr)
+         || expr->ts.kind != gfc_default_character_kind
+         || expr->ts.type != BT_CHARACTER || expr->rank != 0)
+       gfc_error ("MESSAGE clause at %L requires a scalar default-kind "
+                  "CHARACTER expression", &expr->where);
+    }
   if (!openacc
       && code
       && omp_clauses->lists[OMP_LIST_MAP] == NULL
@@ -7461,6 +7578,8 @@ omp_code_to_statement (gfc_code *code)
       return ST_OMP_CANCEL;
     case EXEC_OMP_CANCELLATION_POINT:
       return ST_OMP_CANCELLATION_POINT;
+    case EXEC_OMP_ERROR:
+      return ST_OMP_ERROR;
     case EXEC_OMP_FLUSH:
       return ST_OMP_FLUSH;
     case EXEC_OMP_DISTRIBUTE:
@@ -7971,6 +8090,7 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns)
       resolve_omp_do (code);
       break;
     case EXEC_OMP_CANCEL:
+    case EXEC_OMP_ERROR:
     case EXEC_OMP_MASKED:
     case EXEC_OMP_PARALLEL_WORKSHARE:
     case EXEC_OMP_PARALLEL:
index d004732..d37a0b5 100644 (file)
@@ -908,6 +908,7 @@ decode_omp_directive (void)
       matcho ("do", gfc_match_omp_do, ST_OMP_DO);
       break;
     case 'e':
+      matcho ("error", gfc_match_omp_error, ST_OMP_ERROR);
       matcho ("end atomic", gfc_match_omp_eos_error, ST_OMP_END_ATOMIC);
       matcho ("end critical", gfc_match_omp_end_critical, ST_OMP_END_CRITICAL);
       matchs ("end distribute parallel do simd", gfc_match_omp_eos_error,
@@ -1183,6 +1184,9 @@ decode_omp_directive (void)
          prog_unit->omp_target_seen = true;
        break;
       }
+    case ST_OMP_ERROR:
+      if (new_st.ext.omp_clauses->at != OMP_AT_EXECUTION)
+       return ST_NONE;
     default:
       break;
     }
@@ -1654,7 +1658,7 @@ next_statement (void)
   case ST_OMP_BARRIER: case ST_OMP_TASKWAIT: case ST_OMP_TASKYIELD: \
   case ST_OMP_CANCEL: case ST_OMP_CANCELLATION_POINT: case ST_OMP_DEPOBJ: \
   case ST_OMP_TARGET_UPDATE: case ST_OMP_TARGET_ENTER_DATA: \
-  case ST_OMP_TARGET_EXIT_DATA: case ST_OMP_ORDERED_DEPEND: \
+  case ST_OMP_TARGET_EXIT_DATA: case ST_OMP_ORDERED_DEPEND: case ST_OMP_ERROR: \
   case ST_ERROR_STOP: case ST_OMP_SCAN: case ST_SYNC_ALL: \
   case ST_SYNC_IMAGES: case ST_SYNC_MEMORY: case ST_LOCK: case ST_UNLOCK: \
   case ST_FORM_TEAM: case ST_CHANGE_TEAM: \
@@ -1716,7 +1720,6 @@ next_statement (void)
   case ST_OMP_DECLARE_TARGET: case ST_OMP_DECLARE_REDUCTION: \
   case ST_OMP_REQUIRES: case ST_OACC_ROUTINE: case ST_OACC_DECLARE
 
-
 /* Block end statements.  Errors associated with interchanging these
    are detected in gfc_match_end().  */
 
@@ -2544,6 +2547,9 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_END_WORKSHARE:
       p = "!$OMP END WORKSHARE";
       break;
+    case ST_OMP_ERROR:
+      p = "!$OMP ERROR";
+      break;
     case ST_OMP_FLUSH:
       p = "!$OMP FLUSH";
       break;
index 117062b..5b9ba43 100644 (file)
@@ -10817,6 +10817,7 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns)
        case EXEC_OMP_DISTRIBUTE_SIMD:
        case EXEC_OMP_DO:
        case EXEC_OMP_DO_SIMD:
+       case EXEC_OMP_ERROR:
        case EXEC_OMP_LOOP:
        case EXEC_OMP_MASKED:
        case EXEC_OMP_MASKED_TASKLOOP:
@@ -12254,6 +12255,7 @@ start:
        case EXEC_OMP_DISTRIBUTE_SIMD:
        case EXEC_OMP_DO:
        case EXEC_OMP_DO_SIMD:
+       case EXEC_OMP_ERROR:
        case EXEC_OMP_LOOP:
        case EXEC_OMP_MASTER:
        case EXEC_OMP_MASTER_TASKLOOP:
index 7d87709..6bf730c 100644 (file)
@@ -225,6 +225,7 @@ gfc_free_statement (gfc_code *p)
     case EXEC_OMP_DISTRIBUTE_SIMD:
     case EXEC_OMP_DO:
     case EXEC_OMP_DO_SIMD:
+    case EXEC_OMP_ERROR:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_END_SINGLE:
     case EXEC_OMP_MASKED_TASKLOOP:
index e0a0014..91888f3 100644 (file)
@@ -5369,6 +5369,38 @@ gfc_trans_omp_depobj (gfc_code *code)
 }
 
 static tree
+gfc_trans_omp_error (gfc_code *code)
+{
+  stmtblock_t block;
+  gfc_se se;
+  tree len, message;
+  bool fatal = code->ext.omp_clauses->severity == OMP_SEVERITY_FATAL;
+  tree fndecl = builtin_decl_explicit (fatal ? BUILT_IN_GOMP_ERROR
+                                            : BUILT_IN_GOMP_WARNING);
+  gfc_start_block (&block);
+  gfc_init_se (&se, NULL );
+  if (!code->ext.omp_clauses->message)
+    {
+      message = null_pointer_node;
+      len = build_int_cst (size_type_node, 0);
+    }
+  else
+    {
+      gfc_conv_expr (&se, code->ext.omp_clauses->message);
+      message = se.expr;
+      if (!POINTER_TYPE_P (TREE_TYPE (message)))
+       /* To ensure an ARRAY_TYPE is not passed as such.  */
+       message = gfc_build_addr_expr (NULL, message);
+      len = se.string_length;
+    }
+  gfc_add_block_to_block (&block, &se.pre);
+  gfc_add_expr_to_block (&block, build_call_expr_loc (input_location, fndecl,
+                                                     2, message, len));
+  gfc_add_block_to_block (&block, &se.post);
+  return gfc_finish_block (&block);
+}
+
+static tree
 gfc_trans_omp_flush (gfc_code *code)
 {
   tree call;
@@ -7096,6 +7128,8 @@ gfc_trans_omp_directive (gfc_code *code)
       return gfc_trans_omp_distribute (code, NULL);
     case EXEC_OMP_DO_SIMD:
       return gfc_trans_omp_do_simd (code, NULL, NULL, NULL_TREE);
+    case EXEC_OMP_ERROR:
+      return gfc_trans_omp_error (code);
     case EXEC_OMP_FLUSH:
       return gfc_trans_omp_flush (code);
     case EXEC_OMP_MASKED:
index 80b724d..eb5682a 100644 (file)
@@ -2155,6 +2155,7 @@ trans_code (gfc_code * code, tree cond)
        case EXEC_OMP_DO:
        case EXEC_OMP_DO_SIMD:
        case EXEC_OMP_LOOP:
+       case EXEC_OMP_ERROR:
        case EXEC_OMP_FLUSH:
        case EXEC_OMP_MASKED:
        case EXEC_OMP_MASKED_TASKLOOP:
diff --git a/gcc/testsuite/gfortran.dg/gomp/error-1.f90 b/gcc/testsuite/gfortran.dg/gomp/error-1.f90
new file mode 100644 (file)
index 0000000..0ee0b4b
--- /dev/null
@@ -0,0 +1,51 @@
+! { dg-additional-options "-ffree-line-length-none" }
+module m
+!$omp error                    ! { dg-error ".OMP ERROR encountered at .1." }
+!$omp error at(compilation)    ! { dg-error ".OMP ERROR encountered at .1." }
+!$omp error severity(fatal)    ! { dg-error ".OMP ERROR encountered at .1." }
+!$omp error message("my msg")  ! { dg-error ".OMP ERROR encountered at .1.: my msg" }
+!$omp error severity(warning)message("another message")at(compilation) ! { dg-warning ".OMP ERROR encountered at .1.: another message" }
+
+type S
+  !$omp error                  ! { dg-error ".OMP ERROR encountered at .1." }
+  !$omp error at(compilation)  ! { dg-error ".OMP ERROR encountered at .1." }
+  !$omp error severity(fatal)  ! { dg-error ".OMP ERROR encountered at .1." }
+  !$omp error message("42")    ! { dg-error ".OMP ERROR encountered at .1.: 42" }
+  !$omp error severity(warning), message("foo"), at(compilation)       ! { dg-warning ".OMP ERROR encountered at .1.: foo" }
+  integer s
+end type S
+end module m
+
+integer function foo (i, x)
+  integer :: i
+  logical :: x
+  !$omp error                  ! { dg-error ".OMP ERROR encountered at .1." }
+  !$omp error at(compilation)  ! { dg-error ".OMP ERROR encountered at .1." }
+  !$omp error severity(fatal)  ! { dg-error ".OMP ERROR encountered at .1." }
+  !$omp error message("42 / 1")        ! { dg-error ".OMP ERROR encountered at .1.: 42 / 1" }
+  !$omp error severity(warning) message("bar") at(compilation) ! { dg-warning ".OMP ERROR encountered at .1.: bar" }
+  if (x) then
+    !$omp error                        ! { dg-error ".OMP ERROR encountered at .1." }
+    i = i + 1
+  end if
+  if (x) then
+    ;
+  else
+    !$omp error at(compilation)        ! { dg-error ".OMP ERROR encountered at .1." }
+    i = i + 1
+  end if
+  select case (.false.)
+    !$omp error severity(fatal)        ! { dg-error ".OMP ERROR encountered at .1." }
+    case default
+      !
+  end select
+  do while (.false.)
+    !$omp error message("42 - 1")      ! { dg-error ".OMP ERROR encountered at .1.: 42 - 1" }
+    i = i + 1
+  end do
+  lab:
+  !$omp error severity(warning) message("bar") at(compilation) ! { dg-warning ".OMP ERROR encountered at .1.: bar" }
+    i++;
+  foo = i
+  return
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/error-2.f90 b/gcc/testsuite/gfortran.dg/gomp/error-2.f90
new file mode 100644 (file)
index 0000000..718e82c
--- /dev/null
@@ -0,0 +1,15 @@
+subroutine foo (x, msg1, msg2)
+  integer x
+  character(len=*) :: msg1, msg2
+  if (x == 0) then
+      !$omp error at(execution)
+  else if (x == 1) then
+      !$omp error severity (warning), at (execution)
+  else if (x == 2) then
+      !$omp error at ( execution ) severity (fatal) message ("baz")
+  else if (x == 3) then
+      !$omp error severity(warning) message (msg1) at(execution)
+  else
+      !$omp error message (msg2), at(execution), severity(fatal)
+  end if
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/error-3.f90 b/gcc/testsuite/gfortran.dg/gomp/error-3.f90
new file mode 100644 (file)
index 0000000..67948cd
--- /dev/null
@@ -0,0 +1,88 @@
+module m
+!$omp error asdf                       ! { dg-error "Failed to match clause" }
+!$omp error at                         ! { dg-error "Failed to match clause" }
+!$omp error at(                                ! { dg-error "Expected COMPILATION or EXECUTION in AT clause at" }
+!$omp error at(runtime)                        ! { dg-error "Expected COMPILATION or EXECUTION in AT clause at" }
+!$omp error at(+                       ! { dg-error "Expected COMPILATION or EXECUTION in AT clause at" }
+!$omp error at(compilation             ! { dg-error "Expected COMPILATION or EXECUTION in AT clause at" }
+!$omp error severity                   ! { dg-error "Failed to match clause" }
+!$omp error severity(                  ! { dg-error "Expected FATAL or WARNING in SEVERITY clause at" }
+!$omp error severity(error)            ! { dg-error "Expected FATAL or WARNING in SEVERITY clause at" }
+!$omp error severity(-                 ! { dg-error "Expected FATAL or WARNING in SEVERITY clause at" }
+!$omp error severity(fatal             ! { dg-error "Expected FATAL or WARNING in SEVERITY clause at" }
+!$omp error message                    ! { dg-error "Failed to match clause" }
+!$omp error message(                   ! { dg-error "Invalid character in name" }
+!$omp error message(0                  ! { dg-error "Failed to match clause" }
+!$omp error message("foo"              ! { dg-error "Failed to match clause" }
+
+!$omp error at(compilation) at(compilation)    ! { dg-error "Failed to match clause at" }
+!$omp error severity(fatal) severity(warning)  ! { dg-error "Failed to match clause at" }
+!$omp error message("foo") message("foo")      ! { dg-error "Failed to match clause at" }
+!$omp error message("foo"),at(compilation),severity(fatal),asdf        ! { dg-error "Failed to match clause" }
+
+!$omp error at(execution)                      ! { dg-error "Unexpected !.OMP ERROR statement in MODULE" }
+
+end module
+
+module m2
+character(len=10) :: msg
+!$omp error message(1)                 ! { dg-error "MESSAGE clause at .1. requires a scalar default-kind CHARACTER expression" }
+!$omp error message(1.2)               ! { dg-error "MESSAGE clause at .1. requires a scalar default-kind CHARACTER expression" }
+!$omp error message(4_"foo")           ! { dg-error "MESSAGE clause at .1. requires a scalar default-kind CHARACTER expression" }
+!$omp error message(["bar","bar"])     ! { dg-error "MESSAGE clause at .1. requires a scalar default-kind CHARACTER expression" }
+!$omp error message(msg)               ! { dg-error "Constant character expression required in MESSAGE clause" }
+
+type S
+  !$omp error at(execution) message("foo")! { dg-error "Unexpected !.OMP ERROR statement at" }
+  integer s
+end type
+end module
+
+subroutine bar
+character(len=10) :: msg
+!$omp error at(execution) message(1)                   ! { dg-error "MESSAGE clause at .1. requires a scalar default-kind CHARACTER expression" }
+!$omp error at(execution) message(1.2)                 ! { dg-error "MESSAGE clause at .1. requires a scalar default-kind CHARACTER expression" }
+!$omp error at(execution) message(4_"foo")             ! { dg-error "MESSAGE clause at .1. requires a scalar default-kind CHARACTER expression" }
+!$omp error at(execution) message(["bar","bar"])       ! { dg-error "MESSAGE clause at .1. requires a scalar default-kind CHARACTER expression" }
+!$omp error at(execution) message(msg)                 ! OK
+
+end
+
+integer function foo (i, x, msg)
+  integer :: i
+  logical :: x
+  character(len=*) :: msg
+  !$omp error message(msg)             ! { dg-error "Constant character expression required in MESSAGE clause" }
+  if (x) then
+    !$omp error at(execution)          ! OK
+  end if
+  i = i + 1
+  if (x) then
+    ;
+  else
+    !$omp error at(execution) severity(warning)        ! OK
+  end if
+  i = i + 1
+  select case (.false.)
+    !$omp error severity(fatal) at(execution)  ! { dg-error "Expected a CASE or END SELECT statement following SELECT CASE" }
+  end select
+  do while (.false.)
+    !$omp error at(execution)message("42 - 1") ! OK
+    i = i + 1
+  end do
+99  continue
+  !$omp error severity(warning) message("bar") at(execution)   ! OK
+    i = i + 1
+  foo = i
+end
+
+
+subroutine foobar
+  if (.true.) &  ! { dg-error "Syntax error in IF-clause after" }
+    !$omp error at(execution)
+
+  continue
+
+  if (.true.) &  ! { dg-error "Syntax error in IF-clause after" }
+    !$omp error  ! { dg-error ".OMP ERROR encountered at" }
+end
diff --git a/libgomp/testsuite/libgomp.fortran/error-1.f90 b/libgomp/testsuite/libgomp.fortran/error-1.f90
new file mode 100644 (file)
index 0000000..92c246c
--- /dev/null
@@ -0,0 +1,78 @@
+! { dg-shouldfail "error directive" }
+
+module m
+  implicit none (external, type)
+contains
+integer function foo (i, x)
+  integer, value :: i, x
+  if (x /= 0) then
+    !$omp error severity(warning)      ! { dg-warning ".OMP ERROR encountered at .1." }
+    i = i + 1
+  end if
+  if (x /= 0) then
+    ! ...
+  else
+    !$omp error severity(warning)      ! { dg-warning ".OMP ERROR encountered at .1." }
+    i = i + 2
+  end if
+  select case(0)
+    !$omp error severity(warning)      ! { dg-warning ".OMP ERROR encountered at .1." }
+    case default
+      !
+  end select
+  do while (.false.)
+    !$omp error message("42 - 1")      severity (warning)  ! { dg-warning ".OMP ERROR encountered at .1.: 42 - 1" }
+    i = i + 4
+  end do
+99 continue
+  !$omp error severity(warning) message("bar") at(compilation)  ! { dg-warning ".OMP ERROR encountered at .1.: bar" }
+    i = i + 8
+  foo = i
+end function
+end module
+
+program main
+  use m
+  implicit none (external, type)
+  character(len=13) :: msg
+  character(len=:), allocatable :: msg2, msg3
+
+  msg = "my message"
+  if (foo (5, 0) /= 15 .or. foo (7, 1) /= 16) &
+    stop 1
+  msg2 = "Paris"
+  msg3 = "To thine own self be true"
+  call bar ("Polonius", "Laertes", msg2, msg3)
+  msg2 = "Hello World"
+  !$omp error at (execution) severity (warning)
+  !$omp error at (execution) severity (warning) message(trim(msg(4:)))
+  !$omp error at (execution) severity (warning) message ("Farewell")
+  !$omp error at (execution) severity (warning) message (msg2)
+  !$omp error at (execution) severity (warning) message (msg(4:6))
+  !$omp error at (execution) severity (fatal) message (msg)
+  ! unreachable due to 'fatal'---------^
+  !$omp error at (execution) severity (warning) message ("foobar")
+contains
+   subroutine bar(x, y, a, b)
+     character(len=*) :: x, y
+     character(len=:), allocatable :: a, b
+     optional :: y, b
+     intent(in) :: x, y, a, b
+     !$omp error at (execution) severity (warning) message (x)
+     !$omp error at (execution) severity (warning) message (y)
+     !$omp error at (execution) severity (warning) message (a)
+     !$omp error at (execution) severity (warning) message (b)
+   end subroutine
+end
+
+! { dg-output "(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered: Polonius(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered: Laertes(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered: Paris(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered: To thine own self be true(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered: message(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered: Farewell(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered: Hello World(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: error directive encountered: mes(\n|\r|\n\r)(\n|\r|\n\r)" }
+! { dg-output "libgomp: fatal error: error directive encountered: my message   (\n|\r|\n\r)" }