diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index df1dad468df162c282d2306430cd98a537972dae..26a5f7128d2d53dc824a69d103684e63285a05df 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -15199,7 +15199,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		      OMP_CLAUSE_LINEAR_STEP (c));
 	    remove = true;
 	  }
-	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+		 && reduction_seen == -2)
 	  OMP_CLAUSE_REDUCTION_INSCAN (c) = 0;
 
 	if (remove)
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index ed805e2e6d2af97b28eb9c9d82dc2a03775641a9..eec34818f1be107a557b5511c76142ffb5099f82 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -1197,6 +1197,14 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 	  if (is_oacc_parallel_or_serial (ctx) || is_oacc_kernels (ctx))
 	    ctx->local_reduction_clauses
 	      = tree_cons (NULL, c, ctx->local_reduction_clauses);
+	  if ((OMP_CLAUSE_REDUCTION_INSCAN (c)
+	       || OMP_CLAUSE_REDUCTION_TASK (c)) && ctx->allocate_map)
+	    {
+	      tree decl = OMP_CLAUSE_DECL (c);
+	      /* For now.  */
+	      if (ctx->allocate_map->get (decl))
+		ctx->allocate_map->remove (decl);
+	    }
 	  /* FALLTHRU */
 
 	case OMP_CLAUSE_IN_REDUCTION:
@@ -4392,13 +4400,17 @@ lower_private_allocate (tree var, tree new_var, tree &allocator,
   if (allocator)
     return false;
   gcc_assert (allocate_ptr == NULL_TREE);
-  if (ctx->allocate_map && DECL_P (new_var))
+  if (ctx->allocate_map
+      && (DECL_P (new_var) || (TYPE_P (new_var) && size)))
     if (tree *allocatorp = ctx->allocate_map->get (var))
       allocator = *allocatorp;
   if (allocator == NULL_TREE)
     return false;
   if (!is_ref && omp_is_reference (var))
-    return false;
+    {
+      allocator = NULL_TREE;
+      return false;
+    }
 
   if (TREE_CODE (allocator) != INTEGER_CST)
     allocator = build_outer_var_ref (allocator, ctx);
@@ -4410,19 +4422,24 @@ lower_private_allocate (tree var, tree new_var, tree &allocator,
       allocator = var;
     }
 
-  tree ptr_type, align, sz;
-  if (is_ref)
+  tree ptr_type, align, sz = size;
+  if (TYPE_P (new_var))
+    {
+      ptr_type = build_pointer_type (new_var);
+      align = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (new_var));
+    }
+  else if (is_ref)
     {
       ptr_type = build_pointer_type (TREE_TYPE (TREE_TYPE (new_var)));
       align = build_int_cst (size_type_node,
 			     TYPE_ALIGN_UNIT (TREE_TYPE (ptr_type)));
-      sz = size;
     }
   else
     {
       ptr_type = build_pointer_type (TREE_TYPE (new_var));
       align = build_int_cst (size_type_node, DECL_ALIGN_UNIT (new_var));
-      sz = fold_convert (size_type_node, DECL_SIZE_UNIT (new_var));
+      if (sz == NULL_TREE)
+	sz = fold_convert (size_type_node, DECL_SIZE_UNIT (new_var));
     }
   if (TREE_CODE (sz) != INTEGER_CST)
     {
@@ -4855,7 +4872,23 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 	      tree type = TREE_TYPE (d);
 	      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
 	      tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+	      tree sz = v;
 	      const char *name = get_name (orig_var);
+	      if (pass != 3 && !TREE_CONSTANT (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, 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));
+		  sz = fold_build2_loc (clause_loc, MULT_EXPR,
+					TREE_TYPE (v), t,
+					TYPE_SIZE_UNIT (TREE_TYPE (type)));
+		}
 	      if (pass == 3)
 		{
 		  tree xv = create_tmp_var (ptr_type_node);
@@ -4913,6 +4946,13 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 		  gimplify_assign (cond, x, ilist);
 		  x = xv;
 		}
+	      else if (lower_private_allocate (var, type, allocator,
+					       allocate_ptr, ilist, ctx,
+					       true,
+					       TREE_CONSTANT (v)
+					       ? TYPE_SIZE_UNIT (type)
+					       : sz))
+		x = allocate_ptr;
 	      else if (TREE_CONSTANT (v))
 		{
 		  x = create_tmp_var_raw (type, name);
@@ -4924,20 +4964,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 		{
 		  tree atmp
 		    = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
-		  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)));
 		  tree al = size_int (TYPE_ALIGN (TREE_TYPE (type)));
-		  x = build_call_expr_loc (clause_loc, atmp, 2, t, al);
+		  x = build_call_expr_loc (clause_loc, atmp, 2, sz, al);
 		}
 
 	      tree ptype = build_pointer_type (TREE_TYPE (type));
@@ -5199,6 +5227,12 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 		  gimple_seq_add_stmt (dlist, g);
 		  gimple_seq_add_stmt (dlist, gimple_build_label (end2));
 		}
+	      if (allocator)
+		{
+		  tree f = builtin_decl_explicit (BUILT_IN_GOMP_FREE);
+		  g = gimple_build_call (f, 2, allocate_ptr, allocator);
+		  gimple_seq_add_stmt (dlist, g);
+		}
 	      continue;
 	    }
 	  else if (pass == 2)
diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-1.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-1.c
index 532795f06f146b359cf9aee13df8dc5a3dd53dcb..5dd51b5a2b96504560b9e111af5ec092e8d2137a 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/allocate-1.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-1.c
@@ -3,7 +3,7 @@
 #include <stdint.h>
 
 void
-foo (int x, omp_allocator_handle_t h, int fl)
+foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
 {
   int y = 0, r = 0, i, i1, l, l2[4], l3, n = 8;
   int i2, j2, n2 = 9, l4;
@@ -11,7 +11,12 @@ foo (int x, omp_allocator_handle_t h, int fl)
   int i4, j4, n4 = 11, l6;
   int i5;
   int v[x], w[x];
+  int r2[4] = { 0, 0, 0, 0 };
   int xo = x;
+  for (i = 0; i < 4; i++)
+    p[i] = 0;
+  for (i = 0; i < 3; i++)
+    q[i] = 0;
   for (i = 0; i < x; i++)
     w[i] = i;
   #pragma omp parallel private (y, v) firstprivate (x) allocate (x, y, v)
@@ -117,6 +122,21 @@ foo (int x, omp_allocator_handle_t h, int fl)
 	if ((fl & 2) && (((uintptr_t) &i5) & 63) != 0)
 	  abort ();
       }
+    #pragma omp for reduction(+:p[2:px], q[:3], r2) allocate(h: p, q, r2)
+    for (i = 0; i < 32; i++)
+      {
+	p[2] += i;
+	p[3] += 2 * i;
+	q[0] += 3 * i;
+	q[2] += 4 * i;
+	r2[0] += 5 * i;
+	r2[3] += 6 * i;
+	/* Can't really rely on alignment of &p[0], the implementation could
+	   allocate the whole array or do what GCC does and allocate only part
+	   of it.  */
+	if ((fl & 1) && (((uintptr_t) &q[0] | (uintptr_t) &r2[0]) & 63) != 0)
+	  abort ();
+      }
   }
   if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
     abort ();
@@ -130,6 +150,10 @@ foo (int x, omp_allocator_handle_t h, int fl)
     abort ();
   if (i5 != 19)
     abort ();
+  if (p[2] != (32 * 31) / 2 || p[3] != 2 * (32 * 31) / 2
+      || q[0] != 3 * (32 * 31) / 2 || q[2] != 4 * (32 * 31) / 2
+      || r2[0] != 5 * (32 * 31) / 2 || r2[3] != 6 * (32 * 31) / 2)
+    abort ();
 }
 
 void
@@ -239,15 +263,16 @@ main ()
 	{ omp_atk_fallback, omp_atv_null_fb } };
   omp_allocator_handle_t a
     = omp_init_allocator (omp_default_mem_space, 2, traits);
+  int p[4], q[3];
   if (a == omp_null_allocator)
     abort ();
   omp_set_default_allocator (omp_default_mem_alloc);
-  foo (42, omp_null_allocator, 0);
-  foo (42, omp_default_mem_alloc, 0);
-  foo (42, a, 1);
+  foo (42, p, q, 2, omp_null_allocator, 0);
+  foo (42, p, q, 2, omp_default_mem_alloc, 0);
+  foo (42, p, q, 2, a, 1);
   omp_set_default_allocator (a);
-  foo (42, omp_null_allocator, 3);
-  foo (42, omp_default_mem_alloc, 2);
+  foo (42, p, q, 2, omp_null_allocator, 3);
+  foo (42, p, q, 2, omp_default_mem_alloc, 2);
   bar (42, a);
   omp_destroy_allocator (a);
   return 0;