Patchwork [WIP,RFH] #pragma omp declare simd (aka OpenMP elemental functions) parsing

login
register
mail settings
Submitter Jakub Jelinek
Date April 29, 2013, 6:32 p.m.
Message ID <20130429183241.GI28963@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/240472/
State New
Headers show

Comments

Jakub Jelinek - April 29, 2013, 6:32 p.m.
Hi!

The following patch are some WIP steps towards #pragma omp declare simd
parsing.  The spec is a little bit vague, talks just that (a sequence of)
#pragma omp declare simd pragmas have to immediately precede a function
declaration or definition and that the arguments referred in its clauses
are the argument names of that function declaration or definition.

ATM the patch just throws that info away completely in
cp_finish_omp_declare_simd after calling finish_omp_clauses on it,
the plan is just for each clause list create some artificial attribute
(say "omp declare simd" with the spaces) and put the clauses as its
argument.

Now, my current problem is that in the declare-simd-1.C testcase
unfortunately on 2 lines I get 3 errors each; the problem is that this
is an explicit specialization and the original decl has no param names (or
could have different parameter names), and before start_decl returns
grokdeclarator -> grokfndecl -> check_explicit_specialization calls
duplicate_decls and throws away the new parameter names (if the new
explicit specialization isn't definition).
Any suggestions what to do?  The problem is that
grokdeclarator, grokfndecl, check_explicit_specialization are decl.c,
and have no access to cp_parser structure which contains the vector.
Should I copy the parser->omp_declare_simd_clauses vector pointer
say into cp_declarator structure so that grokfndecl could grab it from
there?  Also, for the attributes I wonder if it wouldn't be better to
finally replace the PARM_DECLs in the clauses say with parameter indexes,
because otherwise it might be difficult to adjust those during instantiation
etc.

Other comments?

2013-04-29  Jakub Jelinek  <jakub@redhat.com>

	* parser.h (struct cp_parser): Add omp_declare_simd_clauses field.
	* parser.c (cp_ensure_no_omp_declare_simd): New function.
	(enum pragma_context): Add pragma_member and pragma_objc_icode.
	(cp_parser_linkage_specification, cp_parser_namespace_definition,
	cp_parser_class_specifier_1):
	Call cp_ensure_no_omp_declare_simd.
	(cp_parser_init_declarator, cp_parser_member_declaration,
	cp_parser_function_definition_from_specifiers_and_declarator,
	cp_parser_save_member_function_body): Call cp_finish_omp_declare_simd.
	(cp_parser_member_specification_opt): Pass pragma_member instead
	of pragma_external to cp_parser_pragma.
	(cp_parser_objc_interstitial_code): Pass pragma_objc_icode instead
	of pragma_external to cp_parser_pragma.
	(cp_parser_omp_var_list_no_open): If parser->omp_declare_simd_clauses,
	just cp_parser_identifier the argument names.
	(cp_parser_omp_all_clauses): Don't call finish_omp_clauses for
	parser->omp_declare_simd_clauses.
	(OMP_DECLARE_SIMD_CLAUSE_MASK): Define.
	(cp_parser_omp_declare_simd, cp_finish_omp_declare_simd,
	cp_parser_omp_declare): New functions.
	(cp_parser_pragma): Call cp_ensure_no_omp_declare_simd.  Handle
	PRAGMA_OMP_DECLARE_REDUCTION.  Replace == pragma_external with
	!= pragma_stmt and != pragma_compound.

	* g++.dg/gomp/declare-simd-1.C: New test.
	* g++.dg/gomp/declare-simd-2.C: New test.


	Jakub
Jason Merrill - April 30, 2013, 2:35 p.m.
On 04/29/2013 02:32 PM, Jakub Jelinek wrote:
> Should I copy the parser->omp_declare_simd_clauses vector pointer
> say into cp_declarator structure so that grokfndecl could grab it from
> there?

That sounds good.

> Also, for the attributes I wonder if it wouldn't be better to
> finally replace the PARM_DECLs in the clauses say with parameter indexes,
> because otherwise it might be difficult to adjust those during instantiation
> etc.

Yes, that will probably be easier to deal with.

Jason

Patch

--- gcc/cp/parser.h.jj	2013-03-20 10:07:19.000000000 +0100
+++ gcc/cp/parser.h	2013-04-29 12:17:55.445392454 +0200
@@ -340,6 +340,10 @@  typedef struct GTY(()) cp_parser {
   /* The number of template parameter lists that apply directly to the
      current declaration.  */
   unsigned num_template_parameter_lists;
+
+  /* When parsing #pragma omp declare simd, this is a vector of
+     the clauses.  */
+  vec<tree, va_gc> *omp_declare_simd_clauses;
 } cp_parser;
 
 /* In parser.c  */
--- gcc/cp/parser.c.jj	2013-04-24 15:24:45.000000000 +0200
+++ gcc/cp/parser.c	2013-04-29 19:55:05.987702600 +0200
@@ -1169,6 +1169,19 @@  cp_token_cache_new (cp_token *first, cp_
   return cache;
 }
 
+/* Diagnose if #pragma omp declare simd isn't followed immediately
+   by function declaration or definition.  */
+
+static inline void
+cp_ensure_no_omp_declare_simd (cp_parser *parser)
+{
+  if (parser->omp_declare_simd_clauses)
+    {
+      error ("%<#pragma omp declare simd%> not immediately followed by "
+	     "function declaration or definition");
+      parser->omp_declare_simd_clauses = NULL;
+    }
+}
 
 /* Decl-specifiers.  */
 
@@ -2149,7 +2162,13 @@  static bool cp_parser_function_transacti
 static tree cp_parser_transaction_cancel
   (cp_parser *);
 
-enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
+enum pragma_context {
+  pragma_external,
+  pragma_member,
+  pragma_objc_icode,
+  pragma_stmt,
+  pragma_compound
+};
 static bool cp_parser_pragma
   (cp_parser *, enum pragma_context);
 
@@ -11154,6 +11173,8 @@  cp_parser_linkage_specification (cp_pars
      production.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
     {
+      cp_ensure_no_omp_declare_simd (parser);
+
       /* Consume the `{' token.  */
       cp_lexer_consume_token (parser->lexer);
       /* Parse the declarations.  */
@@ -15049,6 +15070,7 @@  cp_parser_namespace_definition (cp_parse
   bool has_visibility;
   bool is_inline;
 
+  cp_ensure_no_omp_declare_simd (parser);
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE))
     {
       maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES);
@@ -15698,6 +15720,8 @@  cp_parser_asm_definition (cp_parser* par
     }
 }
 
+static void cp_finish_omp_declare_simd (cp_parser *, tree);
+
 /* Declarators [gram.dcl.decl] */
 
 /* Parse an init-declarator.
@@ -15989,6 +16013,8 @@  cp_parser_init_declarator (cp_parser* pa
 	  && declarator->id_loc != UNKNOWN_LOCATION
 	  && DECL_SOURCE_LOCATION (decl) == input_location)
 	DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
+      if (parser->omp_declare_simd_clauses)
+	cp_finish_omp_declare_simd (parser, decl);
     }
   else if (scope)
     /* Enter the SCOPE.  That way unqualified names appearing in the
@@ -16091,6 +16117,8 @@  cp_parser_init_declarator (cp_parser* pa
 			prefix_attributes);
       if (decl && TREE_CODE (decl) == FUNCTION_DECL)
 	cp_parser_save_default_args (parser, decl);
+      if (parser->omp_declare_simd_clauses)
+	cp_finish_omp_declare_simd (parser, decl);
     }
 
   /* Finish processing the declaration.  But, skip member
@@ -18302,6 +18330,8 @@  cp_parser_class_specifier_1 (cp_parser*
       return error_mark_node;
     }
 
+  cp_ensure_no_omp_declare_simd (parser);
+
   /* Issue an error message if type-definitions are forbidden here.  */
   cp_parser_check_type_definition (parser);
   /* Remember that we are defining one more class.  */
@@ -19079,7 +19109,7 @@  cp_parser_member_specification_opt (cp_p
 	  /* Accept #pragmas at class scope.  */
 	  if (token->type == CPP_PRAGMA)
 	    {
-	      cp_parser_pragma (parser, pragma_external);
+	      cp_parser_pragma (parser, pragma_member);
 	      break;
 	    }
 
@@ -19531,13 +19561,16 @@  cp_parser_member_declaration (cp_parser*
 	      else
 		if (declarator->kind == cdk_function)
 		  declarator->id_loc = token->location;
-		/* Create the declaration.  */
-		decl = grokfield (declarator, &decl_specifiers,
-				  initializer, /*init_const_expr_p=*/true,
-				  asm_specification,
-				  attributes);
+	      /* Create the declaration.  */
+	      decl = grokfield (declarator, &decl_specifiers,
+				initializer, /*init_const_expr_p=*/true,
+				asm_specification,
+				attributes);
 	    }
 
+	  if (parser->omp_declare_simd_clauses)
+	    cp_finish_omp_declare_simd (parser, decl);
+
 	  /* Reset PREFIX_ATTRIBUTES.  */
 	  while (attributes && TREE_CHAIN (attributes) != first_attribute)
 	    attributes = TREE_CHAIN (attributes);
@@ -21697,6 +21730,11 @@  cp_parser_function_definition_from_speci
   else
     {
       timevar_id_t tv;
+      if (parser->omp_declare_simd_clauses)
+	{
+	  cp_finish_omp_declare_simd (parser, current_function_decl);
+	  parser->omp_declare_simd_clauses = NULL;
+	}
       if (DECL_DECLARED_INLINE_P (current_function_decl))
         tv = TV_PARSE_INLINE;
       else
@@ -22207,6 +22245,12 @@  cp_parser_save_member_function_body (cp_
       return error_mark_node;
     }
 
+  if (parser->omp_declare_simd_clauses)
+    {
+      cp_finish_omp_declare_simd (parser, fn);
+      parser->omp_declare_simd_clauses = NULL;
+    }
+
   /* Remember it, if there default args to post process.  */
   cp_parser_save_default_args (parser, fn);
 
@@ -24544,7 +24588,7 @@  cp_parser_objc_interstitial_code (cp_par
     cp_parser_linkage_specification (parser);
   /* Handle #pragma, if any.  */
   else if (token->type == CPP_PRAGMA)
-    cp_parser_pragma (parser, pragma_external);
+    cp_parser_pragma (parser, pragma_objc_icode);
   /* Allow stray semicolons.  */
   else if (token->type == CPP_SEMICOLON)
     cp_lexer_consume_token (parser->lexer);
@@ -25887,20 +25931,25 @@  cp_parser_omp_var_list_no_open (cp_parse
       tree name, decl;
 
       token = cp_lexer_peek_token (parser->lexer);
-      name = cp_parser_id_expression (parser, /*template_p=*/false,
-				      /*check_dependency_p=*/true,
-				      /*template_p=*/NULL,
-				      /*declarator_p=*/false,
-				      /*optional_p=*/false);
-      if (name == error_mark_node)
+      if (parser->omp_declare_simd_clauses)
+	decl = name = cp_parser_identifier (parser);
+      else
 	{
-	  if (colon)
-	    parser->colon_corrects_to_scope_p
-	      = saved_colon_corrects_to_scope_p;
-	  goto skip_comma;
-	}
+	  name = cp_parser_id_expression (parser, /*template_p=*/false,
+					  /*check_dependency_p=*/true,
+					  /*template_p=*/NULL,
+					  /*declarator_p=*/false,
+					  /*optional_p=*/false);
+	  if (name == error_mark_node)
+	    {
+	      if (colon)
+		parser->colon_corrects_to_scope_p
+		  = saved_colon_corrects_to_scope_p;
+	      goto skip_comma;
+	    }
 
-      decl = cp_parser_lookup_name_simple (parser, name, token->location);
+	  decl = cp_parser_lookup_name_simple (parser, name, token->location);
+	}
       if (decl == error_mark_node)
 	cp_parser_name_lookup_error (parser, name, decl, NLE_NULL,
 				     token->location);
@@ -27040,6 +27089,8 @@  cp_parser_omp_all_clauses (cp_parser *pa
     }
  saw_error:
   cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+  if (parser->omp_declare_simd_clauses)
+    return clauses;
   return finish_omp_clauses (clauses);
 }
 
@@ -28566,6 +28617,166 @@  cp_parser_omp_cancellation_point (cp_par
   finish_omp_cancellation_point (clauses);
 }
 
+/* OpenMP 4.0:
+   # pragma omp declare simd declare-simd-clauses[optseq] new-line  */
+
+#define OMP_DECLARE_SIMD_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
+
+static void
+cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
+			    enum pragma_context context)
+{
+  bool first_p = parser->omp_declare_simd_clauses == NULL;
+  vec_safe_push (parser->omp_declare_simd_clauses, NULL_TREE);
+  tree clauses
+    = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+				 "#pragma omp declare simd", pragma_tok);
+  parser->omp_declare_simd_clauses->last () = clauses;
+  if (first_p)
+    {
+      while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA))
+	cp_parser_pragma (parser, context);
+      switch (context)
+	{
+	case pragma_external:
+	  cp_parser_declaration (parser);
+	  break;
+	case pragma_member:
+	  cp_parser_member_declaration (parser);
+	  break;
+	case pragma_objc_icode:
+	  cp_parser_block_declaration (parser, /*statement_p=*/false);
+	  break;
+	default:
+	  cp_parser_declaration_statement (parser);
+	  break;
+	}
+      if (parser->omp_declare_simd_clauses
+	  && ((*parser->omp_declare_simd_clauses)[0] == NULL
+	      || !DECL_P ((*parser->omp_declare_simd_clauses)[0])))
+	error_at (pragma_tok->location,
+		  "%<#pragma omp declare simd%> not immediately followed by "
+		  "function declaration or definition");
+      parser->omp_declare_simd_clauses = NULL;
+    }
+}
+
+/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
+   and put that into "omp declare simd" attribute.  */
+
+static void
+cp_finish_omp_declare_simd (cp_parser *parser, tree fndecl)
+{
+  tree clauses;
+  int i;
+
+  if (fndecl == error_mark_node)
+    {
+      parser->omp_declare_simd_clauses = NULL;
+      return;
+    }
+  if (TREE_CODE (fndecl) != FUNCTION_DECL)
+    {
+      cp_ensure_no_omp_declare_simd (parser);
+      return;
+    }
+  if ((*parser->omp_declare_simd_clauses)[0]
+      && DECL_P ((*parser->omp_declare_simd_clauses)[0]))
+    {
+      error_at (DECL_SOURCE_LOCATION (fndecl),
+		"%<#pragma omp declare simd%> not immediately followed by "
+		"a single function declaration or definition");
+      parser->omp_declare_simd_clauses = NULL;
+      return;
+    }
+
+  FOR_EACH_VEC_SAFE_ELT (parser->omp_declare_simd_clauses, i, clauses)
+    {
+      tree c, *pc, decl, name;
+      for (pc = &clauses, c = clauses; c; c = *pc)
+	{
+	  bool remove = false;
+	  switch (OMP_CLAUSE_CODE (c))
+	    {
+	    case OMP_CLAUSE_UNIFORM:
+	    case OMP_CLAUSE_LINEAR:
+	    case OMP_CLAUSE_ALIGNED:
+	    case OMP_CLAUSE_REDUCTION:
+	      name = OMP_CLAUSE_DECL (c);
+	      if (name == error_mark_node)
+		remove = true;
+	      else
+		{
+		  for (decl = DECL_ARGUMENTS (fndecl); decl;
+		       decl = TREE_CHAIN (decl))
+		    if (DECL_NAME (decl) == name)
+		      break;
+		  if (decl == NULL_TREE)
+		    {
+		      error_at (OMP_CLAUSE_LOCATION (c),
+				"%qE is not a function parameter", name);
+		      remove = true;
+		    }
+		  else
+		    OMP_CLAUSE_DECL (c) = decl;
+		}
+	      break;
+	    default:
+	      break;
+	    }
+	  if (remove)
+	    *pc = OMP_CLAUSE_CHAIN (c);
+	  else
+	    pc = &OMP_CLAUSE_CHAIN (c);
+	}
+      clauses = finish_omp_clauses (clauses);
+    }
+
+  vec_safe_truncate (parser->omp_declare_simd_clauses, 1);
+  (*parser->omp_declare_simd_clauses)[0] = fndecl;
+}
+
+/* OpenMP 4.0
+   #pragma omp declare simd declare-simd-clauses[optseq] new-line
+   #pragma omp declare reduction (reduction-id : typename-list : expression) \
+      identity-clause[opt] new-line */
+
+static void
+cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
+		       enum pragma_context context)
+{
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      const char *p = IDENTIFIER_POINTER (id);
+
+      if (strcmp (p, "simd") == 0)
+        {
+          cp_lexer_consume_token (parser->lexer);
+	  cp_parser_omp_declare_simd (parser, pragma_tok,
+				      context);
+	  return;
+        }
+      cp_ensure_no_omp_declare_simd (parser);
+/*    if (strcmp (p, "reduction") == 0)
+	{
+          cp_lexer_consume_token (parser->lexer);
+	  cp_parser_omp_declare_reduction (parser, pragma_tok,
+					   context);
+	  return;
+	}  */
+    }
+  cp_parser_error (parser, "expected %<simd%> or %<reduction%>");
+  cp_parser_require_pragma_eol (parser, pragma_tok);
+}
+
 /* Main entry point to OpenMP statement pragmas.  */
 
 static void
@@ -28965,6 +29176,8 @@  cp_parser_pragma (cp_parser *parser, enu
   parser->lexer->in_pragma = true;
 
   id = pragma_tok->pragma_kind;
+  if (id != PRAGMA_OMP_DECLARE_REDUCTION)
+    cp_ensure_no_omp_declare_simd (parser);
   switch (id)
     {
     case PRAGMA_GCC_PCH_PREPROCESS:
@@ -29070,6 +29283,10 @@  cp_parser_pragma (cp_parser *parser, enu
       cp_parser_omp_threadprivate (parser, pragma_tok);
       return false;
 
+    case PRAGMA_OMP_DECLARE_REDUCTION:
+      cp_parser_omp_declare (parser, pragma_tok, context);
+      return false;
+
     case PRAGMA_OMP_ATOMIC:
     case PRAGMA_OMP_CRITICAL:
     case PRAGMA_OMP_FOR:
@@ -29081,7 +29298,7 @@  cp_parser_pragma (cp_parser *parser, enu
     case PRAGMA_OMP_SINGLE:
     case PRAGMA_OMP_TASK:
     case PRAGMA_OMP_TASKGROUP:
-      if (context == pragma_external)
+      if (context != pragma_stmt && context != pragma_compound)
 	goto bad_stmt;
       cp_parser_omp_construct (parser, pragma_tok);
       return true;
--- gcc/testsuite/g++.dg/gomp/declare-simd-1.C.jj	2013-04-29 18:59:47.906163791 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-simd-1.C	2013-04-29 20:05:38.772193408 +0200
@@ -0,0 +1,203 @@ 
+// Test parsing of #pragma omp declare simd
+// { dg-do compile }
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) \
+	    linear (c : 4) simdlen (8)
+#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a \
+									    : 4) simdlen (4)
+int f1 (int a, int *b, int c);
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+int f2 (int a, int *b, int c)
+{
+  return a + *b + c;
+}
+
+#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+template <typename T>
+T f3 (int a, int *b, T c);
+
+template <>
+int f3 (int, int *, int);
+
+#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+template <typename T>
+int f4 (int a, int *b, T c)
+{
+  return a + *b + c;
+}
+
+template <>
+int f4 (int, int *, int);
+
+template <typename T>
+int f5 (int a, int *b, T c);
+
+#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+template <>
+int f5 (int a, int *b, int c);
+
+template <int N>
+int f6 (int a, int *b, int c);
+
+#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+template <>
+int f6<3> (int a, int *b, int c);
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (long long)) linear (c : 4) simdlen (8)
+__extension__
+long long f7 (long long a, long long *b, long long c);
+
+#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+extern "C"
+int f8 (int a, int *b, int c);
+
+extern "C"
+{
+  #pragma omp declare simd
+  int f9 (int a, int *b, int c);
+}
+
+namespace N1
+{
+  namespace N2
+  {
+    #pragma omp declare simd simdlen (2) aligned (b : sizeof (long long) * 2)
+    __extension__ long long
+    f10 (long long *b)
+    {
+      return *b;
+    }
+  }
+}
+
+struct A
+{
+  #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+  int f11 (int a, int *b, int c);
+
+  #pragma omp declare simd
+  template <int N>
+  int f12 (int a, int *b, int c);
+
+  #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+  static int f13 (int a, int *b, int c);
+
+  #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+  int f14 (int a, int *b, int c) { return a + *b + c; }
+
+  #pragma omp declare simd
+  template <int N>
+  int f15 (int a, int *b, int c) { return a + *b + c; }
+
+  #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+  static int f16 (int a, int *b, int c) { return a + *b + c; }
+};
+
+template <>
+int A::f12<2> (int, int *, int);
+
+template <>
+int A::f15<2> (int, int *, int);
+
+template <typename T>
+struct B
+{
+  #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+  int f17 (int a, int *b, int c);
+
+  #pragma omp declare simd
+  template <int N>
+  int f18 (int a, int *b, int c);
+
+  #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+  static int f19 (int a, int *b, int c);
+
+  #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+  int f20 (int a, int *b, int c) { return a + *b + c; }
+
+  #pragma omp declare simd
+  template <int N>
+  int f21 (int a, int *b, int c) { return a + *b + c; }
+
+  #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4)
+  static int f22 (int a, int *b, int c) { return a + *b + c; }
+
+  template <int N>
+  int f23 (int, int *, int);
+
+  template <int N>
+  static int f24 (int, int *, int);
+
+  template <int N>
+  int f25 (int, int *, int);
+
+  template <int N>
+  static int f26 (int, int *, int);
+};
+
+B <int> b;
+
+template <>
+template <>
+int B<int>::f18<0> (int, int *, int);
+
+template <>
+template <>
+int B<int>::f21<9> (int, int *, int);
+
+#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c)
+template <>
+template <>
+int B<int>::f23<7> (int a, int *b, int c);
+
+#pragma omp declare simd simdlen (4) aligned (b : 8 * sizeof (int)) linear (a, c : 2)
+template <>
+template <>
+int B<int>::f24<-1> (int a, int *b, int c);
+
+#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c)
+template <>
+template <>
+int B<int>::f25<7> (int a, int *b, int c)
+{
+  return a + *b + c;
+}
+
+#pragma omp declare simd simdlen (4) aligned (b : 8 * sizeof (int)) linear (a, c : 2)
+template <>
+template <>
+int B<int>::f26<-1> (int a, int *b, int c)
+{
+  return a + *b + c;
+}
+
+int
+f27 (int x)
+{
+  #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int))
+  extern int f28 (int a, int *b, int c);
+  {
+    x++;
+    #pragma omp declare simd simdlen (4) linear (c)
+    extern int f29 (int a, int *b, int c);
+  }
+  return x;
+}
+
+#pragma omp declare simd simdlen (16)
+int
+f30 (int x)
+{
+  #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int))
+  extern int f31 (int a, int *b, int c);
+  return x;
+}
--- gcc/testsuite/g++.dg/gomp/declare-simd-2.C.jj	2013-04-29 19:58:25.434598426 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-simd-2.C	2013-04-29 20:08:29.891246677 +0200
@@ -0,0 +1,53 @@ 
+// Test parsing of #pragma omp declare simd
+// { dg-do compile }
+
+#pragma omp declare simd
+int a;	// { dg-error "not immediately followed by function declaration or definition" }
+
+#pragma omp declare simd
+int fn1 (int a), fn2 (int a);	// { dg-error "not immediately followed by a single function declaration or definition" }
+
+#pragma omp declare simd
+int b, fn3 (int a);	// { dg-error "not immediately followed by function declaration or definition" }
+
+#pragma omp declare simd linear (a)
+int fn4 (int a), c;	// { dg-error "not immediately followed by function declaration or definition" }
+
+#pragma omp declare simd
+extern "C"		// { dg-error "not immediately followed by function declaration or definition" }
+{
+  int fn5 (int a);
+}
+
+#pragma omp declare simd // { dg-error "not immediately followed by function declaration or definition" }
+namespace N1
+{
+  int fn6 (int a);
+}
+
+#pragma omp declare simd simdlen (4)
+struct A
+{			// { dg-error "not immediately followed by function declaration or definition" }
+  int fn7 (int a);
+};
+
+#pragma omp declare simd
+template <typename T>
+struct B
+{			// { dg-error "not immediately followed by function declaration or definition" }
+  int fn8 (int a);
+};
+
+struct C
+{
+#pragma omp declare simd // { dg-error "not immediately followed by function declaration or definition" }
+  public:		 // { dg-error "expected unqualified-id before" }
+    int fn9 (int a);
+};
+
+int t;
+
+#pragma omp declare simd
+#pragma omp declare simd
+#pragma omp threadprivate(t)	// { dg-error "not immediately followed by function declaration or definition" }
+int fn10 (int a);