Hi!

Ping.

On Wed, 13 Jul 2016 16:10:31 +0200, I wrote:
> 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 <tho...@codesourcery.com>
> 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(-)
> 
> 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<c_token>);
> -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 %<simd%> attribute cannot be "
> +      error ("%<#pragma omp declare simd%> or %<simd%> 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" } */


Grüße
 Thomas

Reply via email to