public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] openmp: Add support for declare simd and declare variant in a attribute syntax
@ 2021-08-10  9:34 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2021-08-10  9:34 UTC (permalink / raw)
  To: gcc-patches

Hi!

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.).

Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.

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.

--- gcc/cp/parser.h.jj	2021-08-09 11:36:38.449390046 +0200
+++ gcc/cp/parser.h	2021-08-09 15:14:20.375843582 +0200
@@ -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.  */
--- gcc/cp/parser.c.jj	2021-08-09 11:36:38.412390555 +0200
+++ gcc/cp/parser.c	2021-08-09 20:47:06.620792815 +0200
@@ -1440,6 +1440,24 @@ cp_finalize_omp_declare_simd (cp_parser
     }
 }
 
+/* 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.  */
 
@@ -11661,7 +11679,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)
@@ -11858,6 +11876,98 @@ cp_parser_handle_statement_omp_attribute
   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:
@@ -11935,12 +12045,57 @@ cp_parser_statement (cp_parser* parser,
     }
   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;
@@ -12058,6 +12213,7 @@ cp_parser_statement (cp_parser* parser,
      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
@@ -12120,7 +12276,46 @@ cp_parser_statement (cp_parser* parser,
 	    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)
@@ -14770,6 +14965,12 @@ cp_parser_simple_declaration (cp_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.  */
@@ -14962,6 +15163,7 @@ cp_parser_simple_declaration (cp_parser*
 	  else
 	    {
 	      pop_deferring_access_checks ();
+	      cp_finalize_omp_declare_simd (parser, &odsd);
 	      return;
 	    }
 	}
@@ -15042,6 +15244,7 @@ cp_parser_simple_declaration (cp_parser*
 
  done:
   pop_deferring_access_checks ();
+  cp_finalize_omp_declare_simd (parser, &odsd);
 }
 
 /* Helper of cp_parser_simple_declaration, parse a decomposition declaration.
@@ -18659,6 +18862,13 @@ cp_parser_explicit_instantiation (cp_par
 				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.  */
@@ -18727,6 +18937,8 @@ cp_parser_explicit_instantiation (cp_par
   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.
@@ -21964,10 +22176,6 @@ cp_parser_init_declarator (cp_parser* pa
   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)
@@ -22031,6 +22239,10 @@ cp_parser_init_declarator (cp_parser* pa
   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);
@@ -22679,13 +22891,27 @@ cp_parser_direct_declarator (cp_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);
@@ -26435,6 +26661,13 @@ cp_parser_member_declaration (cp_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))
@@ -26554,6 +26787,10 @@ cp_parser_member_declaration (cp_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);
@@ -26942,6 +27179,7 @@ cp_parser_member_declaration (cp_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.
@@ -31067,6 +31305,13 @@ cp_parser_single_declaration (cp_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);
 
@@ -31195,6 +31440,8 @@ cp_parser_single_declaration (cp_parser*
   parser->qualifying_scope = NULL_TREE;
   parser->object_scope = NULL_TREE;
 
+  cp_finalize_omp_declare_simd (parser, &odsd);
+
   return decl;
 }
 
@@ -43546,9 +43793,10 @@ cp_parser_omp_declare_simd (cp_parser *p
       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;
@@ -43985,7 +44233,7 @@ cp_parser_omp_context_selector_specifica
 
 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))
@@ -44044,7 +44292,7 @@ cp_finish_omp_declare_variant (cp_parser
   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);
@@ -44121,11 +44369,10 @@ cp_parser_late_parsing_omp_declare_simd
       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",
@@ -44142,12 +44389,142 @@ cp_parser_late_parsing_omp_declare_simd
 	{
 	  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;
 }
--- gcc/testsuite/g++.dg/gomp/attrs-1.C.jj	2021-07-27 09:47:44.221778658 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-1.C	2021-08-09 17:42:20.227904251 +0200
@@ -501,10 +501,18 @@ bar (int d, int m, int i1, int i2, int i
     }
   }
   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))]]
--- gcc/testsuite/g++.dg/gomp/attrs-2.C.jj	2021-07-27 09:47:44.222778645 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-2.C	2021-08-09 16:11:37.310671705 +0200
@@ -501,7 +501,7 @@ bar (int d, int m, int i1, int i2, int i
     }
   }
   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))]]
   ;
--- gcc/testsuite/g++.dg/gomp/attrs-10.C.jj	2021-08-09 15:14:20.375843582 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-10.C	2021-08-09 20:49:46.058619042 +0200
@@ -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);
+}
--- gcc/testsuite/g++.dg/gomp/attrs-11.C.jj	2021-08-09 17:41:19.316739285 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-11.C	2021-08-09 20:51:13.377428535 +0200
@@ -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" }


	Jakub


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

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

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-10  9:34 [committed] openmp: Add support for declare simd and declare variant in a attribute syntax Jakub Jelinek

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).