aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c-family/c-omp.c4
-rw-r--r--gcc/c-family/c-pragma.c1
-rw-r--r--gcc/c-family/c-pragma.h1
-rw-r--r--gcc/c/c-parser.c171
-rw-r--r--gcc/cp/parser.c207
-rw-r--r--gcc/fortran/f95-lang.c5
-rw-r--r--gcc/fortran/types.def1
-rw-r--r--gcc/omp-builtins.def4
-rw-r--r--gcc/testsuite/c-c++-common/gomp/error-1.c45
-rw-r--r--gcc/testsuite/c-c++-common/gomp/error-2.c24
-rw-r--r--gcc/testsuite/c-c++-common/gomp/error-3.c70
-rw-r--r--gcc/testsuite/g++.dg/gomp/attrs-1.C4
-rw-r--r--gcc/testsuite/g++.dg/gomp/attrs-13.C34
-rw-r--r--gcc/testsuite/g++.dg/gomp/attrs-2.C4
-rw-r--r--gcc/testsuite/g++.dg/gomp/error-1.C42
-rw-r--r--libgomp/error.c31
-rw-r--r--libgomp/libgomp.map2
-rw-r--r--libgomp/libgomp_g.h5
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/error-1.c49
19 files changed, 696 insertions, 8 deletions
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index d4e98bf..18de7e4 100644
--- a/gcc/c-family/c-omp.c
+++ b/gcc/c-family/c-omp.c
@@ -2991,8 +2991,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 238309d..a9be8df 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -1326,6 +1326,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 dc9e8a6..0c5b07a 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/c-parser.c b/gcc/c/c-parser.c
index ab79e9c..c578307 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1588,6 +1588,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);
@@ -12485,6 +12486,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);
@@ -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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d321364..63c9503 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11760,10 +11760,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)
@@ -45590,6 +45610,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
@@ -46703,6 +46901,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/f95-lang.c b/gcc/fortran/f95-lang.c
index 5fc8481..026228d 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 8626ed0..85b85ed 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 b168575..4520dc0 100644
--- a/gcc/omp-builtins.def
+++ b/gcc/omp-builtins.def
@@ -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)
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 0000000..6a40f85
--- /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 0000000..4e13f03
--- /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 0000000..d2b8b83
--- /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 435d54f..cd20845 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 0000000..35e2435
--- /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 bea657f..5c54905 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 0000000..a636550
--- /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/error.c b/libgomp/error.c
index 3ddf3aa..9b69a4b 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 ac1653e..e0c813c 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 5e3612b..40e5cf0 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 0000000..5f454c1
--- /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" } */