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.129.124]) by sourceware.org (Postfix) with ESMTPS id 4FB7038133E4 for ; Mon, 30 May 2022 11:52:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4FB7038133E4 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-209-Yqo1cuiDNPqQtMrrH7w8Iw-1; Mon, 30 May 2022 07:52:20 -0400 X-MC-Unique: Yqo1cuiDNPqQtMrrH7w8Iw-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7ED3480418B; Mon, 30 May 2022 11:52:20 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.33.36.77]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 23BD82166B2A; Mon, 30 May 2022 11:52:19 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 24UBqHNm3614204 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Mon, 30 May 2022 13:52:17 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 24UBqGo53614203; Mon, 30 May 2022 13:52:16 +0200 Date: Mon, 30 May 2022 13:52:16 +0200 From: Jakub Jelinek To: Kwok Cheung Yeung Cc: gcc-patches Subject: Re: [PATCH 5/7] openmp: Add C++ support for parsing metadirectives Message-ID: Reply-To: Jakub Jelinek References: <8e830d64-4a71-2799-fda4-5ca77917f832@codesourcery.com> MIME-Version: 1.0 In-Reply-To: <8e830d64-4a71-2799-fda4-5ca77917f832@codesourcery.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 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=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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: Mon, 30 May 2022 11:52:24 -0000 On Fri, Dec 10, 2021 at 05:37:34PM +0000, Kwok Cheung Yeung wrote: > From e9bb138d4c3f560e48e408facce2361533685a98 Mon Sep 17 00:00:00 2001 > From: Kwok Cheung Yeung > Date: Mon, 6 Dec 2021 22:58:01 +0000 > Subject: [PATCH 5/7] openmp: Add C++ support for parsing metadirectives > > This adds support for parsing OpenMP metadirectives in the C++ front end. > > 2021-12-10 Kwok Cheung Yeung > > gcc/cp/ > * parser.c (cp_parser_skip_to_end_of_statement): Handle parentheses. > (cp_parser_skip_to_end_of_block_or_statement): Likewise. > (cp_parser_omp_context_selector): Add extra argument. Allow > non-constant expressions. > (cp_parser_omp_context_selector_specification): Add extra argument and > propagate to cp_parser_omp_context_selector. > (analyze_metadirective_body): New. > (cp_parser_omp_metadirective): New. > (cp_parser_omp_construct): Handle PRAGMA_OMP_METADIRECTIVE. > (cp_parser_pragma): Handle PRAGMA_OMP_METADIRECTIVE. > --- > gcc/cp/parser.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 417 insertions(+), 8 deletions(-) > > diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c > index 6f273bfe21f..afbfe148949 100644 > --- a/gcc/cp/parser.c > +++ b/gcc/cp/parser.c > @@ -3907,6 +3907,17 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser) > ++nesting_depth; > break; > > + case CPP_OPEN_PAREN: > + /* Track parentheses in case the statement is a standalone 'for' > + statement - we want to skip over the semicolons separating the > + operands. */ > + ++nesting_depth; > + break; > + > + case CPP_CLOSE_PAREN: > + --nesting_depth; > + break; > + > case CPP_KEYWORD: > if (token->keyword != RID__EXPORT > && token->keyword != RID__MODULE > @@ -3996,6 +4007,17 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser) > nesting_depth++; > break; > > + case CPP_OPEN_PAREN: > + /* Track parentheses in case the statement is a standalone 'for' > + statement - we want to skip over the semicolons separating the > + operands. */ > + nesting_depth++; > + break; > + > + case CPP_CLOSE_PAREN: > + nesting_depth--; > + break; > + Like for C FE, I think this is too risky. > case CTX_PROPERTY_EXPR: > - t = cp_parser_constant_expression (parser); > + /* Allow non-constant expressions in metadirectives. */ > + t = metadirective_p > + ? cp_parser_expression (parser) > + : cp_parser_constant_expression (parser); > if (t != error_mark_node) > { > t = fold_non_dependent_expr (t); > - if (!value_dependent_expression_p (t) > - && (!INTEGRAL_TYPE_P (TREE_TYPE (t)) > - || !tree_fits_shwi_p (t))) > + if (metadirective_p && !INTEGRAL_TYPE_P (TREE_TYPE (t))) Like in the other patch, but more importantly, if t is type_dependent_expression_p, you shouldn't diagnose it, it might be integral after instantiation. But it needs to be diagnosed later during instantiation if it isn't integral then... > + cp_token *token = cp_lexer_peek_token (parser->lexer); > + bool stop = false; > + > + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_CASE)) > + in_case = true; > + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL)) > + in_label_decl = true; > + > + switch (token->type) > + { > + case CPP_EOF: > + break; > + case CPP_NAME: > + if ((!in_case > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) > + || in_label_decl) > + labels.safe_push (token->u.value); Similar thing as for C, identifier : can appear in various spots even when it isn't a label, in C++ even in many more cases. Say nested struct definition, struct S : T {}; or (that is for both C and C++) e.g. bitfields struct V { int v : 13; }; > + goto add; > + case CPP_OPEN_BRACE: > + ++nesting_depth; > + goto add; > + case CPP_CLOSE_BRACE: > + if (--nesting_depth == 0) > + stop = true; > + goto add; > + case CPP_OPEN_PAREN: > + ++bracket_depth; > + goto add; > + case CPP_CLOSE_PAREN: > + --bracket_depth; > + goto add; > + case CPP_COLON: > + in_case = false; > + goto add; > + case CPP_SEMICOLON: > + if (nesting_depth == 0 && bracket_depth == 0) > + stop = true; > + /* Local label declarations are terminated by a semicolon. */ > + in_label_decl = false; > + goto add; > + default: > + add: > + tokens.safe_push (*token); > + cp_lexer_consume_token (parser->lexer); > + if (stop) > + break; > + continue; > + } > + break; > + } > +} > + > +/* OpenMP 5.0: > + > + # pragma omp metadirective [clause[, clause]] > +*/ > + > +static tree > +cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok, > + char *p_name, omp_clause_mask, tree *, > + bool *if_p) > +{ > + tree ret; > + auto_vec directive_tokens; > + auto_vec body_tokens; > + auto_vec body_labels; > + auto_vec directives; > + auto_vec ctxs; > + bool default_seen = false; > + int directive_token_idx = 0; > + location_t loc = cp_lexer_peek_token (parser->lexer)->location; > + tree standalone_body = NULL_TREE; > + vec candidates; > + > + ret = make_node (OMP_METADIRECTIVE); Better write tree ret = make_node ... i.e. at least where easily possible declare vars on first use rather than at the start of function. Also, same comments I wrote in the C FE patch. > + SET_EXPR_LOCATION (ret, loc); > + TREE_TYPE (ret) = void_type_node; > + OMP_METADIRECTIVE_CLAUSES (ret) = NULL_TREE; > + strcat (p_name, " metadirective"); > + > + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) > + { > + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME) > + && cp_lexer_next_token_is_not (parser->lexer, CPP_KEYWORD)) > + { > + cp_parser_error (parser, "expected % or %"); > + goto fail; > + } > + > + location_t match_loc = cp_lexer_peek_token (parser->lexer)->location; > + const char *p > + = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value); > + cp_lexer_consume_token (parser->lexer); > + bool default_p = strcmp (p, "default") == 0; > + if (default_p) > + { > + if (default_seen) > + { > + cp_parser_error (parser, "there can only be one default clause " > + "in a metadirective"); > + goto fail; > + } > + else > + default_seen = true; > + } > + if (!strcmp (p, "when") == 0 && !default_p) > + { > + cp_parser_error (parser, "expected % or %"); > + goto fail; > + } > + > + matching_parens parens; > + tree ctx = NULL_TREE; > + bool skip = false; > + > + if (!parens.require_open (parser)) > + goto fail; > + > + if (!default_p) > + { > + ctx = cp_parser_omp_context_selector_specification (parser, false, > + true); > + if (ctx == error_mark_node) > + goto fail; > + ctx = omp_check_context_selector (match_loc, ctx); > + if (ctx == error_mark_node) > + goto fail; > + > + /* Remove the selector from further consideration if can be > + evaluated as a non-match at this point. */ > + skip = (omp_context_selector_matches (ctx, true) == 0); > + > + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) > + { > + cp_parser_error (parser, "expected colon"); > + goto fail; > + } > + cp_lexer_consume_token (parser->lexer); > + } > + > + /* Read in the directive type and create a dummy pragma token for > + it. */ > + location_t loc = cp_lexer_peek_token (parser->lexer)->location; > + > + p = NULL; > + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) > + p = "nothing"; > + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) > + { > + p = "for"; > + cp_lexer_consume_token (parser->lexer); > + } > + else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) > + { > + cp_token *token = cp_lexer_consume_token (parser->lexer); > + p = IDENTIFIER_POINTER (token->u.value); > + } > + > + if (p == NULL) > + { > + cp_parser_error (parser, "expected directive name"); > + goto fail; > + } > + > + const struct c_omp_directive *omp_directive > + = c_omp_categorize_directive (p, NULL, NULL); > + > + if (omp_directive == NULL) > + { > + cp_parser_error (parser, "unknown directive name"); > + goto fail; > + } > + if (omp_directive->id == PRAGMA_OMP_METADIRECTIVE) > + { > + cp_parser_error (parser, > + "metadirectives cannot be used as directive " > + "variants"); > + goto fail; > + } > + if (omp_directive->kind == C_OMP_DIR_DECLARATIVE) > + { > + sorry_at (loc, "declarative directive variants are not supported"); > + goto fail; > + } > + > + if (!skip) > + { > + cp_token pragma_token; > + pragma_token.type = CPP_PRAGMA; > + pragma_token.location = loc; > + pragma_token.u.value = build_int_cst (NULL, omp_directive->id); > + > + directives.safe_push (omp_directive); > + directive_tokens.safe_push (pragma_token); > + ctxs.safe_push (ctx); > + } > + > + /* Read in tokens for the directive clauses. */ > + int nesting_depth = 0; > + while (1) > + { > + cp_token *token = cp_lexer_peek_token (parser->lexer); > + switch (token->type) > + { > + case CPP_EOF: > + case CPP_PRAGMA_EOL: > + break; > + case CPP_OPEN_PAREN: > + ++nesting_depth; > + goto add; > + case CPP_CLOSE_PAREN: > + if (nesting_depth-- == 0) > + break; > + goto add; > + default: > + add: > + if (!skip) > + directive_tokens.safe_push (*token); > + cp_lexer_consume_token (parser->lexer); > + continue; > + } > + break; > + } > + > + cp_lexer_consume_token (parser->lexer); > + > + if (!skip) > + { > + cp_token eol_token = {}; > + eol_token.type = CPP_PRAGMA_EOL; > + eol_token.keyword = RID_MAX; > + directive_tokens.safe_push (eol_token); > + } > + } > + cp_parser_skip_to_pragma_eol (parser, pragma_tok); > + > + if (!default_seen) > + { > + /* Add a default clause that evaluates to 'omp nothing'. */ > + const struct c_omp_directive *omp_directive > + = c_omp_categorize_directive ("nothing", NULL, NULL); > + > + cp_token pragma_token = {}; > + pragma_token.type = CPP_PRAGMA; > + pragma_token.keyword = RID_MAX; > + pragma_token.location = UNKNOWN_LOCATION; > + pragma_token.u.value = build_int_cst (NULL, PRAGMA_OMP_NOTHING); > + > + directives.safe_push (omp_directive); > + directive_tokens.safe_push (pragma_token); > + ctxs.safe_push (NULL_TREE); > + > + cp_token eol_token = {}; > + eol_token.type = CPP_PRAGMA_EOL; > + eol_token.keyword = RID_MAX; > + directive_tokens.safe_push (eol_token); > + } > + > + analyze_metadirective_body (parser, body_tokens, body_labels); > + > + /* Process each candidate directive. */ > + unsigned i; > + tree ctx; > + cp_lexer *lexer; > + > + lexer = cp_lexer_alloc (); > + lexer->debugging_p = parser->lexer->debugging_p; > + vec_safe_reserve (lexer->buffer, > + directive_tokens.length () + body_tokens.length () + 2); > + > + FOR_EACH_VEC_ELT (ctxs, i, ctx) > + { > + lexer->buffer->truncate (0); > + > + /* Add the directive tokens. */ > + do > + lexer->buffer->quick_push (directive_tokens [directive_token_idx++]); > + while (lexer->buffer->last ().type != CPP_PRAGMA_EOL); > + > + /* Add the body tokens. */ > + for (unsigned j = 0; j < body_tokens.length (); j++) > + lexer->buffer->quick_push (body_tokens[j]); > + > + /* Make sure nothing tries to read past the end of the tokens. */ > + cp_token eof_token = {}; > + eof_token.type = CPP_EOF; > + eof_token.keyword = RID_MAX; > + lexer->buffer->quick_push (eof_token); > + lexer->buffer->quick_push (eof_token); > + > + lexer->next_token = lexer->buffer->address(); > + lexer->last_token = lexer->next_token + lexer->buffer->length () - 1; > + > + cp_lexer *old_lexer = parser->lexer; > + parser->lexer = lexer; > + cp_lexer_set_source_position_from_token (lexer->next_token); > + > + tree directive = push_stmt_list (); > + tree directive_stmt = begin_compound_stmt (0); > + > + /* Declare all labels that occur within the directive body as > + local. */ > + for (unsigned j = 0; j < body_labels.length (); j++) > + finish_label_decl (body_labels[j]); > + cp_parser_pragma (parser, pragma_compound, if_p); > + > + finish_compound_stmt (directive_stmt); > + directive = pop_stmt_list (directive); > + > + bool standalone_p > + = directives[i]->kind == C_OMP_DIR_STANDALONE > + || directives[i]->kind == C_OMP_DIR_UTILITY; > + if (standalone_p) > + { > + /* Parsing standalone directives will not consume the body > + tokens, so do that here. */ > + if (standalone_body == NULL_TREE) > + { > + standalone_body = push_stmt_list (); > + cp_parser_statement (parser, NULL_TREE, false, if_p); > + standalone_body = pop_stmt_list (standalone_body); > + } > + else > + cp_parser_skip_to_end_of_block_or_statement (parser); > + } > + > + tree body = standalone_p ? standalone_body : NULL_TREE; > + tree variant = build_tree_list (ctx, build_tree_list (directive, body)); > + OMP_METADIRECTIVE_CLAUSES (ret) > + = chainon (OMP_METADIRECTIVE_CLAUSES (ret), variant); > + > + /* Check that all valid tokens have been consumed. */ > + gcc_assert (cp_lexer_next_token_is (parser->lexer, CPP_EOF)); > + > + parser->lexer = old_lexer; > + cp_lexer_set_source_position_from_token (old_lexer->next_token); > + } > + > + /* Try to resolve the metadirective early. */ > + candidates = omp_resolve_metadirective (ret); > + if (!candidates.is_empty ()) > + ret = c_omp_expand_metadirective (candidates); > + > + add_stmt (ret); > + > + return ret; > + > +fail: > + /* Skip the metadirective pragma. */ > + cp_parser_skip_to_pragma_eol (parser, pragma_tok); > + > + /* Skip the metadirective body. */ > + cp_parser_skip_to_end_of_block_or_statement (parser); > + return error_mark_node; > +} > + > + > /* Helper function of cp_parser_omp_declare_reduction. Parse the combiner > expression and optional initializer clause of > #pragma omp declare reduction. We store the expression(s) as > @@ -47077,6 +47480,11 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) > stmt = cp_parser_omp_master (parser, pragma_tok, p_name, mask, NULL, > if_p); > break; > + case PRAGMA_OMP_METADIRECTIVE: > + strcpy (p_name, "#pragma omp"); > + stmt = cp_parser_omp_metadirective (parser, pragma_tok, p_name, mask, > + NULL, if_p); > + break; > case PRAGMA_OMP_PARALLEL: > strcpy (p_name, "#pragma omp"); > stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL, > @@ -47727,6 +48135,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) > case PRAGMA_OMP_LOOP: > case PRAGMA_OMP_MASKED: > case PRAGMA_OMP_MASTER: > + case PRAGMA_OMP_METADIRECTIVE: > case PRAGMA_OMP_PARALLEL: > case PRAGMA_OMP_SCOPE: > case PRAGMA_OMP_SECTIONS: > -- I miss handling of OMP_METADIRECTIVE in pt.c and testsuite coverage of metadirectives in templates (both function templates and class templates in whose methods metadirectives are used). And something I forgot to note in the C FE patch, there is the "The context selector that appears in a when clause must not specify any properties for the simd selector." restriction I haven't seen being checked for (and tested in the testsuite). Jakub