public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-11] openmp: Add support for declare simd and declare variant in a attribute syntax
@ 2021-08-10 12:41 Tobias Burnus
  0 siblings, 0 replies; only message in thread
From: Tobias Burnus @ 2021-08-10 12:41 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:190b211afc913191c374b6c81f82d74d4ec8ec72

commit 190b211afc913191c374b6c81f82d74d4ec8ec72
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Aug 10 14:35:11 2021 +0200

    openmp: Add support for declare simd and declare variant in a attribute syntax
    
    This patch adds support for declare simd and declare variant in attribute
    syntax.  Either in attribute-specifier-seq at the start of declaration, in
    that case it has similar restriction to pragma-syntax, that there is a single
    function declaration/definition in the declaration, rather than variable
    declaration or more than one function declarations or mix of function and
    variable declarations.  Or after the declarator id, in that case it applies
    just to the single function declaration and the same declaration can have
    multiple such attributes.  Or both.
    
    Furthermore, cp_parser_statement has been adjusted so that it doesn't
    accept [[omp::directive (parallel)]] etc. before statements that don't
    take attributes at all, or where those attributes don't appertain to
    the statement but something else (e.g. to label, using directive,
    declaration, etc.).
    
    2021-08-10  Jakub Jelinek  <jakub@redhat.com>
    
    gcc/cp/
            * parser.h (struct cp_omp_declare_simd_data): Remove
            in_omp_attribute_pragma and clauses members, add loc and attribs.
            (struct cp_oacc_routine_data): Remove loc member, add clauses
            member.
            * parser.c (cp_finalize_omp_declare_simd): New function.
            (cp_parser_handle_statement_omp_attributes): Mention in
            function comment the function is used also for
            attribute-declaration.
            (cp_parser_handle_directive_omp_attributes): New function.
            (cp_parser_statement): Don't call
            cp_parser_handle_statement_omp_attributes if statement doesn't
            have attribute-specifier-seq at the beginning at all or if
            if those attributes don't appertain to the statement.
            (cp_parser_simple_declaration): Call
            cp_parser_handle_directive_omp_attributes and
            cp_finalize_omp_declare_simd.
            (cp_parser_explicit_instantiation): Likewise.
            (cp_parser_init_declarator): Initialize prefix_attributes
            only after parsing declarators.
            (cp_parser_direct_declarator): Call
            cp_parser_handle_directive_omp_attributes and
            cp_finalize_omp_declare_simd.
            (cp_parser_member_declaration): Likewise.
            (cp_parser_single_declaration): Likewise.
            (cp_parser_omp_declare_simd): Don't initialize
            data.in_omp_attribute_pragma, instead initialize
            data.attribs[0] and data.attribs[1].
            (cp_finish_omp_declare_variant): Remove
            in_omp_attribute_pragma argument, instead use
            parser->lexer->in_omp_attribute_pragma.
            (cp_parser_late_parsing_omp_declare_simd): Adjust
            cp_finish_omp_declare_variant caller.  Handle attribute-syntax
            declare simd/variant.
    gcc/testsuite/
            * g++.dg/gomp/attrs-1.C (bar): Add missing semicolon after
            [[omp::directive (threadprivate (t2))]].  Add tests with
            if/while/switch after parallel in attribute syntax.
            (corge): Add missing omp:: before directive.
            * g++.dg/gomp/attrs-2.C (bar): Add missing semicolon after
            [[omp::directive (threadprivate (t2))]].
            * g++.dg/gomp/attrs-10.C: New test.
            * g++.dg/gomp/attrs-11.C: New test.
    
    (cherry picked from commit c40c6a50fd4da342c87a715ae83927a37797e094)

Diff:
---
 gcc/cp/ChangeLog.omp                 |  39 ++++
 gcc/cp/parser.c                      | 419 +++++++++++++++++++++++++++++++++--
 gcc/cp/parser.h                      |   7 +-
 gcc/testsuite/ChangeLog.omp          |  14 ++
 gcc/testsuite/g++.dg/gomp/attrs-1.C  |  12 +-
 gcc/testsuite/g++.dg/gomp/attrs-10.C | 240 ++++++++++++++++++++
 gcc/testsuite/g++.dg/gomp/attrs-11.C |  74 +++++++
 gcc/testsuite/g++.dg/gomp/attrs-2.C  |   2 +-
 8 files changed, 779 insertions(+), 28 deletions(-)

diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp
index 278c9aa67fd..b457f5d901e 100644
--- a/gcc/cp/ChangeLog.omp
+++ b/gcc/cp/ChangeLog.omp
@@ -1,3 +1,42 @@
+2021-08-10  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-10  Jakub Jelinek  <jakub@redhat.com>
+
+	* parser.h (struct cp_omp_declare_simd_data): Remove
+	in_omp_attribute_pragma and clauses members, add loc and attribs.
+	(struct cp_oacc_routine_data): Remove loc member, add clauses
+	member.
+	* parser.c (cp_finalize_omp_declare_simd): New function.
+	(cp_parser_handle_statement_omp_attributes): Mention in
+	function comment the function is used also for
+	attribute-declaration.
+	(cp_parser_handle_directive_omp_attributes): New function.
+	(cp_parser_statement): Don't call
+	cp_parser_handle_statement_omp_attributes if statement doesn't
+	have attribute-specifier-seq at the beginning at all or if
+	if those attributes don't appertain to the statement.
+	(cp_parser_simple_declaration): Call
+	cp_parser_handle_directive_omp_attributes and
+	cp_finalize_omp_declare_simd.
+	(cp_parser_explicit_instantiation): Likewise.
+	(cp_parser_init_declarator): Initialize prefix_attributes
+	only after parsing declarators.
+	(cp_parser_direct_declarator): Call
+	cp_parser_handle_directive_omp_attributes and
+	cp_finalize_omp_declare_simd.
+	(cp_parser_member_declaration): Likewise.
+	(cp_parser_single_declaration): Likewise.
+	(cp_parser_omp_declare_simd): Don't initialize
+	data.in_omp_attribute_pragma, instead initialize
+	data.attribs[0] and data.attribs[1].
+	(cp_finish_omp_declare_variant): Remove
+	in_omp_attribute_pragma argument, instead use
+	parser->lexer->in_omp_attribute_pragma.
+	(cp_parser_late_parsing_omp_declare_simd): Adjust
+	cp_finish_omp_declare_variant caller.  Handle attribute-syntax
+	declare simd/variant.
+
 2021-08-01  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4c73128a11b..5a7a4c98390 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1440,6 +1440,24 @@ cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl)
     }
 }
 
+/* Similarly, but for use in declaration parsing functions
+   which call cp_parser_handle_directive_omp_attributes.  */
+
+static inline void
+cp_finalize_omp_declare_simd (cp_parser *parser, cp_omp_declare_simd_data *data)
+{
+  if (parser->omp_declare_simd != data)
+    return;
+
+  if (!parser->omp_declare_simd->error_seen
+      && !parser->omp_declare_simd->fndecl_seen)
+    error_at (parser->omp_declare_simd->loc,
+	      "%<declare %s%> directive not immediately followed by "
+	      "function declaration or definition",
+	      parser->omp_declare_simd->variant_p ? "variant" : "simd");
+  parser->omp_declare_simd = NULL;
+}
+
 /* Diagnose if #pragma acc routine isn't followed immediately by function
    declaration or definition.  */
 
@@ -11630,7 +11648,7 @@ struct cp_omp_attribute_data
 };
 
 /* Handle omp::directive and omp::sequence attributes in ATTRS
-   (if any) at the start of a statement.  */
+   (if any) at the start of a statement or in attribute-declaration.  */
 
 static tree
 cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs)
@@ -11827,6 +11845,98 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs)
   return attrs;
 }
 
+/* Handle omp::directive and omp::sequence attributes in *PATTRS
+   (if any) at the start or after declaration-id of a declaration.  */
+
+static void
+cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs,
+					   cp_omp_declare_simd_data *data,
+					   bool start)
+{
+  if (!flag_openmp && !flag_openmp_simd)
+    return;
+
+  int cnt = 0;
+  bool bad = false;
+  bool variant_p = false;
+  location_t loc = UNKNOWN_LOCATION;
+  for (tree pa = *pattrs; pa; pa = TREE_CHAIN (pa))
+    if (get_attribute_namespace (pa) == omp_identifier
+	&& is_attribute_p ("directive", get_attribute_name (pa)))
+      {
+	for (tree a = TREE_VALUE (pa); a; a = TREE_CHAIN (a))
+	  {
+	    tree d = TREE_VALUE (a);
+	    gcc_assert (TREE_CODE (d) == DEFERRED_PARSE);
+	    cp_token *first = DEFPARSE_TOKENS (d)->first;
+	    cp_token *last = DEFPARSE_TOKENS (d)->last;
+	    const char *directive[3] = {};
+	    for (int i = 0; i < 3; i++)
+	      {
+		tree id = NULL_TREE;
+		if (first + i == last)
+		  break;
+		if (first[i].type == CPP_NAME)
+		  id = first[i].u.value;
+		else if (first[i].type == CPP_KEYWORD)
+		  id = ridpointers[(int) first[i].keyword];
+		else
+		  break;
+		directive[i] = IDENTIFIER_POINTER (id);
+	      }
+	    const c_omp_directive *dir = NULL;
+	    if (directive[0])
+	      dir = c_omp_categorize_directive (directive[0], directive[1],
+						directive[2]);
+	    if (dir == NULL)
+	      continue;
+	    if (dir->id == PRAGMA_OMP_DECLARE
+		&& (strcmp (directive[1], "simd") == 0
+		    || strcmp (directive[1], "variant") == 0))
+	      {
+		if (cnt++ == 0)
+		  {
+		    variant_p = strcmp (directive[1], "variant") == 0;
+		    loc = first->location;
+		  }
+		if (start && parser->omp_declare_simd && !bad)
+		  {
+		    error_at (first->location,
+			      "mixing OpenMP directives with attribute and "
+			      "pragma syntax on the same declaration");
+		    bad = true;
+		  }
+	      }
+	  }
+      }
+
+  if (bad)
+    {
+      for (tree *pa = pattrs; *pa; )
+	if (get_attribute_namespace (*pa) == omp_identifier
+	    && is_attribute_p ("directive", get_attribute_name (*pa)))
+	  *pa = TREE_CHAIN (*pa);
+	else
+	  pa = &TREE_CHAIN (*pa);
+      return;
+    }
+  if (cnt == 0)
+    return;
+
+  if (parser->omp_declare_simd == NULL)
+    {
+      data->error_seen = false;
+      data->fndecl_seen = false;
+      data->variant_p = variant_p;
+      data->loc = loc;
+      data->tokens = vNULL;
+      data->attribs[0] = NULL;
+      data->attribs[1] = NULL;
+      parser->omp_declare_simd = data;
+    }
+  parser->omp_declare_simd->attribs[!start] = pattrs;
+}
+
 /* Parse a statement.
 
    statement:
@@ -11904,12 +12014,57 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
     }
   has_std_attrs = cp_lexer_peek_token (parser->lexer) != token;
 
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  bool omp_attrs_forbidden_p;
+  omp_attrs_forbidden_p = parser->omp_attrs_forbidden_p;
+
   if (std_attrs && (flag_openmp || flag_openmp_simd))
-    std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs);
+    {
+      bool handle_omp_attribs = false;
+      if (token->type == CPP_KEYWORD)
+	switch (token->keyword)
+	  {
+	  case RID_IF:
+	  case RID_SWITCH:
+	  case RID_WHILE:
+	  case RID_DO:
+	  case RID_FOR:
+	  case RID_BREAK:
+	  case RID_CONTINUE:
+	  case RID_RETURN:
+	  case RID_CO_RETURN:
+	  case RID_GOTO:
+	  case RID_AT_TRY:
+	  case RID_AT_CATCH:
+	  case RID_AT_FINALLY:
+	  case RID_AT_SYNCHRONIZED:
+	  case RID_AT_THROW:
+	  case RID_TRY:
+	  case RID_TRANSACTION_ATOMIC:
+	  case RID_TRANSACTION_RELAXED:
+	  case RID_SYNCHRONIZED:
+	  case RID_ATOMIC_NOEXCEPT:
+	  case RID_ATOMIC_CANCEL:
+	  case RID_TRANSACTION_CANCEL:
+	    handle_omp_attribs = true;
+	    break;
+	  default:
+	    break;
+	  }
+      else if (token->type == CPP_SEMICOLON
+	       || token->type == CPP_OPEN_BRACE
+	       || token->type == CPP_PRAGMA)
+	handle_omp_attribs = true;
+      if (handle_omp_attribs)
+	{
+	  std_attrs = cp_parser_handle_statement_omp_attributes (parser,
+								 std_attrs);
+	  token = cp_lexer_peek_token (parser->lexer);
+	}
+    }
   parser->omp_attrs_forbidden_p = false;
 
-  /* Peek at the next token.  */
-  token = cp_lexer_peek_token (parser->lexer);
   /* Remember the location of the first token in the statement.  */
   cp_token *statement_token = token;
   statement_location = token->location;
@@ -12027,6 +12182,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
      a statement all its own.  */
   else if (token->type == CPP_PRAGMA)
     {
+     do_pragma:;
       cp_lexer *lexer = parser->lexer;
       bool do_restart = false;
       /* Only certain OpenMP pragmas are attached to statements, and thus
@@ -12089,7 +12245,46 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 	    return;
 	  /* It didn't work, restore the post-attribute position.  */
 	  if (has_std_attrs)
-	    cp_lexer_set_token_position (parser->lexer, statement_token);
+	    {
+	      cp_lexer_set_token_position (parser->lexer, statement_token);
+	      if (flag_openmp || flag_openmp_simd)
+		{
+		  size_t i = 1;
+		  bool handle_omp_attribs = true;
+		  while (cp_lexer_peek_nth_token (parser->lexer, i)->keyword
+			 == RID_EXTENSION)
+		    i++;
+		  switch (cp_lexer_peek_nth_token (parser->lexer, i)->keyword)
+		    {
+		    case RID_ASM:
+		    case RID_NAMESPACE:
+		    case RID_USING:
+		    case RID_LABEL:
+		    case RID_STATIC_ASSERT:
+		      /* Don't handle OpenMP attribs on keywords that
+			 always start a declaration statement but don't
+			 accept attribute before it and therefore
+			 the tentative cp_parser_declaration_statement
+			 fails to parse because of that.  */
+		      handle_omp_attribs = false;
+		      break;
+		    default:
+		      break;
+		    }
+
+		  if (handle_omp_attribs)
+		    {
+		      parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p;
+		      std_attrs
+			= cp_parser_handle_statement_omp_attributes
+					(parser, std_attrs);
+		      parser->omp_attrs_forbidden_p = false;
+		      token = cp_lexer_peek_token (parser->lexer);
+		      if (token->type == CPP_PRAGMA)
+			goto do_pragma;
+		    }
+		}
+	    }
 	}
       /* All preceding labels have been parsed at this point.  */
       if (loc_after_labels != NULL)
@@ -14639,6 +14834,12 @@ cp_parser_simple_declaration (cp_parser* parser,
   /* We no longer need to defer access checks.  */
   stop_deferring_access_checks ();
 
+  cp_omp_declare_simd_data odsd;
+  if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd))
+    cp_parser_handle_directive_omp_attributes (parser,
+					       &decl_specifiers.attributes,
+					       &odsd, true);
+
   /* In a block scope, a valid declaration must always have a
      decl-specifier-seq.  By not trying to parse declarators, we can
      resolve the declaration/expression ambiguity more quickly.  */
@@ -14836,6 +15037,7 @@ cp_parser_simple_declaration (cp_parser* parser,
 		  = (enum omp_requires) (omp_requires_mask
 					 | OMP_REQUIRES_TARGET_USED);
 	      pop_deferring_access_checks ();
+	      cp_finalize_omp_declare_simd (parser, &odsd);
 	      return;
 	    }
 	}
@@ -14916,6 +15118,7 @@ cp_parser_simple_declaration (cp_parser* parser,
 
  done:
   pop_deferring_access_checks ();
+  cp_finalize_omp_declare_simd (parser, &odsd);
 }
 
 /* Helper of cp_parser_simple_declaration, parse a decomposition declaration.
@@ -18522,6 +18725,13 @@ cp_parser_explicit_instantiation (cp_parser* parser)
 				CP_PARSER_FLAGS_OPTIONAL,
 				&decl_specifiers,
 				&declares_class_or_enum);
+
+  cp_omp_declare_simd_data odsd;
+  if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd))
+    cp_parser_handle_directive_omp_attributes (parser,
+					       &decl_specifiers.attributes,
+					       &odsd, true);
+
   /* If there was exactly one decl-specifier, and it declared a class,
      and there's no declarator, then we have an explicit type
      instantiation.  */
@@ -18590,6 +18800,8 @@ cp_parser_explicit_instantiation (cp_parser* parser)
   cp_parser_consume_semicolon_at_end_of_statement (parser);
 
   timevar_pop (TV_TEMPLATE_INST);
+
+  cp_finalize_omp_declare_simd (parser, &odsd);
 }
 
 /* Parse an explicit-specialization.
@@ -21819,10 +22031,6 @@ cp_parser_init_declarator (cp_parser* parser,
   if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval))
     flags |= CP_PARSER_FLAGS_CONSTEVAL;
 
-  /* Gather the attributes that were provided with the
-     decl-specifiers.  */
-  prefix_attributes = decl_specifiers->attributes;
-
   /* Assume that this is not the declarator for a function
      definition.  */
   if (function_definition_p)
@@ -21886,6 +22094,10 @@ cp_parser_init_declarator (cp_parser* parser,
   else
     asm_specification = NULL_TREE;
 
+  /* Gather the attributes that were provided with the
+     decl-specifiers.  */
+  prefix_attributes = decl_specifiers->attributes;
+
   /* Look for attributes.  */
   attributes_start_token = cp_lexer_peek_token (parser->lexer);
   attributes = cp_parser_attributes_opt (parser);
@@ -22534,13 +22746,27 @@ cp_parser_direct_declarator (cp_parser* parser,
 
 		  attrs = cp_parser_std_attribute_spec_seq (parser);
 
+		  cp_omp_declare_simd_data odsd;
+		  if ((flag_openmp || flag_openmp_simd)
+		      && declarator
+		      && declarator->std_attributes
+		      && declarator->kind == cdk_id)
+		    {
+		      tree *pa = &declarator->std_attributes;
+		      cp_parser_handle_directive_omp_attributes (parser, pa,
+								 &odsd, false);
+		    }
+
 		  /* In here, we handle cases where attribute is used after
 		     the function declaration.  For example:
 		     void func (int x) __attribute__((vector(..)));  */
 		  tree gnu_attrs = NULL_TREE;
 		  tree requires_clause = NULL_TREE;
-		  late_return = (cp_parser_late_return_type_opt
-				 (parser, declarator, requires_clause));
+		  late_return
+		    = cp_parser_late_return_type_opt (parser, declarator,
+						      requires_clause);
+
+		  cp_finalize_omp_declare_simd (parser, &odsd);
 
 		  /* Parse the virt-specifier-seq.  */
 		  virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
@@ -26284,6 +26510,13 @@ cp_parser_member_declaration (cp_parser* parser)
 				 | CP_PARSER_FLAGS_TYPENAME_OPTIONAL),
 				&decl_specifiers,
 				&declares_class_or_enum);
+
+  cp_omp_declare_simd_data odsd;
+  if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd))
+    cp_parser_handle_directive_omp_attributes (parser,
+					       &decl_specifiers.attributes,
+					       &odsd, true);
+
   /* Check for an invalid type-name.  */
   if (!decl_specifiers.any_type_specifiers_p
       && cp_parser_parse_and_diagnose_invalid_type_name (parser))
@@ -26390,6 +26623,10 @@ cp_parser_member_declaration (cp_parser* parser)
 	 being declared.  */
       prefix_attributes = decl_specifiers.attributes;
       decl_specifiers.attributes = NULL_TREE;
+      if (parser->omp_declare_simd
+	  && (parser->omp_declare_simd->attribs[0]
+	      == &decl_specifiers.attributes))
+	parser->omp_declare_simd->attribs[0] = &prefix_attributes;
 
       /* See if these declarations will be friends.  */
       friend_p = cp_parser_friend_p (&decl_specifiers);
@@ -26778,6 +27015,7 @@ cp_parser_member_declaration (cp_parser* parser)
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
  out:
   parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+  cp_finalize_omp_declare_simd (parser, &odsd);
 }
 
 /* Parse a pure-specifier.
@@ -30903,6 +31141,13 @@ cp_parser_single_declaration (cp_parser* parser,
 				 | CP_PARSER_FLAGS_TYPENAME_OPTIONAL),
 				&decl_specifiers,
 				&declares_class_or_enum);
+
+  cp_omp_declare_simd_data odsd;
+  if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd))
+    cp_parser_handle_directive_omp_attributes (parser,
+					       &decl_specifiers.attributes,
+					       &odsd, true);
+
   if (friend_p)
     *friend_p = cp_parser_friend_p (&decl_specifiers);
 
@@ -31031,6 +31276,8 @@ cp_parser_single_declaration (cp_parser* parser,
   parser->qualifying_scope = NULL_TREE;
   parser->object_scope = NULL_TREE;
 
+  cp_finalize_omp_declare_simd (parser, &odsd);
+
   return decl;
 }
 
@@ -43393,9 +43640,10 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
       data.error_seen = false;
       data.fndecl_seen = false;
       data.variant_p = variant_p;
-      data.in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
       data.tokens = vNULL;
-      data.clauses = NULL_TREE;
+      data.attribs[0] = NULL;
+      data.attribs[1] = NULL;
+      data.loc = UNKNOWN_LOCATION;
       /* It is safe to take the address of a local variable; it will only be
 	 used while this scope is live.  */
       parser->omp_declare_simd = &data;
@@ -43832,7 +44080,7 @@ cp_parser_omp_context_selector_specification (cp_parser *parser,
 
 static tree
 cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
-			       tree attrs, bool in_omp_attribute_pragma)
+			       tree attrs)
 {
   matching_parens parens;
   if (!parens.require_open (parser))
@@ -43891,7 +44139,7 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
   location_t varid_loc = make_location (caret_loc, start_loc, finish_loc);
 
   /* For now only in C++ attributes, do it always for OpenMP 5.1.  */
-  if (in_omp_attribute_pragma
+  if (parser->lexer->in_omp_attribute_pragma
       && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
       && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
     cp_lexer_consume_token (parser->lexer);
@@ -43968,11 +44216,10 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs)
       cp_lexer_consume_token (parser->lexer);
       if (strcmp (kind, "simd") == 0)
 	{
-	  /* For now only in C++ attributes, do it always for OpenMP 5.1.  */
-	  if (data->in_omp_attribute_pragma
-	      && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+	  /* For now only in C++ attributes, do it always for OpenMP 5.1.
+	  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
 	      && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
-	    cp_lexer_consume_token (parser->lexer);
+	    cp_lexer_consume_token (parser->lexer);  */
 
 	  cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
 					  "#pragma omp declare simd",
@@ -43989,12 +44236,142 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs)
 	{
 	  gcc_assert (strcmp (kind, "variant") == 0);
 	  attrs
-	    = cp_finish_omp_declare_variant (parser, pragma_tok, attrs,
-					     data->in_omp_attribute_pragma);
+	    = cp_finish_omp_declare_variant (parser, pragma_tok, attrs);
 	}
       cp_parser_pop_lexer (parser);
     }
 
+  cp_lexer *lexer = NULL;
+  for (int i = 0; i < 2; i++)
+    {
+      if (data->attribs[i] == NULL)
+	continue;
+      for (tree *pa = data->attribs[i]; *pa; )
+	if (get_attribute_namespace (*pa) == omp_identifier
+	    && is_attribute_p ("directive", get_attribute_name (*pa)))
+	  {
+	    for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a))
+	      {
+		tree d = TREE_VALUE (a);
+		gcc_assert (TREE_CODE (d) == DEFERRED_PARSE);
+		cp_token *first = DEFPARSE_TOKENS (d)->first;
+		cp_token *last = DEFPARSE_TOKENS (d)->last;
+		const char *directive[3] = {};
+		for (int j = 0; j < 3; j++)
+		  {
+		    tree id = NULL_TREE;
+		    if (first + j == last)
+		      break;
+		    if (first[j].type == CPP_NAME)
+		      id = first[j].u.value;
+		    else if (first[j].type == CPP_KEYWORD)
+		      id = ridpointers[(int) first[j].keyword];
+		    else
+		      break;
+		    directive[j] = IDENTIFIER_POINTER (id);
+		  }
+		const c_omp_directive *dir = NULL;
+		if (directive[0])
+		  dir = c_omp_categorize_directive (directive[0], directive[1],
+						    directive[2]);
+		if (dir == NULL)
+		  {
+		    error_at (first->location,
+			      "unknown OpenMP directive name in "
+			      "%<omp::directive%> attribute argument");
+		    continue;
+		  }
+		if (dir->id != PRAGMA_OMP_DECLARE
+		    || (strcmp (directive[1], "simd") != 0
+			&& strcmp (directive[1], "variant") != 0))
+		  {
+		    error_at (first->location,
+			      "OpenMP directive other than %<declare simd%> "
+			      "or %<declare variant%> appertains to a "
+			      "declaration");
+		    continue;
+		  }
+
+		if (!flag_openmp && strcmp (directive[1], "simd") != 0)
+		  continue;
+		if (lexer == NULL)
+		  {
+		    lexer = cp_lexer_alloc ();
+		    lexer->debugging_p = parser->lexer->debugging_p;
+		  }
+		vec_safe_reserve (lexer->buffer, (last - first) + 2);
+		cp_token tok = {};
+		tok.type = CPP_PRAGMA;
+		tok.keyword = RID_MAX;
+		tok.u.value = build_int_cst (NULL, PRAGMA_OMP_DECLARE);
+		tok.location = first->location;
+		lexer->buffer->quick_push (tok);
+		while (++first < last)
+		  lexer->buffer->quick_push (*first);
+		tok = {};
+		tok.type = CPP_PRAGMA_EOL;
+		tok.keyword = RID_MAX;
+		tok.location = last->location;
+		lexer->buffer->quick_push (tok);
+		tok = {};
+		tok.type = CPP_EOF;
+		tok.keyword = RID_MAX;
+		tok.location = last->location;
+		lexer->buffer->quick_push (tok);
+		lexer->next = parser->lexer;
+		lexer->next_token = lexer->buffer->address ();
+		lexer->last_token = lexer->next_token
+				    + lexer->buffer->length ()
+		      - 1;
+		lexer->in_omp_attribute_pragma = true;
+		parser->lexer = lexer;
+		/* Move the current source position to that of the first token
+		   in the new lexer.  */
+		cp_lexer_set_source_position_from_token (lexer->next_token);
+
+		cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer);
+		tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+		const char *kind = IDENTIFIER_POINTER (id);
+		cp_lexer_consume_token (parser->lexer);
+
+		tree c, cl;
+		if (strcmp (kind, "simd") == 0)
+		  {
+		    if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+			&& cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+		      cp_lexer_consume_token (parser->lexer);
+
+		    omp_clause_mask mask = OMP_DECLARE_SIMD_CLAUSE_MASK;
+		    cl = cp_parser_omp_all_clauses (parser, mask,
+						    "#pragma omp declare simd",
+						    pragma_tok);
+		    if (cl)
+		      cl = tree_cons (NULL_TREE, cl, NULL_TREE);
+		    c = build_tree_list (get_identifier ("omp declare simd"),
+					 cl);
+		    TREE_CHAIN (c) = attrs;
+		    if (processing_template_decl)
+		      ATTR_IS_DEPENDENT (c) = 1;
+		    attrs = c;
+		  }
+		else
+		  {
+		    gcc_assert (strcmp (kind, "variant") == 0);
+		    attrs
+		      = cp_finish_omp_declare_variant (parser, pragma_tok,
+						       attrs);
+		  }
+		gcc_assert (parser->lexer != lexer);
+		vec_safe_truncate (lexer->buffer, 0);
+	      }
+	    *pa = TREE_CHAIN (*pa);
+	  }
+	else
+	  pa = &TREE_CHAIN (*pa);
+    }
+  if (lexer)
+    cp_lexer_destroy (lexer);
+
   data->fndecl_seen = true;
   return attrs;
 }
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index e62742db95d..3669587cebd 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -216,15 +216,14 @@ struct cp_omp_declare_simd_data {
   bool error_seen; /* Set if error has been reported.  */
   bool fndecl_seen; /* Set if one fn decl/definition has been seen already.  */
   bool variant_p; /* Set for #pragma omp declare variant.  */
-  bool in_omp_attribute_pragma; /* True if declare simd/variant comes from
-				   C++11 attribute rather than pragma.  */
+  location_t loc;
   vec<cp_token_cache_ptr> tokens;
-  tree clauses;
+  tree *attribs[2];
 };
 
 /* Helper data structure for parsing #pragma acc routine.  */
 struct cp_oacc_routine_data : cp_omp_declare_simd_data {
-  location_t loc;
+  tree clauses;
 };
 
 /* The cp_parser structure represents the C++ parser.  */
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index 300a9a75f9a..fa94fc47017 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,17 @@
+2021-08-10  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backported from master:
+	2021-08-10  Jakub Jelinek  <jakub@redhat.com>
+
+	* g++.dg/gomp/attrs-1.C (bar): Add missing semicolon after
+	[[omp::directive (threadprivate (t2))]].  Add tests with
+	if/while/switch after parallel in attribute syntax.
+	(corge): Add missing omp:: before directive.
+	* g++.dg/gomp/attrs-2.C (bar): Add missing semicolon after
+	[[omp::directive (threadprivate (t2))]].
+	* g++.dg/gomp/attrs-10.C: New test.
+	* g++.dg/gomp/attrs-11.C: New test.
+
 2021-08-01  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C
index 6bbdcac7fba..5c7007be8a6 100644
--- a/gcc/testsuite/g++.dg/gomp/attrs-1.C
+++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C
@@ -501,10 +501,18 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
     }
   }
   extern int t2;
-  [[omp::directive (threadprivate (t2))]]
+  [[omp::directive (threadprivate (t2))]];
   extern int t2;
   [[omp::directive (declare reduction (dr: int: omp_out += omp_in) initializer (omp_priv = 0))]]
   ;
+  [[omp::directive (parallel)]]
+  if (0)
+    ;
+  [[omp::directive (parallel)]]
+  while (0)
+    ;
+  [[omp::directive (parallel)]]
+  switch (0) { case 1: break; default: break; }
 }
 
 void corge1 ();
@@ -521,7 +529,7 @@ corge ()
     omp::directive (declare simd simdlen(8) notinbranch)]]
   extern int corge3 (int l, int *p);
   [[omp::directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch),
-    directive (declare simd simdlen(8) notinbranch)]]
+    omp::directive (declare simd simdlen(8) notinbranch)]]
   extern int corge4 (int l, int *p);
   [[omp::sequence (directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch),
     omp::directive (declare simd simdlen(8) notinbranch))]]
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-10.C b/gcc/testsuite/g++.dg/gomp/attrs-10.C
new file mode 100644
index 00000000000..a78f892c237
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/attrs-10.C
@@ -0,0 +1,240 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-fopenmp -ffat-lto-objects -fdump-tree-gimple" }
+
+extern "C" void abort ();
+
+[[omp::directive (declare simd, linear (l))]] extern int f1 (int l);
+extern int f2 (int), f3 [[omp::directive (declare simd, uniform (m))]] (int m), f4 (int), z;
+[[omp::directive (declare simd, linear (l), simdlen(4))]] extern int f5 [[omp::directive (declare simd uniform (l) simdlen (8) notinbranch)]] (int l);
+
+int
+f1 (int l)
+{
+  return l;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f2 (int l)
+{
+  return l + 1;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f2i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f3 (int l)
+{
+  return l + 2;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f4 (int l)
+{
+  return l + 3;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f4i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f5 (int l)
+{	// { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-1 }
+  return l + 4;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f5i:" { target { i?86-*-* x86_64-*-* } } } }
+
+[[omp::directive (declare simd, linear (l), simdlen(4), notinbranch),
+  omp::directive (declare simd, uniform (l), simdlen(4), inbranch)]]
+int
+f6 [[omp::sequence (directive (declare simd uniform (l) simdlen (8), notinbranch),
+		    omp::directive (declare simd linear (l) simdlen (8) inbranch))]] (int l)
+{	// { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-2 }
+  return l + 5;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M4l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]N4u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]N8l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f7 (int l)
+{
+  return l + 6;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f7i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f8 (int l)
+{
+  return l + 7;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f8i:" { target { i?86-*-* x86_64-*-* } } } }
+
+[[omp::sequence (omp::directive (declare variant (f7), match (construct={parallel})),
+		 directive (declare simd uniform (l), simdlen(4)))]]
+int
+f9 [[omp::directive (declare simd uniform (l) simdlen (8)),
+     omp::directive (declare variant (f8) match (construct={parallel,for}))]] (int l)
+{	// { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-2 }
+  return l + 8;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int z;
+
+void
+test ()
+{
+  [[omp::directive (parallel)]]
+  if (f9 (3) != 9)
+    abort ();
+  [[omp::directive (parallel for)]]
+  for (int i = 0; i < 1; i++)
+    if (f9 (4) != 11)
+      abort ();
+  if (f9 (5) != 13)
+    abort ();
+}
+
+// { dg-final { scan-tree-dump-times " = f7 \\\(3\\\);" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times " = f8 \\\(4\\\);" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times " = f9 \\\(5\\\);" 1 "gimple" } }
+
+template <int N>
+int
+f10 (int x)
+{
+  return x + N;
+}
+
+template [[omp::directive (declare simd, notinbranch)]] int f10<0> (int);
+
+// { dg-final { scan-assembler-times "_ZGVbN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template  int f10<1> [[omp::directive (declare simd inbranch linear(x))]] (int x);
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template <int N>
+int f11 (int);
+
+template <> [[omp::directive (declare simd, inbranch)]] int
+f11<0> (int x)
+{
+  return x;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template <> int
+f11<1> [[omp::directive (declare simd, notinbranch, linear (y))]] (int y)
+{
+  return y;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+struct S
+{
+  [[omp::sequence (directive (declare simd, inbranch, uniform (this)))]] int f12 (int x);
+  int f13 [[gnu::noinline, omp::directive (declare simd notinbranch uniform (this) linear (y))]] (int y) { return y; }
+};
+
+int
+S::f12 (int x)
+{
+  return x;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+// { dg-final { scan-assembler-times "_ZGVbN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f14 (S &p, int x)
+{
+  return p.f13 (x);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-11.C b/gcc/testsuite/g++.dg/gomp/attrs-11.C
new file mode 100644
index 00000000000..a8e27b74df5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/attrs-11.C
@@ -0,0 +1,74 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-fopenmp -Wno-attributes" }
+
+namespace N {}
+namespace O { typedef int T; };
+
+void
+foo ()
+{
+  [[omp::directive (parallel)]] asm ("");			// { dg-error "expected" }
+  [[omp::directive (parallel)]] __extension__ asm ("");		// { dg-error "expected" }
+  __extension__ [[omp::directive (parallel)]] asm ("");		// { dg-error "expected" }
+  [[omp::directive (parallel)]] namespace M = ::N;		// { dg-error "expected" }
+  [[omp::directive (parallel)]] using namespace N;		// { dg-bogus "expected" "" { xfail *-*-* } }
+  [[omp::directive (parallel)]] using O::T;			// { dg-error "expected" }
+  [[omp::directive (parallel)]] __label__ foo;			// { dg-error "expected" }
+  [[omp::directive (parallel)]] static_assert (true, "");	// { dg-error "expected" }
+  [[omp::directive (parallel)]] int a = 5;			// { dg-error "not allowed to be specified in this context" }
+  int b = 0;
+  [[omp::directive (parallel)]] l: b++;				// { dg-error "not allowed to be specified in this context" }
+  switch (0)
+    {
+      [[omp::directive (parallel)]] case 6: break;		// { dg-error "not allowed to be specified in this context" }
+      [[omp::directive (parallel)]] default: break;		// { dg-error "not allowed to be specified in this context" }
+    }
+}
+
+void
+bar ()
+{
+  [[omp::directive (declare simd)]] int a;		// { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" }
+  [[omp::directive (declare simd)]] int b, f1 (int);	// { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" }
+  [[omp::directive (declare simd)]] int f2 (int), c;	// { dg-error "not immediately followed by function declaration or definition" }
+  int d [[omp::directive (declare simd)]];		// { dg-error "not allowed to be specified in this context" }
+  int f3 [[omp::directive (declare simd)]] (int), f4 [[omp::directive (declare simd)]] (int);
+  __extension__ [[omp::directive (declare simd)]] int f5 (int);
+  __extension__ int f6 [[omp::directive (declare simd, notinbranch)]] (int);
+  #pragma omp declare simd notinbranch
+  [[omp::directive (declare simd inbranch)]] int f7 (int);	// { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" }
+  [[omp::directive (declare simd notinbranch)]]
+  #pragma omp declare simd inbranch	// { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" }
+  int f8 (int);
+  static int t1, t2, t3, t4;
+  [[omp::directive (declare simd), omp::directive (foobar)]] int f9 (int);	// { dg-error "unknown OpenMP directive name" }
+  [[omp::directive (foobar), omp::directive (declare simd)]] int f10 (int);	// { dg-error "unknown OpenMP directive name" }
+  [[omp::directive (threadprivate (t1)), omp::directive (declare simd)]] int f10 (int);	// { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+  [[omp::directive (declare simd), omp::directive (threadprivate (t2))]] int f11 (int);	// { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+  int f12 [[omp::directive (declare simd), omp::directive (foobar)]] (int);	// { dg-error "unknown OpenMP directive name" }
+  int f13 [[omp::directive (foobar), omp::directive (declare simd)]] (int);	// { dg-error "unknown OpenMP directive name" }
+  int f14 [[omp::directive (threadprivate (t3)), omp::directive (declare simd)]] (int);	// { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+  int f15 [[omp::directive (declare simd), omp::directive (threadprivate (t4))]] (int);	// { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+}
+
+[[omp::directive (declare simd)]] int a;		// { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" }
+[[omp::directive (declare simd)]] int b, f16 (int);	// { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" }
+[[omp::directive (declare simd)]] int f17 (int), c;	// { dg-error "not immediately followed by function declaration or definition" }
+int d [[omp::directive (declare simd)]];		// { dg-error "not allowed to be specified in this context" }
+int f18 [[omp::directive (declare simd)]] (int), f19 [[omp::directive (declare simd)]] (int);
+__extension__ [[omp::directive (declare simd)]] int f20 (int);
+__extension__ int f21 [[omp::directive (declare simd, notinbranch)]] (int);
+#pragma omp declare simd notinbranch
+[[omp::directive (declare simd inbranch)]] int f22 (int);	// { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" }
+[[omp::directive (declare simd notinbranch)]]		// { dg-error "'declare simd' directive not immediately followed by function declaration or definition" }
+#pragma omp declare simd inbranch	// { dg-error "'#pragma' is not allowed here" }
+int f23 (int);
+int t5, t6, t7, t8;
+[[omp::directive (declare simd), omp::directive (foobar)]] int f24 (int);	// { dg-error "unknown OpenMP directive name" }
+[[omp::directive (foobar), omp::directive (declare simd)]] int f25 (int);	// { dg-error "unknown OpenMP directive name" }
+[[omp::directive (threadprivate (t5)), omp::directive (declare simd)]] int f26 (int);	// { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+[[omp::directive (declare simd), omp::directive (threadprivate (t6))]] int f27 (int);	// { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+int f28 [[omp::directive (declare simd), omp::directive (foobar)]] (int);	// { dg-error "unknown OpenMP directive name" }
+int f29 [[omp::directive (foobar), omp::directive (declare simd)]] (int);	// { dg-error "unknown OpenMP directive name" }
+int f30 [[omp::directive (threadprivate (t7)), omp::directive (declare simd)]] (int);	// { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
+int f31 [[omp::directive (declare simd), omp::directive (threadprivate (t8))]] (int);	// { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" }
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C
index 189dc6b1859..1b59abdbd1e 100644
--- a/gcc/testsuite/g++.dg/gomp/attrs-2.C
+++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C
@@ -501,7 +501,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
     }
   }
   extern int t2;
-  [[omp::directive (threadprivate (t2))]]
+  [[omp::directive (threadprivate (t2))]];
   extern int t2;
   [[omp::directive (declare reduction (dr: int: omp_out += omp_in),initializer (omp_priv = 0))]]
   ;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-10 12:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-10 12:41 [gcc/devel/omp/gcc-11] openmp: Add support for declare simd and declare variant in a attribute syntax Tobias Burnus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).