public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-11] openmp: Implement the error directive
@ 2021-08-20 13:31 Tobias Burnus
  0 siblings, 0 replies; only message in thread
From: Tobias Burnus @ 2021-08-20 13:31 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:8cb8bdfd5e702262a902891970fad7b1c40a8854

commit 8cb8bdfd5e702262a902891970fad7b1c40a8854
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Aug 20 14:19:07 2021 +0200

    openmp: Implement the error directive
    
    This patch implements the error directive.  Depending on clauses it is either
    a compile time diagnostics (in that case diagnosed right away) or runtime
    diagnostics (libgomp API call that diagnoses at runtime), and either fatal
    or warning (error or warning at compile time or fatal error vs. error at
    runtime) and either has no message or user supplied message (this kind of
    e.g. deprecated attribute).  The directive is also stand-alone directive
    when at runtime while utility (thus disappears from the IL as if it wasn't
    there for parsing like nothing directive) at compile time.
    
    There are some clarifications in the works ATM, so this patch doesn't yet
    require that for compile time diagnostics the user message must be a constant
    string literal, there are uncertainities on what exactly is valid argument
    of message clause (whether just const char * type, convertible to const char *,
    qualified/unqualified const char * or char * or what else) and what to do
    in templates.  Currently even in templates it is diagnosed right away for
    compile time diagnostics, if we'll need to substitute it, we'd need to queue
    something into the IL, have pt.c handle it and diagnose only later.
    
    2021-08-20  Jakub Jelinek  <jakub@redhat.com>
    
    gcc/
            * omp-builtins.def (BUILT_IN_GOMP_WARNING, BUILT_IN_GOMP_ERROR): New
            builtins.
    gcc/c-family/
            * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_ERROR.
            * c-pragma.c (omp_pragmas): Add error directive.
            * c-omp.c (omp_directives): Uncomment error directive entry.
    gcc/c/
            * c-parser.c (c_parser_omp_error): New function.
            (c_parser_pragma): Handle PRAGMA_OMP_ERROR.
    gcc/cp/
            * parser.c (cp_parser_handle_statement_omp_attributes): Determine if
            PRAGMA_OMP_ERROR directive is C_OMP_DIR_STANDALONE.
            (cp_parser_omp_error): New function.
            (cp_parser_pragma): Handle PRAGMA_OMP_ERROR.
    gcc/fortran/
            * types.def (BT_FN_VOID_CONST_PTR_SIZE): New DEF_FUNCTION_TYPE_2.
            * f95-lang.c (ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST): Define.
    gcc/testsuite/
            * c-c++-common/gomp/error-1.c: New test.
            * c-c++-common/gomp/error-2.c: New test.
            * c-c++-common/gomp/error-3.c: New test.
            * g++.dg/gomp/attrs-1.C (bar): Add error directive test.
            * g++.dg/gomp/attrs-2.C (bar): Add error directive test.
            * g++.dg/gomp/attrs-13.C: New test.
            * g++.dg/gomp/error-1.C: New test.
    libgomp/
            * libgomp.map (GOMP_5.1): Add GOMP_error and GOMP_warning.
            * libgomp_g.h (GOMP_warning, GOMP_error): Declare.
            * error.c (GOMP_warning, GOMP_error): New functions.
            * testsuite/libgomp.c-c++-common/error-1.c: New test.
    
    (cherry picked from commit 0d973c0a0d90a0a302e7eda1a4d9709be3c5b102)

Diff:
---
 gcc/ChangeLog.omp                                |   8 +
 gcc/c-family/ChangeLog.omp                       |   9 +
 gcc/c-family/c-omp.c                             |   4 +-
 gcc/c-family/c-pragma.c                          |   1 +
 gcc/c-family/c-pragma.h                          |   1 +
 gcc/c/ChangeLog.omp                              |   8 +
 gcc/c/c-parser.c                                 | 171 +++++++++++++++++++
 gcc/cp/ChangeLog.omp                             |  10 ++
 gcc/cp/parser.c                                  | 207 ++++++++++++++++++++++-
 gcc/fortran/ChangeLog.omp                        |   8 +
 gcc/fortran/f95-lang.c                           |   5 +-
 gcc/fortran/types.def                            |   1 +
 gcc/omp-builtins.def                             |   4 +
 gcc/testsuite/ChangeLog.omp                      |  13 ++
 gcc/testsuite/c-c++-common/gomp/error-1.c        |  45 +++++
 gcc/testsuite/c-c++-common/gomp/error-2.c        |  24 +++
 gcc/testsuite/c-c++-common/gomp/error-3.c        |  70 ++++++++
 gcc/testsuite/g++.dg/gomp/attrs-1.C              |   4 +-
 gcc/testsuite/g++.dg/gomp/attrs-13.C             |  34 ++++
 gcc/testsuite/g++.dg/gomp/attrs-2.C              |   4 +-
 gcc/testsuite/g++.dg/gomp/error-1.C              |  42 +++++
 libgomp/ChangeLog.omp                            |  10 ++
 libgomp/error.c                                  |  31 ++++
 libgomp/libgomp.map                              |   2 +
 libgomp/libgomp_g.h                              |   5 +
 libgomp/testsuite/libgomp.c-c++-common/error-1.c |  49 ++++++
 26 files changed, 762 insertions(+), 8 deletions(-)

diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp
index c1945272361..59149205a44 100644
--- a/gcc/ChangeLog.omp
+++ b/gcc/ChangeLog.omp
@@ -1,3 +1,11 @@
+2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-20  Jakub Jelinek  <jakub@redhat.com>
+
+	* omp-builtins.def (BUILT_IN_GOMP_WARNING, BUILT_IN_GOMP_ERROR): New
+	builtins.
+
 2021-08-17  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/c-family/ChangeLog.omp b/gcc/c-family/ChangeLog.omp
index a3366bb06d2..4664df3d0f4 100644
--- a/gcc/c-family/ChangeLog.omp
+++ b/gcc/c-family/ChangeLog.omp
@@ -1,3 +1,12 @@
+2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-20  Jakub Jelinek  <jakub@redhat.com>
+
+	* c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_ERROR.
+	* c-pragma.c (omp_pragmas): Add error directive.
+	* c-omp.c (omp_directives): Uncomment error directive entry.
+
 2021-08-18  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index a553302a6b0..c8634701742 100644
--- a/gcc/c-family/c-omp.c
+++ b/gcc/c-family/c-omp.c
@@ -3775,8 +3775,8 @@ static const struct c_omp_directive omp_directives[] = {
   /* { "end", "metadirective", nullptr, PRAGMA_OMP_END,
     C_OMP_DIR_???, ??? },  */
   /* error with at(execution) is C_OMP_DIR_STANDALONE.  */
-  /* { "error", nullptr, nullptr, PRAGMA_OMP_ERROR,
-    C_OMP_DIR_UTILITY, false },  */
+  { "error", nullptr, nullptr, PRAGMA_OMP_ERROR,
+    C_OMP_DIR_UTILITY, false },
   { "flush", nullptr, nullptr, PRAGMA_OMP_FLUSH,
     C_OMP_DIR_STANDALONE, false },
   { "for", nullptr, nullptr, PRAGMA_OMP_FOR,
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index ef428dae010..6b17cb1775c 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -1316,6 +1316,7 @@ static const struct omp_pragma_def omp_pragmas[] = {
   { "cancellation", PRAGMA_OMP_CANCELLATION_POINT },
   { "critical", PRAGMA_OMP_CRITICAL },
   { "depobj", PRAGMA_OMP_DEPOBJ },
+  { "error", PRAGMA_OMP_ERROR },
   { "end", PRAGMA_OMP_END_DECLARE_TARGET },
   { "flush", PRAGMA_OMP_FLUSH },
   { "nothing", PRAGMA_OMP_NOTHING },
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index dc9e8a6616d..0c5b07ab4e1 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -53,6 +53,7 @@ enum pragma_kind {
   PRAGMA_OMP_DECLARE,
   PRAGMA_OMP_DEPOBJ,
   PRAGMA_OMP_DISTRIBUTE,
+  PRAGMA_OMP_ERROR,
   PRAGMA_OMP_END_DECLARE_TARGET,
   PRAGMA_OMP_FLUSH,
   PRAGMA_OMP_FOR,
diff --git a/gcc/c/ChangeLog.omp b/gcc/c/ChangeLog.omp
index b28671f2b2f..21942b8b9df 100644
--- a/gcc/c/ChangeLog.omp
+++ b/gcc/c/ChangeLog.omp
@@ -1,3 +1,11 @@
+2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-20  Jakub Jelinek  <jakub@redhat.com>
+
+	* c-parser.c (c_parser_omp_error): New function.
+	(c_parser_pragma): Handle PRAGMA_OMP_ERROR.
+
 2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 389a749dce9..3c8aa11d892 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1587,6 +1587,7 @@ static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *);
 static void c_parser_omp_end_declare_target (c_parser *);
 static bool c_parser_omp_declare (c_parser *, enum pragma_context);
 static void c_parser_omp_requires (c_parser *);
+static bool c_parser_omp_error (c_parser *, enum pragma_context);
 static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *);
 static void c_parser_oacc_routine (c_parser *, enum pragma_context);
 
@@ -12449,6 +12450,9 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
       c_parser_omp_nothing (parser);
       return false;
 
+    case PRAGMA_OMP_ERROR:
+      return c_parser_omp_error (parser, context);
+
     case PRAGMA_OMP_ORDERED:
       return c_parser_omp_ordered (parser, context, if_p);
 
@@ -21957,6 +21961,173 @@ c_parser_omp_nothing (c_parser *parser)
   c_parser_skip_to_pragma_eol (parser);
 }
 
+/* OpenMP 5.1
+   #pragma omp error clauses[optseq] new-line  */
+
+static bool
+c_parser_omp_error (c_parser *parser, enum pragma_context context)
+{
+  int at_compilation = -1;
+  int severity_fatal = -1;
+  tree message = NULL_TREE;
+  bool first = true;
+  bool bad = false;
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  c_parser_consume_pragma (parser);
+
+  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    {
+      if (!first
+	  && c_parser_next_token_is (parser, CPP_COMMA)
+	  && c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+	c_parser_consume_token (parser);
+
+      first = false;
+
+      if (!c_parser_next_token_is (parser, CPP_NAME))
+	break;
+
+      const char *p
+	= IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      location_t cloc = c_parser_peek_token (parser)->location;
+      static const char *args[] = {
+	"execution", "compilation", "warning", "fatal"
+      };
+      int *v = NULL;
+      int idx = 0, n = -1;
+      tree m = NULL_TREE;
+
+      if (!strcmp (p, "at"))
+	v = &at_compilation;
+      else if (!strcmp (p, "severity"))
+	{
+	  v = &severity_fatal;
+	  idx += 2;
+	}
+      else if (strcmp (p, "message"))
+	{
+	  error_at (cloc,
+		    "expected %<at%>, %<severity%> or %<message%> clause");
+	  c_parser_skip_to_pragma_eol (parser, false);
+	  return false;
+	}
+
+      c_parser_consume_token (parser);
+
+      matching_parens parens;
+      if (parens.require_open (parser))
+	{
+	  if (v == NULL)
+	    {
+	      location_t expr_loc = c_parser_peek_token (parser)->location;
+	      c_expr expr = c_parser_expr_no_commas (parser, NULL);
+	      expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true);
+	      m = convert (const_string_type_node, expr.value);
+	      m = c_fully_fold (m, false, NULL);
+	    }
+	  else
+	    {
+	      if (c_parser_next_token_is (parser, CPP_NAME))
+		{
+		  tree val = c_parser_peek_token (parser)->value;
+		  const char *q = IDENTIFIER_POINTER (val);
+
+		  if (!strcmp (q, args[idx]))
+		    n = 0;
+		  else if (!strcmp (q, args[idx + 1]))
+		    n = 1;
+		}
+	      if (n == -1)
+		{
+		  error_at (c_parser_peek_token (parser)->location,
+			    "expected %qs or %qs", args[idx], args[idx + 1]);
+		  bad = true;
+		  switch (c_parser_peek_token (parser)->type)
+		    {
+		    case CPP_EOF:
+		    case CPP_PRAGMA_EOL:
+		    case CPP_CLOSE_PAREN:
+		      break;
+		    default:
+		      if (c_parser_peek_2nd_token (parser)->type
+			  == CPP_CLOSE_PAREN)
+			c_parser_consume_token (parser);
+		      break;
+		    }
+		}
+	      else
+		c_parser_consume_token (parser);
+	    }
+
+	  parens.skip_until_found_close (parser);
+
+	  if (v == NULL)
+	    {
+	      if (message)
+		{
+		  error_at (cloc, "too many %qs clauses", p);
+		  bad = true;
+		}
+	      else
+		message = m;
+	    }
+	  else if (n != -1)
+	    {
+	      if (*v != -1)
+		{
+		  error_at (cloc, "too many %qs clauses", p);
+		  bad = true;
+		}
+	      else
+		*v = n;
+	    }
+	}
+      else
+	bad = true;
+    }
+  c_parser_skip_to_pragma_eol (parser);
+  if (bad)
+    return true;
+
+  if (at_compilation == -1)
+    at_compilation = 1;
+  if (severity_fatal == -1)
+    severity_fatal = 1;
+  if (!at_compilation)
+    {
+      if (context != pragma_compound)
+	{
+	  error_at (loc, "%<#pragma omp error%> with %<at(execution)%> clause "
+			 "may only be used in compound statements");
+	  return true;
+	}
+      tree fndecl
+	= builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR
+						: BUILT_IN_GOMP_WARNING);
+      if (!message)
+	message = build_zero_cst (const_string_type_node);
+      tree stmt = build_call_expr_loc (loc, fndecl, 2, message,
+				       build_all_ones_cst (size_type_node));
+      add_stmt (stmt);
+      return true;
+    }
+  const char *msg = NULL;
+  if (message)
+    {
+      msg = c_getstr (message);
+      if (msg == NULL)
+	msg = _("<message unknown at compile time>");
+    }
+  if (msg)
+    emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+		     "%<pragma omp error%> encountered: %s", msg);
+  else
+    emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+		     "%<pragma omp error%> encountered");
+  return false;
+}
+
 /* Main entry point to parsing most OpenMP pragmas.  */
 
 static void
diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp
index f3ab79c467c..1b5241c8d30 100644
--- a/gcc/cp/ChangeLog.omp
+++ b/gcc/cp/ChangeLog.omp
@@ -1,3 +1,13 @@
+2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-20  Jakub Jelinek  <jakub@redhat.com>
+
+	* parser.c (cp_parser_handle_statement_omp_attributes): Determine if
+	PRAGMA_OMP_ERROR directive is C_OMP_DIR_STANDALONE.
+	(cp_parser_omp_error): New function.
+	(cp_parser_pragma): Handle PRAGMA_OMP_ERROR.
+
 2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 11d2f438021..27e9f8b8944 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11724,10 +11724,30 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs)
 				    "depend") == 0)
 		  kind = C_OMP_DIR_STANDALONE;
 	      }
-	    /* else if (dir->id == PRAGMA_OMP_ERROR)
+	    else if (dir->id == PRAGMA_OMP_ERROR)
 	      {
-		error with at(execution) clause is C_OMP_DIR_STANDALONE.
-	      }  */
+		/* error with at(execution) clause is C_OMP_DIR_STANDALONE.  */
+		int paren_depth = 0;
+		for (int i = 1; first + i < last; i++)
+		  if (first[i].type == CPP_OPEN_PAREN)
+		    paren_depth++;
+		  else if (first[i].type == CPP_CLOSE_PAREN)
+		    paren_depth--;
+		  else if (paren_depth == 0
+			   && first + i + 2 < last
+			   && first[i].type == CPP_NAME
+			   && first[i + 1].type == CPP_OPEN_PAREN
+			   && first[i + 2].type == CPP_NAME
+			   && !strcmp (IDENTIFIER_POINTER (first[i].u.value),
+				       "at")
+			   && !strcmp (IDENTIFIER_POINTER (first[i
+								 + 2].u.value),
+				       "execution"))
+		    {
+		      kind = C_OMP_DIR_STANDALONE;
+		      break;
+		    }
+	      }
 	    cp_omp_attribute_data v = { DEFPARSE_TOKENS (d), dir, kind };
 	    vec.safe_push (v);
 	    if (flag_openmp || dir->simd)
@@ -45379,6 +45399,184 @@ cp_parser_omp_nothing (cp_parser *parser, cp_token *pragma_tok)
 }
 
 
+/* OpenMP 5.1
+   #pragma omp error clauses[optseq] new-line  */
+
+static bool
+cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok,
+		     enum pragma_context context)
+{
+  int at_compilation = -1;
+  int severity_fatal = -1;
+  tree message = NULL_TREE;
+  bool first = true;
+  bool bad = false;
+  location_t loc = pragma_tok->location;
+
+  while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+    {
+      /* For now only in C++ attributes, do it always for OpenMP 5.1.  */
+      if ((!first || parser->lexer->in_omp_attribute_pragma)
+	  && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+	  && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+	cp_lexer_consume_token (parser->lexer);
+
+      first = false;
+
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+	break;
+
+      const char *p
+	= IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
+      location_t cloc = cp_lexer_peek_token (parser->lexer)->location;
+      static const char *args[] = {
+	"execution", "compilation", "warning", "fatal"
+      };
+      int *v = NULL;
+      int idx = 0, n = -1;
+      tree m = NULL_TREE;
+
+      if (!strcmp (p, "at"))
+	v = &at_compilation;
+      else if (!strcmp (p, "severity"))
+	{
+	  v = &severity_fatal;
+	  idx += 2;
+	}
+      else if (strcmp (p, "message"))
+	{
+	  error_at (cloc,
+		    "expected %<at%>, %<severity%> or %<message%> clause");
+	  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+	  return false;
+	}
+
+      cp_lexer_consume_token (parser->lexer);
+
+      matching_parens parens;
+      if (parens.require_open (parser))
+	{
+	  if (v == NULL)
+	    {
+	      m = cp_parser_assignment_expression (parser);
+	      if (type_dependent_expression_p (m))
+		m = build1 (IMPLICIT_CONV_EXPR, const_string_type_node, m);
+	      else
+		m = perform_implicit_conversion_flags (const_string_type_node, m,
+						       tf_warning_or_error,
+						       LOOKUP_NORMAL);
+	    }
+	  else
+	    {
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+		{
+		  tree val = cp_lexer_peek_token (parser->lexer)->u.value;
+		  const char *q = IDENTIFIER_POINTER (val);
+
+		  if (!strcmp (q, args[idx]))
+		    n = 0;
+		  else if (!strcmp (q, args[idx + 1]))
+		    n = 1;
+		}
+	      if (n == -1)
+		{
+		  error_at (cp_lexer_peek_token (parser->lexer)->location,
+			    "expected %qs or %qs", args[idx], args[idx + 1]);
+		  bad = true;
+		  switch (cp_lexer_peek_token (parser->lexer)->type)
+		    {
+		    case CPP_EOF:
+		    case CPP_PRAGMA_EOL:
+		    case CPP_CLOSE_PAREN:
+		      break;
+		    default:
+		      if (cp_lexer_nth_token_is (parser->lexer, 2,
+						 CPP_CLOSE_PAREN))
+			cp_lexer_consume_token (parser->lexer);
+		      break;
+		    }
+		}
+	      else
+		cp_lexer_consume_token (parser->lexer);
+	    }
+
+	  if (!parens.require_close (parser))
+	    cp_parser_skip_to_closing_parenthesis (parser,
+						   /*recovering=*/true,
+						   /*or_comma=*/false,
+						   /*consume_paren=*/
+						   true);
+
+	  if (v == NULL)
+	    {
+	      if (message)
+		{
+		  error_at (cloc, "too many %qs clauses", p);
+		  bad = true;
+		}
+	      else
+		message = m;
+	    }
+	  else if (n != -1)
+	    {
+	      if (*v != -1)
+		{
+		  error_at (cloc, "too many %qs clauses", p);
+		  bad = true;
+		}
+	      else
+		*v = n;
+	    }
+	}
+      else
+	bad = true;
+    }
+  cp_parser_require_pragma_eol (parser, pragma_tok);
+  if (bad)
+    return true;
+
+  if (at_compilation == -1)
+    at_compilation = 1;
+  if (severity_fatal == -1)
+    severity_fatal = 1;
+  if (!at_compilation)
+    {
+      if (context != pragma_compound)
+	{
+	  error_at (loc, "%<#pragma omp error%> with %<at(execution)%> clause "
+			 "may only be used in compound statements");
+	  return true;
+	}
+      tree fndecl
+	= builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR
+						: BUILT_IN_GOMP_WARNING);
+      if (!message)
+	message = build_zero_cst (const_string_type_node);
+      tree stmt = build_call_expr_loc (loc, fndecl, 2, message,
+				       build_all_ones_cst (size_type_node));
+      add_stmt (stmt);
+      return true;
+    }
+
+  if (in_discarded_stmt)
+    return false;
+
+  const char *msg = NULL;
+  if (message)
+    {
+      msg = c_getstr (fold_for_warn (message));
+      if (msg == NULL)
+	msg = _("<message unknown at compile time>");
+    }
+  if (msg)
+    emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+		     "%<pragma omp error%> encountered: %s", msg);
+  else
+    emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+		     "%<pragma omp error%> encountered");
+  return false;
+}
+
 /* OpenMP 4.5:
    #pragma omp taskloop taskloop-clause[optseq] new-line
      for-loop
@@ -46492,6 +46690,9 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
       cp_parser_omp_nothing (parser, pragma_tok);
       return false;
 
+    case PRAGMA_OMP_ERROR:
+      return cp_parser_omp_error (parser, pragma_tok, context);
+
     case PRAGMA_OMP_ORDERED:
       if (context != pragma_stmt && context != pragma_compound)
 	goto bad_stmt;
diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp
index a6acea420df..1d5122525eb 100644
--- a/gcc/fortran/ChangeLog.omp
+++ b/gcc/fortran/ChangeLog.omp
@@ -1,3 +1,11 @@
+2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-20  Jakub Jelinek  <jakub@redhat.com>
+
+	* types.def (BT_FN_VOID_CONST_PTR_SIZE): New DEF_FUNCTION_TYPE_2.
+	* f95-lang.c (ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST): Define.
+
 2021-08-11  Sandra Loosemore  <sandra@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index bf8f38e3031..1b3ea0f67c6 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -535,7 +535,7 @@ gfc_builtin_function (tree decl)
   return decl;
 }
 
-/* So far we need just these 8 attribute types.  */
+/* So far we need just these 10 attribute types.  */
 #define ATTR_NULL			0
 #define ATTR_LEAF_LIST			(ECF_LEAF)
 #define ATTR_NOTHROW_LEAF_LIST		(ECF_NOTHROW | ECF_LEAF)
@@ -546,6 +546,9 @@ gfc_builtin_function (tree decl)
 #define ATTR_CONST_NOTHROW_LIST		(ECF_NOTHROW | ECF_CONST)
 #define ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST \
 					(ECF_NOTHROW)
+#define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
+					(ECF_COLD | ECF_NORETURN | \
+					 ECF_NOTHROW | ECF_LEAF)
 
 static void
 gfc_define_builtin (const char *name, tree type, enum built_in_function code,
diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def
index bd51a22d7a0..87633045c3e 100644
--- a/gcc/fortran/types.def
+++ b/gcc/fortran/types.def
@@ -120,6 +120,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
 DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
 DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTRMODE,
 		     BT_VOID, BT_PTR, BT_PTRMODE)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_CONST_PTR_SIZE, BT_VOID, BT_CONST_PTR, BT_SIZE)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def
index 48b1c475de2..bc783cf123d 100644
--- a/gcc/omp-builtins.def
+++ b/gcc/omp-builtins.def
@@ -461,3 +461,7 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ALLOC,
 		  ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_FREE,
 		  "GOMP_free", BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_WARNING, "GOMP_warning",
+		  BT_FN_VOID_CONST_PTR_SIZE, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ERROR, "GOMP_error",
+		  BT_FN_VOID_CONST_PTR_SIZE, ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index 7b27cb3cfb0..64c2b59e5ae 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,16 @@
+2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-20  Jakub Jelinek  <jakub@redhat.com>
+
+	* c-c++-common/gomp/error-1.c: New test.
+	* c-c++-common/gomp/error-2.c: New test.
+	* c-c++-common/gomp/error-3.c: New test.
+	* g++.dg/gomp/attrs-1.C (bar): Add error directive test.
+	* g++.dg/gomp/attrs-2.C (bar): Add error directive test.
+	* g++.dg/gomp/attrs-13.C: New test.
+	* g++.dg/gomp/error-1.C: New test.
+
 2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/testsuite/c-c++-common/gomp/error-1.c b/gcc/testsuite/c-c++-common/gomp/error-1.c
new file mode 100644
index 00000000000..6a40f85b382
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/error-1.c
@@ -0,0 +1,45 @@
+#pragma omp error			/* { dg-error "'pragma omp error' encountered" } */
+#pragma omp error at(compilation)	/* { dg-error "'pragma omp error' encountered" } */
+#pragma omp error severity(fatal)	/* { dg-error "'pragma omp error' encountered" } */
+#pragma omp error message("my msg")	/* { dg-error "'pragma omp error' encountered: my msg" } */
+#pragma omp error severity(warning)message("another message")at(compilation)	/* { dg-warning "'pragma omp error' encountered: another message" } */
+
+struct S {
+  #pragma omp error			/* { dg-error "'pragma omp error' encountered" } */
+  #pragma omp error at(compilation)	/* { dg-error "'pragma omp error' encountered" } */
+  #pragma omp error severity(fatal)	/* { dg-error "'pragma omp error' encountered" } */
+  #pragma omp error message("42")	/* { dg-error "'pragma omp error' encountered: 42" } */
+  #pragma omp error severity(warning), message("foo"), at(compilation)	/* { dg-warning "'pragma omp error' encountered: foo" } */
+  int s;
+};
+
+int
+foo (int i, int x)
+{
+  #pragma omp error			/* { dg-error "'pragma omp error' encountered" } */
+  #pragma omp error at(compilation)	/* { dg-error "'pragma omp error' encountered" } */
+  #pragma omp error severity(fatal)	/* { dg-error "'pragma omp error' encountered" } */
+  #pragma omp error message("42 / 1")	/* { dg-error "'pragma omp error' encountered: 42 / 1" } */
+  #pragma omp error severity(warning) message("bar") at(compilation)	/* { dg-warning "'pragma omp error' encountered: bar" } */
+  if (x)
+    #pragma omp error			/* { dg-error "'pragma omp error' encountered" } */
+    i++;
+  if (x)
+    ;
+  else
+    #pragma omp error at(compilation)	/* { dg-error "'pragma omp error' encountered" } */
+    i++;
+  switch (0)
+    #pragma omp error severity(fatal)	/* { dg-error "'pragma omp error' encountered" } */
+    {
+    default:
+      break;
+    }
+  while (0)
+    #pragma omp error message("42 - 1")	/* { dg-error "'pragma omp error' encountered: 42 - 1" } */
+    i++;
+  lab:
+  #pragma omp error severity(warning) message("bar") at(compilation)	/* { dg-warning "'pragma omp error' encountered: bar" } */
+    i++;
+  return i;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/error-2.c b/gcc/testsuite/c-c++-common/gomp/error-2.c
new file mode 100644
index 00000000000..4e13f03ec8d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/error-2.c
@@ -0,0 +1,24 @@
+void
+foo (int x, const char *msg1, const char *msg2)
+{
+  if (x == 0)
+    {
+      #pragma omp error at(execution)
+    }
+  else if (x == 1)
+    {
+      #pragma omp error severity (warning), at (execution)
+    }
+  else if (x == 2)
+    {
+      #pragma omp error at ( execution ) severity (fatal) message ("baz")
+    }
+  else if (x == 3)
+    {
+      #pragma omp error severity(warning) message (msg1) at(execution)
+    }
+  else
+    {
+      #pragma omp error message (msg2), at(execution), severity(fatal)
+    }
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/error-3.c b/gcc/testsuite/c-c++-common/gomp/error-3.c
new file mode 100644
index 00000000000..d2b8b830bd1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/error-3.c
@@ -0,0 +1,70 @@
+#pragma omp error asdf				/* { dg-error "expected 'at', 'severity' or 'message' clause" } */
+#pragma omp error at				/* { dg-error "expected '\\\(' before end of line" } */
+#pragma omp error at(				/* { dg-error "expected 'execution' or 'compilation'" } */
+						/* { dg-error "expected '\\\)' before end of line" "" { target *-*-* } .-1 } */
+#pragma omp error at(runtime)			/* { dg-error "expected 'execution' or 'compilation'" } */
+#pragma omp error at(+				/* { dg-error "expected 'execution' or 'compilation'" } */
+						/* { dg-error "expected '\\\)' before '\\\+' token" "" { target *-*-* } .-1 } */
+#pragma omp error at(compilation		/* { dg-error "expected '\\\)' before end of line" } */
+						/* { dg-error "'pragma omp error' encountered" "" { target *-*-* } .-1 } */
+#pragma omp error severity			/* { dg-error "expected '\\\(' before end of line" } */
+#pragma omp error severity(			/* { dg-error "expected 'warning' or 'fatal'" } */
+						/* { dg-error "expected '\\\)' before end of line" "" { target *-*-* } .-1 } */
+#pragma omp error severity(error)		/* { dg-error "expected 'warning' or 'fatal'" } */
+#pragma omp error severity(-			/* { dg-error "expected 'warning' or 'fatal'" } */
+						/* { dg-error "expected '\\\)' before '-' token" "" { target *-*-* } .-1 } */
+#pragma omp error severity(fatal		/* { dg-error "expected '\\\)' before end of line" } */
+						/* { dg-error "'pragma omp error' encountered" "" { target *-*-* } .-1 } */
+#pragma omp error message			/* { dg-error "expected '\\\(' before end of line" } */
+#pragma omp error message(			/* { dg-error "expected expression before end of line" "" { target c } } */
+						/* { dg-error "expected primary-expression before end of line" "" { target c++ } .-1 } */
+						/* { dg-error "expected '\\\)' before end of line" "" { target c++ } .-2 } */
+						/* { dg-error "'pragma omp error' encountered: <message unknown at compile time>" "" { target *-*-* } .-3 } */
+#pragma omp error message(0			/* { dg-error "expected '\\\)' before end of line" } */
+						/* { dg-error "'pragma omp error' encountered: <message unknown at compile time>" "" { target *-*-* } .-1 } */
+#pragma omp error message("foo"			/* { dg-error "expected '\\\)' before end of line" } */
+						/* { dg-error "'pragma omp error' encountered: foo" "" { target *-*-* } .-1 } */
+#pragma omp error message(1)			/* { dg-error "'pragma omp error' encountered: <message unknown at compile time>" } */
+						/* { dg-error "invalid conversion from 'int' to 'const char\\*'" "" { target c++ } .-1 } */
+#pragma omp error message(1.2)			/* { dg-error "cannot convert to a pointer type" "" { target c } } */
+						/* { dg-error "could not convert" "" { target c++ } .-1 } */
+						/* { dg-error "'pragma omp error' encountered: <message unknown at compile time>" "" { target *-*-* } .-2 } */
+#pragma omp error message(L"bar")		/* { dg-error "'pragma omp error' encountered: <message unknown at compile time>" } */
+						/* { dg-error "could not convert" "" { target c++ } .-1 } */
+#pragma omp error message("foo"),at(compilation),severity(fatal),	/* { dg-error "expected end of line before ',' token" } */
+						/* { dg-error "'pragma omp error' encountered: foo" "" { target *-*-* } .-1 } */
+#pragma omp error message("foo"),at(compilation),severity(fatal),asdf	/* { dg-error "expected 'at', 'severity' or 'message' clause" } */
+#pragma omp error at(compilation) at(compilation)	/* { dg-error "too many 'at' clauses" } */
+#pragma omp error severity(fatal) severity(warning)	/* { dg-error "too many 'severity' clauses" } */
+#pragma omp error message("foo") message("foo")		/* { dg-error "too many 'message' clauses" } */
+#pragma omp error at(execution)			/* { dg-error "'#pragma omp error' with 'at\\\(execution\\\)' clause may only be used in compound statements" } */
+
+struct S
+{
+  #pragma omp error at(execution) message("foo")/* { dg-error "'#pragma omp error' with 'at\\\(execution\\\)' clause may only be used in compound statements" } */
+  int s;
+};
+
+int
+foo (int i, int x, const char *msg)
+{
+  #pragma omp error message(msg)		/* { dg-error "'pragma omp error' encountered: <message unknown at compile time>" } */
+  if (x)
+    #pragma omp error at(execution)		/* { dg-error "'#pragma omp error' with 'at\\\(execution\\\)' clause may only be used in compound statements" } */
+  i++;
+  if (x)
+    ;
+  else
+    #pragma omp error at(execution) severity(warning)	/* { dg-error "'#pragma omp error' with 'at\\\(execution\\\)' clause may only be used in compound statements" } */
+  i++;
+  switch (0)
+    #pragma omp error severity(fatal) at(execution)	/* { dg-error "'#pragma omp error' with 'at\\\(execution\\\)' clause may only be used in compound statements" } */
+    ;
+  while (0)
+    #pragma omp error at(execution)message("42 - 1")	/* { dg-error "'#pragma omp error' with 'at\\\(execution\\\)' clause may only be used in compound statements" } */
+    i++;
+  lab:
+  #pragma omp error severity(warning) message("bar") at(execution)	/* { dg-error "'#pragma omp error' with 'at\\\(execution\\\)' clause may only be used in compound statements" } */
+    i++;
+  return i;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C
index 435d54fb762..cd20845b634 100644
--- a/gcc/testsuite/g++.dg/gomp/attrs-1.C
+++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C
@@ -109,9 +109,11 @@ baz (int d, int m, int i1, int i2, int p, int *idp, int s,
 
 void
 bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
-     int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm)
+     int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm,
+     const char *msg)
 {
   [[omp::directive (nothing)]];
+  [[omp::directive (error at (execution) severity (warning) message (msg))]];
   [[omp::directive (for simd
     private (p) firstprivate (f) lastprivate (l) linear (ll:1) reduction(+:r) schedule(static, 4) collapse(1) nowait
     safelen(8) simdlen(4) aligned(q: 32) nontemporal(ntm) if(i1) order(concurrent) allocate (f))]]
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-13.C b/gcc/testsuite/g++.dg/gomp/attrs-13.C
new file mode 100644
index 00000000000..35e2435cb74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/attrs-13.C
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++11 } }
+
+[[omp::directive(error)]];			// { dg-error "'pragma omp error' encountered" }
+[[omp::directive(error, at(compilation))]];	// { dg-error "'pragma omp error' encountered" }
+[[omp::directive(error severity(fatal))]];	// { dg-error "'pragma omp error' encountered" }
+[[omp::directive(error, message("my msg"))]];	// { dg-error "'pragma omp error' encountered: my msg" }
+[[omp::directive(error severity(warning)message("another message")at(compilation))]];	// { dg-warning "'pragma omp error' encountered: another message" }
+
+int
+foo (int i, int x)
+{
+  [[omp::directive(error)]];			// { dg-error "'pragma omp error' encountered" }
+  [[omp::directive(error, at(compilation))]];	// { dg-error "'pragma omp error' encountered" }
+  [[omp::directive(error severity(fatal))]];	// { dg-error "'pragma omp error' encountered" }
+  [[omp::directive(error, message("42 / 1"))]];	// { dg-error "'pragma omp error' encountered: 42 / 1" }
+  [[omp::directive(error severity(warning) message("bar") at(compilation))]];	// { dg-warning "'pragma omp error' encountered: bar" }
+  if (x)
+    [[omp::directive(error)]];			// { dg-error "'pragma omp error' encountered" }
+  i++;
+  if (x)
+    ;
+  else
+    [[omp::directive(error at(compilation))]];	// { dg-error "'pragma omp error' encountered" }
+  i++;
+  switch (0)
+    [[omp::directive(error, severity(fatal))]];	// { dg-error "'pragma omp error' encountered" }
+  while (0)
+    [[omp::directive(error, message("42 - 1"))]];	// { dg-error "'pragma omp error' encountered: 42 - 1" }
+  i++;
+  lab:
+  [[omp::directive(error, severity(warning) message("bar"), at(compilation))]];	// { dg-warning "'pragma omp error' encountered: bar" }
+  i++;
+  return i;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C
index bea657f02b9..5c54905576d 100644
--- a/gcc/testsuite/g++.dg/gomp/attrs-2.C
+++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C
@@ -109,9 +109,11 @@ baz (int d, int m, int i1, int i2, int p, int *idp, int s,
 
 void
 bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
-     int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm)
+     int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm,
+     const char *msg)
 {
   [[omp::directive (nothing)]];
+  [[omp::directive (error, at (execution), severity (warning), message (msg))]];
   [[omp::directive (for simd,
     private (p),firstprivate (f),lastprivate (l),linear (ll:1),reduction(+:r),schedule(static, 4),collapse(1),nowait,
     safelen(8),simdlen(4),aligned(q: 32),nontemporal(ntm),if(i1),order(concurrent),allocate (f))]]
diff --git a/gcc/testsuite/g++.dg/gomp/error-1.C b/gcc/testsuite/g++.dg/gomp/error-1.C
new file mode 100644
index 00000000000..a636550bc0c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/error-1.C
@@ -0,0 +1,42 @@
+// { dg-do compile { target c++17 } }
+
+void
+foo ()
+{
+  if constexpr (false)
+    {
+      #pragma omp error								// { dg-bogus "'pragma omp error' encountered" }
+    }
+  else
+    {
+      #pragma omp error at(compilation) severity(warning) message("foo")	// { dg-warning "'pragma omp error' encountered: foo" }
+    }
+  if constexpr (true)
+    {
+      #pragma omp error message("bar")						// { dg-error "'pragma omp error' encountered: bar" }
+    }
+  else
+    {
+      #pragma omp error message("baz")						// { dg-bogus "'pragma omp error' encountered" }
+    }
+}
+
+template <typename T>
+bool
+bar (T x)
+{
+  #pragma omp error at(execution) message (x)
+  return false;
+}
+
+bool a = bar ("foo");
+
+template <typename T>
+bool
+baz (T x)
+{
+  #pragma omp error at(execution) message (x)					// { dg-error "could not convert" }
+  return false;
+}
+
+bool b = baz (L"foo");
diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp
index c6e8facc9fc..33090eefb7d 100644
--- a/libgomp/ChangeLog.omp
+++ b/libgomp/ChangeLog.omp
@@ -1,3 +1,13 @@
+2021-08-20  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-20  Jakub Jelinek  <jakub@redhat.com>
+
+	* libgomp.map (GOMP_5.1): Add GOMP_error and GOMP_warning.
+	* libgomp_g.h (GOMP_warning, GOMP_error): Declare.
+	* error.c (GOMP_warning, GOMP_error): New functions.
+	* testsuite/libgomp.c-c++-common/error-1.c: New test.
+
 2021-08-18  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/libgomp/error.c b/libgomp/error.c
index 3ddf3aafa49..9b69a4b33fe 100644
--- a/libgomp/error.c
+++ b/libgomp/error.c
@@ -89,3 +89,34 @@ gomp_fatal (const char *fmt, ...)
   gomp_vfatal (fmt, list);
   va_end (list);
 }
+
+void
+GOMP_warning (const char *msg, size_t msglen)
+{
+  if (msg && msglen == (size_t) -1)
+    gomp_error ("error directive encountered: %s", msg);
+  else if (msg)
+    {
+      fputs ("\nlibgomp: error directive encountered: ", stderr);
+      fwrite (msg, 1, msglen, stderr);
+      fputc ('\n', stderr);
+    }
+  else
+    gomp_error ("error directive encountered");
+}
+
+void
+GOMP_error (const char *msg, size_t msglen)
+{
+  if (msg && msglen == (size_t) -1)
+    gomp_fatal ("fatal error: error directive encountered: %s", msg);
+  else if (msg)
+    {
+      fputs ("\nlibgomp: fatal error: error directive encountered: ", stderr);
+      fwrite (msg, 1, msglen, stderr);
+      fputc ('\n', stderr);
+      exit (EXIT_FAILURE);
+    }
+  else
+    gomp_fatal ("fatal error: error directive encountered");
+}
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index ef844ea77e6..e5ac670029c 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -382,7 +382,9 @@ GOMP_5.0.1 {
 
 GOMP_5.1 {
   global:
+	GOMP_error;
 	GOMP_scope_start;
+	GOMP_warning;
 } GOMP_5.0.1;
 
 OACC_2.0 {
diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h
index 236bcf3cbd2..c24df8059dd 100644
--- a/libgomp/libgomp_g.h
+++ b/libgomp/libgomp_g.h
@@ -366,6 +366,11 @@ extern void GOMP_teams_reg (void (*) (void *), void *, unsigned, unsigned,
 extern void *GOMP_alloc (size_t, size_t, uintptr_t);
 extern void GOMP_free (void *, uintptr_t);
 
+/* error.c */
+
+extern void GOMP_warning (const char *, size_t);
+extern void GOMP_error (const char *, size_t);
+
 /* oacc-async.c */
 
 extern void GOACC_wait (int, int, ...);
diff --git a/libgomp/testsuite/libgomp.c-c++-common/error-1.c b/libgomp/testsuite/libgomp.c-c++-common/error-1.c
new file mode 100644
index 00000000000..5f454c1adaa
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/error-1.c
@@ -0,0 +1,49 @@
+/* { dg-shouldfail "error directive" } */
+
+#ifdef __cplusplus
+extern "C"
+#endif
+void abort ();
+
+int
+foo (int i, int x)
+{
+  if (x)
+    #pragma omp error severity(warning)	/* { dg-warning "'pragma omp error' encountered" } */
+    i++;
+  if (!x)
+    ;
+  else
+    #pragma omp error severity(warning)	/* { dg-warning "'pragma omp error' encountered" } */
+    i += 2;
+  switch (0)
+    #pragma omp error severity(warning)	/* { dg-warning "'pragma omp error' encountered" } */
+    {
+    default:
+      break;
+    }
+  while (0)
+    #pragma omp error message("42 - 1")	severity (warning) /* { dg-warning "'pragma omp error' encountered: 42 - 1" } */
+    i += 4;
+  lab:
+  #pragma omp error severity(warning) message("bar") at(compilation)	/* { dg-warning "'pragma omp error' encountered: bar" } */
+    i += 8;
+  return i;
+}
+
+int
+main ()
+{
+  if (foo (5, 0) != 13 || foo (6, 1) != 17)
+    abort ();
+  #pragma omp error at (execution) severity (warning)
+  const char *msg = "my message" + 2;
+  #pragma omp error at (execution) severity (warning) message (msg + 1)
+  #pragma omp error at (execution) severity (fatal) message (msg - 2)
+  #pragma omp error at (execution) severity (warning) message ("foobar")
+  return 0;
+}
+
+/* { 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: fatal error: error directive encountered: my message" } */


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

only message in thread, other threads:[~2021-08-20 13:31 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-20 13:31 [gcc/devel/omp/gcc-11] openmp: Implement the error directive 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).