On Tue, Apr 30, 2013 at 10:35:21AM -0400, Jason Merrill wrote:
> 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.

Ok, here is a complete patch for C++ FE only support of the #pragma omp
declare simd parsing.

The info is stored as "omp declare simd" attribute with an argument
which is either NULL_TREE (barebone #pragma omp declare simd) or
list of OMP_CLAUSEs).  Tested on x86_64-linux, any comments on this
before I commit it to the gomp4 branch?  Like, isn't it too invasive to the
C++ FE?

2013-05-06  Jakub Jelinek  <ja...@redhat.com>

        * tree.c (omp_declare_simd_clauses_equal): New function.
        (attribute_value_equal): Call it for -fopenmp if
        TREE_VALUE of the attributes are both OMP_CLAUSEs.
        * tree.h (omp_declare_simd_clauses_equal): Declare.
c-family/
        * c-common.c (c_common_attribute_table): Add "omp declare simd"
        attribute.
        (handle_omp_declare_simd_attribute): New function.
        * c-common.h (c_omp_declare_simd_clauses_to_numbers,
        c_omp_declare_simd_clauses_to_decls): Declare.
        * c-omp.c (c_omp_declare_simd_clause_cmp,
        c_omp_declare_simd_clauses_to_numbers,
        c_omp_declare_simd_clauses_to_decls): New functions.
cp/
        * cp-tree.h (start_decl, start_function, grokmethod, grokfield): Add
        omp_declare_simd_clauses argument.
        (finish_omp_declare_simd): Declare.
        * decl2.c (grokfield): Add omp_declare_simd_clauses argument,
        pass it through to grokdeclarator.
        (grokbitfield): Adjust grokdeclarator caller.
        (is_late_template_attribute): Return true for "omp declare simd"
        attribute.
        (cp_check_const_attributes): Don't check TREE_VALUE of arg if
        arg isn't a TREE_LIST.
        * decl.c (shadow_tag, groktypename): Adjust grokdeclarator callers.
        (start_decl, start_function, grokmethod): Add omp_declare_simd_clauses
        argument, pass it through to grokdeclarator.
        (grokfndecl): Add omp_declare_simd_clauses argument, call
        finish_omp_declare_simd if non-NULL.
        (grokdeclarator): Add omp_declare_simd_clauses argument, pass it
        through to grokfndecl.
        * decl.h (grokdeclarator): Add omp_declare_simd_clauses argument.
        * pt.c (apply_late_template_attributes): Handle "omp declare simd"
        attribute specially.
        (tsubst_omp_clauses): Add declare_simd argument, don't call
        finish_omp_clauses if it is set.  Handle OpenMP 4.0 clauses.
        (tsubst_expr): Adjust tsubst_omp_clauses callers.
        * semantics.c (finish_omp_clauses): Diagnose inbranch notinbranch.
        (finish_omp_declare_simd): New function.
        * parser.h (struct cp_parser): Add omp_declare_simd_clauses field.
        * parser.c (cp_ensure_no_omp_declare_simd,
        cp_finish_omp_declare_simd): New functions.
        (enum pragma_context): Add pragma_member and pragma_objc_icode.
        (cp_parser_trait_expr, cp_parser_conversion_type_id,
        cp_parser_template_parameter, cp_parser_explicit_instantiation,
        cp_parser_enum_specifier, cp_parser_parameter_declaration_list,
        cp_parser_exception_declaration, cp_parser_sizeof_operand,
        cp_parser_objc_method_tail_params_opt,
        cp_parser_objc_try_catch_finally_statement): Adjust grokdeclarator
        callers.
        (cp_parser_lambda_declarator_opt): Adjust grokmethod caller.
        (cp_parser_condition): Adjust start_decl caller.
        (cp_parser_linkage_specification, cp_parser_namespace_definition,
        cp_parser_class_specifier_1): Call cp_ensure_no_omp_declare_simd.
        (cp_parser_alias_declaration): Adjust grokfield and start_decl
        callers.
        (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, pass parser->omp_declare_simd_clauses
        to start_decl, grokfield, start_function or grokmethod.
        (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_objc_class_ivars, cp_parser_objc_struct_declaration): Adjust
        grokfield caller.
        (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_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.
testsuite/
        * g++.dg/gomp/declare-simd-1.C: New test.
        * g++.dg/gomp/declare-simd-2.C: New test.

--- gcc/tree.c.jj       2013-03-27 13:01:09.000000000 +0100
+++ gcc/tree.c  2013-05-06 11:49:55.300466043 +0200
@@ -4397,6 +4397,48 @@ build_type_attribute_qual_variant (tree
   return ttype;
 }
 
+/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
+   the same.  */
+
+bool
+omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
+{
+  tree cl1, cl2;
+  for (cl1 = clauses1, cl2 = clauses2;
+       cl1 && cl2;
+       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
+    {
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
+       return false;
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
+       {
+         if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
+                               OMP_CLAUSE_DECL (cl2)) != 1)
+           return false;
+       }
+      switch (OMP_CLAUSE_CODE (cl1))
+       {
+       case OMP_CLAUSE_ALIGNED:
+         if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
+                               OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
+           return false;
+         break;
+       case OMP_CLAUSE_LINEAR:
+         if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
+                               OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
+           return false;
+         break;
+       case OMP_CLAUSE_SIMDLEN:
+         if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
+                               OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
+           return false;
+       default:
+         break;
+       }
+    }
+  return true;
+}
+
 /* Compare two attributes for their value identity.  Return true if the
    attribute values are known to be equal; otherwise return false.
 */
@@ -4414,6 +4456,13 @@ attribute_value_equal (const_tree attr1,
     return (simple_cst_list_equal (TREE_VALUE (attr1),
                                   TREE_VALUE (attr2)) == 1);
 
+  if (flag_openmp
+      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
+      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
+      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
+    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
+                                          TREE_VALUE (attr2));
+
   return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
 }
 
--- gcc/tree.h.jj       2013-04-30 18:03:33.000000000 +0200
+++ gcc/tree.h  2013-05-06 12:00:18.625085694 +0200
@@ -5051,6 +5051,10 @@ extern tree build_type_attribute_variant
 extern tree build_decl_attribute_variant (tree, tree);
 extern tree build_type_attribute_qual_variant (tree, tree, int);
 
+/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
+   the same.  */
+extern bool omp_declare_simd_clauses_equal (tree, tree);
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
--- gcc/c-family/c-common.c.jj  2013-04-10 19:11:23.000000000 +0200
+++ gcc/c-family/c-common.c     2013-05-06 15:34:11.823524239 +0200
@@ -368,6 +368,8 @@ static tree handle_optimize_attribute (t
 static tree ignore_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *);
 static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
+static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int,
+                                              bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -738,6 +740,8 @@ const struct attribute_spec c_common_att
      The name contains space to prevent its usage in source code.  */
   { "fn spec",               1, 1, false, true, true,
                              handle_fnspec_attribute, false },
+  { "omp declare simd",       0, -1, true,  false, false,
+                             handle_omp_declare_simd_attribute, false },
   { NULL,                     0, 0, false, false, false, NULL, false }
 };
 
@@ -7958,6 +7962,15 @@ handle_fnspec_attribute (tree *node ATTR
   return NULL_TREE;
 }
 
+/* Handle an "omp declare simd" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *)
+{
+  return NULL_TREE;
+}
+
 /* Handle a "returns_twice" attribute; arguments as in
    struct attribute_spec.handler.  */
 
--- gcc/c-family/c-common.h.jj  2013-04-30 18:03:33.000000000 +0200
+++ gcc/c-family/c-common.h     2013-05-06 11:41:07.024543300 +0200
@@ -1042,6 +1042,8 @@ extern void c_finish_omp_taskyield (loca
 extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree,
                              tree, tree, tree);
 extern void c_split_parallel_clauses (location_t, tree, tree *, tree *);
+extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree);
+extern void c_omp_declare_simd_clauses_to_decls (tree, tree);
 extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
 
 /* Not in c-omp.c; provided by the front end.  */
--- gcc/c-family/c-omp.c.jj     2013-04-30 18:03:33.000000000 +0200
+++ gcc/c-family/c-omp.c        2013-05-06 14:54:55.226010022 +0200
@@ -637,6 +637,100 @@ c_split_parallel_clauses (location_t loc
     }
 }
 
+/* qsort callback to compare #pragma omp declare simd clauses.  */
+
+static int
+c_omp_declare_simd_clause_cmp (const void *p, const void *q)
+{
+  tree a = *(const tree *) p;
+  tree b = *(const tree *) q;
+  if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_CODE (b))
+    {
+      if (OMP_CLAUSE_CODE (a) > OMP_CLAUSE_CODE (b))
+       return -1;
+      return 1;
+    }
+  if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_SIMDLEN
+      && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_INBRANCH
+      && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_NOTINBRANCH)
+    {
+      int c = tree_low_cst (OMP_CLAUSE_DECL (a), 0);
+      int d = tree_low_cst (OMP_CLAUSE_DECL (b), 0);
+      if (c < d)
+       return 1;
+      if (c > d)
+       return -1;
+    }
+  return 0;
+}
+
+/* Change PARM_DECLs in OMP_CLAUSE_DECL of #pragma omp declare simd
+   CLAUSES on FNDECL into argument indexes and sort them.  */
+
+tree
+c_omp_declare_simd_clauses_to_numbers (tree fndecl, tree clauses)
+{
+  tree c;
+  vec<tree> clvec = vNULL;
+
+  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    {
+      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN
+         && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH
+         && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH)
+       {
+         tree decl = OMP_CLAUSE_DECL (c);
+         tree arg;
+         int idx;
+         for (arg = DECL_ARGUMENTS (fndecl), idx = 0; arg;
+              arg = TREE_CHAIN (arg), idx++)
+           if (arg == decl)
+             break;
+         if (arg == NULL_TREE)
+           {
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "%qD is not an argument of %qD", decl, fndecl);
+             continue;
+           }
+         OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, idx);
+       }
+      clvec.safe_push (c);
+    }
+  if (!clvec.is_empty ())
+    {
+      unsigned int len = clvec.length (), i;
+      clvec.qsort (c_omp_declare_simd_clause_cmp);
+      clauses = clvec[0];
+      for (i = 0; i < len; i++)
+       OMP_CLAUSE_CHAIN (clvec[i]) = (i < len - 1) ? clvec[i + 1] : NULL_TREE;
+    }
+  clvec.release ();
+  return clauses;
+}
+
+/* Change argument indexes in CLAUSES of FNDECL back to PARM_DECLs.  */
+
+void
+c_omp_declare_simd_clauses_to_decls (tree fndecl, tree clauses)
+{
+  tree c;
+
+  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN
+       && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH
+       && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH)
+      {
+       int idx = tree_low_cst (OMP_CLAUSE_DECL (c), 0), i;
+       tree arg;
+       for (arg = DECL_ARGUMENTS (fndecl), i = 0; arg;
+            arg = TREE_CHAIN (arg), i++)
+         if (i == idx)
+           break;
+       gcc_assert (arg);
+       OMP_CLAUSE_DECL (c) = arg;
+      }
+}
+
 /* True if OpenMP sharing attribute of DECL is predetermined.  */
 
 enum omp_clause_default_kind
--- gcc/cp/cp-tree.h.jj 2013-04-30 18:03:33.000000000 +0200
+++ gcc/cp/cp-tree.h    2013-05-02 15:24:50.000000000 +0200
@@ -5124,7 +5124,8 @@ extern void warn_misplaced_attr_for_clas
 extern tree check_tag_decl                     (cp_decl_specifier_seq *, bool);
 extern tree shadow_tag                         (cp_decl_specifier_seq *);
 extern tree groktypename                       (cp_decl_specifier_seq *, const 
cp_declarator *, bool);
-extern tree start_decl                         (const cp_declarator *, 
cp_decl_specifier_seq *, int, tree, tree, tree *);
+extern tree start_decl                         (const cp_declarator *, 
cp_decl_specifier_seq *,
+                                                int, tree, tree, tree *, 
vec<tree, va_gc> *);
 extern void start_decl_1                       (tree, bool);
 extern bool check_array_initializer            (tree, tree, tree);
 extern void cp_finish_decl                     (tree, tree, bool, tree, int);
@@ -5150,12 +5151,14 @@ extern void finish_enum                         (tree);
 extern void build_enumerator                   (tree, tree, tree, location_t);
 extern tree lookup_enumerator                  (tree, tree);
 extern void start_preparsed_function           (tree, tree, int);
-extern int start_function                      (cp_decl_specifier_seq *, const 
cp_declarator *, tree);
+extern int start_function                      (cp_decl_specifier_seq *, const 
cp_declarator *, tree,
+                                                vec<tree, va_gc> *);
 extern tree begin_function_body                        (void);
 extern void finish_function_body               (tree);
 extern tree outer_curly_brace_block            (tree);
 extern tree finish_function                    (int);
-extern tree grokmethod                         (cp_decl_specifier_seq *, const 
cp_declarator *, tree);
+extern tree grokmethod                         (cp_decl_specifier_seq *, const 
cp_declarator *, tree,
+                                                vec<tree, va_gc> *);
 extern void maybe_register_incomplete_var      (tree);
 extern void maybe_commonize_var                        (tree);
 extern void complete_vars                      (tree);
@@ -5204,7 +5207,7 @@ extern tree delete_sanity                 (tree, tree,
 extern tree check_classfn                      (tree, tree, tree);
 extern void check_member_template              (tree);
 extern tree grokfield (const cp_declarator *, cp_decl_specifier_seq *,
-                      tree, bool, tree, tree);
+                      tree, bool, tree, tree, vec<tree, va_gc> *);
 extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *,
                          tree, tree);
 extern tree cp_reconstruct_complex_type                (tree, tree);
@@ -5702,6 +5705,7 @@ extern void simplify_aggr_init_expr               (tr
 extern void finalize_nrv                       (tree *, tree, tree);
 extern void note_decl_for_pch                  (tree);
 extern tree finish_omp_clauses                 (tree);
+extern void finish_omp_declare_simd            (tree, vec<tree, va_gc> *);
 extern void finish_omp_threadprivate           (tree);
 extern tree begin_omp_structured_block         (void);
 extern tree finish_omp_structured_block                (tree);
--- gcc/cp/decl2.c.jj   2013-03-20 10:07:19.000000000 +0100
+++ gcc/cp/decl2.c      2013-05-06 15:03:22.094114612 +0200
@@ -796,7 +796,7 @@ grokfield (const cp_declarator *declarat
           cp_decl_specifier_seq *declspecs,
           tree init, bool init_const_expr_p,
           tree asmspec_tree,
-          tree attrlist)
+          tree attrlist, vec<tree, va_gc> *omp_declare_simd_clauses)
 {
   tree value;
   const char *asmspec = 0;
@@ -809,7 +809,8 @@ grokfield (const cp_declarator *declarat
       && TREE_CHAIN (init) == NULL_TREE)
     init = NULL_TREE;
 
-  value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist);
+  value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist,
+                         omp_declare_simd_clauses);
   if (! value || error_operand_p (value))
     /* friend or constructor went bad.  */
     return error_mark_node;
@@ -1019,7 +1020,8 @@ grokbitfield (const cp_declarator *decla
              cp_decl_specifier_seq *declspecs, tree width,
              tree attrlist)
 {
-  tree value = grokdeclarator (declarator, declspecs, BITFIELD, 0, &attrlist);
+  tree value
+    = grokdeclarator (declarator, declspecs, BITFIELD, 0, &attrlist, NULL);
 
   if (value == error_mark_node) 
     return NULL_TREE; /* friends went bad.  */
@@ -1111,6 +1113,11 @@ is_late_template_attribute (tree attr, t
   if (is_attribute_p ("unused", name))
     return false;
 
+  /* #pragma omp declare simd attribute needs to be always finalized.  */
+  if (flag_openmp
+      && is_attribute_p ("omp declare simd", name))
+    return true;
+
   /* If any of the arguments are dependent expressions, we can't evaluate
      the attribute until instantiation time.  */
   for (arg = args; arg; arg = TREE_CHAIN (arg))
@@ -1296,6 +1303,9 @@ cp_check_const_attributes (tree attribut
   for (attr = attributes; attr; attr = TREE_CHAIN (attr))
     {
       tree arg;
+      if (TREE_VALUE (attr) == NULL_TREE
+         || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST)
+       continue;
       for (arg = TREE_VALUE (attr); arg; arg = TREE_CHAIN (arg))
        {
          tree expr = TREE_VALUE (arg);
--- gcc/cp/decl.c.jj    2013-03-20 10:07:19.000000000 +0100
+++ gcc/cp/decl.c       2013-05-02 15:24:39.449467830 +0200
@@ -4368,7 +4368,7 @@ shadow_tag (cp_decl_specifier_seq *decls
       if (TYPE_FIELDS (t))
        {
          tree decl = grokdeclarator (/*declarator=*/NULL,
-                                     declspecs, NORMAL, 0, NULL);
+                                     declspecs, NORMAL, 0, NULL, NULL);
          finish_anon_union (decl);
        }
     }
@@ -4389,7 +4389,7 @@ groktypename (cp_decl_specifier_seq *typ
     = is_template_arg ? TEMPLATE_TYPE_ARG : TYPENAME;
   attrs = type_specifiers->attributes;
   type_specifiers->attributes = NULL_TREE;
-  type = grokdeclarator (declarator, type_specifiers, context, 0, &attrs);
+  type = grokdeclarator (declarator, type_specifiers, context, 0, &attrs, 
NULL);
   if (attrs && type != error_mark_node)
     {
       if (CLASS_TYPE_P (type))
@@ -4430,7 +4430,8 @@ start_decl (const cp_declarator *declara
            int initialized,
            tree attributes,
            tree prefix_attributes,
-           tree *pushed_scope_p)
+           tree *pushed_scope_p,
+           vec<tree, va_gc> *omp_declare_simd_clauses)
 {
   tree decl;
   tree context;
@@ -4448,7 +4449,7 @@ start_decl (const cp_declarator *declara
   attributes = chainon (attributes, prefix_attributes);
 
   decl = grokdeclarator (declarator, declspecs, NORMAL, initialized,
-                        &attributes);
+                        &attributes, omp_declare_simd_clauses);
 
   deprecated_state = DEPRECATED_NORMAL;
 
@@ -7323,7 +7324,8 @@ grokfndecl (tree ctype,
            int template_count,
            tree in_namespace,
            tree* attrlist,
-           location_t location)
+           location_t location,
+           vec<tree, va_gc> *omp_declare_simd_clauses)
 {
   tree decl;
   int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
@@ -7594,6 +7596,9 @@ grokfndecl (tree ctype,
   if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl))
     TREE_NOTHROW (decl) = 1;
 
+  if (omp_declare_simd_clauses)
+    finish_omp_declare_simd (decl, omp_declare_simd_clauses);
+
   /* Caller will do the rest of this.  */
   if (check < 0)
     return decl;
@@ -8589,7 +8595,8 @@ grokdeclarator (const cp_declarator *dec
                cp_decl_specifier_seq *declspecs,
                enum decl_context decl_context,
                int initialized,
-               tree* attrlist)
+               tree* attrlist,
+               vec<tree, va_gc> *omp_declare_simd_clauses)
 {
   tree type = NULL_TREE;
   int longlong = 0;
@@ -10416,7 +10423,8 @@ grokdeclarator (const cp_declarator *dec
                                inlinep | (2 * constexpr_p),
                               sfk,
                               funcdef_flag, template_count, in_namespace,
-                              attrlist, declarator->id_loc);
+                              attrlist, declarator->id_loc,
+                              omp_declare_simd_clauses);
             decl = set_virt_specifiers (decl, virt_specifiers);
            if (decl == NULL_TREE)
              return error_mark_node;
@@ -10637,7 +10645,8 @@ grokdeclarator (const cp_declarator *dec
                           publicp, inlinep | (2 * constexpr_p), sfk,
                            funcdef_flag,
                           template_count, in_namespace, attrlist,
-                          declarator->id_loc);
+                          declarator->id_loc,
+                          omp_declare_simd_clauses);
        if (decl == NULL_TREE)
          return error_mark_node;
 
@@ -13313,11 +13322,12 @@ start_preparsed_function (tree decl1, tr
 int
 start_function (cp_decl_specifier_seq *declspecs,
                const cp_declarator *declarator,
-               tree attrs)
+               tree attrs, vec<tree, va_gc> *omp_declare_simd_clauses)
 {
   tree decl1;
 
-  decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs);
+  decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs,
+                         omp_declare_simd_clauses);
   if (decl1 == error_mark_node)
     return 0;
   /* If the declarator is not suitable for a function definition,
@@ -13959,10 +13969,11 @@ finish_function (int flags)
 
 tree
 grokmethod (cp_decl_specifier_seq *declspecs,
-           const cp_declarator *declarator, tree attrlist)
+           const cp_declarator *declarator, tree attrlist,
+           vec<tree, va_gc> *omp_declare_simd_clauses)
 {
   tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0,
-                               &attrlist);
+                               &attrlist, omp_declare_simd_clauses);
 
   if (fndecl == error_mark_node)
     return error_mark_node;
--- gcc/cp/decl.h.jj    2013-03-20 10:07:19.000000000 +0100
+++ gcc/cp/decl.h       2013-05-02 15:19:31.331158878 +0200
@@ -34,7 +34,7 @@ enum decl_context
 /* We need this in here to get the decl_context definition.  */
 extern tree grokdeclarator (const cp_declarator *,
                            cp_decl_specifier_seq *,
-                           enum decl_context, int, tree*);
+                           enum decl_context, int, tree*, vec<tree, va_gc> *);
 
 /* States indicating how grokdeclarator() should handle declspecs marked
    with __attribute__((deprecated)).  An object declared as
--- gcc/cp/parser.c.jj  2013-04-30 18:03:33.847124246 +0200
+++ gcc/cp/parser.c     2013-05-02 15:54:49.833404915 +0200
@@ -1169,6 +1169,41 @@ 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
+      && (*parser->omp_declare_simd_clauses)[0] != error_mark_node)
+    {
+      error ("%<#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 inline void
+cp_finish_omp_declare_simd (cp_parser *parser, tree fndecl)
+{
+  if (__builtin_expect (parser->omp_declare_simd_clauses != NULL, 0))
+    {
+      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;
+       }
+    }
+}
 
 /* Decl-specifiers.  */
 
@@ -2149,7 +2184,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);
 
@@ -8126,7 +8167,7 @@ cp_parser_trait_expr (cp_parser* parser,
 
   /* Call grokdeclarator to figure out what type this is.  */
   type1 = grokdeclarator (NULL, &decl_specs, TYPENAME,
-                         /*initialized=*/0, /*attrlist=*/NULL);
+                         /*initialized=*/0, /*attrlist=*/NULL, NULL);
 
   if (binary)
     {
@@ -8143,7 +8184,7 @@ cp_parser_trait_expr (cp_parser* parser,
 
       /* Call grokdeclarator to figure out what type this is.  */
       type2 = grokdeclarator (NULL, &decl_specs, TYPENAME,
-                             /*initialized=*/0, /*attrlist=*/NULL);
+                             /*initialized=*/0, /*attrlist=*/NULL, NULL);
     }
 
   cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
@@ -8600,9 +8641,7 @@ cp_parser_lambda_declarator_opt (cp_pars
                                        /*late_return_type=*/NULL_TREE);
     declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr);
 
-    fco = grokmethod (&return_type_specs,
-                     declarator,
-                     attributes);
+    fco = grokmethod (&return_type_specs, declarator, attributes, NULL);
     if (fco != error_mark_node)
       {
        DECL_INITIALIZED_IN_CLASS_P (fco) = 1;
@@ -9447,7 +9486,7 @@ cp_parser_condition (cp_parser* parser)
          decl = start_decl (declarator, &type_specifiers,
                             /*initialized_p=*/true,
                             attributes, /*prefix_attributes=*/NULL_TREE,
-                            &pushed_scope);
+                            &pushed_scope, NULL);
 
          /* Parse the initializer.  */
          if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
@@ -11154,6 +11193,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.  */
@@ -11524,7 +11565,7 @@ cp_parser_conversion_type_id (cp_parser*
   declarator = cp_parser_conversion_declarator_opt (parser);
 
   type_specified =  grokdeclarator (declarator, &type_specifiers, TYPENAME,
-                                   /*initialized=*/0, &attributes);
+                                   /*initialized=*/0, &attributes, NULL);
   if (attributes)
     cplus_decl_attributes (&type_specified, attributes, /*flags=*/0);
 
@@ -12398,7 +12439,7 @@ cp_parser_template_parameter (cp_parser*
   parm = grokdeclarator (parameter_declarator->declarator,
                         &parameter_declarator->decl_specifiers,
                         TPARM, /*initialized=*/0,
-                        /*attrlist=*/NULL);
+                        /*attrlist=*/NULL, NULL);
   if (parm == error_mark_node)
     return error_mark_node;
 
@@ -13449,7 +13490,7 @@ cp_parser_explicit_instantiation (cp_par
                       " %<constexpr%> specifier");
 
          decl = grokdeclarator (declarator, &decl_specifiers,
-                                NORMAL, 0, &decl_specifiers.attributes);
+                                NORMAL, 0, &decl_specifiers.attributes, NULL);
          /* Turn access control back on for names used during
             template instantiation.  */
          pop_deferring_access_checks ();
@@ -14702,7 +14743,7 @@ cp_parser_enum_specifier (cp_parser* par
       if (type_specifiers.type != error_mark_node)
         {
           underlying_type = grokdeclarator (NULL, &type_specifiers, TYPENAME,
-                                            /*initialized=*/0, NULL);
+                                           /*initialized=*/0, NULL, NULL);
           if (underlying_type == error_mark_node)
             underlying_type = NULL_TREE;
         }
@@ -15049,6 +15090,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);
@@ -15443,10 +15485,10 @@ cp_parser_alias_declaration (cp_parser*
   member_p = at_class_scope_p ();
   if (member_p)
     decl = grokfield (declarator, &decl_specs, NULL_TREE, false,
-                     NULL_TREE, attributes);
+                     NULL_TREE, attributes, NULL);
   else
     decl = start_decl (declarator, &decl_specs, 0,
-                      attributes, NULL_TREE, &pushed_scope);
+                      attributes, NULL_TREE, &pushed_scope, NULL);
   if (decl == error_mark_node)
     return decl;
 
@@ -15981,7 +16023,8 @@ cp_parser_init_declarator (cp_parser* pa
       decl = start_decl (declarator, decl_specifiers,
                         range_for_decl_p? SD_INITIALIZED : is_initialized,
                         attributes, prefix_attributes,
-                        &pushed_scope);
+                        &pushed_scope, parser->omp_declare_simd_clauses);
+      cp_finish_omp_declare_simd (parser, decl);
       /* Adjust location of decl if declarator->id_loc is more appropriate:
         set, and decl wasn't merged with another decl, in which case its
         location would be different from input_location, and more accurate.  */
@@ -16088,9 +16131,10 @@ cp_parser_init_declarator (cp_parser* pa
       decl = grokfield (declarator, decl_specifiers,
                        initializer, !is_non_constant_init,
                        /*asmspec=*/NULL_TREE,
-                       prefix_attributes);
+                       prefix_attributes, parser->omp_declare_simd_clauses);
       if (decl && TREE_CODE (decl) == FUNCTION_DECL)
        cp_parser_save_default_args (parser, decl);
+      cp_finish_omp_declare_simd (parser, decl);
     }
 
   /* Finish processing the declaration.  But, skip member
@@ -17425,7 +17469,7 @@ cp_parser_parameter_declaration_list (cp
                               &parameter->decl_specifiers,
                               PARM,
                               parameter->default_argument != NULL_TREE,
-                              &parameter->decl_specifiers.attributes);
+                              &parameter->decl_specifiers.attributes, NULL);
 
       deprecated_state = DEPRECATED_NORMAL;
 
@@ -18302,6 +18346,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 +19125,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 +19577,15 @@ 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, 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);
@@ -20230,7 +20278,8 @@ cp_parser_exception_declaration (cp_pars
   if (!type_specifiers.any_specifiers_p)
     return error_mark_node;
 
-  return grokdeclarator (declarator, &type_specifiers, CATCHPARM, 1, NULL);
+  return grokdeclarator (declarator, &type_specifiers, CATCHPARM, 1,
+                        NULL, NULL);
 }
 
 /* Parse a throw-expression.
@@ -21666,7 +21715,8 @@ cp_parser_function_definition_from_speci
   bool success_p;
 
   /* Begin the function-definition.  */
-  success_p = start_function (decl_specifiers, declarator, attributes);
+  success_p = start_function (decl_specifiers, declarator, attributes,
+                             parser->omp_declare_simd_clauses);
 
   /* The things we're about to see are not directly qualified by any
      template headers we've seen thus far.  */
@@ -21678,6 +21728,12 @@ cp_parser_function_definition_from_speci
      might be a friend.  */
   perform_deferred_access_checks (tf_warning_or_error);
 
+  if (success_p)
+    {
+      cp_finish_omp_declare_simd (parser, current_function_decl);
+      parser->omp_declare_simd_clauses = NULL;
+    }
+
   if (!success_p)
     {
       /* Skip the entire function.  */
@@ -22196,7 +22252,9 @@ cp_parser_save_member_function_body (cp_
   tree fn;
 
   /* Create the FUNCTION_DECL.  */
-  fn = grokmethod (decl_specifiers, declarator, attributes);
+  fn = grokmethod (decl_specifiers, declarator, attributes,
+                  parser->omp_declare_simd_clauses);
+  cp_finish_omp_declare_simd (parser, fn);
   /* If something went badly wrong, bail out now.  */
   if (fn == error_mark_node)
     {
@@ -22698,7 +22756,7 @@ cp_parser_sizeof_operand (cp_parser* par
                                 &decl_specs,
                                 TYPENAME,
                                 /*initialized=*/0,
-                                /*attrlist=*/NULL);
+                                /*attrlist=*/NULL, NULL);
        }
     }
   else if (pack_expansion_p)
@@ -24500,7 +24558,7 @@ cp_parser_objc_method_tail_params_opt (c
       parm = grokdeclarator (parmdecl->declarator,
                             &parmdecl->decl_specifiers,
                             PARM, /*initialized=*/0,
-                            /*attrlist=*/NULL);
+                            /*attrlist=*/NULL, NULL);
 
       chainon (params, build_tree_list (NULL_TREE, parm));
       token = cp_lexer_peek_token (parser->lexer);
@@ -24544,7 +24602,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);
@@ -24848,7 +24906,7 @@ cp_parser_objc_class_ivars (cp_parser* p
          else
            decl = grokfield (declarator, &declspecs,
                              NULL_TREE, /*init_const_expr_p=*/false,
-                             NULL_TREE, attributes);
+                             NULL_TREE, attributes, NULL);
 
          /* Add the instance variable.  */
          if (decl != error_mark_node && decl != NULL_TREE)
@@ -25182,7 +25240,7 @@ cp_parser_objc_try_catch_finally_stateme
            parameter_declaration = grokdeclarator (parm->declarator,
                                                    &parm->decl_specifiers,
                                                    PARM, /*initialized=*/0,
-                                                   /*attrlist=*/NULL);
+                                                   /*attrlist=*/NULL, NULL);
        }
       if (seen_open_paren)
        cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
@@ -25392,7 +25450,7 @@ cp_parser_objc_struct_declaration (cp_pa
       
       decl = grokfield (declarator, &declspecs,
                        NULL_TREE, /*init_const_expr_p=*/false,
-                       NULL_TREE, attributes);
+                       NULL_TREE, attributes, NULL);
 
       if (decl == error_mark_node || decl == NULL_TREE)
        return error_mark_node;
@@ -25887,20 +25945,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 +27103,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);
 }
 
@@ -27799,7 +27864,7 @@ cp_parser_omp_for_loop (cp_parser *parse
                  decl = start_decl (declarator, &type_specifiers,
                                     SD_INITIALIZED, attributes,
                                     /*prefix_attributes=*/NULL_TREE,
-                                    &pushed_scope);
+                                    &pushed_scope, NULL);
 
                  auto_node = type_uses_auto (TREE_TYPE (decl));
                  if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ))
@@ -28599,6 +28664,91 @@ 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] != error_mark_node
+         && (*parser->omp_declare_simd_clauses)[0] != integer_zero_node)
+       error_at (pragma_tok->location,
+                 "%<#pragma omp declare simd%> not immediately followed by "
+                 "function declaration or definition");
+      parser->omp_declare_simd_clauses = NULL;
+    }
+}
+
+/* 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
@@ -28998,6 +29148,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:
@@ -29103,6 +29255,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:
@@ -29114,7 +29270,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/cp/parser.h.jj  2013-04-30 18:00:00.578297018 +0200
+++ gcc/cp/parser.h     2013-05-02 15:51:18.285572977 +0200
@@ -340,6 +340,15 @@ 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, each tree is either NULL_TREE, or OMP_CLAUSE
+     with optional chain of other clauses.  If error regarding
+     omp declare simd has been reported already, either
+     omp_declare_simd_clauses is set to NULL, or first element set
+     to error_mark_node.  If a FUNCTION_DECL has been seen already,
+     first element is set to integer_zero_node.  */
+  vec<tree, va_gc> *omp_declare_simd_clauses;
 } cp_parser;
 
 /* In parser.c  */
--- gcc/cp/pt.c.jj      2013-04-30 18:03:33.000000000 +0200
+++ gcc/cp/pt.c 2013-05-06 15:17:20.725304601 +0200
@@ -8431,6 +8431,8 @@ can_complete_type_without_circularity (t
     return 1;
 }
 
+static tree tsubst_omp_clauses (tree, bool, tree, tsubst_flags_t, tree);
+
 /* Apply any attributes which had to be deferred until instantiation
    time.  DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes;
    ARGS, COMPLAIN, IN_DECL are as tsubst.  */
@@ -8472,15 +8474,28 @@ apply_late_template_attributes (tree *de
            {
              *p = TREE_CHAIN (t);
              TREE_CHAIN (t) = NULL_TREE;
+             if (flag_openmp
+                 && is_attribute_p ("omp declare simd",
+                                    get_attribute_name (t))
+                 && TREE_VALUE (t))
+               {
+                 tree clauses = TREE_VALUE (t);
+                 clauses = tsubst_omp_clauses (clauses, true, args,
+                                               complain, in_decl);
+                 c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
+                 clauses = finish_omp_clauses (clauses);
+                 TREE_VALUE (t)
+                   = c_omp_declare_simd_clauses_to_numbers (*decl_p, clauses);
+               }
              /* If the first attribute argument is an identifier, don't
                 pass it through tsubst.  Attributes like mode, format,
                 cleanup and several target specific attributes expect it
                 unmodified.  */
-             if (TREE_VALUE (t)
-                 && TREE_CODE (TREE_VALUE (t)) == TREE_LIST
-                 && TREE_VALUE (TREE_VALUE (t))
-                 && (TREE_CODE (TREE_VALUE (TREE_VALUE (t)))
-                     == IDENTIFIER_NODE))
+             else if (TREE_VALUE (t)
+                      && TREE_CODE (TREE_VALUE (t)) == TREE_LIST
+                      && TREE_VALUE (TREE_VALUE (t))
+                      && (TREE_CODE (TREE_VALUE (TREE_VALUE (t)))
+                          == IDENTIFIER_NODE))
                {
                  tree chain
                    = tsubst_expr (TREE_CHAIN (TREE_VALUE (t)), args, complain,
@@ -12562,8 +12577,8 @@ tsubst_copy (tree t, tree args, tsubst_f
 /* Like tsubst_copy, but specifically for OpenMP clauses.  */
 
 static tree
-tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain,
-                   tree in_decl)
+tsubst_omp_clauses (tree clauses, bool declare_simd,
+                   tree args, tsubst_flags_t complain, tree in_decl)
 {
   tree new_clauses = NULL, nc, oc;
 
@@ -12596,22 +12611,52 @@ tsubst_omp_clauses (tree clauses, tree a
        case OMP_CLAUSE_SCHEDULE:
        case OMP_CLAUSE_COLLAPSE:
        case OMP_CLAUSE_FINAL:
+       case OMP_CLAUSE_DEPEND:
+       case OMP_CLAUSE_FROM:
+       case OMP_CLAUSE_TO:
+       case OMP_CLAUSE_UNIFORM:
+       case OMP_CLAUSE_MAP:
+       case OMP_CLAUSE_DEVICE:
+       case OMP_CLAUSE_DIST_SCHEDULE:
+       case OMP_CLAUSE_NUM_TEAMS:
+       case OMP_CLAUSE_SAFELEN:
+       case OMP_CLAUSE_SIMDLEN:
          OMP_CLAUSE_OPERAND (nc, 0)
            = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, 
                           in_decl, /*integral_constant_expression_p=*/false);
          break;
+       case OMP_CLAUSE_LINEAR:
+       case OMP_CLAUSE_ALIGNED:
+         OMP_CLAUSE_OPERAND (nc, 0)
+           = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain,
+                          in_decl, /*integral_constant_expression_p=*/false);
+         OMP_CLAUSE_OPERAND (nc, 1)
+           = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain,
+                          in_decl, /*integral_constant_expression_p=*/false);
+         break;
+
        case OMP_CLAUSE_NOWAIT:
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_DEFAULT:
        case OMP_CLAUSE_UNTIED:
        case OMP_CLAUSE_MERGEABLE:
+       case OMP_CLAUSE_INBRANCH:
+       case OMP_CLAUSE_NOTINBRANCH:
+       case OMP_CLAUSE_PROC_BIND:
+       case OMP_CLAUSE_FOR:
+       case OMP_CLAUSE_PARALLEL:
+       case OMP_CLAUSE_SECTIONS:
+       case OMP_CLAUSE_TASKGROUP:
          break;
        default:
          gcc_unreachable ();
        }
     }
 
-  return finish_omp_clauses (nreverse (new_clauses));
+  new_clauses = nreverse (new_clauses);
+  if (!declare_simd)
+    new_clauses = finish_omp_clauses (new_clauses);
+  return new_clauses;
 }
 
 /* Like tsubst_copy_and_build, but unshare TREE_LIST nodes.  */
@@ -13181,7 +13226,7 @@ tsubst_expr (tree t, tree args, tsubst_f
       break;
 
     case OMP_PARALLEL:
-      tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t),
+      tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false,
                                args, complain, in_decl);
       stmt = begin_omp_parallel ();
       RECUR (OMP_PARALLEL_BODY (t));
@@ -13190,7 +13235,7 @@ tsubst_expr (tree t, tree args, tsubst_f
       break;
 
     case OMP_TASK:
-      tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t),
+      tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false,
                                args, complain, in_decl);
       stmt = begin_omp_task ();
       RECUR (OMP_TASK_BODY (t));
@@ -13206,7 +13251,7 @@ tsubst_expr (tree t, tree args, tsubst_f
        tree declv, initv, condv, incrv;
        int i;
 
-       clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t),
+       clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false,
                                      args, complain, in_decl);
        declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
        initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
@@ -13237,7 +13282,8 @@ tsubst_expr (tree t, tree args, tsubst_f
 
     case OMP_SECTIONS:
     case OMP_SINGLE:
-      tmp = tsubst_omp_clauses (OMP_CLAUSES (t), args, complain, in_decl);
+      tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false,
+                               args, complain, in_decl);
       stmt = push_stmt_list ();
       RECUR (OMP_BODY (t));
       stmt = pop_stmt_list (stmt);
--- gcc/cp/semantics.c.jj       2013-04-30 18:03:33.000000000 +0200
+++ gcc/cp/semantics.c  2013-05-06 15:46:54.200232432 +0200
@@ -4028,6 +4028,7 @@ finish_omp_clauses (tree clauses)
   bitmap_head aligned_head;
   tree c, t, *pc = &clauses;
   const char *name;
+  bool branch_seen = false;
 
   bitmap_obstack_initialize (NULL);
   bitmap_initialize (&generic_head, &bitmap_default_obstack);
@@ -4426,8 +4427,6 @@ finish_omp_clauses (tree clauses)
        case OMP_CLAUSE_UNTIED:
        case OMP_CLAUSE_COLLAPSE:
        case OMP_CLAUSE_MERGEABLE:
-       case OMP_CLAUSE_INBRANCH:
-       case OMP_CLAUSE_NOTINBRANCH:
        case OMP_CLAUSE_PARALLEL:
        case OMP_CLAUSE_FOR:
        case OMP_CLAUSE_SECTIONS:
@@ -4435,6 +4434,17 @@ finish_omp_clauses (tree clauses)
        case OMP_CLAUSE_PROC_BIND:
          break;
 
+       case OMP_CLAUSE_INBRANCH:
+       case OMP_CLAUSE_NOTINBRANCH:
+         if (branch_seen)
+           {
+             error ("%<inbranch%> clause is incompatible with "
+                    "%<notinbranch%>");
+             remove = true;
+           }
+         branch_seen = true;
+         break;
+
        default:
          gcc_unreachable ();
        }
@@ -4619,6 +4629,90 @@ finish_omp_clauses (tree clauses)
   return clauses;
 }
 
+/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
+   and put that into "omp declare simd" attribute.  */
+
+void
+finish_omp_declare_simd (tree fndecl, vec<tree, va_gc> *clauses)
+{
+  tree cl;
+  int i;
+
+  if (TREE_CODE (fndecl) != FUNCTION_DECL)
+    return;
+  if ((*clauses)[0] == integer_zero_node)
+    {
+      error_at (DECL_SOURCE_LOCATION (fndecl),
+               "%<#pragma omp declare simd%> not immediately followed by "
+               "a single function declaration or definition");
+      (*clauses)[0] = error_mark_node;
+      return;
+    }
+  if ((*clauses)[0] == error_mark_node)
+    return;
+
+  FOR_EACH_VEC_SAFE_ELT (clauses, i, cl)
+    {
+      tree c, *pc, decl, name;
+      for (pc = &cl, c = cl; 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);
+       }
+      cl = finish_omp_clauses (cl);
+      cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl);
+      if (!processing_template_decl)
+       {
+         for (c = lookup_attribute ("omp declare simd",
+                                    DECL_ATTRIBUTES (fndecl));
+              c; c = lookup_attribute ("omp declare simd",
+                                       TREE_CHAIN (c)))
+           if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl))
+             break;
+         if (c)
+           continue;
+       }
+      c = build_tree_list (get_identifier ("omp declare simd"), cl);
+      TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
+      if (processing_template_decl)
+       ATTR_IS_DEPENDENT (c) = 1;
+      DECL_ATTRIBUTES (fndecl) = c;
+    }
+
+  (*clauses)[0] = integer_zero_node;
+}
+
 /* For all variables in the tree_list VARS, mark them as thread local.  */
 
 void
--- gcc/testsuite/g++.dg/gomp/declare-simd-1.C.jj       2013-05-02 
13:09:28.009970712 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-simd-1.C  2013-05-06 15:49:22.454392922 
+0200
@@ -0,0 +1,212 @@
+// 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) notinbranch
+#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a \
+                                                                           : 
4) simdlen (4) inbranch
+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) notinbranch 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) inbranch 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) notinbranch 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) notinbranch simdlen (8)
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear 
(a : 4) simdlen (4) inbranch
+  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) notinbranch
+  #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear 
(a : 4) simdlen (4) inbranch
+  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;
+}
+
+template <int N>
+struct C
+{
+  #pragma omp declare simd simdlen (N) aligned (a : N * sizeof (int)) linear 
(c : N) notinbranch
+  int f32 (int a, int *b, int c);
+};
+
+C <2> c;
--- gcc/testsuite/g++.dg/gomp/declare-simd-2.C.jj       2013-05-02 
13:09:28.009970712 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-simd-2.C  2013-05-06 15:55:10.743401334 
+0200
@@ -0,0 +1,60 @@
+// 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);
+
+#pragma omp declare simd inbranch notinbranch
+int fn11 (int);                // { dg-error "clause is incompatible with" }
+
+#pragma omp declare simd simdlen (N)   // { dg-error "was not declared in this 
scope" }
+template <int N>
+int fn12 (int);


        Jakub

Reply via email to