From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 19D653853C02 for ; Fri, 23 Jul 2021 08:09:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 19D653853C02 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-350-sdyGIbtGOB2g8lsajxx0SA-1; Fri, 23 Jul 2021 04:09:29 -0400 X-MC-Unique: sdyGIbtGOB2g8lsajxx0SA-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id AA435185303A for ; Fri, 23 Jul 2021 08:09:28 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-112-143.ams2.redhat.com [10.36.112.143]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 300B83AC1 for ; Fri, 23 Jul 2021 08:09:27 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.16.1/8.16.1) with ESMTPS id 16N89Q9D1599833 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT) for ; Fri, 23 Jul 2021 10:09:26 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.16.1/8.16.1/Submit) id 16N89PxD1599832 for gcc-patches@gcc.gnu.org; Fri, 23 Jul 2021 10:09:25 +0200 Date: Fri, 23 Jul 2021 10:09:25 +0200 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Subject: [committed] openmp: Diagnose invalid mixing of the attribute and pragma syntax directives Message-ID: <20210723080925.GZ2380545@tucnak> Reply-To: Jakub Jelinek MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Status: No, score=-6.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 23 Jul 2021 08:09:33 -0000 Hi! 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. Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. 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. --- gcc/c-family/c-pragma.h.jj 2021-07-22 12:37:20.409533286 +0200 +++ gcc/c-family/c-pragma.h 2021-07-22 12:44:57.903028283 +0200 @@ -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, --- gcc/cp/parser.h.jj 2021-07-02 21:59:12.350171752 +0200 +++ gcc/cp/parser.h 2021-07-22 15:26:41.905013091 +0200 @@ -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 --- gcc/cp/parser.c.jj 2021-07-22 12:37:20.445532774 +0200 +++ gcc/cp/parser.c 2021-07-22 17:47:26.025761491 +0200 @@ -11665,6 +11665,7 @@ cp_parser_handle_statement_omp_attribute 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_attribute 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_attribute 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_attribute " 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, 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_p } 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 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 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 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 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 *parse 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, c "#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); --- gcc/testsuite/g++.dg/gomp/attrs-4.C.jj 2021-07-22 16:32:23.295177963 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-4.C 2021-07-22 18:34:59.823183344 +0200 @@ -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++) + ; +} --- gcc/testsuite/g++.dg/gomp/attrs-5.C.jj 2021-07-22 18:30:03.934285592 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-5.C 2021-07-22 18:31:39.517960417 +0200 @@ -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)]]; +} Jakub