Hi!

In C/C++, OpenMP 4.1 is going to allow array sections and arrays in
reduction clauses.  This patch implements it.  Committed to gomp-4_1-branch.

2015-06-10  Jakub Jelinek  <ja...@redhat.com>

        * tree.c (omp_clause_num_ops): Bump number of OMP_CLAUSE_REDUCTION
        arguments to 5.
        (walk_tree_1): Adjust for 5 instead of 4 OMP_CLAUSE_REDUCTION
        arguments.
        * tree-core.h (OMP_CLAUSE_REDUCTION): Document
        OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER.
        * tree.h (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER): Define.
        * tree-nested.c (convert_nonlocal_omp_clauses,
        convert_local_omp_clauses): Temporarily adjust context of
        OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER too if non-NULL.
        * gimplify.c (omp_add_variable): Call omp_notice_variable
        on TYPE_SIZE_UNIT only if it is a DECL_P.
        (find_decl_expr): New function.
        (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_REDUCTION
        with MEM_REF OMP_CLAUSE_DECL.
        * omp-low.c (scan_sharing_clauses, lower_rec_input_clauses,
        lower_reduction_clauses, lower_send_clauses): Likewise.
gcc/c/
        * c-parser.c (c_parser_omp_variable_list): Allow array sections
        for OMP_CLAUSE_REDUCTION.
        (c_parser_omp_clause_reduction): Compute element type even for
        arrays and array sections.
        (c_parser_omp_declare_reduction): STRIP_NOPS before checking
        for &omp_priv.
        * c-typeck.c (handle_omp_array_sections_1): Fix a comment typo.
        Handle OMP_CLAUSE_REDUCTION array sections.  Report zero size
        array sections on OMP_CLAUSE_DEPEND.
        (handle_omp_array_sections): Use auto_vec for types, drop
        types.release () calls.  Handle OMP_CLAUSE_REDUCTION array sections.
        (c_finish_omp_clauses): Handle OMP_CLAUSE_REDUCTION array sections
        and arrays.
gcc/cp/
        * parser.c (cp_parser_omp_var_list_no_open): Allow array sections
        for OMP_CLAUSE_REDUCTION.
        * semantics.c (omp_clause_decl_field, omp_note_field_privatization,
        omp_privatize_field): New functions.
        (omp_clause_printable_decl): Use omp_clause_decl_field, move
        earlier.
        (handle_omp_array_sections_1): Fix a comment typo.
        Handle OMP_CLAUSE_REDUCTION array sections.  Report zero size
        array sections on OMP_CLAUSE_DEPEND.
        (handle_omp_array_sections): Handle OMP_CLAUSE_REDUCTION array
        sections.
        (finish_omp_reduction_clause): Handle OMP_CLAUSE_REDUCTION array
        sections and arrays.
        (finish_omp_clauses): Likewise.  Use omp_note_field_privatization,
        omp_clause_decl_field and omp_privatize_field.
gcc/c-family/
        * c-omp.c (c_omp_split_clauses): Copy over also
        OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER.
gcc/testsuite/
        * gcc.dg/gomp/clause-1.c (foo): Remove one dg-error directive.
        * g++.dg/gomp/clause-3.C (foo): Likewise.
        * gcc.dg/gomp/reduction-1.c: New test.
        * c-c++-common/gomp/depend-3.c: New test.
        * c-c++-common/gomp/reduction-1.c: New test.
        * c-c++-common/gomp/udr-1.c: New test.
libgomp/
        * testsuite/libgomp.c/reduction-7.c: New test.
        * testsuite/libgomp.c/reduction-8.c: New test.
        * testsuite/libgomp.c/reduction-9.c: New test.
        * testsuite/libgomp.c/reduction-10.c: New test.
        * testsuite/libgomp.c++/taskloop-5.C (foo): Wrap #pragma omp
        parallel bodies into #pragma omp single.
        * testsuite/libgomp.c++/reduction-5.C: New test.
        * testsuite/libgomp.c++/reduction-6.C: New test.
        * testsuite/libgomp.c++/reduction-7.C: New test.
        * testsuite/libgomp.c++/reduction-8.C: New test.
        * testsuite/libgomp.c++/reduction-9.C: New test.
        * testsuite/libgomp.c++/reduction-10.C: New test.

--- gcc/tree.c.jj       2015-05-19 18:56:50.000000000 +0200
+++ gcc/tree.c  2015-06-08 10:49:02.965545605 +0200
@@ -321,7 +321,7 @@ unsigned const char omp_clause_num_ops[]
   1, /* OMP_CLAUSE_SHARED  */
   1, /* OMP_CLAUSE_FIRSTPRIVATE  */
   2, /* OMP_CLAUSE_LASTPRIVATE  */
-  4, /* OMP_CLAUSE_REDUCTION  */
+  5, /* OMP_CLAUSE_REDUCTION  */
   1, /* OMP_CLAUSE_COPYIN  */
   1, /* OMP_CLAUSE_COPYPRIVATE  */
   3, /* OMP_CLAUSE_LINEAR  */
@@ -11361,7 +11361,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func
        case OMP_CLAUSE_REDUCTION:
          {
            int i;
-           for (i = 0; i < 4; i++)
+           for (i = 0; i < 5; i++)
              WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, i));
            WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
          }
--- gcc/tree-core.h.jj  2015-05-06 17:04:52.000000000 +0200
+++ gcc/tree-core.h     2015-06-08 11:08:41.914555026 +0200
@@ -230,7 +230,10 @@ enum omp_clause_code {
      Operand 2: OMP_CLAUSE_REDUCTION_MERGE: Stmt-list to merge private var
                 into the shared one.
      Operand 3: OMP_CLAUSE_REDUCTION_PLACEHOLDER: A dummy VAR_DECL
-                placeholder used in OMP_CLAUSE_REDUCTION_{INIT,MERGE}.  */
+                placeholder used in OMP_CLAUSE_REDUCTION_{INIT,MERGE}.
+     Operand 4: OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER: Another dummy
+               VAR_DECL placeholder, used like the above for C/C++ array
+               reductions.  */
   OMP_CLAUSE_REDUCTION,
 
   /* OpenMP clause: copyin (variable_list).  */
--- gcc/tree.h.jj       2015-05-21 11:12:09.000000000 +0200
+++ gcc/tree.h  2015-06-08 10:48:20.855190071 +0200
@@ -1458,6 +1458,8 @@ extern void protected_set_expr_location
   (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_merge
 #define OMP_CLAUSE_REDUCTION_PLACEHOLDER(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 3)
+#define OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 4)
 
 /* True if a REDUCTION clause may reference the original list item (omp_orig)
    in its OMP_CLAUSE_REDUCTION_{,GIMPLE_}INIT.  */
--- gcc/tree-nested.c.jj        2015-05-06 18:01:30.000000000 +0200
+++ gcc/tree-nested.c   2015-06-08 11:22:30.655894530 +0200
@@ -1236,6 +1236,9 @@ convert_nonlocal_omp_clauses (tree *pcla
                = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
              DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
                = info->context;
+             if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+               DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+                 = info->context;
              walk_body (convert_nonlocal_reference_stmt,
                         convert_nonlocal_reference_op, info,
                         &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
@@ -1244,6 +1247,9 @@ convert_nonlocal_omp_clauses (tree *pcla
                         &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
              DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
                = old_context;
+             if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+               DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+                 = old_context;
            }
          break;
 
@@ -1881,6 +1887,9 @@ convert_local_omp_clauses (tree *pclause
                = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
              DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
                = info->context;
+             if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+               DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+                 = info->context;
              walk_body (convert_local_reference_stmt,
                         convert_local_reference_op, info,
                         &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause));
@@ -1889,6 +1898,9 @@ convert_local_omp_clauses (tree *pclause
                         &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause));
              DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
                = old_context;
+             if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+               DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause))
+                 = old_context;
            }
          break;
 
--- gcc/gimplify.c.jj   2015-05-29 16:01:15.000000000 +0200
+++ gcc/gimplify.c      2015-06-10 17:57:35.278144016 +0200
@@ -5739,7 +5739,7 @@ omp_add_variable (struct gimplify_omp_ct
       if ((flags & GOVD_SHARED) == 0)
        {
          t = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl)));
-         if (TREE_CODE (t) != INTEGER_CST)
+         if (DECL_P (t))
            omp_notice_variable (ctx, t, true);
        }
     }
@@ -6129,6 +6129,22 @@ omp_no_lastprivate (struct gimplify_omp_
   while (1);
 }
 
+/* Callback for walk_tree to find a DECL_EXPR for the given DECL.  */
+
+static tree
+find_decl_expr (tree *tp, int *walk_subtrees, void *data)
+{
+  tree t = *tp;
+
+  /* If this node has been visited, unmark it and keep looking.  */
+  if (TREE_CODE (t) == DECL_EXPR && DECL_EXPR_DECL (t) == (tree) data)
+    return t;
+
+  if (IS_TYPE_OR_DECL_P (t))
+    *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
 /* Scan the OMP clauses in *LIST_P, installing mappings into a new
    and previous omp contexts.  */
 
@@ -6211,7 +6227,28 @@ gimplify_scan_omp_clauses (tree *list_p,
        case OMP_CLAUSE_REDUCTION:
          flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT;
          check_non_private = "reduction";
-         goto do_add;
+         decl = OMP_CLAUSE_DECL (c);
+         if (TREE_CODE (decl) == MEM_REF)
+           {
+             tree type = TREE_TYPE (decl);
+             if (gimplify_expr (&TYPE_MAX_VALUE (TYPE_DOMAIN (type)), pre_p,
+                                NULL, is_gimple_val, fb_rvalue) == GS_ERROR)
+               {
+                 remove = true;
+                 break;
+               }
+             tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+             if (DECL_P (v))
+               {
+                 omp_firstprivatize_variable (ctx, v);
+                 omp_notice_variable (ctx, v, true);
+               }
+             decl = TREE_OPERAND (decl, 0);
+             if (TREE_CODE (decl) == ADDR_EXPR
+                 || TREE_CODE (decl) == INDIRECT_REF)
+               decl = TREE_OPERAND (decl, 0);
+           }
+         goto do_add_decl;
        case OMP_CLAUSE_LINEAR:
          if (gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), pre_p, NULL,
                             is_gimple_val, fb_rvalue) == GS_ERROR)
@@ -6371,6 +6408,7 @@ gimplify_scan_omp_clauses (tree *list_p,
 
        do_add:
          decl = OMP_CLAUSE_DECL (c);
+       do_add_decl:
          if (error_operand_p (decl))
            {
              remove = true;
@@ -6393,6 +6431,14 @@ gimplify_scan_omp_clauses (tree *list_p,
            {
              omp_add_variable (ctx, OMP_CLAUSE_REDUCTION_PLACEHOLDER (c),
                                GOVD_LOCAL | GOVD_SEEN);
+             if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c)
+                 && walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
+                               find_decl_expr,
+                               OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c),
+                               NULL) == NULL_TREE)
+               omp_add_variable (ctx,
+                                 OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c),
+                                 GOVD_LOCAL | GOVD_SEEN);
              gimplify_omp_ctxp = ctx;
              push_gimplify_context ();
 
@@ -6496,6 +6542,11 @@ gimplify_scan_omp_clauses (tree *list_p,
            omp_notice_variable (outer_ctx, decl, true);
          if (check_non_private
              && region_type == ORT_WORKSHARE
+             && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION
+                 || decl == OMP_CLAUSE_DECL (c)
+                 || (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF
+                     && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0))
+                         == ADDR_EXPR)))
              && omp_check_private (ctx, decl, false))
            {
              error ("%s variable %qE is private in outer context",
--- gcc/omp-low.c.jj    2015-06-02 14:22:19.000000000 +0200
+++ gcc/omp-low.c       2015-06-09 19:56:41.821729677 +0200
@@ -1856,6 +1856,27 @@ scan_sharing_clauses (tree clauses, omp_
          OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_FIRSTPRIVATE);
          goto do_private;
 
+       case OMP_CLAUSE_REDUCTION:
+         decl = OMP_CLAUSE_DECL (c);
+         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+             && TREE_CODE (decl) == MEM_REF)
+           {
+             tree t = TREE_OPERAND (decl, 0);
+             if (TREE_CODE (t) == INDIRECT_REF
+                 || TREE_CODE (t) == ADDR_EXPR)
+               t = TREE_OPERAND (t, 0);
+             install_var_local (t, ctx);
+             if (is_taskreg_ctx (ctx)
+                 && !is_global_var (maybe_lookup_decl_in_outer_ctx (t, ctx))
+                 && !is_variable_sized (t))
+               {
+                 by_ref = use_pointer_for_field (t, ctx);
+                 install_var_field (t, by_ref, 3, ctx);
+               }
+             break;
+           }
+         goto do_private;
+
        case OMP_CLAUSE_LASTPRIVATE:
          /* Let the corresponding firstprivate clause create
             the variable.  */
@@ -1870,7 +1891,6 @@ scan_sharing_clauses (tree clauses, omp_
              break;
            }
          /* FALLTHRU */
-       case OMP_CLAUSE_REDUCTION:
        case OMP_CLAUSE_LINEAR:
          decl = OMP_CLAUSE_DECL (c);
        do_private:
@@ -2102,7 +2122,6 @@ scan_sharing_clauses (tree clauses, omp_
            }
          /* FALLTHRU */
        case OMP_CLAUSE_PRIVATE:
-       case OMP_CLAUSE_REDUCTION:
        case OMP_CLAUSE_LINEAR:
          decl = OMP_CLAUSE_DECL (c);
          if (is_variable_sized (decl))
@@ -2110,11 +2129,20 @@ scan_sharing_clauses (tree clauses, omp_
          fixup_remapped_decl (decl, ctx,
                               OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
                               && OMP_CLAUSE_PRIVATE_DEBUG (c));
-         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
-             && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
+             && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c))
            scan_array_reductions = true;
-         else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
-                  && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c))
+         break;
+
+       case OMP_CLAUSE_REDUCTION:
+         decl = OMP_CLAUSE_DECL (c);
+         if (TREE_CODE (decl) != MEM_REF)
+           {
+             if (is_variable_sized (decl))
+               install_var_local (decl, ctx);
+             fixup_remapped_decl (decl, ctx, false);
+           }
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
            scan_array_reductions = true;
          break;
 
@@ -3861,13 +3889,17 @@ lower_rec_input_clauses (tree clauses, g
          if (OMP_CLAUSE_LINEAR_ARRAY (c))
            max_vf = 1;
          /* FALLTHRU */
-       case OMP_CLAUSE_REDUCTION:
        case OMP_CLAUSE_PRIVATE:
        case OMP_CLAUSE_FIRSTPRIVATE:
        case OMP_CLAUSE_LASTPRIVATE:
          if (is_variable_sized (OMP_CLAUSE_DECL (c)))
            max_vf = 1;
          break;
+       case OMP_CLAUSE_REDUCTION:
+         if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF
+             || is_variable_sized (OMP_CLAUSE_DECL (c)))
+           max_vf = 1;
+         break;
        default:
          continue;
        }
@@ -3970,6 +4002,22 @@ lower_rec_input_clauses (tree clauses, g
            }
 
          new_var = var = OMP_CLAUSE_DECL (c);
+         if (c_kind == OMP_CLAUSE_REDUCTION && TREE_CODE (var) == MEM_REF)
+           {
+             var = TREE_OPERAND (var, 0);
+             if (TREE_CODE (var) == INDIRECT_REF
+                 || TREE_CODE (var) == ADDR_EXPR)
+               var = TREE_OPERAND (var, 0);
+             if (is_variable_sized (var))
+               {
+                 gcc_assert (DECL_HAS_VALUE_EXPR_P (var));
+                 var = DECL_VALUE_EXPR (var);
+                 gcc_assert (TREE_CODE (var) == INDIRECT_REF);
+                 var = TREE_OPERAND (var, 0);
+                 gcc_assert (DECL_P (var));
+               }
+             new_var = var;
+           }
          if (c_kind != OMP_CLAUSE_COPYIN)
            new_var = lookup_decl (var, ctx);
 
@@ -3978,6 +4026,236 @@ lower_rec_input_clauses (tree clauses, g
              if (pass != 0)
                continue;
            }
+         /* C/C++ array section reductions.  */
+         else if (c_kind == OMP_CLAUSE_REDUCTION
+                  && var != OMP_CLAUSE_DECL (c))
+           {
+             if (pass == 0)
+               continue;
+
+             tree orig_var = TREE_OPERAND (OMP_CLAUSE_DECL (c), 0);
+             if (TREE_CODE (orig_var) == INDIRECT_REF
+                 || TREE_CODE (orig_var) == ADDR_EXPR)
+               orig_var = TREE_OPERAND (orig_var, 0);
+             tree d = OMP_CLAUSE_DECL (c);
+             tree type = TREE_TYPE (d);
+             gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+             tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+             const char *name = NULL;
+             if (DECL_NAME (orig_var))
+               name = IDENTIFIER_POINTER (DECL_NAME (orig_var));
+             if (TREE_CONSTANT (v))
+               {
+                 x = create_tmp_var_raw (type, name);
+                 gimple_add_tmp_var (x);
+                 TREE_ADDRESSABLE (x) = 1;
+                 x = build_fold_addr_expr_loc (clause_loc, x);
+               }
+             else
+               {
+                 tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
+                 tree t = maybe_lookup_decl (v, ctx);
+                 if (t)
+                   v = t;
+                 else
+                   v = maybe_lookup_decl_in_outer_ctx (v, ctx);
+                 gimplify_expr (&v, ilist, NULL, is_gimple_val, fb_rvalue);
+                 t = fold_build2_loc (clause_loc, PLUS_EXPR,
+                                      TREE_TYPE (v), v,
+                                      build_int_cst (TREE_TYPE (v), 1));
+                 t = fold_build2_loc (clause_loc, MULT_EXPR,
+                                      TREE_TYPE (v), t,
+                                      TYPE_SIZE_UNIT (TREE_TYPE (type)));
+                 x = build_call_expr_loc (clause_loc, atmp, 1, t);
+               }
+
+             tree ptype = build_pointer_type (TREE_TYPE (type));
+             x = fold_convert_loc (clause_loc, ptype, x);
+             tree y = create_tmp_var (ptype, name);
+             gimplify_assign (y, x, ilist);
+             x = y;
+             if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR)
+               {
+                 if (orig_var != var)
+                   {
+                     gcc_assert (is_variable_sized (orig_var));
+                     x = fold_convert_loc (clause_loc, TREE_TYPE (new_var),
+                                           x);
+                     gimplify_assign (new_var, x, ilist);
+                     tree new_orig_var = lookup_decl (orig_var, ctx);
+                     tree t = build_fold_indirect_ref (new_var);
+                     DECL_IGNORED_P (new_var) = 0;
+                     TREE_THIS_NOTRAP (t);
+                     SET_DECL_VALUE_EXPR (new_orig_var, t);
+                     DECL_HAS_VALUE_EXPR_P (new_orig_var) = 1;
+                   }
+                 else
+                   {
+                     x = build2 (MEM_REF, TREE_TYPE (new_var), x,
+                                 build_int_cst (ptype, 0));
+                     SET_DECL_VALUE_EXPR (new_var, x);
+                     DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+                   }
+               }
+             else
+               {
+                 gcc_assert (orig_var == var);
+                 if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF)
+                   {
+                     x = create_tmp_var (ptype, name);
+                     TREE_ADDRESSABLE (x) = 1;
+                     gimplify_assign (x, y, ilist);
+                     x = build_fold_addr_expr_loc (clause_loc, x);
+                   }
+                 x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
+                 gimplify_assign (new_var, x, ilist);
+               }
+             tree y1 = create_tmp_var (ptype, NULL);
+             gimplify_assign (y1, y, ilist);
+             tree i2 = NULL_TREE, y2 = NULL_TREE;
+             tree body2 = NULL_TREE, end2 = NULL_TREE;
+             tree y3 = NULL_TREE, y4 = NULL_TREE;
+             if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) || is_simd)
+               {
+                 y2 = create_tmp_var (ptype, NULL);
+                 gimplify_assign (y2, y, ilist);
+                 tree ref = build_outer_var_ref (var, ctx);
+                 /* For ref build_outer_var_ref already performs this.  */
+                 if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF)
+                   gcc_assert (is_reference (var));
+                 else if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR)
+                   ref = build_fold_addr_expr (ref);
+                 else if (is_reference (var))
+                   ref = build_fold_addr_expr (ref);
+                 ref = fold_convert_loc (clause_loc, ptype, ref);
+                 if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+                     && OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c))
+                   {
+                     y3 = create_tmp_var (ptype, NULL);
+                     gimplify_assign (y3, unshare_expr (ref), ilist);
+                   }
+                 if (is_simd)
+                   {
+                     y4 = create_tmp_var (ptype, NULL);
+                     gimplify_assign (y4, ref, dlist);
+                   }
+               }
+             tree i = create_tmp_var (TREE_TYPE (v), NULL);
+             gimplify_assign (i, build_int_cst (TREE_TYPE (v), 0), ilist);
+             tree body = create_artificial_label (UNKNOWN_LOCATION);
+             tree end = create_artificial_label (UNKNOWN_LOCATION);
+             gimple_seq_add_stmt (ilist, gimple_build_label (body));
+             if (y2)
+               {
+                 i2 = create_tmp_var (TREE_TYPE (v), NULL);
+                 gimplify_assign (i2, build_int_cst (TREE_TYPE (v), 0), dlist);
+                 body2 = create_artificial_label (UNKNOWN_LOCATION);
+                 end2 = create_artificial_label (UNKNOWN_LOCATION);
+                 gimple_seq_add_stmt (dlist, gimple_build_label (body2));
+               }
+             if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+               {
+                 tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+                 tree decl_placeholder
+                   = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c);
+                 SET_DECL_VALUE_EXPR (decl_placeholder,
+                                      build_simple_mem_ref (y1));
+                 DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 1;
+                 SET_DECL_VALUE_EXPR (placeholder,
+                                      y3 ? build_simple_mem_ref (y3)
+                                      : error_mark_node);
+                 DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
+                 x = lang_hooks.decls.omp_clause_default_ctor
+                               (c, build_simple_mem_ref (y1),
+                                y3 ? build_simple_mem_ref (y3) : NULL_TREE);
+                 if (x)
+                   gimplify_and_add (x, ilist);
+                 if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))
+                   {
+                     gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c);
+                     lower_omp (&tseq, ctx);
+                     gimple_seq_add_seq (ilist, tseq);
+                   }
+                 OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
+                 if (is_simd)
+                   {
+                     SET_DECL_VALUE_EXPR (decl_placeholder,
+                                          build_simple_mem_ref (y2));
+                     SET_DECL_VALUE_EXPR (placeholder,
+                                          build_simple_mem_ref (y4));
+                     gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
+                     lower_omp (&tseq, ctx);
+                     gimple_seq_add_seq (dlist, tseq);
+                     OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL;
+                   }
+                 DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
+                 DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 0;
+                 x = lang_hooks.decls.omp_clause_dtor
+                                       (c, build_simple_mem_ref (y2));
+                 if (x)
+                   {
+                     gimple_seq tseq = NULL;
+                     dtor = x;
+                     gimplify_stmt (&dtor, &tseq);
+                     gimple_seq_add_seq (dlist, tseq);
+                   }
+               }
+             else
+               {
+                 x = omp_reduction_init (c, TREE_TYPE (type));
+                 enum tree_code code = OMP_CLAUSE_REDUCTION_CODE (c);
+
+                 /* reduction(-:var) sums up the partial results, so it
+                    acts identically to reduction(+:var).  */
+                 if (code == MINUS_EXPR)
+                   code = PLUS_EXPR;
+
+                 gimplify_assign (build_simple_mem_ref (y1), x, ilist);
+                 if (is_simd)
+                   {
+                     x = build2 (code, TREE_TYPE (type),
+                                 build_simple_mem_ref (y4),
+                                 build_simple_mem_ref (y2));
+                     gimplify_assign (build_simple_mem_ref (y4), x, dlist);
+                   }
+               }
+             gimple g
+               = gimple_build_assign (y1, POINTER_PLUS_EXPR, y1,
+                                      TYPE_SIZE_UNIT (TREE_TYPE (type)));
+             gimple_seq_add_stmt (ilist, g);
+             if (y3)
+               {
+                 g = gimple_build_assign (y3, POINTER_PLUS_EXPR, y3,
+                                          TYPE_SIZE_UNIT (TREE_TYPE (type)));
+                 gimple_seq_add_stmt (ilist, g);
+               }
+             g = gimple_build_assign (i, PLUS_EXPR, i,
+                                      build_int_cst (TREE_TYPE (i), 1));
+             gimple_seq_add_stmt (ilist, g);
+             g = gimple_build_cond (LE_EXPR, i, v, body, end);
+             gimple_seq_add_stmt (ilist, g);
+             gimple_seq_add_stmt (ilist, gimple_build_label (end));
+             if (y2)
+               {
+                 g = gimple_build_assign (y2, POINTER_PLUS_EXPR, y2,
+                                          TYPE_SIZE_UNIT (TREE_TYPE (type)));
+                 gimple_seq_add_stmt (dlist, g);
+                 if (y4)
+                   {
+                     g = gimple_build_assign
+                                       (y4, POINTER_PLUS_EXPR, y4,
+                                        TYPE_SIZE_UNIT (TREE_TYPE (type)));
+                     gimple_seq_add_stmt (dlist, g);
+                   }
+                 g = gimple_build_assign (i2, PLUS_EXPR, i2,
+                                          build_int_cst (TREE_TYPE (i2), 1));
+                 gimple_seq_add_stmt (dlist, g);
+                 g = gimple_build_cond (LE_EXPR, i2, v, body2, end2);
+                 gimple_seq_add_stmt (dlist, g);
+                 gimple_seq_add_stmt (dlist, gimple_build_label (end2));
+               }
+             continue;
+           }
          else if (is_variable_sized (var))
            {
              /* For variable sized types, we need to allocate the
@@ -4770,7 +5048,8 @@ lower_reduction_clauses (tree clauses, g
   for (c = clauses; c && count < 2; c = OMP_CLAUSE_CHAIN (c))
     if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
       {
-       if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+       if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+           || TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF)
          {
            /* Never use OMP_ATOMIC for array reductions or UDRs.  */
            count = -1;
@@ -4795,16 +5074,32 @@ lower_reduction_clauses (tree clauses, g
 
   for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
     {
-      tree var, ref, new_var;
+      tree var, ref, new_var, orig_var;
       enum tree_code code;
       location_t clause_loc = OMP_CLAUSE_LOCATION (c);
 
       if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION)
        continue;
 
-      var = OMP_CLAUSE_DECL (c);
+      orig_var = var = OMP_CLAUSE_DECL (c);
+      if (TREE_CODE (var) == MEM_REF)
+       {
+         var = TREE_OPERAND (var, 0);
+         if (TREE_CODE (var) == INDIRECT_REF
+             || TREE_CODE (var) == ADDR_EXPR)
+           var = TREE_OPERAND (var, 0);
+         orig_var = var;
+         if (is_variable_sized (var))
+           {
+             gcc_assert (DECL_HAS_VALUE_EXPR_P (var));
+             var = DECL_VALUE_EXPR (var);
+             gcc_assert (TREE_CODE (var) == INDIRECT_REF);
+             var = TREE_OPERAND (var, 0);
+             gcc_assert (DECL_P (var));
+           }
+       }
       new_var = lookup_decl (var, ctx);
-      if (is_reference (var))
+      if (var == OMP_CLAUSE_DECL (c) && is_reference (var))
        new_var = build_simple_mem_ref_loc (clause_loc, new_var);
       ref = build_outer_var_ref (var, ctx);
       code = OMP_CLAUSE_REDUCTION_CODE (c);
@@ -4831,6 +5126,92 @@ lower_reduction_clauses (tree clauses, g
          gimplify_and_add (x, stmt_seqp);
          return;
        }
+      else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF)
+       {
+         tree d = OMP_CLAUSE_DECL (c);
+         tree type = TREE_TYPE (d);
+         tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+         tree i = create_tmp_var (TREE_TYPE (v), NULL);
+         tree ptype = build_pointer_type (TREE_TYPE (type));
+         /* For ref build_outer_var_ref already performs this, so
+            only new_var needs a dereference.  */
+         if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF)
+           {
+             new_var = build_simple_mem_ref_loc (clause_loc, new_var);
+             gcc_assert (is_reference (var) && var == orig_var);
+           }
+         else if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR)
+           {
+             if (orig_var == var)
+               {
+                 new_var = build_fold_addr_expr (new_var);
+                 ref = build_fold_addr_expr (ref);
+               }
+           }
+         else
+           {
+             gcc_assert (orig_var == var);
+             if (is_reference (var))
+               ref = build_fold_addr_expr (ref);
+           }
+         if (DECL_P (v))
+           {
+             tree t = maybe_lookup_decl (v, ctx);
+             if (t)
+               v = t;
+             else
+               v = maybe_lookup_decl_in_outer_ctx (v, ctx);
+             gimplify_expr (&v, stmt_seqp, NULL, is_gimple_val, fb_rvalue);
+           }
+         new_var = fold_convert_loc (clause_loc, ptype, new_var);
+         ref = fold_convert_loc (clause_loc, ptype, ref);
+         tree m = create_tmp_var (ptype, NULL);
+         gimplify_assign (m, new_var, stmt_seqp);
+         new_var = m;
+         m = create_tmp_var (ptype, NULL);
+         gimplify_assign (m, ref, stmt_seqp);
+         ref = m;
+         gimplify_assign (i, build_int_cst (TREE_TYPE (v), 0), stmt_seqp);
+         tree body = create_artificial_label (UNKNOWN_LOCATION);
+         tree end = create_artificial_label (UNKNOWN_LOCATION);
+         gimple_seq_add_stmt (&sub_seq, gimple_build_label (body));
+         tree priv = build_simple_mem_ref_loc (clause_loc, new_var);
+         tree out = build_simple_mem_ref_loc (clause_loc, ref);
+         if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+           {
+             tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+             tree decl_placeholder
+               = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c);
+             SET_DECL_VALUE_EXPR (placeholder, out);
+             DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
+             SET_DECL_VALUE_EXPR (decl_placeholder, priv);
+             DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 1;
+             lower_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c), ctx);
+             gimple_seq_add_seq (&sub_seq,
+                                 OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c));
+             OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL;
+             OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL;
+             OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = NULL;
+           }
+         else
+           {
+             x = build2 (code, TREE_TYPE (out), out, priv);
+             out = unshare_expr (out);
+             gimplify_assign (out, x, &sub_seq);
+           }
+         gimple g = gimple_build_assign (new_var, POINTER_PLUS_EXPR, new_var,
+                                         TYPE_SIZE_UNIT (TREE_TYPE (type)));
+         gimple_seq_add_stmt (&sub_seq, g);
+         g = gimple_build_assign (ref, POINTER_PLUS_EXPR, ref,
+                                  TYPE_SIZE_UNIT (TREE_TYPE (type)));
+         gimple_seq_add_stmt (&sub_seq, g);
+         g = gimple_build_assign (i, PLUS_EXPR, i,
+                                  build_int_cst (TREE_TYPE (i), 1));
+         gimple_seq_add_stmt (&sub_seq, g);
+         g = gimple_build_cond (LE_EXPR, i, v, body, end);
+         gimple_seq_add_stmt (&sub_seq, g);
+         gimple_seq_add_stmt (&sub_seq, gimple_build_label (end));
+       }
       else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
        {
          tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
@@ -4966,6 +5347,16 @@ lower_send_clauses (tree clauses, gimple
        }
 
       val = OMP_CLAUSE_DECL (c);
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+         && TREE_CODE (val) == MEM_REF)
+       {
+         val = TREE_OPERAND (val, 0);
+         if (TREE_CODE (val) == INDIRECT_REF
+             || TREE_CODE (val) == ADDR_EXPR)
+           val = TREE_OPERAND (val, 0);
+         if (is_variable_sized (val))
+           continue;
+       }
       var = lookup_decl_in_outer_ctx (val, ctx);
 
       if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_COPYIN
@@ -5001,7 +5392,9 @@ lower_send_clauses (tree clauses, gimple
          continue;
        }
 
-      if (is_variable_sized (val))
+      if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION
+          || val == OMP_CLAUSE_DECL (c))
+         && is_variable_sized (val))
        continue;
       by_ref = use_pointer_for_field (val, NULL);
 
@@ -5031,7 +5424,10 @@ lower_send_clauses (tree clauses, gimple
 
        case OMP_CLAUSE_REDUCTION:
          do_in = true;
-         do_out = !(by_ref || is_reference (val));
+         if (val == OMP_CLAUSE_DECL (c))
+           do_out = !(by_ref || is_reference (val));
+         else
+           by_ref = TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE;
          break;
 
        default:
--- gcc/c/c-parser.c.jj 2015-05-26 19:12:30.000000000 +0200
+++ gcc/c/c-parser.c    2015-06-10 14:52:06.258288807 +0200
@@ -10191,6 +10191,7 @@ c_parser_omp_variable_list (c_parser *pa
            case OMP_CLAUSE_FROM:
            case OMP_CLAUSE_TO:
            case OMP_CLAUSE_DEPEND:
+           case OMP_CLAUSE_REDUCTION:
              while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
                {
                  tree low_bound = NULL_TREE, length = NULL_TREE;
@@ -11067,7 +11068,27 @@ c_parser_omp_clause_reduction (c_parser
                                           OMP_CLAUSE_REDUCTION, list);
          for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
            {
-             tree type = TREE_TYPE (OMP_CLAUSE_DECL (c));
+             tree d = OMP_CLAUSE_DECL (c), type;
+             if (TREE_CODE (d) != TREE_LIST)
+               type = TREE_TYPE (d);
+             else
+               {
+                 int cnt = 0;
+                 tree t;
+                 for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t))
+                   cnt++;
+                 type = TREE_TYPE (t);
+                 while (cnt > 0)
+                   {
+                     if (TREE_CODE (type) != POINTER_TYPE
+                         && TREE_CODE (type) != ARRAY_TYPE)
+                       break;
+                     type = TREE_TYPE (type);
+                     cnt--;
+                   }
+               }
+             while (TREE_CODE (type) == ARRAY_TYPE)
+               type = TREE_TYPE (type);
              OMP_CLAUSE_REDUCTION_CODE (c) = code;
              if (code == ERROR_MARK
                  || !(INTEGRAL_TYPE_P (type)
@@ -15084,9 +15105,13 @@ c_parser_omp_declare_reduction (c_parser
                  int j;
                  tree c = initializer.value;
                  for (j = 0; j < call_expr_nargs (c); j++)
-                   if (TREE_CODE (CALL_EXPR_ARG (c, j)) == ADDR_EXPR
-                       && TREE_OPERAND (CALL_EXPR_ARG (c, j), 0) == omp_priv)
-                     break;
+                   {
+                     tree a = CALL_EXPR_ARG (c, j);
+                     STRIP_NOPS (a);
+                     if (TREE_CODE (a) == ADDR_EXPR
+                         && TREE_OPERAND (a, 0) == omp_priv)
+                       break;
+                   }
                  if (j == call_expr_nargs (c))
                    error ("one of the initializer call arguments should be "
                           "%<&omp_priv%>");
--- gcc/c/c-typeck.c.jj 2015-05-19 18:56:47.000000000 +0200
+++ gcc/c/c-typeck.c    2015-06-10 15:23:36.445054654 +0200
@@ -11591,7 +11591,7 @@ c_finish_omp_cancellation_point (locatio
    map(a[:b][2:1][:c][:2][:d][e:f][2:5])
    FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c]
    all are or may have length of 1, array-section-subscript [:2] is the
-   first one knonwn not to have length 1.  For array-section-subscript
+   first one known not to have length 1.  For array-section-subscript
    <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't
    0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we
    can if MAYBE_ZERO_LEN is false.  MAYBE_ZERO_LEN will be true in the above
@@ -11671,11 +11671,32 @@ handle_omp_array_sections_1 (tree c, tre
   if (length != NULL_TREE)
     {
       if (!integer_nonzerop (length))
-       maybe_zero_len = true;
+       {
+         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+             || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+           {
+             if (integer_zerop (length))
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "zero length array section in %qs clause",
+                           omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+                 return error_mark_node;
+               }
+           }
+         else
+           maybe_zero_len = true;
+       }
       if (first_non_one == types.length ()
          && (TREE_CODE (length) != INTEGER_CST || integer_onep (length)))
        first_non_one++;
     }
+  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+      && !integer_zerop (low_bound))
+    {
+      error_at (OMP_CLAUSE_LOCATION (c),
+               "%<reduction%> array section has to be zero-based");
+      return error_mark_node;
+    }
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
       if (length == NULL_TREE
@@ -11723,7 +11744,17 @@ handle_omp_array_sections_1 (tree c, tre
                  return error_mark_node;
                }
              if (tree_int_cst_equal (size, low_bound))
-               maybe_zero_len = true;
+               {
+                 if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+                     || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+                   {
+                     error_at (OMP_CLAUSE_LOCATION (c),
+                               "zero length array section in %qs clause",
+                               omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+                     return error_mark_node;
+                   }
+                 maybe_zero_len = true;
+               }
              else if (length == NULL_TREE
                       && first_non_one == types.length ()
                       && tree_int_cst_equal
@@ -11733,7 +11764,9 @@ handle_omp_array_sections_1 (tree c, tre
            }
          else if (length == NULL_TREE)
            {
-             maybe_zero_len = true;
+             if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+                 && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION)
+               maybe_zero_len = true;
              if (first_non_one == types.length ())
                first_non_one++;
            }
@@ -11767,7 +11800,9 @@ handle_omp_array_sections_1 (tree c, tre
        }
       else if (length == NULL_TREE)
        {
-         maybe_zero_len = true;
+         if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+             && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION)
+           maybe_zero_len = true;
          if (first_non_one == types.length ())
            first_non_one++;
        }
@@ -11828,24 +11863,17 @@ handle_omp_array_sections (tree c)
 {
   bool maybe_zero_len = false;
   unsigned int first_non_one = 0;
-  vec<tree> types = vNULL;
+  auto_vec<tree, 10> types;
   tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
                                            maybe_zero_len, first_non_one);
   if (first == error_mark_node)
-    {
-      types.release ();
-      return true;
-    }
+    return true;
   if (first == NULL_TREE)
-    {
-      types.release ();
-      return false;
-    }
+    return false;
   if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
     {
       tree t = OMP_CLAUSE_DECL (c);
       tree tem = NULL_TREE;
-      types.release ();
       /* Need to evaluate side effects in the length expressions
         if any.  */
       while (TREE_CODE (t) == TREE_LIST)
@@ -11915,7 +11943,6 @@ handle_omp_array_sections (tree c)
                                "array section is not contiguous in %qs "
                                "clause",
                                omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
-                     types.release ();
                      return true;
                    }
                }
@@ -11934,7 +11961,9 @@ handle_omp_array_sections (tree c)
            {
              tree l;
 
-             if (i > first_non_one && length && integer_nonzerop (length))
+             if (i > first_non_one
+                 && ((length && integer_nonzerop (length))
+                     || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION))
                continue;
              if (length)
                l = fold_convert (sizetype, length);
@@ -11959,6 +11988,22 @@ handle_omp_array_sections (tree c)
              else if (size == NULL_TREE)
                {
                  size = size_in_bytes (TREE_TYPE (types[i]));
+                 tree eltype = TREE_TYPE (types[num - 1]);
+                 while (TREE_CODE (eltype) == ARRAY_TYPE)
+                   eltype = TREE_TYPE (eltype);
+                 if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+                   {
+                     if (integer_zerop (size)
+                         || integer_zerop (size_in_bytes (eltype)))
+                       {
+                         error_at (OMP_CLAUSE_LOCATION (c),
+                                   "zero length array section in %qs clause",
+                                   omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+                         return error_mark_node;
+                       }
+                     size = size_binop (EXACT_DIV_EXPR, size,
+                                        size_in_bytes (eltype));
+                   }
                  size = size_binop (MULT_EXPR, size, l);
                  if (condition)
                    size = fold_build3 (COND_EXPR, sizetype, condition,
@@ -11968,9 +12013,24 @@ handle_omp_array_sections (tree c)
                size = size_binop (MULT_EXPR, size, l);
            }
        }
-      types.release ();
       if (side_effects)
        size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+       {
+         size = size_binop (MINUS_EXPR, size, size_one_node);
+         size = c_fully_fold (size, false, NULL);
+         tree index_type = build_index_type (size);
+         tree eltype = TREE_TYPE (first);
+         while (TREE_CODE (eltype) == ARRAY_TYPE)
+           eltype = TREE_TYPE (eltype);
+         tree type = build_array_type (eltype, index_type);
+         tree ptype = build_pointer_type (eltype);
+         if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+           t = build_fold_addr_expr (t);
+         t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0));
+         OMP_CLAUSE_DECL (c) = t;
+         return false;
+       }
       first = c_fully_fold (first, false, NULL);
       OMP_CLAUSE_DECL (c) = first;
       if (size)
@@ -12050,7 +12110,7 @@ c_finish_omp_clauses (tree clauses)
 {
   bitmap_head generic_head, firstprivate_head, lastprivate_head;
   bitmap_head aligned_head;
-  tree c, t, *pc;
+  tree c, t, type, *pc;
   tree simdlen = NULL_TREE, safelen = NULL_TREE;
   bool branch_seen = false;
   bool copyprivate_seen = false;
@@ -12082,9 +12142,61 @@ c_finish_omp_clauses (tree clauses)
        case OMP_CLAUSE_REDUCTION:
          need_implicitly_determined = true;
          t = OMP_CLAUSE_DECL (c);
+         if (TREE_CODE (t) == TREE_LIST)
+           {
+             if (handle_omp_array_sections (c))
+               {
+                 remove = true;
+                 break;
+               }
+
+             t = OMP_CLAUSE_DECL (c);
+           }
+         t = require_complete_type (t);
+         if (t == error_mark_node)
+           {
+             remove = true;
+             break;
+           }
+         type = TREE_TYPE (t);
+         if (TREE_CODE (t) == MEM_REF)
+           type = TREE_TYPE (type);
+         if (TREE_CODE (type) == ARRAY_TYPE)
+           {
+             tree oatype = type;
+             gcc_assert (TREE_CODE (t) != MEM_REF);
+             while (TREE_CODE (type) == ARRAY_TYPE)
+               type = TREE_TYPE (type);
+             if (integer_zerop (TYPE_SIZE_UNIT (type)))
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "%qD in %<reduction%> clause is a zero size array",
+                           t);
+                 remove = true;
+                 break;
+               }
+             tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype),
+                                     TYPE_SIZE_UNIT (type));
+             if (integer_zerop (size))
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "%qD in %<reduction%> clause is a zero size array",
+                           t);
+                 remove = true;
+                 break;
+               }
+             size = size_binop (MINUS_EXPR, size, size_one_node);
+             tree index_type = build_index_type (size);
+             tree atype = build_array_type (type, index_type);
+             tree ptype = build_pointer_type (type);
+             if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+               t = build_fold_addr_expr (t);
+             t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0));
+             OMP_CLAUSE_DECL (c) = t;
+           }
          if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE
-             && (FLOAT_TYPE_P (TREE_TYPE (t))
-                 || TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE))
+             && (FLOAT_TYPE_P (type)
+                 || TREE_CODE (type) == COMPLEX_TYPE))
            {
              enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c);
              const char *r_name = NULL;
@@ -12096,11 +12208,11 @@ c_finish_omp_clauses (tree clauses)
                case MINUS_EXPR:
                  break;
                case MIN_EXPR:
-                 if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
+                 if (TREE_CODE (type) == COMPLEX_TYPE)
                    r_name = "min";
                  break;
                case MAX_EXPR:
-                 if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
+                 if (TREE_CODE (type) == COMPLEX_TYPE)
                    r_name = "max";
                  break;
                case BIT_AND_EXPR:
@@ -12113,11 +12225,11 @@ c_finish_omp_clauses (tree clauses)
                  r_name = "|";
                  break;
                case TRUTH_ANDIF_EXPR:
-                 if (FLOAT_TYPE_P (TREE_TYPE (t)))
+                 if (FLOAT_TYPE_P (type))
                    r_name = "&&";
                  break;
                case TRUTH_ORIF_EXPR:
-                 if (FLOAT_TYPE_P (TREE_TYPE (t)))
+                 if (FLOAT_TYPE_P (type))
                    r_name = "||";
                  break;
                default:
@@ -12135,37 +12247,49 @@ c_finish_omp_clauses (tree clauses)
          else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node)
            {
              error_at (OMP_CLAUSE_LOCATION (c),
-                       "user defined reduction not found for %qD", t);
+                       "user defined reduction not found for %qE", t);
              remove = true;
              break;
            }
          else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
            {
              tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
-             tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+             type = TYPE_MAIN_VARIANT (type);
              tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c),
                                             VAR_DECL, NULL_TREE, type);
+             tree decl_placeholder = NULL_TREE;
              OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
              DECL_ARTIFICIAL (placeholder) = 1;
              DECL_IGNORED_P (placeholder) = 1;
+             if (TREE_CODE (t) == MEM_REF)
+               {
+                 decl_placeholder = build_decl (OMP_CLAUSE_LOCATION (c),
+                                                VAR_DECL, NULL_TREE, type);
+                 OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder;
+                 DECL_ARTIFICIAL (decl_placeholder) = 1;
+                 DECL_IGNORED_P (decl_placeholder) = 1;
+               }
              if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0)))
                c_mark_addressable (placeholder);
              if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1)))
-               c_mark_addressable (OMP_CLAUSE_DECL (c));
+               c_mark_addressable (decl_placeholder ? decl_placeholder
+                                   : OMP_CLAUSE_DECL (c));
              OMP_CLAUSE_REDUCTION_MERGE (c)
                = c_clone_omp_udr (TREE_VEC_ELT (list, 2),
                                   TREE_VEC_ELT (list, 0),
                                   TREE_VEC_ELT (list, 1),
-                                  OMP_CLAUSE_DECL (c), placeholder);
+                                  decl_placeholder ? decl_placeholder
+                                  : OMP_CLAUSE_DECL (c), placeholder);
              OMP_CLAUSE_REDUCTION_MERGE (c)
                = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR,
                              void_type_node, NULL_TREE,
-                              OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE);
+                             OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE);
              TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1;
              if (TREE_VEC_LENGTH (list) == 6)
                {
                  if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3)))
-                   c_mark_addressable (OMP_CLAUSE_DECL (c));
+                   c_mark_addressable (decl_placeholder ? decl_placeholder
+                                       : OMP_CLAUSE_DECL (c));
                  if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4)))
                    c_mark_addressable (placeholder);
                  tree init = TREE_VEC_ELT (list, 5);
@@ -12174,11 +12298,15 @@ c_finish_omp_clauses (tree clauses)
                  OMP_CLAUSE_REDUCTION_INIT (c)
                    = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4),
                                       TREE_VEC_ELT (list, 3),
-                                      OMP_CLAUSE_DECL (c), placeholder);
+                                      decl_placeholder ? decl_placeholder
+                                      : OMP_CLAUSE_DECL (c), placeholder);
                  if (TREE_VEC_ELT (list, 5) == error_mark_node)
-                   OMP_CLAUSE_REDUCTION_INIT (c)
-                     = build2 (INIT_EXPR, TREE_TYPE (t), t,
-                               OMP_CLAUSE_REDUCTION_INIT (c));
+                   {
+                     tree v = decl_placeholder ? decl_placeholder : t;
+                     OMP_CLAUSE_REDUCTION_INIT (c)
+                       = build2 (INIT_EXPR, TREE_TYPE (v), v,
+                                 OMP_CLAUSE_REDUCTION_INIT (c));
+                   }
                  if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
                                 c_find_omp_placeholder_r,
                                 placeholder, NULL))
@@ -12187,12 +12315,13 @@ c_finish_omp_clauses (tree clauses)
              else
                {
                  tree init;
-                 if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
-                   init = build_constructor (TREE_TYPE (t), NULL);
+                 tree v = decl_placeholder ? decl_placeholder : t;
+                 if (AGGREGATE_TYPE_P (TREE_TYPE (v)))
+                   init = build_constructor (TREE_TYPE (v), NULL);
                  else
-                   init = fold_convert (TREE_TYPE (t), integer_zero_node);
+                   init = fold_convert (TREE_TYPE (v), integer_zero_node);
                  OMP_CLAUSE_REDUCTION_INIT (c)
-                   = build2 (INIT_EXPR, TREE_TYPE (t), t, init);
+                   = build2 (INIT_EXPR, TREE_TYPE (v), v, init);
                }
              OMP_CLAUSE_REDUCTION_INIT (c)
                = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR,
@@ -12200,7 +12329,22 @@ c_finish_omp_clauses (tree clauses)
                               OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE);
              TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1;
            }
-         goto check_dup_generic;
+         if (TREE_CODE (t) == MEM_REF)
+           {
+             if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t))) == NULL_TREE
+                 || TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t))))
+                    != INTEGER_CST)
+               {
+                 sorry ("variable length element type in array "
+                        "%<reduction%> clause");
+                 remove = true;
+                 break;
+               }
+             t = TREE_OPERAND (t, 0);
+             if (TREE_CODE (t) == ADDR_EXPR)
+               t = TREE_OPERAND (t, 0);
+           }
+         goto check_dup_generic_t;
 
        case OMP_CLAUSE_COPYPRIVATE:
          copyprivate_seen = true;
@@ -12254,6 +12398,7 @@ c_finish_omp_clauses (tree clauses)
 
        check_dup_generic:
          t = OMP_CLAUSE_DECL (c);
+       check_dup_generic_t:
          if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
            {
              error_at (OMP_CLAUSE_LOCATION (c),
--- gcc/cp/parser.c.jj  2015-06-02 19:02:27.000000000 +0200
+++ gcc/cp/parser.c     2015-06-03 19:48:09.172144901 +0200
@@ -27839,6 +27839,7 @@ cp_parser_omp_var_list_no_open (cp_parse
            case OMP_CLAUSE_FROM:
            case OMP_CLAUSE_TO:
            case OMP_CLAUSE_DEPEND:
+           case OMP_CLAUSE_REDUCTION:
              while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
                {
                  tree low_bound = NULL_TREE, length = NULL_TREE;
--- gcc/cp/semantics.c.jj       2015-06-03 10:21:14.000000000 +0200
+++ gcc/cp/semantics.c  2015-06-10 16:09:56.462993941 +0200
@@ -4276,6 +4276,91 @@ cxx_omp_create_clause_info (tree c, tree
   return errorcount != save_errorcount;
 }
 
+/* If DECL is DECL_OMP_PRIVATIZED_MEMBER, return corresponding
+   FIELD_DECL, otherwise return DECL itself.  */
+
+static tree
+omp_clause_decl_field (tree decl)
+{
+  if (VAR_P (decl)
+      && DECL_HAS_VALUE_EXPR_P (decl)
+      && DECL_ARTIFICIAL (decl)
+      && DECL_LANG_SPECIFIC (decl)
+      && DECL_OMP_PRIVATIZED_MEMBER (decl))
+    {
+      tree f = DECL_VALUE_EXPR (decl);
+      if (TREE_CODE (f) == INDIRECT_REF)
+       f = TREE_OPERAND (f, 0);
+      if (TREE_CODE (f) == COMPONENT_REF)
+       {
+         f = TREE_OPERAND (f, 1);
+         gcc_assert (TREE_CODE (f) == FIELD_DECL);
+         return f;
+       }
+    }
+  return NULL_TREE;
+}
+
+/* Adjust DECL if needed for printing using %qE.  */
+
+static tree
+omp_clause_printable_decl (tree decl)
+{
+  tree t = omp_clause_decl_field (decl);
+  if (t)
+    return t;
+  return decl;
+}
+
+/* For a FIELD_DECL F and corresponding DECL_OMP_PRIVATIZED_MEMBER
+   VAR_DECL T that doesn't need a DECL_EXPR added, record it for
+   privatization.  */
+
+static void
+omp_note_field_privatization (tree f, tree t)
+{
+  if (!omp_private_member_map)
+    omp_private_member_map = new hash_map<tree, tree>;
+  tree &v = omp_private_member_map->get_or_insert (f);
+  if (v == NULL_TREE)
+    {
+      v = t;
+      omp_private_member_vec.safe_push (f);
+      /* Signal that we don't want to create DECL_EXPR for this dummy var.  */
+      omp_private_member_vec.safe_push (integer_zero_node);
+    }
+}
+
+/* Privatize FIELD_DECL T, return corresponding DECL_OMP_PRIVATIZED_MEMBER
+   dummy VAR_DECL.  */
+
+static tree
+omp_privatize_field (tree t)
+{
+  tree m = finish_non_static_data_member (t, NULL_TREE, NULL_TREE);
+  if (m == error_mark_node)
+    return error_mark_node;
+  if (!omp_private_member_map)
+    omp_private_member_map = new hash_map<tree, tree>;
+  if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+    {
+      gcc_assert (TREE_CODE (m) == INDIRECT_REF);
+      m = TREE_OPERAND (m, 0);
+    }
+  tree &v = omp_private_member_map->get_or_insert (t);
+  if (v == NULL_TREE)
+    {
+      v = create_temporary_var (TREE_TYPE (m));
+      if (!DECL_LANG_SPECIFIC (v))
+       retrofit_lang_decl (v);
+      DECL_OMP_PRIVATIZED_MEMBER (v) = 1;
+      SET_DECL_VALUE_EXPR (v, m);
+      DECL_HAS_VALUE_EXPR_P (v) = 1;
+      omp_private_member_vec.safe_push (t);
+    }
+  return v;
+}
+
 /* Helper function for handle_omp_array_sections.  Called recursively
    to handle multiple array-section-subscripts.  C is the clause,
    T current expression (initially OMP_CLAUSE_DECL), which is either
@@ -4290,7 +4375,7 @@ cxx_omp_create_clause_info (tree c, tree
    map(a[:b][2:1][:c][:2][:d][e:f][2:5])
    FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c]
    all are or may have length of 1, array-section-subscript [:2] is the
-   first one knonwn not to have length 1.  For array-section-subscript
+   first one known not to have length 1.  For array-section-subscript
    <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't
    0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we
    can if MAYBE_ZERO_LEN is false.  MAYBE_ZERO_LEN will be true in the above
@@ -4333,6 +4418,9 @@ handle_omp_array_sections_1 (tree c, tre
       return t;
     }
 
+  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+      && TREE_CODE (TREE_CHAIN (t)) == FIELD_DECL)
+    TREE_CHAIN (t) = omp_privatize_field (TREE_CHAIN (t));
   ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
                                     maybe_zero_len, first_non_one);
   if (ret == error_mark_node || ret == NULL_TREE)
@@ -4382,11 +4470,32 @@ handle_omp_array_sections_1 (tree c, tre
   if (length != NULL_TREE)
     {
       if (!integer_nonzerop (length))
-       maybe_zero_len = true;
+       {
+         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+             || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+           {
+             if (integer_zerop (length))
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "zero length array section in %qs clause",
+                           omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+                 return error_mark_node;
+               }
+           }
+         else
+           maybe_zero_len = true;
+       }
       if (first_non_one == types.length ()
          && (TREE_CODE (length) != INTEGER_CST || integer_onep (length)))
        first_non_one++;
     }
+  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+      && !integer_zerop (low_bound))
+    {
+      error_at (OMP_CLAUSE_LOCATION (c),
+               "%<reduction%> array section has to be zero-based");
+      return error_mark_node;
+    }
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
       if (length == NULL_TREE
@@ -4434,7 +4543,17 @@ handle_omp_array_sections_1 (tree c, tre
                  return error_mark_node;
                }
              if (tree_int_cst_equal (size, low_bound))
-               maybe_zero_len = true;
+               {
+                 if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+                     || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+                   {
+                     error_at (OMP_CLAUSE_LOCATION (c),
+                               "zero length array section in %qs clause",
+                               omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+                     return error_mark_node;
+                   }
+                 maybe_zero_len = true;
+               }
              else if (length == NULL_TREE
                       && first_non_one == types.length ()
                       && tree_int_cst_equal
@@ -4444,7 +4563,9 @@ handle_omp_array_sections_1 (tree c, tre
            }
          else if (length == NULL_TREE)
            {
-             maybe_zero_len = true;
+             if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+                 && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION)
+               maybe_zero_len = true;
              if (first_non_one == types.length ())
                first_non_one++;
            }
@@ -4478,7 +4599,9 @@ handle_omp_array_sections_1 (tree c, tre
        }
       else if (length == NULL_TREE)
        {
-         maybe_zero_len = true;
+         if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+             && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION)
+           maybe_zero_len = true;
          if (first_non_one == types.length ())
            first_non_one++;
        }
@@ -4539,7 +4662,7 @@ handle_omp_array_sections (tree c)
 {
   bool maybe_zero_len = false;
   unsigned int first_non_one = 0;
-  auto_vec<tree> types;
+  auto_vec<tree, 10> types;
   tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
                                            maybe_zero_len, first_non_one);
   if (first == error_mark_node)
@@ -4643,7 +4766,9 @@ handle_omp_array_sections (tree c)
            {
              tree l;
 
-             if (i > first_non_one && length && integer_nonzerop (length))
+             if (i > first_non_one
+                 && ((length && integer_nonzerop (length))
+                     || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION))
                continue;
              if (length)
                l = fold_convert (sizetype, length);
@@ -4668,6 +4793,12 @@ handle_omp_array_sections (tree c)
              else if (size == NULL_TREE)
                {
                  size = size_in_bytes (TREE_TYPE (types[i]));
+                 tree eltype = TREE_TYPE (types[num - 1]);
+                 while (TREE_CODE (eltype) == ARRAY_TYPE)
+                   eltype = TREE_TYPE (eltype);
+                 if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+                   size = size_binop (EXACT_DIV_EXPR, size,
+                                      size_in_bytes (eltype));
                  size = size_binop (MULT_EXPR, size, l);
                  if (condition)
                    size = fold_build3 (COND_EXPR, sizetype, condition,
@@ -4681,6 +4812,24 @@ handle_omp_array_sections (tree c)
        {
          if (side_effects)
            size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
+         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+           {
+             size = size_binop (MINUS_EXPR, size, size_one_node);
+             tree index_type = build_index_type (size);
+             tree eltype = TREE_TYPE (first);
+             while (TREE_CODE (eltype) == ARRAY_TYPE)
+               eltype = TREE_TYPE (eltype);
+             tree type = build_array_type (eltype, index_type);
+             tree ptype = build_pointer_type (eltype);
+             if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
+                 && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (t))))
+               t = convert_from_reference (t);
+             else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+               t = build_fold_addr_expr (t);
+             t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0));
+             OMP_CLAUSE_DECL (c) = t;
+             return false;
+           }
          OMP_CLAUSE_DECL (c) = first;
          OMP_CLAUSE_SIZE (c) = size;
          if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
@@ -5107,30 +5256,6 @@ find_omp_placeholder_r (tree *tp, int *,
   return NULL_TREE;
 }
 
-/* Adjust DECL if needed for printing using %qE.  */
-
-static tree
-omp_clause_printable_decl (tree decl)
-{
-  if (VAR_P (decl)
-      && DECL_HAS_VALUE_EXPR_P (decl)
-      && DECL_ARTIFICIAL (decl)
-      && DECL_LANG_SPECIFIC (decl)
-      && DECL_OMP_PRIVATIZED_MEMBER (decl))
-    {
-      tree f = DECL_VALUE_EXPR (decl);
-      if (TREE_CODE (f) == INDIRECT_REF)
-       f = TREE_OPERAND (f, 0);
-      if (TREE_CODE (f) == COMPONENT_REF)
-       {
-         f = TREE_OPERAND (f, 1);
-         gcc_assert (TREE_CODE (f) == FIELD_DECL);
-         return f;
-       }
-    }
-  return decl;
-}
-
 /* Helper function of finish_omp_clauses.  Handle OMP_CLAUSE_REDUCTION C.
    Return true if there is some error and the clause should be removed.  */
 
@@ -5139,9 +5264,45 @@ finish_omp_reduction_clause (tree c, boo
 {
   tree t = OMP_CLAUSE_DECL (c);
   bool predefined = false;
+  if (TREE_CODE (t) == TREE_LIST)
+    {
+      gcc_assert (processing_template_decl);
+      return false;
+    }
   tree type = TREE_TYPE (t);
+  if (TREE_CODE (t) == MEM_REF)
+    type = TREE_TYPE (type);
   if (TREE_CODE (type) == REFERENCE_TYPE)
     type = TREE_TYPE (type);
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree oatype = type;
+      gcc_assert (TREE_CODE (t) != MEM_REF);
+      while (TREE_CODE (type) == ARRAY_TYPE)
+       type = TREE_TYPE (type);
+      if (!processing_template_decl)
+       {
+         t = require_complete_type (t);
+         if (t == error_mark_node)
+           return true;
+         tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype),
+                                 TYPE_SIZE_UNIT (type));
+         if (integer_zerop (size))
+           {
+             error ("%qE in %<reduction%> clause is a zero size array",
+                    omp_clause_printable_decl (t));
+             return true;
+           }
+         size = size_binop (MINUS_EXPR, size, size_one_node);
+         tree index_type = build_index_type (size);
+         tree atype = build_array_type (type, index_type);
+         tree ptype = build_pointer_type (type);
+         if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+           t = build_fold_addr_expr (t);
+         t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0));
+         OMP_CLAUSE_DECL (c) = t;
+       }
+    }
   if (type == error_mark_node)
     return true;
   else if (ARITHMETIC_TYPE_P (type))
@@ -5174,9 +5335,9 @@ finish_omp_reduction_clause (tree c, boo
       default:
        break;
       }
-  else if (TREE_CODE (type) == ARRAY_TYPE || TYPE_READONLY (type))
+  else if (TYPE_READONLY (type))
     {
-      error ("%qE has invalid type for %<reduction%>",
+      error ("%qE has const type for %<reduction%>",
             omp_clause_printable_decl (t));
       return true;
     }
@@ -5198,9 +5359,7 @@ finish_omp_reduction_clause (tree c, boo
 
   tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
 
-  type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  type = TYPE_MAIN_VARIANT (type);
   OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
   if (id == NULL_TREE)
     id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c),
@@ -5218,7 +5377,7 @@ finish_omp_reduction_clause (tree c, boo
       if (TREE_CODE (body) == STATEMENT_LIST)
        {
          tree_stmt_iterator tsi;
-         tree placeholder = NULL_TREE;
+         tree placeholder = NULL_TREE, decl_placeholder = NULL_TREE;
          int i;
          tree stmts[7];
          tree atype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id)));
@@ -5239,14 +5398,24 @@ finish_omp_reduction_clause (tree c, boo
              DECL_ARTIFICIAL (placeholder) = 1;
              DECL_IGNORED_P (placeholder) = 1;
              OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
+             if (TREE_CODE (t) == MEM_REF)
+               {
+                 decl_placeholder = build_lang_decl (VAR_DECL, NULL_TREE,
+                                                     type);
+                 DECL_ARTIFICIAL (decl_placeholder) = 1;
+                 DECL_IGNORED_P (decl_placeholder) = 1;
+                 OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder;
+               }
              if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0])))
                cxx_mark_addressable (placeholder);
              if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1]))
                  && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
                     != REFERENCE_TYPE)
-               cxx_mark_addressable (OMP_CLAUSE_DECL (c));
+               cxx_mark_addressable (decl_placeholder ? decl_placeholder
+                                     : OMP_CLAUSE_DECL (c));
              tree omp_out = placeholder;
-             tree omp_in = convert_from_reference (OMP_CLAUSE_DECL (c));
+             tree omp_in = decl_placeholder ? decl_placeholder
+                           : convert_from_reference (OMP_CLAUSE_DECL (c));
              if (need_static_cast)
                {
                  tree rtype = build_reference_type (atype);
@@ -5268,10 +5437,12 @@ finish_omp_reduction_clause (tree c, boo
              gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR
                          && TREE_CODE (stmts[4]) == DECL_EXPR);
              if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3])))
-               cxx_mark_addressable (OMP_CLAUSE_DECL (c));
+               cxx_mark_addressable (decl_placeholder ? decl_placeholder
+                                     : OMP_CLAUSE_DECL (c));
              if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4])))
                cxx_mark_addressable (placeholder);
-             tree omp_priv = convert_from_reference (OMP_CLAUSE_DECL (c));
+             tree omp_priv = decl_placeholder ? decl_placeholder
+                             : convert_from_reference (OMP_CLAUSE_DECL (c));
              tree omp_orig = placeholder;
              if (need_static_cast)
                {
@@ -5310,7 +5481,8 @@ finish_omp_reduction_clause (tree c, boo
              else
                {
                  tree init;
-                 tree v = convert_from_reference (t);
+                 tree v = decl_placeholder ? decl_placeholder
+                          : convert_from_reference (t);
                  if (AGGREGATE_TYPE_P (TREE_TYPE (v)))
                    init = build_constructor (TREE_TYPE (v), NULL);
                  else
@@ -5329,6 +5501,9 @@ finish_omp_reduction_clause (tree c, boo
             omp_clause_printable_decl (t));
       return true;
     }
+  if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF)
+    gcc_assert (TYPE_SIZE_UNIT (type)
+               && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST);
   return false;
 }
 
@@ -5365,6 +5540,32 @@ finish_omp_clauses (tree clauses, bool a
          goto check_dup_generic;
        case OMP_CLAUSE_REDUCTION:
          field_ok = allow_fields;
+         t = OMP_CLAUSE_DECL (c);
+         if (TREE_CODE (t) == TREE_LIST)
+           {
+             if (handle_omp_array_sections (c))
+               {
+                 remove = true;
+                 break;
+               }
+             if (TREE_CODE (t) == TREE_LIST)
+               {
+                 while (TREE_CODE (t) == TREE_LIST)
+                   t = TREE_CHAIN (t);
+               }
+             else
+               {
+                 gcc_assert (TREE_CODE (t) == MEM_REF);
+                 t = TREE_OPERAND (t, 0);
+                 if (TREE_CODE (t) == ADDR_EXPR
+                     || TREE_CODE (t) == INDIRECT_REF)
+                   t = TREE_OPERAND (t, 0);
+               }
+             tree n = omp_clause_decl_field (t);
+             if (n)
+               t = n;
+             goto check_dup_generic_t;
+           }
          goto check_dup_generic;
        case OMP_CLAUSE_COPYPRIVATE:
          copyprivate_seen = true;
@@ -5435,7 +5636,15 @@ finish_omp_clauses (tree clauses, bool a
            }
          goto check_dup_generic;
        check_dup_generic:
-         t = OMP_CLAUSE_DECL (c);
+         t = omp_clause_decl_field (OMP_CLAUSE_DECL (c));
+         if (t)
+           {
+             if (!remove)
+               omp_note_field_privatization (t, OMP_CLAUSE_DECL (c));
+           }
+         else
+           t = OMP_CLAUSE_DECL (c);
+       check_dup_generic_t:
          if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
              && (!field_ok || TREE_CODE (t) != FIELD_DECL))
            {
@@ -5461,65 +5670,22 @@ finish_omp_clauses (tree clauses, bool a
          if (!field_ok)
            break;
        handle_field_decl:
-         if (!remove && TREE_CODE (t) == FIELD_DECL)
-           {
-             tree m = finish_non_static_data_member (t, NULL_TREE, NULL_TREE);
-             if (m == error_mark_node)
-               {
-                 remove = true;
-                 break;
-               }
-             if (!omp_private_member_map)
-               omp_private_member_map = new hash_map<tree, tree>;
-             if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
-               {
-                 gcc_assert (TREE_CODE (m) == INDIRECT_REF);
-                 m = TREE_OPERAND (m, 0);
-               }
-             tree &v = omp_private_member_map->get_or_insert (t);
-             if (v == NULL_TREE)
-               {
-                 v = create_temporary_var (TREE_TYPE (m));
-                 if (!DECL_LANG_SPECIFIC (v))
-                   retrofit_lang_decl (v);
-                 DECL_OMP_PRIVATIZED_MEMBER (v) = 1;
-                 SET_DECL_VALUE_EXPR (v, m);
-                 DECL_HAS_VALUE_EXPR_P (v) = 1;
-                 omp_private_member_vec.safe_push (t);
-               }
-             OMP_CLAUSE_DECL (c) = v;
-           }
-         else if (!remove
-                  && VAR_P (t)
-                  && DECL_HAS_VALUE_EXPR_P (t)
-                  && DECL_ARTIFICIAL (t)
-                  && DECL_LANG_SPECIFIC (t)
-                  && DECL_OMP_PRIVATIZED_MEMBER (t))
-           {
-             tree f = DECL_VALUE_EXPR (t);
-             if (TREE_CODE (f) == INDIRECT_REF)
-               f = TREE_OPERAND (f, 0);
-             if (TREE_CODE (f) == COMPONENT_REF)
-               {
-                 f = TREE_OPERAND (f, 1);
-                 gcc_assert (TREE_CODE (f) == FIELD_DECL);
-                 if (!omp_private_member_map)
-                   omp_private_member_map = new hash_map<tree, tree>;
-                 tree &v = omp_private_member_map->get_or_insert (f);
-                 if (v == NULL_TREE)
-                   {
-                     v = t;
-                     omp_private_member_vec.safe_push (f);
-                     /* Signal that we don't want to create
-                        DECL_EXPR for this dummy var.  */
-                     omp_private_member_vec.safe_push (integer_zero_node);
-                   }
-               }
+         if (!remove
+             && TREE_CODE (t) == FIELD_DECL
+             && t == OMP_CLAUSE_DECL (c))
+           {
+             OMP_CLAUSE_DECL (c) = omp_privatize_field (t);
+             if (OMP_CLAUSE_DECL (c) == error_mark_node)
+               remove = true;
            }
          break;
 
        case OMP_CLAUSE_FIRSTPRIVATE:
-         t = OMP_CLAUSE_DECL (c);
+         t = omp_clause_decl_field (OMP_CLAUSE_DECL (c));
+         if (t)
+           omp_note_field_privatization (t, OMP_CLAUSE_DECL (c));
+         else
+           t = OMP_CLAUSE_DECL (c);
          if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
              && (!allow_fields || TREE_CODE (t) != FIELD_DECL))
            {
@@ -5542,7 +5708,11 @@ finish_omp_clauses (tree clauses, bool a
          goto handle_field_decl;
 
        case OMP_CLAUSE_LASTPRIVATE:
-         t = OMP_CLAUSE_DECL (c);
+         t = omp_clause_decl_field (OMP_CLAUSE_DECL (c));
+         if (t)
+           omp_note_field_privatization (t, OMP_CLAUSE_DECL (c));
+         else
+           t = OMP_CLAUSE_DECL (c);
          if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
              && (!allow_fields || TREE_CODE (t) != FIELD_DECL))
            {
--- gcc/c-family/c-omp.c.jj     2015-05-21 11:12:09.000000000 +0200
+++ gcc/c-family/c-omp.c        2015-06-08 10:50:52.570868184 +0200
@@ -964,6 +964,8 @@ c_omp_split_clauses (location_t loc, enu
                = OMP_CLAUSE_REDUCTION_CODE (clauses);
              OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
                = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses);
+             OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c)
+               = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clauses);
              OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
              cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c;
            }
@@ -979,6 +981,8 @@ c_omp_split_clauses (location_t loc, enu
                    = OMP_CLAUSE_REDUCTION_CODE (clauses);
                  OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
                    = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses);
+                 OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c)
+                   = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clauses);
                  OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
                  cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c;
                  s = C_OMP_CLAUSE_SPLIT_TEAMS;
--- gcc/testsuite/gcc.dg/gomp/clause-1.c.jj     2015-04-24 12:31:52.000000000 
+0200
+++ gcc/testsuite/gcc.dg/gomp/clause-1.c        2015-06-09 20:00:25.872225946 
+0200
@@ -46,7 +46,7 @@ foo (int x)
     ;
 #pragma omp p reduction (*:s) /* { dg-error "user defined reduction not found 
for" } */
     ;
-#pragma omp p reduction (-:a) /* { dg-error "user defined reduction not found 
for" } */
+#pragma omp p reduction (-:a)
     ;
   d = 0;
 #pragma omp p reduction (*:d)
--- gcc/testsuite/gcc.dg/gomp/reduction-1.c.jj  2015-06-10 15:05:19.742023709 
+0200
+++ gcc/testsuite/gcc.dg/gomp/reduction-1.c     2015-06-10 15:31:46.031471679 
+0200
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+struct S {};
+void foo (void *, void *);
+void bar (void *, void *);
+void baz (void *);
+#pragma omp declare reduction(+:struct S:foo (&omp_out, 
&omp_in))initializer(bar(&omp_priv, &omp_orig))
+
+void
+test (void)
+{
+  struct S b[10];
+  #pragma omp parallel reduction(+:b[0:5])     /* { dg-error "zero length 
array section" } */
+    baz (b);
+  #pragma omp parallel reduction(+:b[:10])     /* { dg-error "zero length 
array section" } */
+    baz (b);
+  #pragma omp parallel reduction(+:b)          /* { dg-error "is a zero size 
array" } */
+    baz (b);
+}
--- gcc/testsuite/g++.dg/gomp/clause-3.C.jj     2015-04-24 12:31:59.000000000 
+0200
+++ gcc/testsuite/g++.dg/gomp/clause-3.C        2015-06-09 20:01:12.858491167 
+0200
@@ -46,7 +46,7 @@ foo (int x)
     ;
 #pragma omp p reduction (*:s) // { dg-error "user defined reduction not found 
for" }
     ;
-#pragma omp p reduction (-:a) // { dg-error "has invalid type for" }
+#pragma omp p reduction (-:a)
     ;
   d = 0;
 #pragma omp p reduction (*:d)
--- gcc/testsuite/c-c++-common/gomp/depend-3.c.jj       2015-06-10 
12:46:57.135106894 +0200
+++ gcc/testsuite/c-c++-common/gomp/depend-3.c  2015-06-10 13:05:02.336153398 
+0200
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void bar (int a[10][10][10]);
+void
+foo (int a[10][10][10], int **b, int x)
+{
+  int c[10][10][10];
+  #pragma omp task depend(out: a[2:4][3:0][:7])        /* { dg-error "zero 
length array section" } */
+    bar (a);
+  #pragma omp task depend(inout: b[:7][0:0][:0]) /* { dg-error "zero length 
array section" } */
+    bar (a);
+  #pragma omp task depend(in: c[:][:][10:])    /* { dg-error "zero length 
array section" } */
+    bar (c);
+  #pragma omp task depend(out: a[2:4][3:0][:x])        /* { dg-error "zero 
length array section" } */
+    bar (a);
+  #pragma omp task depend(inout: b[:x][0:0][:0]) /* { dg-error "zero length 
array section" } */
+    bar (a);
+  #pragma omp task depend(in: c[:][x-2:x][10:])        /* { dg-error "zero 
length array section" } */
+    bar (c);
+}
--- gcc/testsuite/c-c++-common/gomp/reduction-1.c.jj    2015-06-10 
13:02:51.489198677 +0200
+++ gcc/testsuite/c-c++-common/gomp/reduction-1.c       2015-06-10 
16:13:32.521650276 +0200
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void bar (int a[10][10][10]);
+extern int f[][2];                                     /* { dg-error "has 
incomplete type" "" { target c++ } } */
+extern int g[];                                                /* { dg-error 
"has incomplete type" "" { target c++ } } */
+void
+foo (int a[10][10][10], int **b, int x)
+{
+  int c[10][10][0];
+  int d[0];
+  char e[12];
+  #pragma omp parallel reduction(+: a[:4][:0][:7])     /* { dg-error "zero 
length array section" } */
+    bar (a);
+  #pragma omp parallel reduction(+: b[:7][0:0][:0])    /* { dg-error "zero 
length array section" } */
+    bar (a);
+  #pragma omp parallel reduction(+: c[:][:][0:])       /* { dg-error "zero 
length array section|for unknown bound array type length expression must be 
specified" } */
+    bar (a);
+  #pragma omp parallel reduction(+: a[:4][:0][:x])     /* { dg-error "zero 
length array section" } */
+    bar (a);
+  #pragma omp parallel reduction(+: b[:x][0:0][:0])    /* { dg-error "zero 
length array section" } */
+    bar (a);
+  #pragma omp parallel reduction(+: c[:][:x][0:])      /* { dg-error "zero 
length array section|for unknown bound array type length expression must be 
specified" } */
+    bar (a);
+  #pragma omp parallel reduction(+: d)                 /* { dg-error "is a 
zero size array" } */
+    bar (a);
+  #pragma omp parallel reduction(+: a[0:4])
+    bar (a);
+  #pragma omp parallel reduction(+: a[2:4])            /* { dg-error "array 
section has to be zero-based" } */
+    bar (a);
+  #pragma omp parallel reduction(+: e[2:4])            /* { dg-error "array 
section has to be zero-based" } */
+    bar (a);
+  #pragma omp parallel reduction(+: a[0.5:2])          /* { dg-error "low 
bound \[^\n\r]* of array section does not have integral type" } */
+    bar (a);
+  #pragma omp parallel reduction(+: a[0:2.5])          /* { dg-error "length 
\[^\n\r]* of array section does not have integral type" } */
+    bar (a);
+  #pragma omp parallel reduction(+: f[:][0:2])         /* { dg-error "for 
unknown bound array type length expression must be specified" } */
+    bar (a);
+  #pragma omp parallel reduction(+: a[:][0:10])                /* { dg-error 
"for pointer type length expression must be specified" } */
+    bar (a);
+  #pragma omp parallel reduction(+: a[:10][0:12])      /* { dg-error "above 
array section size" } */
+    bar (a);
+  #pragma omp parallel reduction(+: b[0:10][0:10])     /* { dg-error "array 
section is not contiguous" } */
+    bar (a);
+  #pragma omp parallel reduction(+: a[0:2][0:9])       /* { dg-error "array 
section is not contiguous" } */
+    bar (a);
+  #pragma omp parallel reduction(+: f)                 /* { dg-error "has an 
incomplete type|invalid use of array with unspecified bounds" } */
+    bar (a);
+  #pragma omp parallel reduction(+: g)                 /* { dg-error "has an 
incomplete type|invalid use of array with unspecified bounds" } */
+    bar (a);
+}
--- gcc/testsuite/c-c++-common/gomp/udr-1.c.jj  2015-06-10 15:04:03.806195170 
+0200
+++ gcc/testsuite/c-c++-common/gomp/udr-1.c     2015-06-10 15:04:22.893900704 
+0200
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+struct S {};
+void foo (void *, void *);
+void bar (void *, void *);
+void baz (void *);
+#pragma omp declare reduction(+:struct S:foo (&omp_out, 
&omp_in))initializer(bar(&omp_priv, &omp_orig))
+
+void
+test (void)
+{
+  struct S a, b[10];
+  #pragma omp parallel reduction(+:a)
+    baz (&a);
+}
--- libgomp/testsuite/libgomp.c/reduction-10.c.jj       2015-06-10 
16:28:26.025821993 +0200
+++ libgomp/testsuite/libgomp.c/reduction-10.c  2015-06-10 16:24:19.000000000 
+0200
@@ -0,0 +1,105 @@
+struct A { int t; };
+struct B { char t; };
+struct C { unsigned long long t; };
+struct D { long t; };
+void
+add (struct B *x, struct B *y)
+{
+  x->t += y->t;
+}
+void
+zero (struct B *x)
+{
+  x->t = 0;
+}
+void
+orit (struct C *x, struct C *y)
+{
+  y->t |= x->t;
+}
+#pragma omp declare reduction(+:struct A:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:struct B:add (&omp_out, &omp_in)) 
initializer(zero (&omp_priv))
+#pragma omp declare reduction(*:struct A:omp_out.t *= omp_in.t) 
initializer(omp_priv = { 1 })
+#pragma omp declare reduction(|:struct C:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:struct D:omp_out.t = omp_out.t & omp_in.t) 
initializer(omp_priv = { ~0L })
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : 
omp_out) initializer(omp_priv = -6)
+
+struct B z[10];
+
+__attribute__((noinline, noclone)) void
+foo (struct A (*x)[3][2], struct A *y, struct D w[1][2], int p1, long p2, long 
p3, int p4,
+     int p5, long p6, short p7)
+{
+  struct C a[p7 + 4];
+  short b[p7];
+  int i;
+  for (i = 0; i < p7 + 4; i++)
+    {
+      if (i < p7)
+       b[i] = -6;
+      a[i].t = 0;
+    }
+  #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+                          reduction(*:y[:p4]) reduction(|:a[:p5]) \
+                          reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b)
+  for (i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1].t += i;
+      if ((i & 15) == 1)
+       y[0].t *= 3;
+      if ((i & 31) == 2)
+       y[1].t *= 7;
+      if ((i & 63) == 3)
+       y[2].t *= 17;
+      z[i / 32].t += (i & 3);
+      if (i < 4)
+       z[i].t += i;
+      a[i / 32].t |= 1ULL << (i & 30);
+      w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (i = 0; i < 9; i++)
+    if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  struct A a[4][3][2] = {};
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  struct A y[5] = { { 0 }, { 1 }, { 1 }, { 1 }, { 0 } };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  struct D w[1][2] = { { { ~0L }, { ~0L } } };
+  foo (&a[1], y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+  int i, j, k;
+  for (i = 0; i < 4; i++)
+    for (j = 0; j < 3; j++)
+      for (k = 0; k < 2; k++)
+       if (a[i][j][k].t != a2[i][j][k])
+         __builtin_abort ();
+  for (i = 0; i < 5; i++)
+    if (y[i].t != y2[i])
+      __builtin_abort ();
+  for (i = 0; i < 10; i++)
+    if (z[i].t != z2[i])
+      __builtin_abort ();
+  if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+    __builtin_abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/reduction-7.c.jj        2015-06-08 
19:29:10.488133293 +0200
+++ libgomp/testsuite/libgomp.c/reduction-7.c   2015-06-08 19:08:59.000000000 
+0200
@@ -0,0 +1,64 @@
+char z[10] = { 0 };
+
+__attribute__((noinline, noclone)) void
+foo (int (*x)[3][2], int *y, long w[1][2])
+{
+  unsigned long long a[9] = {};
+  short b[5] = {};
+  int i;
+  #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+                          reduction(*:y[:3]) reduction(|:a[:4]) \
+                          reduction(&:w[0:1][:2]) reduction(max:b)
+  for (i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1] += i;
+      if ((i & 15) == 1)
+       y[0] *= 3;
+      if ((i & 31) == 2)
+       y[1] *= 7;
+      if ((i & 63) == 3)
+       y[2] *= 17;
+      z[i / 32] += (i & 3);
+      if (i < 4)
+       z[i] += i;
+      a[i / 32] |= 1ULL << (i & 30);
+      w[0][i & 1] &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (i = 0; i < 9; i++)
+    if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int a[4][3][2] = {};
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  int y[5] = { 0, 1, 1, 1, 0 };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  long w[1][2] = { ~0L, ~0L };
+  foo (&a[1], y + 1, w);
+  if (__builtin_memcmp (a, a2, sizeof (a))
+      || __builtin_memcmp (y, y2, sizeof (y))
+      || __builtin_memcmp (z, z2, sizeof (z))
+      || w[0][0] != ~0x249249L
+      || w[0][1] != ~0x249249L)
+    __builtin_abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/reduction-8.c.jj        2015-06-08 
20:20:39.379830477 +0200
+++ libgomp/testsuite/libgomp.c/reduction-8.c   2015-06-09 09:02:35.000000000 
+0200
@@ -0,0 +1,98 @@
+struct A { int t; };
+struct B { char t; };
+struct C { unsigned long long t; };
+struct D { long t; };
+void
+add (struct B *x, struct B *y)
+{
+  x->t += y->t;
+}
+void
+zero (struct B *x)
+{
+  x->t = 0;
+}
+void
+orit (struct C *x, struct C *y)
+{
+  y->t |= x->t;
+}
+#pragma omp declare reduction(+:struct A:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:struct B:add (&omp_out, &omp_in)) 
initializer(zero (&omp_priv))
+#pragma omp declare reduction(*:struct A:omp_out.t *= omp_in.t) 
initializer(omp_priv = { 1 })
+#pragma omp declare reduction(|:struct C:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:struct D:omp_out.t = omp_out.t & omp_in.t) 
initializer(omp_priv = { ~0L })
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : 
omp_out) initializer(omp_priv = -6)
+
+struct B z[10];
+
+__attribute__((noinline, noclone)) void
+foo (struct A (*x)[3][2], struct A *y, struct D w[1][2])
+{
+  struct C a[9] = {};
+  short b[5] = {};
+  int i;
+  #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+                          reduction(*:y[:3]) reduction(|:a[:4]) \
+                          reduction(&:w[0:1][:2]) reduction(maxb:b)
+  for (i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1].t += i;
+      if ((i & 15) == 1)
+       y[0].t *= 3;
+      if ((i & 31) == 2)
+       y[1].t *= 7;
+      if ((i & 63) == 3)
+       y[2].t *= 17;
+      z[i / 32].t += (i & 3);
+      if (i < 4)
+       z[i].t += i;
+      a[i / 32].t |= 1ULL << (i & 30);
+      w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (i = 0; i < 9; i++)
+    if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  struct A a[4][3][2] = {};
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  struct A y[5] = { { 0 }, { 1 }, { 1 }, { 1 }, { 0 } };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  struct D w[1][2] = { { { ~0L }, { ~0L } } };
+  foo (&a[1], y + 1, w);
+  int i, j, k;
+  for (i = 0; i < 4; i++)
+    for (j = 0; j < 3; j++)
+      for (k = 0; k < 2; k++)
+       if (a[i][j][k].t != a2[i][j][k])
+         __builtin_abort ();
+  for (i = 0; i < 5; i++)
+    if (y[i].t != y2[i])
+      __builtin_abort ();
+  for (i = 0; i < 10; i++)
+    if (z[i].t != z2[i])
+      __builtin_abort ();
+  if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+    __builtin_abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/reduction-9.c.jj        2015-06-09 
19:58:53.161675767 +0200
+++ libgomp/testsuite/libgomp.c/reduction-9.c   2015-06-09 16:52:21.000000000 
+0200
@@ -0,0 +1,71 @@
+char z[10] = { 0 };
+
+__attribute__((noinline, noclone)) void
+foo (int (*x)[3][2], int *y, long w[1][2], int p1, long p2, long p3, int p4,
+     int p5, long p6, short p7)
+{
+  unsigned long long a[p7 + 4];
+  short b[p7];
+  int i;
+  for (i = 0; i < p7 + 4; i++)
+    {
+      if (i < p7)
+       b[i] = -6;
+      a[i] = 0;
+    }
+  #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+                          reduction(*:y[:p4]) reduction(|:a[:p5]) \
+                          reduction(&:w[0:p6 - 1][:p6]) reduction(max:b)
+  for (i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1] += i;
+      if ((i & 15) == 1)
+       y[0] *= 3;
+      if ((i & 31) == 2)
+       y[1] *= 7;
+      if ((i & 63) == 3)
+       y[2] *= 17;
+      z[i / 32] += (i & 3);
+      if (i < 4)
+       z[i] += i;
+      a[i / 32] |= 1ULL << (i & 30);
+      w[0][i & 1] &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (i = 0; i < 9; i++)
+    if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int a[4][3][2] = {};
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  int y[5] = { 0, 1, 1, 1, 0 };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  long w[1][2] = { ~0L, ~0L };
+  foo (&a[1], y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+  if (__builtin_memcmp (a, a2, sizeof (a))
+      || __builtin_memcmp (y, y2, sizeof (y))
+      || __builtin_memcmp (z, z2, sizeof (z))
+      || w[0][0] != ~0x249249L
+      || w[0][1] != ~0x249249L)
+    __builtin_abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/taskloop-5.C.jj       2015-06-02 
11:32:01.000000000 +0200
+++ libgomp/testsuite/libgomp.c++/taskloop-5.C  2015-06-08 17:18:27.833303433 
+0200
@@ -4,6 +4,7 @@ __attribute__((noinline, noclone)) void
 foo (int &b)
 {
 #pragma omp parallel
+#pragma omp single
   {
     bool f = false;
   #pragma omp taskloop firstprivate (b, f)
@@ -23,6 +24,7 @@ foo (int &b)
   }
   int n;
 #pragma omp parallel
+#pragma omp single
   {
     bool f = false;
   #pragma omp taskloop firstprivate (f) lastprivate (b, n)
@@ -40,6 +42,7 @@ foo (int &b)
     __builtin_abort ();
   b = 9;
 #pragma omp parallel
+#pragma omp single
   {
     bool f = false;
   #pragma omp taskloop firstprivate (b, f) lastprivate (b, n)
--- libgomp/testsuite/libgomp.c++/reduction-5.C.jj      2015-06-05 
21:30:00.958847239 +0200
+++ libgomp/testsuite/libgomp.c++/reduction-5.C 2015-06-08 17:50:15.000000000 
+0200
@@ -0,0 +1,127 @@
+char z[10] = { 0 };
+
+__attribute__((noinline, noclone)) void
+foo (int (*&x)[3][2], int *y, long (&w)[1][2])
+{
+  unsigned long long a[9] = {};
+  short b[5] = {};
+  #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+                          reduction(*:y[:3]) reduction(|:a[:4]) \
+                          reduction(&:w[0:][:2]) reduction(max:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1] += i;
+      if ((i & 15) == 1)
+       y[0] *= 3;
+      if ((i & 31) == 2)
+       y[1] *= 7;
+      if ((i & 63) == 3)
+       y[2] *= 17;
+      z[i / 32] += (i & 3);
+      if (i < 4)
+       z[i] += i;
+      a[i / 32] |= 1ULL << (i & 30);
+      w[0][i & 1] &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (int i = 0; i < 9; i++)
+    if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+    __builtin_abort ();
+}
+
+int a3[4][3][2];
+int (*p3)[3][2] = &a3[1];
+int y3[5] = { 0, 1, 1, 1, 0 };
+long w3[1][2] = { ~0L, ~0L };
+short bb[5];
+
+struct S
+{
+  int (*&x)[3][2];
+  int *y;
+  long (&w)[1][2];
+  char z[10];
+  short (&b)[5];
+  unsigned long long a[9];
+  S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {}
+  __attribute__((noinline, noclone)) void foo ();
+};
+
+void
+S::foo ()
+{
+  #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+                          reduction(*:y[:3]) reduction(|:a[:4]) \
+                          reduction(&:w[0:][:2]) reduction(max:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1] += i;
+      if ((i & 15) == 1)
+       y[0] *= 3;
+      if ((i & 31) == 2)
+       y[1] *= 7;
+      if ((i & 63) == 3)
+       y[2] *= 17;
+      z[i / 32] += (i & 3);
+      if (i < 4)
+       z[i] += i;
+      a[i / 32] |= 1ULL << (i & 30);
+      w[0][i & 1] &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+}
+
+int
+main ()
+{
+  int a[4][3][2] = {};
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  int (*p)[3][2] = &a[1];
+  int y[5] = { 0, 1, 1, 1, 0 };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  long w[1][2] = { ~0L, ~0L };
+  foo (p, y + 1, w);
+  if (__builtin_memcmp (a, a2, sizeof (a))
+      || __builtin_memcmp (y, y2, sizeof (y))
+      || __builtin_memcmp (z, z2, sizeof (z))
+      || w[0][0] != ~0x249249L
+      || w[0][1] != ~0x249249L)
+    __builtin_abort ();
+  S s;
+  s.foo ();
+  for (int i = 0; i < 9; i++)
+    if (s.a[i] != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (__builtin_memcmp (a3, a2, sizeof (a3))
+      || __builtin_memcmp (y3, y2, sizeof (y3))
+      || __builtin_memcmp (s.z, z2, sizeof (s.z))
+      || w3[0][0] != ~0x249249L
+      || w3[0][1] != ~0x249249L)
+    __builtin_abort ();
+  if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+    __builtin_abort ();
+}
--- libgomp/testsuite/libgomp.c++/reduction-6.C.jj      2015-06-08 
16:07:14.557996117 +0200
+++ libgomp/testsuite/libgomp.c++/reduction-6.C 2015-06-10 18:15:23.000000000 
+0200
@@ -0,0 +1,195 @@
+template <typename T>
+struct A
+{
+  A () { t = 0; }
+  A (T x) { t = x; }
+  A (const A &x) { t = x.t; }
+  ~A () {}
+  T t;
+};
+template <typename T>
+struct M
+{
+  M () { t = 1; }
+  M (T x) { t = x; }
+  M (const M &x) { t = x.t; }
+  ~M () {}
+  T t;
+};
+template <typename T>
+struct B
+{
+  B () { t = ~(T) 0; }
+  B (T x) { t = x; }
+  B (const B &x) { t = x.t; }
+  ~B () {}
+  T t;
+};
+template <typename T>
+void
+add (T &x, T &y)
+{
+  x.t += y.t;
+}
+template <typename T>
+void
+zero (T &x)
+{
+  x.t = 0;
+}
+template <typename T>
+void
+orit (T *x, T *y)
+{
+  y->t |= x->t;
+}
+B<long> bb;
+#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) 
initializer(zero (omp_priv))
+#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) 
initializer(omp_priv = 1)
+#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) 
initializer(orit (&omp_priv, &omp_orig))
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : 
omp_out) initializer(omp_priv = -6)
+
+A<char> z[10];
+
+__attribute__((noinline, noclone)) void
+foo (A<int> (*&x)[3][2], M<int> *y, B<long> (&w)[1][2])
+{
+  A<unsigned long long> a[9];
+  short bb[5] = {};
+  short (&b)[5] = bb;
+  #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+                          reduction(*:y[:3]) reduction(|:a[:4]) \
+                          reduction(&:w[0:][:2]) reduction(maxb:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1].t += i;
+      if ((i & 15) == 1)
+       y[0].t *= 3;
+      if ((i & 31) == 2)
+       y[1].t *= 7;
+      if ((i & 63) == 3)
+       y[2].t *= 17;
+      z[i / 32].t += (i & 3);
+      if (i < 4)
+       z[i].t += i;
+      a[i / 32].t |= 1ULL << (i & 30);
+      w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (int i = 0; i < 9; i++)
+    if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+    __builtin_abort ();
+}
+
+A<int> a3[4][3][2];
+A<int> (*p3)[3][2] = &a3[1];
+M<int> y3[5] = { 0, 1, 1, 1, 0 };
+B<long> w3[1][2];
+
+struct S
+{
+  A<int> (*&x)[3][2];
+  M<int> *y;
+  B<long> (&w)[1][2];
+  A<char> z[10];
+  short b[5];
+  A<unsigned long long> a[9];
+  S() : x(p3), y(y3+1), w(w3), z(), a(), b() {}
+  __attribute__((noinline, noclone)) void foo ();
+};
+
+void
+S::foo ()
+{
+  #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \
+                          reduction(*:y[:3]) reduction(|:a[:4]) \
+                          reduction(&:w[0:][:2]) reduction(maxb:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1].t += i;
+      if ((i & 15) == 1)
+       y[0].t *= 3;
+      if ((i & 31) == 2)
+       y[1].t *= 7;
+      if ((i & 63) == 3)
+       y[2].t *= 17;
+      z[i / 32].t += (i & 3);
+      if (i < 4)
+       z[i].t += i;
+      a[i / 32].t |= 1ULL << (i & 30);
+      w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+}
+
+int
+main ()
+{
+  A<int> a[4][3][2];
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  A<int> (*p)[3][2] = &a[1];
+  M<int> y[5] = { 0, 1, 1, 1, 0 };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  B<long> w[1][2];
+  foo (p, y + 1, w);
+  for (int i = 0; i < 4; i++)
+    for (int j = 0; j < 3; j++)
+      for (int k = 0; k < 2; k++)
+       if (a[i][j][k].t != a2[i][j][k])
+         __builtin_abort ();
+  for (int i = 0; i < 5; i++)
+    if (y[i].t != y2[i])
+      __builtin_abort ();
+  for (int i = 0; i < 10; i++)
+    if (z[i].t != z2[i])
+      __builtin_abort ();
+  if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+    __builtin_abort ();
+  S s;
+  s.foo ();
+  for (int i = 0; i < 9; i++)
+    if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  for (int i = 0; i < 4; i++)
+    for (int j = 0; j < 3; j++)
+      for (int k = 0; k < 2; k++)
+       if (a3[i][j][k].t != a2[i][j][k])
+         __builtin_abort ();
+  for (int i = 0; i < 5; i++)
+    if (y3[i].t != y2[i])
+      __builtin_abort ();
+  for (int i = 0; i < 10; i++)
+    if (s.z[i].t != z2[i])
+      __builtin_abort ();
+  if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L)
+    __builtin_abort ();
+  if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22
+      || s.b[3] != 84 || s.b[4] != 127)
+    __builtin_abort ();
+}
--- libgomp/testsuite/libgomp.c++/reduction-7.C.jj      2015-06-10 
17:08:23.089694851 +0200
+++ libgomp/testsuite/libgomp.c++/reduction-7.C 2015-06-10 17:08:07.000000000 
+0200
@@ -0,0 +1,134 @@
+char z[10] = { 0 };
+
+__attribute__((noinline, noclone)) void
+foo (int (*&x)[3][2], int *y, long (&w)[1][2], int p1, long p2, long p3, int 
p4,
+     int p5, long p6, short p7)
+{
+  unsigned long long a[p7 + 4];
+  short b[p7];
+  for (int i = 0; i < p7 + 4; i++)
+    {
+      if (i < p7)
+       b[i] = -6;
+      a[i] = 0;
+    }
+  #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+                          reduction(*:y[:p4]) reduction(|:a[:p5]) \
+                          reduction(&:w[0:p6 - 1][:p6]) reduction(max:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1] += i;
+      if ((i & 15) == 1)
+       y[0] *= 3;
+      if ((i & 31) == 2)
+       y[1] *= 7;
+      if ((i & 63) == 3)
+       y[2] *= 17;
+      z[i / 32] += (i & 3);
+      if (i < 4)
+       z[i] += i;
+      a[i / 32] |= 1ULL << (i & 30);
+      w[0][i & 1] &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (int i = 0; i < 9; i++)
+    if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127)
+    __builtin_abort ();
+}
+
+int a3[4][3][2];
+int (*p3)[3][2] = &a3[1];
+int y3[5] = { 0, 1, 1, 1, 0 };
+long w3[1][2] = { ~0L, ~0L };
+short bb[5];
+
+struct S
+{
+  int (*&x)[3][2];
+  int *y;
+  long (&w)[1][2];
+  char z[10];
+  short (&b)[5];
+  unsigned long long a[9];
+  S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {}
+  __attribute__((noinline, noclone)) void foo (int, long, long, int, int, 
long, short);
+};
+
+void
+S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7)
+{
+  #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+                          reduction(*:y[:p4]) reduction(|:a[:p5]) \
+                          reduction(&:w[0:p6 - 1][:p6]) reduction(max:b[0:p7])
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1] += i;
+      if ((i & 15) == 1)
+       y[0] *= 3;
+      if ((i & 31) == 2)
+       y[1] *= 7;
+      if ((i & 63) == 3)
+       y[2] *= 17;
+      z[i / 32] += (i & 3);
+      if (i < 4)
+       z[i] += i;
+      a[i / 32] |= 1ULL << (i & 30);
+      w[0][i & 1] &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+}
+
+int
+main ()
+{
+  int a[4][3][2] = {};
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  int (*p)[3][2] = &a[1];
+  int y[5] = { 0, 1, 1, 1, 0 };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  long w[1][2] = { ~0L, ~0L };
+  foo (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+  if (__builtin_memcmp (a, a2, sizeof (a))
+      || __builtin_memcmp (y, y2, sizeof (y))
+      || __builtin_memcmp (z, z2, sizeof (z))
+      || w[0][0] != ~0x249249L
+      || w[0][1] != ~0x249249L)
+    __builtin_abort ();
+  S s;
+  s.foo (1, 3L, 4L, 3, 4, 2L, 5);
+  for (int i = 0; i < 9; i++)
+    if (s.a[i] != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (__builtin_memcmp (a3, a2, sizeof (a3))
+      || __builtin_memcmp (y3, y2, sizeof (y3))
+      || __builtin_memcmp (s.z, z2, sizeof (s.z))
+      || w3[0][0] != ~0x249249L
+      || w3[0][1] != ~0x249249L)
+    __builtin_abort ();
+  if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+    __builtin_abort ();
+}
--- libgomp/testsuite/libgomp.c++/reduction-8.C.jj      2015-06-10 
18:15:51.897241899 +0200
+++ libgomp/testsuite/libgomp.c++/reduction-8.C 2015-06-10 18:14:26.000000000 
+0200
@@ -0,0 +1,198 @@
+template <typename T>
+struct A
+{
+  A () { t = 0; }
+  A (T x) { t = x; }
+  A (const A &x) { t = x.t; }
+  ~A () {}
+  T t;
+};
+template <typename T>
+struct M
+{
+  M () { t = 1; }
+  M (T x) { t = x; }
+  M (const M &x) { t = x.t; }
+  ~M () {}
+  T t;
+};
+template <typename T>
+struct B
+{
+  B () { t = ~(T) 0; }
+  B (T x) { t = x; }
+  B (const B &x) { t = x.t; }
+  ~B () {}
+  T t;
+};
+template <typename T>
+void
+add (T &x, T &y)
+{
+  x.t += y.t;
+}
+template <typename T>
+void
+zero (T &x)
+{
+  x.t = 0;
+}
+template <typename T>
+void
+orit (T *x, T *y)
+{
+  y->t |= x->t;
+}
+B<long> bb;
+#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) 
initializer(zero (omp_priv))
+#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) 
initializer(omp_priv = 1)
+#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) 
initializer(orit (&omp_priv, &omp_orig))
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : 
omp_out) initializer(omp_priv = -6)
+
+A<char> z[10];
+
+__attribute__((noinline, noclone)) void
+foo (A<int> (*&x)[3][2], M<int> *y, B<long> (&w)[1][2], int p1, long p2, long 
p3, int p4,
+     int p5, long p6, short p7)
+{
+  A<unsigned long long> a[p7 + 4];
+  short bb[p7];
+  short (&b)[p7] = bb;
+  for (int i = 0; i < p7; i++)
+    bb[i] = -6;
+  #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \
+                          reduction(*:y[:p4]) reduction(|:a[:p5]) \
+                          reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1].t += i;
+      if ((i & 15) == 1)
+       y[0].t *= 3;
+      if ((i & 31) == 2)
+       y[1].t *= 7;
+      if ((i & 63) == 3)
+       y[2].t *= 17;
+      z[i / 32].t += (i & 3);
+      if (i < 4)
+       z[i].t += i;
+      a[i / 32].t |= 1ULL << (i & 30);
+      w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (int i = 0; i < 9; i++)
+    if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+    __builtin_abort ();
+}
+
+A<int> a3[4][3][2];
+A<int> (*p3)[3][2] = &a3[1];
+M<int> y3[5] = { 0, 1, 1, 1, 0 };
+B<long> w3[1][2];
+
+struct S
+{
+  A<int> (*&x)[3][2];
+  M<int> *y;
+  B<long> (&w)[1][2];
+  A<char> z[10];
+  short b[5];
+  A<unsigned long long> a[9];
+  S() : x(p3), y(y3+1), w(w3), z(), a(), b() {}
+  __attribute__((noinline, noclone)) void foo (int, long, long, int, int, 
long, short);
+};
+
+void
+S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7)
+{
+  #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2][0:2], z[:p3]) \
+                          reduction(*:y[:p4]) reduction(|:a[:p5]) \
+                          reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1].t += i;
+      if ((i & 15) == 1)
+       y[0].t *= 3;
+      if ((i & 31) == 2)
+       y[1].t *= 7;
+      if ((i & 63) == 3)
+       y[2].t *= 17;
+      z[i / 32].t += (i & 3);
+      if (i < 4)
+       z[i].t += i;
+      a[i / 32].t |= 1ULL << (i & 30);
+      w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[2])
+       b[2] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+}
+
+int
+main ()
+{
+  A<int> a[4][3][2];
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  A<int> (*p)[3][2] = &a[1];
+  M<int> y[5] = { 0, 1, 1, 1, 0 };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  B<long> w[1][2];
+  foo (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+  for (int i = 0; i < 4; i++)
+    for (int j = 0; j < 3; j++)
+      for (int k = 0; k < 2; k++)
+       if (a[i][j][k].t != a2[i][j][k])
+         __builtin_abort ();
+  for (int i = 0; i < 5; i++)
+    if (y[i].t != y2[i])
+      __builtin_abort ();
+  for (int i = 0; i < 10; i++)
+    if (z[i].t != z2[i])
+      __builtin_abort ();
+  if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+    __builtin_abort ();
+  S s;
+  s.foo (1, 3L, 4L, 3, 4, 2L, 5);
+  for (int i = 0; i < 9; i++)
+    if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  for (int i = 0; i < 4; i++)
+    for (int j = 0; j < 3; j++)
+      for (int k = 0; k < 2; k++)
+       if (a3[i][j][k].t != a2[i][j][k])
+         __builtin_abort ();
+  for (int i = 0; i < 5; i++)
+    if (y3[i].t != y2[i])
+      __builtin_abort ();
+  for (int i = 0; i < 10; i++)
+    if (s.z[i].t != z2[i])
+      __builtin_abort ();
+  if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L)
+    __builtin_abort ();
+  if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22
+      || s.b[3] != 84 || s.b[4] != 127)
+    __builtin_abort ();
+}
--- libgomp/testsuite/libgomp.c++/reduction-9.C.jj      2015-06-10 
19:02:56.760724297 +0200
+++ libgomp/testsuite/libgomp.c++/reduction-9.C 2015-06-10 19:02:23.000000000 
+0200
@@ -0,0 +1,130 @@
+char z[10] = { 0 };
+
+template <int N>
+__attribute__((noinline, noclone)) void
+foo (int (*&x)[3][N], int *y, long (&w)[1][N])
+{
+  unsigned long long a[9] = {};
+  short b[5] = {};
+  #pragma omp parallel for reduction(+:x[0:N][:][0:N], z[:4]) \
+                          reduction(*:y[:3]) reduction(|:a[:4]) \
+                          reduction(&:w[0:][:N]) reduction(max:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1] += i;
+      if ((i & 15) == 1)
+       y[0] *= 3;
+      if ((i & 31) == N)
+       y[1] *= 7;
+      if ((i & 63) == 3)
+       y[N] *= 17;
+      z[i / 32] += (i & 3);
+      if (i < 4)
+       z[i] += i;
+      a[i / 32] |= 1ULL << (i & 30);
+      w[0][i & 1] &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[N])
+       b[N] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (int i = 0; i < 9; i++)
+    if (a[i] != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (b[0] != 78 || b[1] != 12 || b[N] != 22 || b[3] != 84 || b[4] != 127)
+    __builtin_abort ();
+}
+
+int a3[4][3][2];
+int (*p3)[3][2] = &a3[1];
+int y3[5] = { 0, 1, 1, 1, 0 };
+long w3[1][2] = { ~0L, ~0L };
+short bb[5];
+
+template <int N>
+struct S
+{
+  int (*&x)[3][N];
+  int *y;
+  long (&w)[1][N];
+  char z[10];
+  short (&b)[5];
+  unsigned long long a[9];
+  S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {}
+  __attribute__((noinline, noclone)) void foo ();
+};
+
+template <int N>
+void
+S<N>::foo ()
+{
+  #pragma omp parallel for reduction(+:x[0:N][:][0:N], z[:4]) \
+                          reduction(*:y[:3]) reduction(|:a[:4]) \
+                          reduction(&:w[0:][:N]) reduction(max:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1] += i;
+      if ((i & 15) == 1)
+       y[0] *= 3;
+      if ((i & 31) == N)
+       y[1] *= 7;
+      if ((i & 63) == 3)
+       y[N] *= 17;
+      z[i / 32] += (i & 3);
+      if (i < 4)
+       z[i] += i;
+      a[i / 32] |= 1ULL << (i & 30);
+      w[0][i & 1] &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[N])
+       b[N] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+}
+
+int
+main ()
+{
+  int a[4][3][2] = {};
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  int (*p)[3][2] = &a[1];
+  int y[5] = { 0, 1, 1, 1, 0 };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  long w[1][2] = { ~0L, ~0L };
+  foo<2> (p, y + 1, w);
+  if (__builtin_memcmp (a, a2, sizeof (a))
+      || __builtin_memcmp (y, y2, sizeof (y))
+      || __builtin_memcmp (z, z2, sizeof (z))
+      || w[0][0] != ~0x249249L
+      || w[0][1] != ~0x249249L)
+    __builtin_abort ();
+  S<2> s;
+  s.foo ();
+  for (int i = 0; i < 9; i++)
+    if (s.a[i] != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (__builtin_memcmp (a3, a2, sizeof (a3))
+      || __builtin_memcmp (y3, y2, sizeof (y3))
+      || __builtin_memcmp (s.z, z2, sizeof (s.z))
+      || w3[0][0] != ~0x249249L
+      || w3[0][1] != ~0x249249L)
+    __builtin_abort ();
+  if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127)
+    __builtin_abort ();
+}
--- libgomp/testsuite/libgomp.c++/reduction-10.C.jj     2015-06-10 
19:05:53.932997634 +0200
+++ libgomp/testsuite/libgomp.c++/reduction-10.C        2015-06-10 
19:05:19.000000000 +0200
@@ -0,0 +1,201 @@
+template <typename T>
+struct A
+{
+  A () { t = 0; }
+  A (T x) { t = x; }
+  A (const A &x) { t = x.t; }
+  ~A () {}
+  T t;
+};
+template <typename T>
+struct M
+{
+  M () { t = 1; }
+  M (T x) { t = x; }
+  M (const M &x) { t = x.t; }
+  ~M () {}
+  T t;
+};
+template <typename T>
+struct B
+{
+  B () { t = ~(T) 0; }
+  B (T x) { t = x; }
+  B (const B &x) { t = x.t; }
+  ~B () {}
+  T t;
+};
+template <typename T>
+void
+add (T &x, T &y)
+{
+  x.t += y.t;
+}
+template <typename T>
+void
+zero (T &x)
+{
+  x.t = 0;
+}
+template <typename T>
+void
+orit (T *x, T *y)
+{
+  y->t |= x->t;
+}
+B<long> bb;
+#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t)
+#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) 
initializer(zero (omp_priv))
+#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) 
initializer(omp_priv = 1)
+#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out))
+#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) 
initializer(orit (&omp_priv, &omp_orig))
+#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : 
omp_out) initializer(omp_priv = -6)
+
+A<char> z[10];
+
+template <int N>
+__attribute__((noinline, noclone)) void
+foo (A<int> (*&x)[3][N], M<int> *y, B<long> (&w)[1][N], int p1, long p2, long 
p3, int p4,
+     int p5, long p6, short p7)
+{
+  A<unsigned long long> a[p7 + 4];
+  short bb[p7];
+  short (&b)[p7] = bb;
+  for (int i = 0; i < p7; i++)
+    bb[i] = -6;
+  #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2 + N - 2], z[:p3]) \
+                          reduction(*:y[:p4]) reduction(|:a[:p5 - N + 2]) \
+                          reduction(&:w[0:p6 - 3 + N][:p6]) reduction(maxb:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1].t += i;
+      if ((i & 15) == 1)
+       y[0].t *= 3;
+      if ((i & 31) == N)
+       y[1].t *= 7;
+      if ((i & 63) == 3)
+       y[N].t *= 17;
+      z[i / 32].t += (i & 3);
+      if (i < 4)
+       z[i].t += i;
+      a[i / 32].t |= 1ULL << (i & 30);
+      w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[N])
+       b[N] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+  for (int i = 0; i < 9; i++)
+    if (a[i].t != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  if (bb[0] != 78 || bb[1] != 12 || bb[N] != 22 || bb[3] != 84 || bb[4] != 127)
+    __builtin_abort ();
+}
+
+A<int> a3[4][3][2];
+A<int> (*p3)[3][2] = &a3[1];
+M<int> y3[5] = { 0, 1, 1, 1, 0 };
+B<long> w3[1][2];
+
+template <int N>
+struct S
+{
+  A<int> (*&x)[3][N];
+  M<int> *y;
+  B<long> (&w)[1][N];
+  A<char> z[10];
+  short b[5];
+  A<unsigned long long> a[9];
+  S() : x(p3), y(y3+1), w(w3), z(), a(), b() {}
+  __attribute__((noinline, noclone)) void foo (int, long, long, int, int, 
long, short);
+};
+
+template <int N>
+void
+S<N>::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7)
+{
+  #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2][0:N], z[:p3 + N - 2]) \
+                          reduction(*:y[:p4]) reduction(|:a[:p5]) \
+                          reduction(&:w[0:p6 - 3 + N][:p6]) reduction(maxb:b)
+  for (int i = 0; i < 128; i++)
+    {
+      x[i / 64][i % 3][(i / 4) & 1].t += i;
+      if ((i & 15) == 1)
+       y[0].t *= 3;
+      if ((i & 31) == N)
+       y[1].t *= 7;
+      if ((i & 63) == 3)
+       y[N].t *= 17;
+      z[i / 32].t += (i & 3);
+      if (i < 4)
+       z[i].t += i;
+      a[i / 32].t |= 1ULL << (i & 30);
+      w[0][i & 1].t &= ~(1L << (i / 17 * 3));
+      if ((i % 79) > b[0])
+       b[0] = i % 79;
+      if ((i % 13) > b[1])
+       b[1] = i % 13;
+      if ((i % 23) > b[N])
+       b[N] = i % 23;
+      if ((i % 85) > b[3])
+       b[3] = i % 85;
+      if ((i % 192) > b[4])
+       b[4] = i % 192;
+    }
+}
+
+int
+main ()
+{
+  A<int> a[4][3][2];
+  static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }},
+                           {{ 312, 381 }, { 295, 356 }, { 337, 335 }},
+                           {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }},
+                           {{ 0, 0 }, { 0, 0 }, { 0, 0 }}};
+  A<int> (*p)[3][2] = &a[1];
+  M<int> y[5] = { 0, 1, 1, 1, 0 };
+  int y2[5] = { 0, 6561, 2401, 289, 0 };
+  char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 };
+  B<long> w[1][2];
+  foo<2> (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5);
+  for (int i = 0; i < 4; i++)
+    for (int j = 0; j < 3; j++)
+      for (int k = 0; k < 2; k++)
+       if (a[i][j][k].t != a2[i][j][k])
+         __builtin_abort ();
+  for (int i = 0; i < 5; i++)
+    if (y[i].t != y2[i])
+      __builtin_abort ();
+  for (int i = 0; i < 10; i++)
+    if (z[i].t != z2[i])
+      __builtin_abort ();
+  if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L)
+    __builtin_abort ();
+  S<2> s;
+  s.foo (1, 3L, 4L, 3, 4, 2L, 5);
+  for (int i = 0; i < 9; i++)
+    if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0))
+      __builtin_abort ();
+  for (int i = 0; i < 4; i++)
+    for (int j = 0; j < 3; j++)
+      for (int k = 0; k < 2; k++)
+       if (a3[i][j][k].t != a2[i][j][k])
+         __builtin_abort ();
+  for (int i = 0; i < 5; i++)
+    if (y3[i].t != y2[i])
+      __builtin_abort ();
+  for (int i = 0; i < 10; i++)
+    if (s.z[i].t != z2[i])
+      __builtin_abort ();
+  if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L)
+    __builtin_abort ();
+  if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22
+      || s.b[3] != 84 || s.b[4] != 127)
+    __builtin_abort ();
+}

        Jakub

Reply via email to