From patchwork Wed Jul 13 14:10:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Thomas Schwinge X-Patchwork-Id: 647956 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rqLNN2gQFz9s9W for ; Thu, 14 Jul 2016 00:11:15 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=M7sXtivY; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:in-reply-to:references:date:message-id:mime-version :content-type:content-transfer-encoding; q=dns; s=default; b=SWd 4Mek7lnCisnCx9RPLz2WsBY+QWX+A0JSyybsfkBST6atlLMUK8P7y3prnIRapKf5 nFNxlUlD/DVTTLOU0sWPQVanSjhjIU2LnibE+UlkhWe7TRn/siqrRP1AlK83LY5M cfdGRKYsxyOq/7+zqKlgWasmkZDCN0C83u/FEIwQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:in-reply-to:references:date:message-id:mime-version :content-type:content-transfer-encoding; s=default; bh=z9xgRSLTL 9a6ra4HKTesRjHg94s=; b=M7sXtivYWHajpcUp7obQZePKueMkYBySDD4yPejW5 OfbcXNZWpb8RS7B2xAOCrmCf4zfD8DnA0Z2cSpJbCZQmmIgr88Pyip2lm93cjzCD qhKJVKN4YTnWPgTaP0XzqP/yC9KyAHV5f6LPP2nRTLhQYCrA3DeftyHAs6VoFQbb U8= Received: (qmail 123578 invoked by alias); 13 Jul 2016 14:11:04 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 123568 invoked by uid 89); 13 Jul 2016 14:11:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=gang, 365548 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Wed, 13 Jul 2016 14:10:53 +0000 Received: from nat-ies.mentorg.com ([192.94.31.2] helo=SVR-IES-FEM-01.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1bNKsC-0004vM-3P from Thomas_Schwinge@mentor.com ; Wed, 13 Jul 2016 07:10:48 -0700 Received: from hertz.schwinge.homeip.net (137.202.0.76) by SVR-IES-FEM-01.mgc.mentorg.com (137.202.0.104) with Microsoft SMTP Server id 14.3.224.2; Wed, 13 Jul 2016 15:10:46 +0100 From: Thomas Schwinge To: Jakub Jelinek , Subject: Rework C/C++ OpenACC routine parsing (was: C/C++: Simplify handling of location information for OpenACC routine directives) In-Reply-To: <87poqhnb39.fsf@hertz.schwinge.homeip.net> References: <87poqhnb39.fsf@hertz.schwinge.homeip.net> User-Agent: Notmuch/0.9-101-g81dad07 (http://notmuchmail.org) Emacs/24.4.1 (x86_64-pc-linux-gnu) Date: Wed, 13 Jul 2016 16:10:31 +0200 Message-ID: <87k2gpmxwo.fsf@hertz.schwinge.homeip.net> MIME-Version: 1.0 Hi! On Wed, 13 Jul 2016 11:25:46 +0200, I wrote: > Working on something else regarding the C/C++ OpenACC routine directive, > I couldn't but untangle [...] > (Another C/C++ OpenACC routine > cleanup patch is emerging, depending on this one.) Here it is; likewise, OK for trunk? (Further cleanup especially of C++ OpenACC routine handling seems to be possible, but I want to synchronize my work at this point.) commit 0bd30acaf4dd634499b1c695ddee555e7675aa18 Author: Thomas Schwinge Date: Thu Jun 23 13:28:09 2016 +0200 Rework C/C++ OpenACC routine parsing gcc/c/ * c-parser.c (struct oacc_routine_data): Add error_seen and fndecl_seen members. (c_finish_oacc_routine): Use these. (c_parser_declaration_or_fndef): Adjust. (c_parser_oacc_routine): Likewise. Support more C language constructs, and improve diagnostics. Move pragma context checking... (c_parser_pragma): ... here. gcc/cp/ * parser.c (cp_ensure_no_oacc_routine): Improve diagnostics. (cp_parser_late_parsing_cilk_simd_fn_info): Fix diagnostics. (cp_parser_late_parsing_oacc_routine, cp_finalize_oacc_routine): Simplify code, and improve diagnostics. (cp_parser_oacc_routine): Likewise. Move pragma context checking... (cp_parser_pragma): ... here. gcc/testsuite/ * c-c++-common/goacc/routine-5.c: Update. --- gcc/c/c-parser.c | 161 +++++++++++++++------- gcc/cp/parser.c | 182 +++++++++++------------- gcc/testsuite/c-c++-common/goacc/routine-5.c | 199 +++++++++++++++++++++++---- 3 files changed, 369 insertions(+), 173 deletions(-) Grüße Thomas diff --git gcc/c/c-parser.c gcc/c/c-parser.c index 7f84ce9..809118a 100644 --- gcc/c/c-parser.c +++ gcc/c/c-parser.c @@ -1273,6 +1273,8 @@ enum c_parser_prec { /* Helper data structure for parsing #pragma acc routine. */ struct oacc_routine_data { + bool error_seen; /* Set if error has been reported. */ + bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ tree clauses; location_t loc; }; @@ -1565,8 +1567,7 @@ c_parser_external_declaration (c_parser *parser) } static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec); -static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool, - bool, bool); +static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool); /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1). If FNDEF_OK is true, a function definition is @@ -1751,8 +1752,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } c_parser_consume_token (parser); if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false, true, - false); + c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); return; } @@ -1850,7 +1850,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, prefix_attrs = specs->attrs; all_prefix_attrs = prefix_attrs; specs->attrs = NULL_TREE; - for (bool first = true;; first = false) + while (true) { struct c_declarator *declarator; bool dummy = false; @@ -1870,8 +1870,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE, omp_declare_simd_clauses); if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, NULL_TREE, - false, first, false); + c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); c_parser_skip_to_end_of_block_or_statement (parser); return; } @@ -1987,8 +1986,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, finish_init (); } if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, d, - false, first, false); + c_finish_oacc_routine (oacc_routine_data, d, false); if (d != error_mark_node) { maybe_warn_string_init (init_loc, TREE_TYPE (d), init); @@ -2033,8 +2031,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, temp_pop_parm_decls (); } if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, d, - false, first, false); + c_finish_oacc_routine (oacc_routine_data, d, false); if (d) finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, NULL_TREE, asm_name); @@ -2146,8 +2143,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, omp_declare_simd_clauses); if (oacc_routine_data) - c_finish_oacc_routine (oacc_routine_data, current_function_decl, - false, first, true); + c_finish_oacc_routine (oacc_routine_data, current_function_decl, true); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; fnbody = c_parser_compound_statement (parser); @@ -10117,6 +10113,13 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; case PRAGMA_OACC_ROUTINE: + if (context != pragma_external) + { + error_at (c_parser_peek_token (parser)->location, + "%<#pragma acc routine%> must be at file scope"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } c_parser_oacc_routine (parser, context); return false; @@ -14029,29 +14032,32 @@ c_parser_oacc_kernels_parallel (location_t loc, c_parser *parser, static void c_parser_oacc_routine (c_parser *parser, enum pragma_context context) { - tree decl = NULL_TREE; + gcc_checking_assert (context == pragma_external); + oacc_routine_data data; + data.error_seen = false; + data.fndecl_seen = false; data.clauses = NULL_TREE; data.loc = c_parser_peek_token (parser)->location; - - if (context != pragma_external) - c_parser_error (parser, "%<#pragma acc routine%> not at file scope"); c_parser_consume_pragma (parser); - /* Scan for optional '( name )'. */ + /* Look for optional '( name )'. */ if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) { - c_parser_consume_token (parser); + c_parser_consume_token (parser); /* '(' */ - c_token *token = c_parser_peek_token (parser); - if (token->type == CPP_NAME && (token->id_kind == C_ID_ID - || token->id_kind == C_ID_TYPENAME)) + tree decl = NULL_TREE; + c_token *name_token = c_parser_peek_token (parser); + location_t name_loc = name_token->location; + if (name_token->type == CPP_NAME + && (name_token->id_kind == C_ID_ID + || name_token->id_kind == C_ID_TYPENAME)) { - decl = lookup_name (token->value); + decl = lookup_name (name_token->value); if (!decl) - error_at (token->location, "%qE has not been declared", - token->value); + error_at (name_loc, + "%qE has not been declared", name_token->value); c_parser_consume_token (parser); } else @@ -14063,22 +14069,56 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context) c_parser_skip_to_pragma_eol (parser, false); return; } + + data.clauses + = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, + "#pragma acc routine"); + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_at (name_loc, "%qD does not refer to a function", decl); + return; + } + + c_finish_oacc_routine (&data, decl, false); } + else /* No optional '( name )'. */ + { + data.clauses + = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, + "#pragma acc routine"); - /* Build a chain of clauses. */ - parser->in_pragma = true; - data.clauses - = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, - "#pragma acc routine"); + /* Emit a helpful diagnostic if there's another pragma following this + one. Also don't allow a static assertion declaration, as in the + following we'll just parse a *single* "declaration or function + definition", and the static assertion counts an one. */ + if (c_parser_next_token_is (parser, CPP_PRAGMA) + || c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) + { + error_at (data.loc, + "%<#pragma acc routine%> not immediately followed by" + " function declaration or definition"); + /* ..., and then just keep going. */ + return; + } - if (decl) - c_finish_oacc_routine (&data, decl, true, true, false); - else if (c_parser_peek_token (parser)->type == CPP_PRAGMA) - /* This will emit an error. */ - c_finish_oacc_routine (&data, NULL_TREE, false, true, false); - else - c_parser_declaration_or_fndef (parser, true, false, false, false, - true, NULL, vNULL, &data); + /* We only have to consider the pragma_external case here. */ + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, vNULL, &data); + restore_extension_diagnostics (ext); + } + else + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, vNULL, &data); + } } /* Finalize an OpenACC routine pragma, applying it to FNDECL. @@ -14086,24 +14126,46 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context) static void c_finish_oacc_routine (struct oacc_routine_data *data, tree fndecl, - bool named, bool first, bool is_defn) + bool is_defn) { - if (!fndecl || TREE_CODE (fndecl) != FUNCTION_DECL || !first) + /* Keep going if we're in error reporting mode. */ + if (data->error_seen + || fndecl == error_mark_node) + return; + + if (data->fndecl_seen) { - if (fndecl != error_mark_node) - error_at (data->loc, "%<#pragma acc routine%> %s", - named ? "does not refer to a function" - : "not followed by single function"); + error_at (data->loc, + "%<#pragma acc routine%> not immediately followed by" + " a single function declaration or definition"); + data->error_seen = true; + return; + } + if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) + { + error_at (data->loc, + "%<#pragma acc routine%> not immediately followed by" + " function declaration or definition"); + data->error_seen = true; return; } if (get_oacc_fn_attrib (fndecl)) - error_at (data->loc, - "%<#pragma acc routine%> already applied to %D", fndecl); + { + error_at (data->loc, + "%<#pragma acc routine%> already applied to %qD", fndecl); + data->error_seen = true; + return; + } if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl))) - error_at (data->loc, "%<#pragma acc routine%> must be applied before %s", - TREE_USED (fndecl) ? "use" : "definition"); + { + error_at (data->loc, + "%<#pragma acc routine%> must be applied before %s", + TREE_USED (fndecl) ? "use" : "definition"); + data->error_seen = true; + return; + } /* Process the routine's dimension clauses. */ tree dims = build_oacc_routine_dims (data->clauses); @@ -14113,6 +14175,9 @@ c_finish_oacc_routine (struct oacc_routine_data *data, tree fndecl, DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("omp declare target"), NULL_TREE, DECL_ATTRIBUTES (fndecl)); + + /* Remember that we've used this "#pragma acc routine". */ + data->fndecl_seen = true; } /* OpenACC 2.0: diff --git gcc/cp/parser.c gcc/cp/parser.c index 28417d8..43bed89 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -1383,8 +1383,8 @@ cp_ensure_no_oacc_routine (cp_parser *parser) if (parser->oacc_routine && !parser->oacc_routine->error_seen) { error_at (parser->oacc_routine->loc, - "%<#pragma acc routine%> not followed by a function " - "declaration or definition"); + "%<#pragma acc routine%> not immediately followed by " + "function declaration or definition"); parser->oacc_routine = NULL; } } @@ -35660,6 +35660,8 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, used while this scope is live. */ parser->omp_declare_simd = &data; } + + /* Store away all pragma tokens. */ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) cp_lexer_consume_token (parser->lexer); @@ -35669,6 +35671,7 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, struct cp_token_cache *cp = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer)); parser->omp_declare_simd->tokens.safe_push (cp); + if (first_p) { while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) @@ -35713,9 +35716,9 @@ cp_parser_late_parsing_cilk_simd_fn_info (cp_parser *parser, tree attrs) if (parser->omp_declare_simd != NULL || lookup_attribute ("simd", attrs)) { - error ("%<#pragma omp declare simd%> of % attribute cannot be " + error ("%<#pragma omp declare simd%> or % attribute cannot be " "used in the same function marked as a Cilk Plus SIMD-enabled " - " function"); + "function"); parser->cilk_simd_fn_info->tokens.release (); XDELETE (parser->cilk_simd_fn_info); parser->cilk_simd_fn_info = NULL; @@ -36487,64 +36490,39 @@ static void cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { - bool first_p = parser->oacc_routine == NULL; + gcc_checking_assert (context == pragma_external); + /* The checking for "another pragma following this one" in the "no optional + '( name )'" case makes sure that we dont re-enter. */ + gcc_checking_assert (parser->oacc_routine == NULL); + cp_oacc_routine_data data; - if (first_p) - { - data.error_seen = false; - data.fndecl_seen = false; - data.tokens = vNULL; - data.clauses = NULL_TREE; - data.loc = pragma_tok->location; - /* It is safe to take the address of a local variable; it will only be - used while this scope is live. */ - parser->oacc_routine = &data; - } + data.error_seen = false; + data.fndecl_seen = false; + data.tokens = vNULL; + data.clauses = NULL_TREE; + data.loc = pragma_tok->location; + /* It is safe to take the address of a local variable; it will only be + used while this scope is live. */ + parser->oacc_routine = &data; - if (context != pragma_external) - { - cp_parser_error (parser, "%<#pragma acc routine%> not at file scope"); - parser->oacc_routine->error_seen = true; - parser->oacc_routine = NULL; - return; - } - - /* Look for optional '( name )'. */ + /* Do we have an optional '( name )'? */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - if (!first_p) - { - while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) - && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) - cp_lexer_consume_token (parser->lexer); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) - parser->oacc_routine->error_seen = true; - cp_parser_require_pragma_eol (parser, pragma_tok); - - error_at (parser->oacc_routine->loc, - "%<#pragma acc routine%> not followed by a " - "function declaration or definition"); - - parser->oacc_routine->error_seen = true; - return; - } - - cp_lexer_consume_token (parser->lexer); - cp_token *token = cp_lexer_peek_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); /* '(' */ /* We parse the name as an id-expression. If it resolves to anything other than a non-overloaded function at namespace scope, it's an error. */ - tree id = cp_parser_id_expression (parser, - /*template_keyword_p=*/false, - /*check_dependency_p=*/false, - /*template_p=*/NULL, - /*declarator_p=*/false, - /*optional_p=*/false); - tree decl = cp_parser_lookup_name_simple (parser, id, token->location); - if (id != error_mark_node && decl == error_mark_node) - cp_parser_name_lookup_error (parser, id, decl, NLE_NULL, - token->location); + location_t name_loc = cp_lexer_peek_token (parser->lexer)->location; + tree name = cp_parser_id_expression (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/false, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + tree decl = cp_parser_lookup_name_simple (parser, name, name_loc); + if (name != error_mark_node && decl == error_mark_node) + cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, name_loc); if (decl == error_mark_node || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) @@ -36554,8 +36532,6 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, return; } - /* Build a chain of clauses. */ - parser->lexer->in_pragma = true; data.clauses = cp_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, "#pragma acc routine", @@ -36565,7 +36541,7 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, && (TREE_CODE (decl) != FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (decl))) { - error_at (data.loc, + error_at (name_loc, "%<#pragma acc routine%> names a set of overloads"); parser->oacc_routine = NULL; return; @@ -36575,60 +36551,58 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, namespaces? */ if (!DECL_NAMESPACE_SCOPE_P (decl)) { - error_at (data.loc, - "%<#pragma acc routine%> does not refer to a " - "namespace scope function"); + error_at (name_loc, + "%qD does not refer to a namespace scope function", decl); parser->oacc_routine = NULL; return; } - if (!decl || TREE_CODE (decl) != FUNCTION_DECL) + if (TREE_CODE (decl) != FUNCTION_DECL) { - error_at (data.loc, - "%<#pragma acc routine%> does not refer to a function"); + error_at (name_loc, "%qD does not refer to a function", decl); parser->oacc_routine = NULL; return; } cp_finalize_oacc_routine (parser, decl, false); - data.tokens.release (); parser->oacc_routine = NULL; } - else + else /* No optional '( name )'. */ { + /* Store away all pragma tokens. */ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) cp_lexer_consume_token (parser->lexer); if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) parser->oacc_routine->error_seen = true; cp_parser_require_pragma_eol (parser, pragma_tok); - struct cp_token_cache *cp = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer)); parser->oacc_routine->tokens.safe_push (cp); - while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) - cp_parser_pragma (parser, context, NULL); - - if (first_p) + /* Emit a helpful diagnostic if there's another pragma following this + one. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) { - cp_parser_declaration (parser); - - if (parser->oacc_routine - && !parser->oacc_routine->error_seen - && !parser->oacc_routine->fndecl_seen) - error_at (data.loc, - "%<#pragma acc routine%> not followed by a " - "function declaration or definition"); - + cp_ensure_no_oacc_routine (parser); data.tokens.release (); - parser->oacc_routine = NULL; + /* ..., and then just keep going. */ + return; } + + /* We only have to consider the pragma_external case here. */ + cp_parser_declaration (parser); + if (parser->oacc_routine + && !parser->oacc_routine->fndecl_seen) + cp_ensure_no_oacc_routine (parser); + else + parser->oacc_routine = NULL; + data.tokens.release (); } } /* Finalize #pragma acc routine clauses after direct declarator has - been parsed, and put that into "oacc function" attribute. */ + been parsed. */ static tree cp_parser_late_parsing_oacc_routine (cp_parser *parser, tree attrs) @@ -36636,17 +36610,17 @@ cp_parser_late_parsing_oacc_routine (cp_parser *parser, tree attrs) struct cp_token_cache *ce; cp_oacc_routine_data *data = parser->oacc_routine; - if ((!data->error_seen && data->fndecl_seen) - || data->tokens.length () != 1) + if (!data->error_seen && data->fndecl_seen) { error_at (data->loc, - "%<#pragma acc routine%> not followed by a " - "function declaration or definition"); + "%<#pragma acc routine%> not immediately followed by " + "a single function declaration or definition"); data->error_seen = true; } if (data->error_seen) return attrs; + gcc_checking_assert (data->tokens.length () == 1); ce = data->tokens[0]; cp_parser_push_lexer_for_tokens (parser, ce); @@ -36654,12 +36628,14 @@ cp_parser_late_parsing_oacc_routine (cp_parser *parser, tree attrs) gcc_assert (cp_lexer_peek_token (parser->lexer)->type == CPP_PRAGMA); cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer); + gcc_checking_assert (parser->oacc_routine->clauses == NULL_TREE); parser->oacc_routine->clauses = cp_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, "#pragma acc routine", pragma_tok); cp_parser_pop_lexer (parser); + /* Later, cp_finalize_oacc_routine will process the clauses, and then set + fndecl_seen. */ - data->fndecl_seen = true; return attrs; } @@ -36671,34 +36647,29 @@ cp_finalize_oacc_routine (cp_parser *parser, tree fndecl, bool is_defn) { if (__builtin_expect (parser->oacc_routine != NULL, 0)) { - if (parser->oacc_routine->error_seen) + /* Keep going if we're in error reporting mode. */ + if (parser->oacc_routine->error_seen + || fndecl == error_mark_node) return; - - if (fndecl == error_mark_node) + + if (parser->oacc_routine->fndecl_seen) { + error_at (parser->oacc_routine->loc, + "%<#pragma acc routine%> not immediately followed by" + " a single function declaration or definition"); parser->oacc_routine = NULL; return; } - if (TREE_CODE (fndecl) != FUNCTION_DECL) { cp_ensure_no_oacc_routine (parser); return; } - if (!fndecl || TREE_CODE (fndecl) != FUNCTION_DECL) - { - error_at (parser->oacc_routine->loc, - "%<#pragma acc routine%> not followed by a function " - "declaration or definition"); - parser->oacc_routine = NULL; - return; - } - if (get_oacc_fn_attrib (fndecl)) { error_at (parser->oacc_routine->loc, - "%<#pragma acc routine%> already applied to %D", fndecl); + "%<#pragma acc routine%> already applied to %qD", fndecl); parser->oacc_routine = NULL; return; } @@ -36720,6 +36691,11 @@ cp_finalize_oacc_routine (cp_parser *parser, tree fndecl, bool is_defn) DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("omp declare target"), NULL_TREE, DECL_ATTRIBUTES (fndecl)); + + /* Don't unset parser->oacc_routine here: we may still need it to + diagnose wrong usage. But, remember that we've used this "#pragma acc + routine". */ + parser->oacc_routine->fndecl_seen = true; } } @@ -37319,6 +37295,12 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) return false; case PRAGMA_OACC_ROUTINE: + if (context != pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma acc routine%> must be at file scope"); + break; + } cp_parser_oacc_routine (parser, pragma_tok, context); return false; diff --git gcc/testsuite/c-c++-common/goacc/routine-5.c gcc/testsuite/c-c++-common/goacc/routine-5.c index 1efd154..17fe67c 100644 --- gcc/testsuite/c-c++-common/goacc/routine-5.c +++ gcc/testsuite/c-c++-common/goacc/routine-5.c @@ -1,64 +1,211 @@ -/* { dg-do compile } */ +/* Miscellaneous OpenACC routine front end checking. */ -#pragma acc routine /* { dg-error "not followed by" } */ +/* Pragma context. */ + +struct PC +{ +#pragma acc routine /* { dg-error ".#pragma acc routine. must be at file scope" } */ +}; + +void PC1( /* { dg-bogus "variable or field .PC1. declared void" "TODO" { xfail c++ } } */ +#pragma acc routine + /* { dg-error ".#pragma acc routine. must be at file scope" "" { target c } 11 } + { dg-error ".#pragma. is not allowed here" "" { target c++ } 11 } */ +) /* { dg-bogus "expected declaration specifiers or .\\.\\.\\.. before .\\). token" "TODO" { xfail c } } */ +{ +} + +void PC2() +{ + if (0) +#pragma acc routine /* { dg-error ".#pragma acc routine. must be at file scope" } */ + ; +} + +void PC3() +{ +#pragma acc routine /* { dg-error ".#pragma acc routine. must be at file scope" } */ +} + + +/* "( name )" syntax. */ + +#pragma acc routine ( /* { dg-error "expected (function name|unqualified-id) before end of line" } */ +#pragma acc routine () /* { dg-error "expected (function name|unqualified-id) before .\\). token" } */ +#pragma acc routine (+) /* { dg-error "expected (function name|unqualified-id) before .\\+. token" } */ +#pragma acc routine (?) /* { dg-error "expected (function name|unqualified-id) before .\\?. token" } */ +#pragma acc routine (:) /* { dg-error "expected (function name|unqualified-id) before .:. token" } */ +#pragma acc routine (4) /* { dg-error "expected (function name|unqualified-id) before numeric constant" } */ +#pragma acc routine ('4') /* { dg-error "expected (function name|unqualified-id) before .4." } */ +#pragma acc routine ("4") /* { dg-error "expected (function name|unqualified-id) before string constant" } */ +extern void R1(void); +extern void R2(void); +#pragma acc routine (R1, R2, R3) worker /* { dg-error "expected .\\). before .,. token" } */ +#pragma acc routine (R1 R2 R3) worker /* { dg-error "expected .\\). before .R2." } */ +#pragma acc routine (R1) worker +#pragma acc routine (R2) worker + + +/* "#pragma acc routine" not immediately followed by (a single) function + declaration or definition. */ + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ int a; -#pragma acc routine /* { dg-error "not followed by" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by a single function declaration or definition" } */ void fn1 (void), fn1b (void); -#pragma acc routine /* { dg-error "not followed by" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ int b, fn2 (void); -#pragma acc routine /* { dg-error "not followed by" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +int b_, fn2_ (void), B_; + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by a single function declaration or definition" } */ int fn3 (void), b2; -#pragma acc routine /* { dg-error "not followed by" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ typedef struct c c; -#pragma acc routine /* { dg-error "not followed by" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ struct d {} d; -#pragma acc routine /* { dg-error "not followed by" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by a single function declaration or definition" } */ +void fn1_2 (void), fn1b_2 (void); + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +int b_2, fn2_2 (void); + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +int b_2_, fn2_2_ (void), B_2_; + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by a single function declaration or definition" } */ +int fn3_2 (void), b2_2; + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +typedef struct c_2 c_2; + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +struct d_2 {} d_2; + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ #pragma acc routine int fn4 (void); int fn5a (void); - -#pragma acc routine /* { dg-error "not followed by" } */ +int fn5b (void); +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ #pragma acc routine (fn5a) +#pragma acc routine (fn5b) int fn5 (void); +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +#pragma acc routine (fn6a) /* { dg-error ".fn6a. has not been declared" } */ +#pragma acc routine (fn6b) /* { dg-error ".fn6b. has not been declared" } */ +int fn6 (void); + #ifdef __cplusplus -#pragma acc routine /* { dg-error "not followed by" "" { target c++ } } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" "" { target c++ } } */ namespace f {} namespace g {} -#pragma acc routine /* { dg-error "not followed by" "" { target c++ } } */ +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" "" { target c++ } } */ using namespace g; -#pragma acc routine (g) /* { dg-error "does not refer to a function" "" { target c++ } } */ +#pragma acc routine (g) /* { dg-error ".g. does not refer to a function" "" { target c++ } } */ #endif /* __cplusplus */ -#pragma acc routine (a) /* { dg-error "does not refer to a function" } */ +#pragma acc routine (a) /* { dg-error ".a. does not refer to a function" } */ -#pragma acc routine (c) /* { dg-error "does not refer to a function" } */ +#pragma acc routine (c) /* { dg-error ".c. does not refer to a function" } */ -#pragma acc routine () vector /* { dg-error "expected (function name|unqualified-id) before .\\). token" } */ +/* Static assert. */ -#pragma acc routine (+) /* { dg-error "expected (function name|unqualified-id) before .\\+. token" } */ +#pragma acc routine /* { dg-bogus ".#pragma acc routine. not immediately followed by function declaration or definition" "TODO" { xfail *-*-* } } */ +#ifndef __cplusplus /* C */ +_Static_assert(0, ""); /* { dg-error "static assertion failed" "" { target c } } */ +#elif __cplusplus < 201103L /* C++98 */ +/* C++98 doesn't support static_assert, so fake an error in combination, and as + expected with the "#pragma acc routine" above. */ +int dummy_instead_of_static_assert; +#else /* C++ */ +static_assert(0, ""); /* { dg-error "static assertion failed" "" { target c++11 } } */ +#endif +void f_static_assert(); +/* Check that we already recognized "f_static_assert" as an OpenACC routine. */ +#pragma acc routine (f_static_assert) /* { dg-error ".#pragma acc routine. already applied to .\[void \]*f_static_assert" "TODO" { xfail *-*-* } } */ -extern void R1(void); -extern void R2(void); -#pragma acc routine (R1, R2, R3) worker /* { dg-error "expected .\\). before .,. token" } */ -#pragma acc routine (R1 R2 R3) worker /* { dg-error "expected .\\). before .R2." } */ -#pragma acc routine (R1) worker -#pragma acc routine (R2) worker +/* __extension__ usage. */ +#pragma acc routine +__extension__ extern void ex1(); +#pragma acc routine (ex1) /* { dg-error ".#pragma acc routine. already applied to .\[void \]*ex1" } */ + +#pragma acc routine +__extension__ __extension__ __extension__ __extension__ __extension__ void ex2() +{ +} +#pragma acc routine (ex2) /* { dg-error ".#pragma acc routine. already applied to .\[void \]*ex2" } */ + +#pragma acc routine /* { dg-error ".#pragma acc routine. not immediately followed by function declaration or definition" } */ +__extension__ int ex3; +#pragma acc routine (ex3) /* { dg-error ".ex3. does not refer to a function" } */ + + +/* "#pragma acc routine" already applied. */ + +extern void fungsi_1(); +#pragma acc routine(fungsi_1) gang +#pragma acc routine(fungsi_1) gang /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_1" } */ +#pragma acc routine(fungsi_1) worker /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_1" } */ +#pragma acc routine(fungsi_1) vector /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_1" } */ + +#pragma acc routine seq +extern void fungsi_2(); +#pragma acc routine(fungsi_2) seq /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_2." } */ +#pragma acc routine(fungsi_2) worker /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_2." } */ +#pragma acc routine(fungsi_2) /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_2." } */ + +#pragma acc routine vector +extern void fungsi_3(); +#pragma acc routine vector /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_3." } */ +void fungsi_3() +{ +} + +extern void fungsi_4(); +#pragma acc routine (fungsi_4) worker +#pragma acc routine gang /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_4." } */ +void fungsi_4() +{ +} + +#pragma acc routine gang +void fungsi_5() +{ +} +#pragma acc routine (fungsi_5) worker /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_5." } */ + +#pragma acc routine seq +void fungsi_6() +{ +} +#pragma acc routine seq /* { dg-error ".#pragma acc routine. already applied to .\[void \]*fungsi_6." } */ +extern void fungsi_6(); + + +/* "#pragma acc routine" must be applied before. */ void Bar (); @@ -67,13 +214,15 @@ void Foo () Bar (); } -#pragma acc routine (Bar) // { dg-error "must be applied before use" } +#pragma acc routine (Bar) // { dg-error ".#pragma acc routine. must be applied before use" } -#pragma acc routine (Foo) gang // { dg-error "must be applied before definition" } +#pragma acc routine (Foo) gang // { dg-error ".#pragma acc routine. must be applied before definition" } #pragma acc routine (Baz) // { dg-error "not been declared" } +/* OpenACC declare. */ + int vb1; /* { dg-error "directive for use" } */ extern int vb2; /* { dg-error "directive for use" } */ static int vb3; /* { dg-error "directive for use" } */