From: Jakub Jelinek Date: Fri, 23 Jul 2021 07:37:36 +0000 (+0200) Subject: openmp: Diagnose invalid mixing of the attribute and pragma syntax directives X-Git-Tag: basepoints/gcc-13~5830 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2c5d803d03209478b4f060785c6f6ba2f0de88ad;p=thirdparty%2Fgcc.git openmp: Diagnose invalid mixing of the attribute and pragma syntax directives The OpenMP 5.1 spec says that the attribute and pragma syntax directives should not be mixed on the same statement. The following patch adds diagnostic for that, [[omp::directive (...)]] #pragma omp ... is always an error and for the other order #pragma omp ... [[omp::directive (...)]] it depends on whether the pragma directive is an OpenMP construct (then it is an error because it needs a structured block or loop or statement as body) or e.g. a standalone directive (then it is fine). Only block scope is handled for now though, namespace scope and class scope still needs implementing even the basic support. 2021-07-23 Jakub Jelinek gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP__START_ and PRAGMA_OMP__LAST_ enumerators. gcc/cp/ * parser.h (struct cp_parser): Add omp_attrs_forbidden_p member. * parser.c (cp_parser_handle_statement_omp_attributes): Diagnose mixing of attribute and pragma syntax directives when seeing omp::directive if parser->omp_attrs_forbidden_p or if attribute syntax directives are followed by OpenMP pragma. (cp_parser_statement): Clear parser->omp_attrs_forbidden_p after the cp_parser_handle_statement_omp_attributes call. (cp_parser_omp_structured_block): Add disallow_omp_attrs argument, if true, set parser->omp_attrs_forbidden_p. (cp_parser_omp_scan_loop_body, cp_parser_omp_sections_scope): Pass false as disallow_omp_attrs to cp_parser_omp_structured_block. (cp_parser_omp_parallel, cp_parser_omp_task): Set parser->omp_attrs_forbidden_p. gcc/testsuite/ * g++.dg/gomp/attrs-4.C: New test. * g++.dg/gomp/attrs-5.C: New test. --- diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index c5d11ce0a524..abd66672f527 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -42,7 +42,9 @@ enum pragma_kind { PRAGMA_OACC_UPDATE, PRAGMA_OACC_WAIT, + /* PRAGMA_OMP__START_ should be equal to the first PRAGMA_OMP_* code. */ PRAGMA_OMP_ALLOCATE, + PRAGMA_OMP__START_ = PRAGMA_OMP_ALLOCATE, PRAGMA_OMP_ATOMIC, PRAGMA_OMP_BARRIER, PRAGMA_OMP_CANCEL, @@ -72,6 +74,8 @@ enum pragma_kind { PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, PRAGMA_OMP_TEAMS, + /* PRAGMA_OMP__LAST_ should be equal to the last PRAGMA_OMP_* code. */ + PRAGMA_OMP__LAST_ = PRAGMA_OMP_TEAMS, PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_IVDEP, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 45216f0a2222..18905cf0fbd7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11665,6 +11665,7 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) auto_vec vec; int cnt = 0; int tokens = 0; + bool bad = false; for (tree *pa = &attrs; *pa; ) if (get_attribute_namespace (*pa) == omp_identifier && is_attribute_p ("directive", get_attribute_name (*pa))) @@ -11676,6 +11677,14 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); cp_token *first = DEFPARSE_TOKENS (d)->first; cp_token *last = DEFPARSE_TOKENS (d)->last; + if (parser->omp_attrs_forbidden_p) + { + error_at (first->location, + "mixing OpenMP directives with attribute and pragma " + "syntax on the same statement"); + parser->omp_attrs_forbidden_p = false; + bad = true; + } const char *directive[3] = {}; for (int i = 0; i < 3; i++) { @@ -11731,6 +11740,9 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) else pa = &TREE_CHAIN (*pa); + if (bad) + return attrs; + unsigned int i; cp_omp_attribute_data *v; cp_omp_attribute_data *construct_seen = nullptr; @@ -11780,6 +11792,18 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) " can only appear on an empty statement"); return attrs; } + if (cnt && cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + enum pragma_kind kind = cp_parser_pragma_kind (token); + if (kind >= PRAGMA_OMP__START_ && kind <= PRAGMA_OMP__LAST_) + { + error_at (token->location, + "mixing OpenMP directives with attribute and pragma " + "syntax on the same statement"); + return attrs; + } + } if (!tokens) return attrs; @@ -11904,6 +11928,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, if (std_attrs && (flag_openmp || flag_openmp_simd)) std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs); + parser->omp_attrs_forbidden_p = false; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -39391,11 +39416,14 @@ cp_parser_end_omp_structured_block (cp_parser *parser, unsigned save) } static tree -cp_parser_omp_structured_block (cp_parser *parser, bool *if_p) +cp_parser_omp_structured_block (cp_parser *parser, bool *if_p, + bool disallow_omp_attrs = true) { tree stmt = begin_omp_structured_block (); unsigned int save = cp_parser_begin_omp_structured_block (parser); + if (disallow_omp_attrs) + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); @@ -40761,7 +40789,7 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) if (!braces.require_open (parser)) return; - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); add_stmt (substmt); @@ -40796,7 +40824,7 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) error ("expected %<#pragma omp scan%>"); clauses = finish_omp_clauses (clauses, C_ORT_OMP); - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build2_loc (tok->location, OMP_SCAN, void_type_node, substmt, clauses); add_stmt (substmt); @@ -41597,7 +41625,7 @@ cp_parser_omp_sections_scope (cp_parser *parser) if (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) != PRAGMA_OMP_SECTION) { - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build1 (OMP_SECTION, void_type_node, substmt); add_stmt (substmt); } @@ -41622,7 +41650,7 @@ cp_parser_omp_sections_scope (cp_parser *parser) error_suppress = true; } - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build1 (OMP_SECTION, void_type_node, substmt); add_stmt (substmt); } @@ -41842,6 +41870,7 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, block = begin_omp_parallel (); save = cp_parser_begin_omp_structured_block (parser); + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); stmt = finish_omp_parallel (clauses, block); @@ -41904,6 +41933,7 @@ cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p) "#pragma omp task", pragma_tok); block = begin_omp_task (); save = cp_parser_begin_omp_structured_block (parser); + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); return finish_omp_task (clauses, block); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 5ef704721e20..6fdd214788a2 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -398,6 +398,9 @@ struct GTY(()) cp_parser { identifiers) rather than an explicit template parameter list. */ bool fully_implicit_function_template_p; + /* TRUE if omp::directive or omp::sequence attributes may not appear. */ + bool omp_attrs_forbidden_p; + /* Tracks the function's template parameter list when declaring a function using generic type parameters. This is either a new chain in the case of a fully implicit function template or an extension of the function's existing diff --git a/gcc/testsuite/g++.dg/gomp/attrs-4.C b/gcc/testsuite/g++.dg/gomp/attrs-4.C new file mode 100644 index 000000000000..005add826ba5 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-4.C @@ -0,0 +1,61 @@ +// { dg-do compile { target c++11 } } + +void +foo (int x) +{ + [[omp::directive (parallel)]] + #pragma omp for // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + for (int i = 0; i < 16; i++) + ; + [[omp::directive (barrier)]] // { dg-error "standalone OpenMP directives in 'omp::directive' attribute can only appear on an empty statement" } + #pragma omp flush + ; + #pragma omp parallel + [[omp::directive (master)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp teams + [[omp::sequence (directive (parallel), directive (master))]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp task + [[omp::directive (flush)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp master + [[omp::directive (flush)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp for ordered + for (int i = 0; i < 16; i++) + #pragma omp ordered + [[omp::directive (flush)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp single + [[omp::directive (flush)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp taskgroup + [[omp::directive (taskyield)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp target data map (tofrom: x) + [[omp::directive (flush)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp target + [[omp::directive (teams)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + [[omp::directive (parallel)]] + #pragma omp master // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + [[omp::sequence (omp::directive (taskloop))]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + for (int i = 0; i < 16; i++) + ; + #pragma omp parallel + [[omp::directive (for)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + for (int i = 0; i < 16; i++) + ; + #pragma omp for + [[omp::directive (master)]] // { dg-error "for statement expected before '\\\[' token" } + ; + #pragma omp target teams + [[omp::directive (parallel)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + ; + #pragma omp parallel master + [[omp::directive (taskloop)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + for (int i = 0; i < 16; i++) + ; +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-5.C b/gcc/testsuite/g++.dg/gomp/attrs-5.C new file mode 100644 index 000000000000..f6d24b9540c6 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-5.C @@ -0,0 +1,46 @@ +// { dg-do compile { target c++11 } } + +typedef struct __attribute__((__aligned__ (sizeof (void *)))) omp_depend_t { + char __omp_depend_t__[2 * sizeof (void *)]; +} omp_depend_t; + +void +foo (int x) +{ + #pragma omp barrier + [[omp::directive (barrier)]]; + #pragma omp parallel + { + #pragma omp cancel parallel + [[omp::directive (cancellation point, parallel)]]; + } + #pragma omp parallel + { + #pragma omp cancellation point parallel + [[omp::directive (cancel parallel)]]; + } + #pragma omp parallel + { + [[omp::directive (cancel, parallel)]]; + #pragma omp cancellation point parallel + } + omp_depend_t depobj; + #pragma omp depobj(depobj) update(inout) + [[omp::directive (depobj(depobj), destroy)]]; + #pragma omp flush + [[omp::directive (flush)]]; + #pragma omp target enter data map (to: x) + [[omp::directive (target exit data, map (from: x))]]; + [[omp::directive (target enter data, map (to: x))]]; + #pragma omp target exit data map (from: x) + [[omp::directive (flush)]]; + #pragma omp target update to (x) + [[omp::directive (flush)]]; + #pragma omp taskwait + [[omp::directive (flush)]]; + #pragma omp taskyield + [[omp::directive (flush)]]; + extern int t; + #pragma omp threadprivate (t) + [[omp::directive (flush)]]; +}