--- gcc/omp-builtins.def.jj	2021-08-19 12:53:44.693106618 +0200
+++ gcc/omp-builtins.def	2021-08-19 17:46:45.960368837 +0200
@@ -463,3 +463,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)
--- gcc/c-family/c-pragma.h.jj	2021-08-19 12:53:44.690106660 +0200
+++ gcc/c-family/c-pragma.h	2021-08-19 14:37:58.004167196 +0200
@@ -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,
--- gcc/c-family/c-pragma.c.jj	2021-08-19 12:53:44.690106660 +0200
+++ gcc/c-family/c-pragma.c	2021-08-19 14:37:58.004167196 +0200
@@ -1326,6 +1326,7 @@ static const struct omp_pragma_def omp_p
   { "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 },
--- gcc/c-family/c-omp.c.jj	2021-08-19 12:53:44.690106660 +0200
+++ gcc/c-family/c-omp.c	2021-08-19 14:37:58.004167196 +0200
@@ -2991,8 +2991,8 @@ static const struct c_omp_directive omp_
   /* { "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,
--- gcc/c/c-parser.c.jj	2021-08-19 13:19:56.217288105 +0200
+++ gcc/c/c-parser.c	2021-08-19 15:22:10.146195464 +0200
@@ -1588,6 +1588,7 @@ static bool c_parser_omp_target (c_parse
 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);
 
@@ -12485,6 +12486,9 @@ c_parser_pragma (c_parser *parser, enum
       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);
 
@@ -21936,6 +21940,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
--- gcc/cp/parser.c.jj	2021-08-19 13:40:26.387178416 +0200
+++ gcc/cp/parser.c	2021-08-19 17:47:20.769883975 +0200
@@ -11760,10 +11760,30 @@ cp_parser_handle_statement_omp_attribute
 				    "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)
@@ -45590,6 +45610,184 @@ cp_parser_omp_nothing (cp_parser *parser
 }
 
 
+/* 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
@@ -46703,6 +46901,9 @@ cp_parser_pragma (cp_parser *parser, enu
       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;
--- gcc/fortran/types.def.jj	2021-08-17 09:24:58.778051205 +0200
+++ gcc/fortran/types.def	2021-08-19 17:47:10.548026356 +0200
@@ -120,6 +120,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_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)
 
--- gcc/fortran/f95-lang.c.jj	2021-08-19 12:53:44.693106618 +0200
+++ gcc/fortran/f95-lang.c	2021-08-19 14:37:58.004167196 +0200
@@ -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,
--- gcc/testsuite/c-c++-common/gomp/error-1.c.jj	2021-08-19 14:37:58.000167251 +0200
+++ gcc/testsuite/c-c++-common/gomp/error-1.c	2021-08-19 14:37:57.999167265 +0200
@@ -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;
+}
--- gcc/testsuite/c-c++-common/gomp/error-2.c.jj	2021-08-19 14:37:58.000167251 +0200
+++ gcc/testsuite/c-c++-common/gomp/error-2.c	2021-08-19 14:37:58.000167251 +0200
@@ -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)
+    }
+}
--- gcc/testsuite/c-c++-common/gomp/error-3.c.jj	2021-08-19 14:37:58.000167251 +0200
+++ gcc/testsuite/c-c++-common/gomp/error-3.c	2021-08-19 17:41:51.712467429 +0200
@@ -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;
+}
--- gcc/testsuite/g++.dg/gomp/attrs-1.C.jj	2021-08-19 11:42:27.417421677 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-1.C	2021-08-19 17:05:23.953934117 +0200
@@ -109,9 +109,11 @@ baz (int d, int m, int i1, int i2, int p
 
 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))]]
--- gcc/testsuite/g++.dg/gomp/attrs-2.C.jj	2021-08-19 11:42:27.421421621 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-2.C	2021-08-19 17:05:06.757173496 +0200
@@ -109,9 +109,11 @@ baz (int d, int m, int i1, int i2, int p
 
 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))]]
--- gcc/testsuite/g++.dg/gomp/attrs-13.C.jj	2021-08-19 17:09:01.228909636 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-13.C	2021-08-19 17:57:29.933397757 +0200
@@ -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;
+}
--- gcc/testsuite/g++.dg/gomp/error-1.C.jj	2021-08-19 17:18:58.231599327 +0200
+++ gcc/testsuite/g++.dg/gomp/error-1.C	2021-08-19 17:56:41.478073032 +0200
@@ -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");
--- libgomp/libgomp.map.jj	2021-08-19 12:53:44.693106618 +0200
+++ libgomp/libgomp.map	2021-08-19 14:37:58.004167196 +0200
@@ -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 {
--- libgomp/libgomp_g.h.jj	2021-08-19 12:53:44.693106618 +0200
+++ libgomp/libgomp_g.h	2021-08-19 14:58:44.728786591 +0200
@@ -366,6 +366,11 @@ extern void GOMP_teams_reg (void (*) (vo
 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, ...);
--- libgomp/error.c.jj	2021-08-19 12:53:44.693106618 +0200
+++ libgomp/error.c	2021-08-19 17:58:55.633203432 +0200
@@ -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");
+}
--- libgomp/testsuite/libgomp.c-c++-common/error-1.c.jj	2021-08-19 15:26:12.576816311 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/error-1.c	2021-08-19 17:59:10.389997780 +0200
@@ -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" } */
