diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index d4e98bfd76b..18de7e42b93 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 238309d4a77..a9be8df0384 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 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/c-parser.c b/gcc/c/c-parser.c index ab79e9c0ea8..c5783075a99 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 %, % or % 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 % 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 = _(""); + } + if (msg) + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "% encountered: %s", msg); + else + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "% 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 d321364220c..63c95039854 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 %, % or % 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 % 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 = _(""); + } + if (msg) + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "% encountered: %s", msg); + else + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "% 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 5fc848158f9..026228da09f 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 8626ed0a4f8..85b85ed0580 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 b168575c917..4520dc01b93 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 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: " "" { target *-*-* } .-3 } */ +#pragma omp error message(0 /* { dg-error "expected '\\\)' before end of line" } */ + /* { dg-error "'pragma omp error' encountered: " "" { 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: " } */ + /* { 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: " "" { target *-*-* } .-2 } */ +#pragma omp error message(L"bar") /* { dg-error "'pragma omp error' encountered: " } */ + /* { 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: " } */ + 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 +bool +bar (T x) +{ + #pragma omp error at(execution) message (x) + return false; +} + +bool a = bar ("foo"); + +template +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 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 ac1653ea7c6..e0c813c2716 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 5e3612bf2db..40e5cf04907 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" } */