[gomp5] Add support for C++ range for loops in #pragma omp {distribute,for,simd,taskloop}

Jakub Jelinek jakub@redhat.com
Wed Jul 18 12:02:00 GMT 2018


Hi!

This patch adds support for C++ range for loops, including range for loops
with structured bindings for OpenMP constructs.

Tested on x86_64-linux, committed to gomp-5_0-branch.

2018-07-18  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* tree.h (OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE): Define.
	* gimplify.c (gimplify_omp_for): Handle C++ range for loops with
	NULL TREE_PURPOSE in OMP_FOR_ORIG_DECLS.  Firstprivatize
	__for_end and __for_range temporaries on OMP_PARALLEL for
	distribute parallel for{, simd}.
	* omp-low.c (lower_rec_input_clauses): Handle
	OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE on OMP_CLAUSE_FIRSTPRIVATE
	clauses.
gcc/c-family/
	* c-omp.c (c_omp_check_loop_iv_r): Look for orig decl of C++
	range for loops too.
gcc/cp/
	* cp-tree.h (cp_convert_omp_range_for, cp_finish_omp_range_for,
	finish_omp_for_block): Declare.
	* parser.c (cp_parser_for): Pass false as new is_omp argument to
	cp_parser_range_for.
	(cp_parser_range_for): Add is_omp argument, return before finalizing
	if it is true.
	(cp_convert_omp_range_for, cp_finish_omp_range_for): New functions.
	(cp_parser_omp_for_loop): Parse C++11 range for loops among omp
	loops.
	(cp_parser_omp_simd, cp_parser_omp_for, cp_parser_omp_distribute,
	cp_parser_omp_taskloop): Call keep_next_level before
	begin_omp_structured_block and call finish_omp_for_block on
	finish_omp_structured_block result.
	* semantics.c (handle_omp_for_class_iterator): Don't create a new
	TREE_LIST if one has been created already for range for, just fill
	TREE_PURPOSE and TREE_VALUE.
	(finish_omp_for): Don't check cond/incr if cond is global_namespace.
	Pass to c_omp_check_loop_iv_exprs orig_declv if non-NULL.  Don't
	use IS_EMPTY_STMT on NULL pre_body.
	(finish_omp_for_block): New function.
	* pt.c (tsubst_decomp_names): Add forward declaration.
	(tsubst_omp_for_iterator): Change orig_declv into a reference.
	Handle range for loops.  Move orig_declv handling after declv/initv
	handling.
	(tsubst_expr): Call keep_next_level before begin_omp_structured_block.
	Call cp_finish_omp_range_for for range for loops and use
	{begin,finish}_omp_structured_block instead of {push,pop}_stmt_list
	if there are any range for loops.  Call finish_omp_for_block on
	finish_omp_structured_block result.
	(dependent_omp_for_p): Always return true for range for loops if
	processing_template_decl.
gcc/testsuite/
	* g++.dg/gomp/for-21.C: New test.
libgomp/
	* testsuite/libgomp.c++/for-23.C: New test.
	* testsuite/libgomp.c++/for-24.C: New test.
	* testsuite/libgomp.c++/for-25.C: New test.

--- gcc/tree.h.jj	2018-07-17 16:41:46.120069780 +0200
+++ gcc/tree.h	2018-07-17 17:24:39.972318592 +0200
@@ -1460,6 +1460,11 @@ extern tree maybe_wrap_with_location (tr
 #define OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FIRSTPRIVATE)->base.public_flag)
 
+/* True on a FIRSTPRIVATE clause if only the reference and not what it refers
+   to should be firstprivatized.  */
+#define OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE(NODE) \
+  TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FIRSTPRIVATE))
+
 /* True on a LASTPRIVATE clause if a FIRSTPRIVATE clause for the same
    decl is present in the chain.  */
 #define OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE(NODE) \
--- gcc/gimplify.c.jj	2018-07-17 16:41:46.221069916 +0200
+++ gcc/gimplify.c	2018-07-17 17:24:39.975318596 +0200
@@ -10259,7 +10259,9 @@ gimplify_omp_for (tree *expr_p, gimple_s
       for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt)); i++)
 	if (OMP_FOR_ORIG_DECLS (inner_for_stmt)
 	    && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt),
-					i)) == TREE_LIST)
+					i)) == TREE_LIST
+	    && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt),
+					   i)))
 	  {
 	    tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), i);
 	    /* Class iterators aren't allowed on OMP_SIMD, so the only
@@ -10313,6 +10315,43 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	    OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]);
 	    OMP_PARALLEL_CLAUSES (*data[1]) = c;
 	  }
+      /* Similarly, take care of C++ range for temporaries, those should
+	 be firstprivate on OMP_PARALLEL if any.  */
+      if (data[1])
+	for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt)); i++)
+	  if (OMP_FOR_ORIG_DECLS (inner_for_stmt)
+	      && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt),
+					  i)) == TREE_LIST
+	      && TREE_CHAIN (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt),
+					   i)))
+	    {
+	      tree orig
+		= TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), i);
+	      tree v = TREE_CHAIN (orig);
+	      tree c = build_omp_clause (UNKNOWN_LOCATION,
+					 OMP_CLAUSE_FIRSTPRIVATE);
+	      /* First add firstprivate clause for the __for_end artificial
+		 decl.  */
+	      OMP_CLAUSE_DECL (c) = TREE_VEC_ELT (v, 1);
+	      if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
+		  == REFERENCE_TYPE)
+		OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE (c) = 1;
+	      OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]);
+	      OMP_PARALLEL_CLAUSES (*data[1]) = c;
+	      if (TREE_VEC_ELT (v, 0))
+		{
+		  /* And now the same for __for_range artificial decl if it
+		     exists.  */
+		  c = build_omp_clause (UNKNOWN_LOCATION,
+					OMP_CLAUSE_FIRSTPRIVATE);
+		  OMP_CLAUSE_DECL (c) = TREE_VEC_ELT (v, 0);
+		  if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
+		      == REFERENCE_TYPE)
+		    OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE (c) = 1;
+		  OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]);
+		  OMP_PARALLEL_CLAUSES (*data[1]) = c;
+		}
+	    }
     }
 
   switch (TREE_CODE (for_stmt))
@@ -10539,7 +10578,11 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	    {
 	      tree orig_decl = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i);
 	      if (TREE_CODE (orig_decl) == TREE_LIST)
-		orig_decl = TREE_PURPOSE (orig_decl);
+		{
+		  orig_decl = TREE_PURPOSE (orig_decl);
+		  if (!orig_decl)
+		    orig_decl = decl;
+		}
 	      gimplify_omp_ctxp->loop_iter_var.quick_push (orig_decl);
 	    }
 	  else
--- gcc/omp-low.c.jj	2018-07-17 16:41:46.229069926 +0200
+++ gcc/omp-low.c	2018-07-17 17:24:39.974318595 +0200
@@ -4012,7 +4012,9 @@ lower_rec_input_clauses (tree clauses, g
 		  gimplify_assign (ptr, x, ilist);
 		}
 	    }
-	  else if (omp_is_reference (var))
+	  else if (omp_is_reference (var)
+		   && (c_kind != OMP_CLAUSE_FIRSTPRIVATE
+		       || !OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE (c)))
 	    {
 	      /* For references that are being privatized for Fortran,
 		 allocate new backing storage for the new pointer
@@ -4180,7 +4182,9 @@ lower_rec_input_clauses (tree clauses, g
 	    case OMP_CLAUSE_FIRSTPRIVATE:
 	      if (is_task_ctx (ctx))
 		{
-		  if (omp_is_reference (var) || is_variable_sized (var))
+		  if ((omp_is_reference (var)
+		       && !OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE (c))
+		      || is_variable_sized (var))
 		    goto do_dtor;
 		  else if (is_global_var (maybe_lookup_decl_in_outer_ctx (var,
 									  ctx))
@@ -4192,6 +4196,18 @@ lower_rec_input_clauses (tree clauses, g
 		      goto do_dtor;
 		    }
 		}
+	      if (OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE (c)
+		  && omp_is_reference (var))
+		{
+		  x = build_outer_var_ref (var, ctx);
+		  gcc_assert (TREE_CODE (x) == MEM_REF
+			      && integer_zerop (TREE_OPERAND (x, 1)));
+		  x = TREE_OPERAND (x, 0);
+		  x = lang_hooks.decls.omp_clause_copy_ctor
+						(c, unshare_expr (new_var), x);
+		  gimplify_and_add (x, ilist);
+		  goto do_dtor;
+		}
 	    do_firstprivate:
 	      x = build_outer_var_ref (var, ctx);
 	      if (is_simd)
--- gcc/c-family/c-omp.c.jj	2018-07-17 16:41:46.220069914 +0200
+++ gcc/c-family/c-omp.c	2018-07-17 17:24:39.973318593 +0200
@@ -1058,7 +1058,13 @@ c_omp_check_loop_iv_r (tree *tp, int *wa
       for (i = 0; i < TREE_VEC_LENGTH (d->declv); i++)
 	if (*tp == TREE_VEC_ELT (d->declv, i)
 	    || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
-		&& *tp == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i))))
+		&& *tp == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i)))
+	    || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
+		&& TREE_CHAIN (TREE_VEC_ELT (d->declv, i))
+		&& (TREE_CODE (TREE_CHAIN (TREE_VEC_ELT (d->declv, i)))
+		    == TREE_VEC)
+		&& *tp == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv,
+								  i)), 2)))
 	  {
 	    location_t loc = d->expr_loc;
 	    if (loc == UNKNOWN_LOCATION)
--- gcc/cp/cp-tree.h.jj	2018-07-17 16:41:46.121069781 +0200
+++ gcc/cp/cp-tree.h	2018-07-17 17:24:39.968318586 +0200
@@ -6550,6 +6550,9 @@ extern bool maybe_clone_body			(tree);
 /* In parser.c */
 extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool,
 				  unsigned short);
+extern void cp_convert_omp_range_for (tree &, vec<tree, va_gc> *, tree &,
+				      tree &, tree &, tree &, tree &, tree &);
+extern void cp_finish_omp_range_for (tree, tree);
 extern bool parsing_nsdmi (void);
 extern bool parsing_default_capturing_generic_lambda_in_template (void);
 extern void inject_this_parameter (tree, cp_cv_quals);
@@ -6972,6 +6975,7 @@ extern tree finish_omp_task			(tree, tre
 extern tree finish_omp_for			(location_t, enum tree_code,
 						 tree, tree, tree, tree, tree,
 						 tree, tree, vec<tree> *, tree);
+extern tree finish_omp_for_block		(tree, tree);
 extern void finish_omp_atomic			(enum tree_code, enum tree_code,
 						 tree, tree, tree, tree, tree,
 						 tree, enum omp_memory_order);
--- gcc/cp/parser.c.jj	2018-07-17 16:41:46.123069784 +0200
+++ gcc/cp/parser.c	2018-07-17 17:24:39.967318585 +0200
@@ -2122,7 +2122,7 @@ static tree cp_parser_for
 static tree cp_parser_c_for
   (cp_parser *, tree, tree, bool, unsigned short);
 static tree cp_parser_range_for
-  (cp_parser *, tree, tree, tree, bool, unsigned short);
+  (cp_parser *, tree, tree, tree, bool, unsigned short, bool);
 static void do_range_for_auto_deduction
   (tree, tree);
 static tree cp_parser_perform_range_for_lookup
@@ -11793,7 +11793,8 @@ cp_parser_for (cp_parser *parser, bool i
   is_range_for = cp_parser_init_statement (parser, &decl);
 
   if (is_range_for)
-    return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll);
+    return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll,
+				false);
   else
     return cp_parser_c_for (parser, scope, init, ivdep, unroll);
 }
@@ -11851,7 +11852,7 @@ cp_parser_c_for (cp_parser *parser, tree
 
 static tree
 cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
-		     bool ivdep, unsigned short unroll)
+		     bool ivdep, unsigned short unroll, bool is_omp)
 {
   tree stmt, range_expr;
   auto_vec <cxx_binding *, 16> bindings;
@@ -11911,6 +11912,11 @@ cp_parser_range_for (cp_parser *parser,
       IDENTIFIER_BINDING (names[i]) = binding;
     }
 
+  /* finish_omp_for has its own code for the following, so just
+     return the range_expr instead.  */
+  if (is_omp)
+    return range_expr;
+
   /* If in template, STMT is converted to a normal for-statement
      at instantiation. If not, it is done just ahead. */
   if (processing_template_decl)
@@ -35791,6 +35797,192 @@ cp_parser_omp_for_loop_init (cp_parser *
   return add_private_clause;
 }
 
+/* Helper for cp_parser_omp_for_loop, handle one range-for loop.  */
+
+void
+cp_convert_omp_range_for (tree &this_pre_body, vec<tree, va_gc> *for_block,
+			  tree &decl, tree &orig_decl, tree &init,
+			  tree &orig_init, tree &cond, tree &incr)
+{
+  tree begin, end, range_temp_decl = NULL_TREE;
+  tree iter_type, begin_expr, end_expr;
+
+  if (processing_template_decl)
+    {
+      if (check_for_bare_parameter_packs (init))
+	init = error_mark_node;
+      if (!type_dependent_expression_p (init)
+	  /* do_auto_deduction doesn't mess with template init-lists.  */
+	  && !BRACE_ENCLOSED_INITIALIZER_P (init))
+	{
+	  tree d = decl;
+	  if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl))
+	    {
+	      tree v = DECL_VALUE_EXPR (decl);
+	      if (TREE_CODE (v) == ARRAY_REF
+		  && VAR_P (TREE_OPERAND (v, 0))
+		  && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+		d = TREE_OPERAND (v, 0);
+	    }
+	  do_range_for_auto_deduction (d, init);
+	}
+      cond = global_namespace;
+      incr = NULL_TREE;
+      orig_init = init;
+      if (this_pre_body)
+	this_pre_body = pop_stmt_list (this_pre_body);
+      return;
+    }
+
+  init = mark_lvalue_use (init);
+
+  if (decl == error_mark_node || init == error_mark_node)
+    /* If an error happened previously do nothing or else a lot of
+       unhelpful errors would be issued.  */
+    begin_expr = end_expr = iter_type = error_mark_node;
+  else
+    {
+      tree range_temp;
+
+      if (VAR_P (init)
+	  && array_of_runtime_bound_p (TREE_TYPE (init)))
+	/* Can't bind a reference to an array of runtime bound.  */
+	range_temp = init;
+      else
+	{
+	  range_temp = build_range_temp (init);
+	  DECL_NAME (range_temp) = NULL_TREE;
+	  pushdecl (range_temp);
+	  cp_finish_decl (range_temp, init,
+			  /*is_constant_init*/false, NULL_TREE,
+			  LOOKUP_ONLYCONVERTING);
+	  range_temp_decl = range_temp;
+	  range_temp = convert_from_reference (range_temp);
+	}
+      iter_type = cp_parser_perform_range_for_lookup (range_temp,
+						      &begin_expr, &end_expr);
+    }
+
+  tree end_iter_type = iter_type;
+  if (cxx_dialect >= cxx17)
+    end_iter_type = cv_unqualified (TREE_TYPE (end_expr));
+  end = build_decl (input_location, VAR_DECL, NULL_TREE, end_iter_type);
+  TREE_USED (end) = 1;
+  DECL_ARTIFICIAL (end) = 1;
+  pushdecl (end);
+  cp_finish_decl (end, end_expr,
+		  /*is_constant_init*/false, NULL_TREE,
+		  LOOKUP_ONLYCONVERTING);
+
+  /* The new for initialization statement.  */
+  begin = build_decl (input_location, VAR_DECL, NULL_TREE, iter_type);
+  TREE_USED (begin) = 1;
+  DECL_ARTIFICIAL (begin) = 1;
+  pushdecl (begin);
+  orig_init = init;
+  if (CLASS_TYPE_P (iter_type))
+    init = NULL_TREE;
+  else
+    {
+      init = begin_expr;
+      begin_expr = NULL_TREE;
+    }
+  cp_finish_decl (begin, begin_expr,
+		  /*is_constant_init*/false, NULL_TREE,
+		  LOOKUP_ONLYCONVERTING);
+
+  /* The new for condition.  */
+  if (CLASS_TYPE_P (iter_type))
+    cond = build2 (NE_EXPR, boolean_type_node, begin, end);
+  else
+    cond = build_x_binary_op (input_location, NE_EXPR,
+			      begin, ERROR_MARK,
+			      end, ERROR_MARK,
+			      NULL, tf_warning_or_error);
+
+  /* The new increment expression.  */
+  if (CLASS_TYPE_P (iter_type))
+    incr = build2 (PREINCREMENT_EXPR, iter_type, begin, NULL_TREE);
+  else
+    incr = finish_unary_op_expr (input_location,
+				 PREINCREMENT_EXPR, begin,
+				 tf_warning_or_error);
+
+  orig_decl = decl;
+  decl = begin;
+  if (for_block)
+    {
+      vec_safe_push (for_block, this_pre_body);
+      this_pre_body = NULL_TREE;
+    }
+
+  tree decomp_first_name = NULL_TREE;
+  unsigned decomp_cnt = 0;
+  if (orig_decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (orig_decl))
+    {
+      tree v = DECL_VALUE_EXPR (orig_decl);
+      if (TREE_CODE (v) == ARRAY_REF
+	  && VAR_P (TREE_OPERAND (v, 0))
+	  && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+	{
+	  tree d = orig_decl;
+	  orig_decl = TREE_OPERAND (v, 0);
+	  decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+	  decomp_first_name = d;
+	}
+    }
+
+  tree auto_node = type_uses_auto (TREE_TYPE (orig_decl));
+  if (auto_node)
+    {
+      tree t = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
+				     tf_none);
+      if (!error_operand_p (t))
+	TREE_TYPE (orig_decl) = do_auto_deduction (TREE_TYPE (orig_decl),
+						   t, auto_node);
+    }
+
+  tree v = make_tree_vec (decomp_cnt + 3);
+  TREE_VEC_ELT (v, 0) = range_temp_decl;
+  TREE_VEC_ELT (v, 1) = end;
+  TREE_VEC_ELT (v, 2) = orig_decl;
+  for (unsigned i = 0; i < decomp_cnt; i++)
+    {
+      TREE_VEC_ELT (v, i + 3) = decomp_first_name;
+      decomp_first_name = DECL_CHAIN (decomp_first_name);
+    }
+  orig_decl = tree_cons (NULL_TREE, NULL_TREE, v);
+}
+
+/* Helper for cp_parser_omp_for_loop, finalize part of range for
+   inside of the collapsed body.  */
+
+void
+cp_finish_omp_range_for (tree orig, tree begin)
+{
+  gcc_assert (TREE_CODE (orig) == TREE_LIST
+	      && TREE_CODE (TREE_CHAIN (orig)) == TREE_VEC);
+  tree decl = TREE_VEC_ELT (TREE_CHAIN (orig), 2);
+  tree decomp_first_name = NULL_TREE;
+  unsigned int decomp_cnt = 0;
+
+  if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+    {
+      decomp_first_name = TREE_VEC_ELT (TREE_CHAIN (orig), 3);
+      decomp_cnt = TREE_VEC_LENGTH (TREE_CHAIN (orig)) - 3;
+      cp_maybe_mangle_decomp (decl, decomp_first_name, decomp_cnt);
+    }
+
+  /* The declaration is initialized with *__begin inside the loop body.  */
+  cp_finish_decl (decl,
+		  build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
+					tf_warning_or_error),
+		  /*is_constant_init*/false, NULL_TREE,
+		  LOOKUP_ONLYCONVERTING);
+  if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+    cp_finish_decomp (decl, decomp_first_name, decomp_cnt);
+}
+
 /* Parse the restricted form of the for statement allowed by OpenMP.  */
 
 static tree
@@ -35798,7 +35990,8 @@ cp_parser_omp_for_loop (cp_parser *parse
 			tree *cclauses, bool *if_p)
 {
   tree init, orig_init, cond, incr, body, decl, pre_body = NULL_TREE, ret;
-  tree real_decl, initv, condv, incrv, declv;
+  tree orig_decl;
+  tree real_decl, initv, condv, incrv, declv, orig_declv;
   tree this_pre_body, cl, ordered_cl = NULL_TREE;
   location_t loc_first;
   bool collapse_err = false;
@@ -35851,6 +36044,7 @@ cp_parser_omp_for_loop (cp_parser *parse
   initv = make_tree_vec (count);
   condv = make_tree_vec (count);
   incrv = make_tree_vec (count);
+  orig_declv = NULL_TREE;
 
   loc_first = cp_lexer_peek_token (parser->lexer)->location;
 
@@ -35872,9 +36066,66 @@ cp_parser_omp_for_loop (cp_parser *parse
       if (!parens.require_open (parser))
 	return NULL;
 
-      init = orig_init = decl = real_decl = NULL;
+      init = orig_init = decl = real_decl = orig_decl = NULL_TREE;
       this_pre_body = push_stmt_list ();
 
+      if (code != OACC_LOOP && cxx_dialect >= cxx11)
+	{
+	  /* Save tokens so that we can put them back.  */
+	  cp_lexer_save_tokens (parser->lexer);
+
+	  /* Look for ':' that is not nested in () or {}.  */
+	  bool is_range_for
+	    = (cp_parser_skip_to_closing_parenthesis_1 (parser,
+							/*recovering=*/false,
+							CPP_COLON,
+							/*consume_paren=*/
+							false) == -1);
+
+	  /* Roll back the tokens we skipped.  */
+	  cp_lexer_rollback_tokens (parser->lexer);
+
+	  if (is_range_for)
+	    {
+	      bool saved_colon_corrects_to_scope_p
+		= parser->colon_corrects_to_scope_p;
+
+	      /* A colon is used in range-based for.  */
+	      parser->colon_corrects_to_scope_p = false;
+
+	      /* Parse the declaration.  */
+	      cp_parser_simple_declaration (parser,
+					    /*function_definition_allowed_p=*/
+					    false, &decl);
+	      parser->colon_corrects_to_scope_p
+		= saved_colon_corrects_to_scope_p;
+
+	      cp_parser_require (parser, CPP_COLON, RT_COLON);
+
+	      init = cp_parser_range_for (parser, NULL_TREE, NULL_TREE, decl,
+					  false, 0, true);
+
+	      cp_convert_omp_range_for (this_pre_body, for_block, decl,
+					orig_decl, init, orig_init,
+					cond, incr);
+	      if (this_pre_body)
+		{
+		  if (pre_body)
+		    {
+		      tree t = pre_body;
+		      pre_body = push_stmt_list ();
+		      add_stmt (t);
+		      add_stmt (this_pre_body);
+		      pre_body = pop_stmt_list (pre_body);
+		    }
+		  else
+		    pre_body = this_pre_body;
+		}
+
+	      goto parse_close_paren;
+	    }
+	}
+
       add_private_clause
 	= cp_parser_omp_for_loop_init (parser, this_pre_body, for_block,
 				       init, orig_init, decl, real_decl);
@@ -36001,6 +36252,7 @@ cp_parser_omp_for_loop (cp_parser *parse
 	    protected_set_expr_location (incr, input_location);
 	}
 
+    parse_close_paren:
       if (!parens.require_close (parser))
 	cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
 					       /*or_comma=*/false,
@@ -36015,6 +36267,14 @@ cp_parser_omp_for_loop (cp_parser *parse
 	  orig_inits.safe_grow_cleared (i + 1);
 	  orig_inits[i] = orig_init;
 	}
+      if (orig_decl)
+	{
+	  if (!orig_declv)
+	    orig_declv = copy_node (declv);
+	  TREE_VEC_ELT (orig_declv, i) = orig_decl;
+	}
+      else if (orig_declv)
+	TREE_VEC_ELT (orig_declv, i) = decl;
 
       if (i == count - 1)
 	break;
@@ -36063,15 +36323,27 @@ cp_parser_omp_for_loop (cp_parser *parse
 
   /* Note that the grammar doesn't call for a structured block here,
      though the loop as a whole is a structured block.  */
-  body = push_stmt_list ();
+  if (orig_declv)
+    {
+      body = begin_omp_structured_block ();
+      for (i = 0; i < count; i++)
+	if (TREE_VEC_ELT (orig_declv, i) != TREE_VEC_ELT (declv, i))
+	  cp_finish_omp_range_for (TREE_VEC_ELT (orig_declv, i),
+				   TREE_VEC_ELT (declv, i));
+    }
+  else
+    body = push_stmt_list ();
   cp_parser_statement (parser, NULL_TREE, false, if_p);
-  body = pop_stmt_list (body);
+  if (orig_declv)
+    body = finish_omp_structured_block (body);
+  else
+    body = pop_stmt_list (body);
 
   if (declv == NULL_TREE)
     ret = NULL_TREE;
   else
-    ret = finish_omp_for (loc_first, code, declv, NULL, initv, condv, incrv,
-			  body, pre_body, &orig_inits, clauses);
+    ret = finish_omp_for (loc_first, code, declv, orig_declv, initv, condv,
+			  incrv, body, pre_body, &orig_inits, clauses);
 
   while (nbraces)
     {
@@ -36168,13 +36440,14 @@ cp_parser_omp_simd (cp_parser *parser, c
 	}
     }
 
+  keep_next_level (true);
   sb = begin_omp_structured_block ();
   save = cp_parser_begin_omp_structured_block (parser);
 
   ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, cclauses, if_p);
 
   cp_parser_end_omp_structured_block (parser, save);
-  add_stmt (finish_omp_structured_block (sb));
+  add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
 
   return ret;
 }
@@ -36267,13 +36540,14 @@ cp_parser_omp_for (cp_parser *parser, cp
       clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
     }
 
+  keep_next_level (true);
   sb = begin_omp_structured_block ();
   save = cp_parser_begin_omp_structured_block (parser);
 
   ret = cp_parser_omp_for_loop (parser, OMP_FOR, clauses, cclauses, if_p);
 
   cp_parser_end_omp_structured_block (parser, save);
-  add_stmt (finish_omp_structured_block (sb));
+  add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
 
   return ret;
 }
@@ -36857,13 +37131,14 @@ cp_parser_omp_distribute (cp_parser *par
       clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
     }
 
+  keep_next_level (true);
   sb = begin_omp_structured_block ();
   save = cp_parser_begin_omp_structured_block (parser);
 
   ret = cp_parser_omp_for_loop (parser, OMP_DISTRIBUTE, clauses, NULL, if_p);
 
   cp_parser_end_omp_structured_block (parser, save);
-  add_stmt (finish_omp_structured_block (sb));
+  add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
 
   return ret;
 }
@@ -38841,6 +39116,7 @@ cp_parser_omp_taskloop (cp_parser *parse
       clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP];
     }
 
+  keep_next_level (true);
   sb = begin_omp_structured_block ();
   save = cp_parser_begin_omp_structured_block (parser);
 
@@ -38848,7 +39124,7 @@ cp_parser_omp_taskloop (cp_parser *parse
 				if_p);
 
   cp_parser_end_omp_structured_block (parser, save);
-  add_stmt (finish_omp_structured_block (sb));
+  add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret));
 
   return ret;
 }
--- gcc/cp/semantics.c.jj	2018-07-17 16:41:46.122069783 +0200
+++ gcc/cp/semantics.c	2018-07-17 17:24:39.969318588 +0200
@@ -8329,12 +8329,22 @@ handle_omp_for_class_iterator (int i, lo
 	= pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (c));
     }
 
+  if (TREE_CODE (TREE_VEC_ELT (orig_declv, i)) == TREE_LIST)
+    {
+      tree t = TREE_VEC_ELT (orig_declv, i);
+      gcc_assert (TREE_PURPOSE (t) == NULL_TREE
+		  && TREE_VALUE (t) == NULL_TREE
+		  && TREE_CODE (TREE_CHAIN (t)) == TREE_VEC);
+      TREE_PURPOSE (t) = TREE_VEC_ELT (declv, i);
+      TREE_VALUE (t) = last;
+    }
+  else
+    TREE_VEC_ELT (orig_declv, i)
+      = tree_cons (TREE_VEC_ELT (declv, i), last, NULL_TREE);
   TREE_VEC_ELT (declv, i) = decl;
   TREE_VEC_ELT (initv, i) = init;
   TREE_VEC_ELT (condv, i) = cond;
   TREE_VEC_ELT (incrv, i) = incr;
-  TREE_VEC_ELT (orig_declv, i)
-    = tree_cons (TREE_VEC_ELT (orig_declv, i), last, NULL_TREE);
 
   return false;
 }
@@ -8416,6 +8426,9 @@ finish_omp_for (location_t locus, enum t
       if (init && EXPR_HAS_LOCATION (init))
 	elocus = EXPR_LOCATION (init);
 
+      if (cond == global_namespace)
+	continue;
+
       if (cond == NULL)
 	{
 	  error_at (elocus, "missing controlling predicate");
@@ -8438,7 +8451,8 @@ finish_omp_for (location_t locus, enum t
       tree orig_init;
       FOR_EACH_VEC_ELT (*orig_inits, i, orig_init)
 	if (orig_init
-	    && !c_omp_check_loop_iv_exprs (locus, declv,
+	    && !c_omp_check_loop_iv_exprs (locus, orig_declv
+						  ? orig_declv : declv,
 					   TREE_VEC_ELT (declv, i), orig_init,
 					   NULL_TREE, cp_walk_subtrees))
 	  fail = true;
@@ -8571,7 +8585,7 @@ finish_omp_for (location_t locus, enum t
       i++;
     }
 
-  if (IS_EMPTY_STMT (pre_body))
+  if (pre_body && IS_EMPTY_STMT (pre_body))
     pre_body = NULL;
 
   omp_for = c_finish_omp_for (locus, code, declv, orig_declv, initv, condv,
@@ -8688,6 +8702,51 @@ finish_omp_for (location_t locus, enum t
   return omp_for;
 }
 
+/* Fix up range for decls.  Those decls were pushed into BIND's BIND_EXPR_VARS
+   and need to be moved into the BIND_EXPR inside of the OMP_FOR's body.  */
+
+tree
+finish_omp_for_block (tree bind, tree omp_for)
+{
+  if (omp_for == NULL_TREE
+      || !OMP_FOR_ORIG_DECLS (omp_for)
+      || bind == NULL_TREE
+      || TREE_CODE (bind) != BIND_EXPR)
+    return bind;
+  tree b = NULL_TREE;
+  for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (omp_for)); i++)
+    if (TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i)) == TREE_LIST
+	&& TREE_CHAIN (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i)))
+      {
+	tree v = TREE_CHAIN (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i));
+	gcc_assert (BIND_EXPR_BLOCK (bind)
+		    && (BIND_EXPR_VARS (bind)
+			== BLOCK_VARS (BIND_EXPR_BLOCK (bind))));
+	for (int j = 2; j < TREE_VEC_LENGTH (v); j++)
+	  for (tree *p = &BIND_EXPR_VARS (bind); *p; p = &DECL_CHAIN (*p))
+	    {
+	      if (*p == TREE_VEC_ELT (v, j))
+		{
+		  tree var = *p;
+		  *p = DECL_CHAIN (*p);
+		  if (b == NULL_TREE)
+		    {
+		      b = make_node (BLOCK);
+		      b = build3 (BIND_EXPR, void_type_node, NULL_TREE,
+				  OMP_FOR_BODY (omp_for), b);
+		      TREE_SIDE_EFFECTS (b) = 1;
+		      OMP_FOR_BODY (omp_for) = b;
+		    }
+		  DECL_CHAIN (var) = BIND_EXPR_VARS (b);
+		  BIND_EXPR_VARS (b) = var;
+		  BLOCK_VARS (BIND_EXPR_BLOCK (b)) = var;
+		}
+	    }
+	BLOCK_VARS (BIND_EXPR_BLOCK (bind)) = BIND_EXPR_VARS (bind);
+      }
+  return bind;
+}
+
 void
 finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs,
 		   tree rhs, tree v, tree lhs1, tree rhs1, tree clauses,
--- gcc/cp/pt.c.jj	2018-07-17 16:41:46.122069783 +0200
+++ gcc/cp/pt.c	2018-07-18 11:41:09.126597620 +0200
@@ -16295,10 +16295,13 @@ tsubst_copy_asm_operands (tree t, tree a
 
 static tree *omp_parallel_combined_clauses;
 
+static tree tsubst_decomp_names (tree, tree, tree, tsubst_flags_t, tree,
+				 tree *, unsigned int *);
+
 /* Substitute one OMP_FOR iterator.  */
 
-static void
-tsubst_omp_for_iterator (tree t, int i, tree declv, tree orig_declv,
+static bool
+tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv,
 			 tree initv, tree condv, tree incrv, tree *clauses,
 			 tree args, tsubst_flags_t complain, tree in_decl,
 			 bool integral_constant_expression_p)
@@ -16306,26 +16309,56 @@ tsubst_omp_for_iterator (tree t, int i,
 #define RECUR(NODE)				\
   tsubst_expr ((NODE), args, complain, in_decl,	\
 	       integral_constant_expression_p)
-  tree decl, init, cond, incr;
+  tree decl, init, cond = NULL_TREE, incr = NULL_TREE;
+  bool ret = false;
 
   init = TREE_VEC_ELT (OMP_FOR_INIT (t), i);
   gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
 
-  if (orig_declv && OMP_FOR_ORIG_DECLS (t))
-    {
-      tree o = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i);
-      if (TREE_CODE (o) == TREE_LIST)
-	TREE_VEC_ELT (orig_declv, i)
-	  = tree_cons (RECUR (TREE_PURPOSE (o)),
-		       RECUR (TREE_VALUE (o)), NULL_TREE);
-      else
-	TREE_VEC_ELT (orig_declv, i) = RECUR (o);
-    }
-
   decl = TREE_OPERAND (init, 0);
   init = TREE_OPERAND (init, 1);
   tree decl_expr = NULL_TREE;
-  if (init && TREE_CODE (init) == DECL_EXPR)
+  bool range_for = TREE_VEC_ELT (OMP_FOR_COND (t), i) == global_namespace;
+  if (range_for)
+    {
+      bool decomp = false;
+      if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl))
+	{
+	  tree v = DECL_VALUE_EXPR (decl);
+	  if (TREE_CODE (v) == ARRAY_REF
+	      && VAR_P (TREE_OPERAND (v, 0))
+	      && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+	    {
+	      tree decomp_first = NULL_TREE;
+	      unsigned decomp_cnt = 0;
+	      tree d = tsubst_decl (TREE_OPERAND (v, 0), args, complain);
+	      maybe_push_decl (d);
+	      d = tsubst_decomp_names (d, TREE_OPERAND (v, 0), args, complain,
+				       in_decl, &decomp_first, &decomp_cnt);
+	      decomp = true;
+	      if (d == error_mark_node)
+		decl = error_mark_node;
+	      else
+		for (unsigned int i = 0; i < decomp_cnt; i++)
+		  {
+		    if (!DECL_HAS_VALUE_EXPR_P (decomp_first))
+		      {
+			tree v = build_nt (ARRAY_REF, d,
+					   size_int (decomp_cnt - i - 1),
+					   NULL_TREE, NULL_TREE);
+			SET_DECL_VALUE_EXPR (decomp_first, v);
+			DECL_HAS_VALUE_EXPR_P (decomp_first) = 1;
+		      }
+		    fit_decomposition_lang_decl (decomp_first, d);
+		    decomp_first = DECL_CHAIN (decomp_first);
+		  }
+	    }
+	}
+      decl = tsubst_decl (decl, args, complain);
+      if (!decomp)
+	maybe_push_decl (decl);
+    }
+  else if (init && TREE_CODE (init) == DECL_EXPR)
     {
       /* We need to jump through some hoops to handle declarations in the
 	 init-statement, since we might need to handle auto deduction,
@@ -16372,14 +16405,44 @@ tsubst_omp_for_iterator (tree t, int i,
     }
   init = RECUR (init);
 
+  if (orig_declv && OMP_FOR_ORIG_DECLS (t))
+    {
+      tree o = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i);
+      if (TREE_CODE (o) == TREE_LIST)
+	TREE_VEC_ELT (orig_declv, i)
+	  = tree_cons (RECUR (TREE_PURPOSE (o)),
+		       RECUR (TREE_VALUE (o)),
+		       NULL_TREE);
+      else
+	TREE_VEC_ELT (orig_declv, i) = RECUR (o);
+    }
+
+  if (range_for)
+    {
+      tree this_pre_body = NULL_TREE;
+      tree orig_init = NULL_TREE;
+      tree orig_decl = NULL_TREE;
+      cp_convert_omp_range_for (this_pre_body, NULL, decl, orig_decl, init,
+				orig_init, cond, incr);
+      if (orig_decl)
+	{
+	  if (orig_declv == NULL_TREE)
+	    orig_declv = copy_node (declv);
+	  TREE_VEC_ELT (orig_declv, i) = orig_decl;
+	  ret = true;
+	}
+      else if (orig_declv)
+	TREE_VEC_ELT (orig_declv, i) = decl;
+    }
+
   tree auto_node = type_uses_auto (TREE_TYPE (decl));
-  if (auto_node && init)
+  if (!range_for && auto_node && init)
     TREE_TYPE (decl)
       = do_auto_deduction (TREE_TYPE (decl), init, auto_node, complain);
 
   gcc_assert (!type_dependent_expression_p (decl));
 
-  if (!CLASS_TYPE_P (TREE_TYPE (decl)))
+  if (!CLASS_TYPE_P (TREE_TYPE (decl)) || range_for)
     {
       if (decl_expr)
 	{
@@ -16390,22 +16453,27 @@ tsubst_omp_for_iterator (tree t, int i,
 	  DECL_INITIAL (DECL_EXPR_DECL (decl_expr)) = init_sav;
 	}
 
-      cond = RECUR (TREE_VEC_ELT (OMP_FOR_COND (t), i));
-      incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i);
-      if (TREE_CODE (incr) == MODIFY_EXPR)
+      if (!range_for)
 	{
-	  tree lhs = RECUR (TREE_OPERAND (incr, 0));
-	  tree rhs = RECUR (TREE_OPERAND (incr, 1));
-	  incr = build_x_modify_expr (EXPR_LOCATION (incr), lhs,
-				      NOP_EXPR, rhs, complain);
+	  cond = RECUR (TREE_VEC_ELT (OMP_FOR_COND (t), i));
+	  incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i);
+	  if (TREE_CODE (incr) == MODIFY_EXPR)
+	    {
+	      tree lhs = RECUR (TREE_OPERAND (incr, 0));
+	      tree rhs = RECUR (TREE_OPERAND (incr, 1));
+	      incr = build_x_modify_expr (EXPR_LOCATION (incr), lhs,
+					  NOP_EXPR, rhs, complain);
+	    }
+	  else
+	    incr = RECUR (incr);
+	  if (orig_declv && !OMP_FOR_ORIG_DECLS (t))
+	    TREE_VEC_ELT (orig_declv, i) = decl;
 	}
-      else
-	incr = RECUR (incr);
       TREE_VEC_ELT (declv, i) = decl;
       TREE_VEC_ELT (initv, i) = init;
       TREE_VEC_ELT (condv, i) = cond;
       TREE_VEC_ELT (incrv, i) = incr;
-      return;
+      return ret;
     }
 
   if (decl_expr)
@@ -16532,10 +16600,13 @@ tsubst_omp_for_iterator (tree t, int i,
       break;
     }
 
+  if (orig_declv && !OMP_FOR_ORIG_DECLS (t))
+    TREE_VEC_ELT (orig_declv, i) = decl;
   TREE_VEC_ELT (declv, i) = decl;
   TREE_VEC_ELT (initv, i) = init;
   TREE_VEC_ELT (condv, i) = cond;
   TREE_VEC_ELT (incrv, i) = incr;
+  return false;
 #undef RECUR
 }
 
@@ -17177,6 +17248,7 @@ tsubst_expr (tree t, tree args, tsubst_f
 	tree orig_declv = NULL_TREE;
 	tree incrv = NULL_TREE;
 	enum c_omp_region_type ort = C_ORT_OMP;
+	bool any_range_for = false;
 	int i;
 
 	if (TREE_CODE (t) == OACC_LOOP)
@@ -17195,6 +17267,7 @@ tsubst_expr (tree t, tree args, tsubst_f
 	    incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t)));
 	  }
 
+	keep_next_level (true);
 	stmt = begin_omp_structured_block ();
 
 	pre_body = push_stmt_list ();
@@ -17203,14 +17276,31 @@ tsubst_expr (tree t, tree args, tsubst_f
 
 	if (OMP_FOR_INIT (t) != NULL_TREE)
 	  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
-	    tsubst_omp_for_iterator (t, i, declv, orig_declv, initv, condv,
-				     incrv, &clauses, args, complain, in_decl,
-				     integral_constant_expression_p);
+	    any_range_for
+	      |= tsubst_omp_for_iterator (t, i, declv, orig_declv, initv,
+					  condv, incrv, &clauses, args,
+					  complain, in_decl,
+					  integral_constant_expression_p);
 	omp_parallel_combined_clauses = NULL;
 
-	body = push_stmt_list ();
+	if (any_range_for)
+	  {
+	    gcc_assert (orig_declv);
+	    body = begin_omp_structured_block ();
+	    for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
+	      if (TREE_VEC_ELT (orig_declv, i) != TREE_VEC_ELT (declv, i)
+		  && TREE_CODE (TREE_VEC_ELT (orig_declv, i)) == TREE_LIST
+		  && TREE_CHAIN (TREE_VEC_ELT (orig_declv, i)))
+		cp_finish_omp_range_for (TREE_VEC_ELT (orig_declv, i),
+					 TREE_VEC_ELT (declv, i));
+	  }
+	else
+	  body = push_stmt_list ();
 	RECUR (OMP_FOR_BODY (t));
-	body = pop_stmt_list (body);
+	if (any_range_for)
+	  body = finish_omp_structured_block (body);
+	else
+	  body = pop_stmt_list (body);
 
 	if (OMP_FOR_INIT (t) != NULL_TREE)
 	  t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv,
@@ -17227,7 +17317,8 @@ tsubst_expr (tree t, tree args, tsubst_f
 	    add_stmt (t);
 	  }
 
-	add_stmt (finish_omp_structured_block (stmt));
+	add_stmt (finish_omp_for_block (finish_omp_structured_block (stmt),
+					t));
 	pop_omp_privatization_clauses (r);
       }
       break;
@@ -25761,6 +25852,9 @@ dependent_omp_for_p (tree declv, tree in
       if (init && type_dependent_expression_p (init))
 	return true;
 
+      if (cond == global_namespace)
+	return true;
+
       if (type_dependent_expression_p (cond))
 	return true;
 
--- gcc/testsuite/g++.dg/gomp/for-21.C.jj	2018-07-17 17:24:39.972318592 +0200
+++ gcc/testsuite/g++.dg/gomp/for-21.C	2018-07-17 17:24:39.972318592 +0200
@@ -0,0 +1,104 @@
+// { dg-do compile { target c++17 } }
+
+void
+f1 (int a[10][10])
+{
+  #pragma omp for collapse (2)
+  for (int i = 0; i < 10; ++i)
+    for (auto j : a[i])		// { dg-error "initializer expression refers to iteration variable 'i'" }
+      ;
+}
+
+void
+f2 (int (&a)[10])
+{
+  #pragma omp for collapse (2)
+  for (auto i : a)
+    for (int j = i * 2; j < i * 4; j++)		// { dg-error "initializer expression refers to iteration variable 'i'" }
+      ;
+}
+
+struct S { int a, b, c; };
+
+void
+f3 (S (&a)[10])
+{
+  #pragma omp for collapse (2)
+  for (auto [i, j, k] : a)			// { dg-error "use of 'i' before deduction of 'auto'" "" { target *-*-* } .+1 }
+    for (int l = i; l < j; l += k)		// { dg-error "use of 'j' before deduction of 'auto'" }
+      ;						// { dg-error "use of 'k' before deduction of 'auto'" "" { target *-*-* } .-1 }
+}
+
+template <int N>
+void
+f4 (int a[10][10])
+{
+  #pragma omp for collapse (2)
+  for (int i = 0; i < 10; ++i)		// { dg-error "initializer expression refers to iteration variable 'i'" }
+    for (auto j : a[i])
+      ;
+}
+
+template <int N>
+void
+f5 (int (&a)[10])
+{
+  #pragma omp for collapse (2)
+  for (auto i : a)
+    for (int j = i * 2; j < i * 4; j++)		// { dg-error "initializer expression refers to iteration variable 'i'" }
+      ;
+}
+
+template <int N>
+void
+f6 (S (&a)[10])
+{
+  #pragma omp for collapse (2)
+  for (auto [i, j, k] : a)			// { dg-error "use of 'i' before deduction of 'auto'" "" { target *-*-* } .-1 }
+    for (int l = i; l < j; l += k)		// { dg-error "use of 'j' before deduction of 'auto'" }
+      ;						// { dg-error "use of 'k' before deduction of 'auto'" "" { target *-*-* } .-3 }
+}
+
+template <typename T>
+void
+f7 (T a[10][10])
+{
+  #pragma omp for collapse (2)
+  for (T i = 0; i < 10; ++i)
+    for (auto j : a[i])		// { dg-error "initializer expression refers to iteration variable 'i'" }
+      ;
+}
+
+template <typename T>
+void
+f8 (T (&a)[10])
+{
+  #pragma omp for collapse (2)
+  for (auto i : a)
+    for (T j = i * 2; j < i * 4; j++)		// { dg-error "initializer expression refers to iteration variable 'i'" }
+      ;
+}
+
+template <typename T, typename U>
+void
+f9 (U (&a)[10])
+{
+  #pragma omp for collapse (2)
+  for (auto [i, j, k] : a)			// { dg-error "use of 'i' before deduction of 'auto'" "" { target *-*-* } .-1 }
+    for (T l = i; l < j; l += k)		// { dg-error "use of 'j' before deduction of 'auto'" }
+      ;						// { dg-error "use of 'k' before deduction of 'auto'" "" { target *-*-* } .-3 }
+}
+
+void
+test ()
+{
+  int a[10][10] {};
+  int b[10] {};
+  S c[10] {};
+  f4 <0> (a);
+  f5 <0> (b);
+  f6 <0> (c);
+  f7 (a);
+  f8 (b);
+  f9 <int, S> (c);
+}
--- libgomp/testsuite/libgomp.c++/for-23.C.jj	2018-07-17 17:24:39.962318578 +0200
+++ libgomp/testsuite/libgomp.c++/for-23.C	2018-07-17 17:24:39.962318578 +0200
@@ -0,0 +1,416 @@
+// { dg-do run }
+// { dg-additional-options "-std=c++17" }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+  T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+  J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+  const I<T> &begin ();
+  const I<T> &end ();
+private:
+  I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+template <typename T>
+class K
+{
+public:
+  K ();
+  ~K ();
+  template <int N> T &get () { if (N == 0) return c; else if (N == 1) return b; return a; }
+  T a, b, c;
+};
+
+template <typename T> K<T>::K () : a {}, b {}, c {} {}
+template <typename T> K<T>::~K () {}
+template <typename T> struct std::tuple_size<K<T>> { static constexpr int value = 3; };
+template <typename T, int N> struct std::tuple_element<N, K<T>> { using type = T; };
+
+template <typename T>
+class L
+{
+public:
+  L ();
+  ~L ();
+  T a, b, c;
+};
+
+template <typename T> L<T>::L () : a {}, b {}, c {} {}
+template <typename T> L<T>::~L () {}
+
+int a[2000];
+long b[40];
+short c[50];
+int d[1024];
+K<int> e[1089];
+L<int> f[1093];
+int results[2000];
+
+template <typename T>
+void
+baz (I<T> &i)
+{
+  if (*i < 0 || *i >= 2000)
+    abort ();
+  results[*i]++;
+}
+
+void
+baz (int i)
+{
+  if (i < 0 || i >= 2000)
+    abort ();
+  results[i]++;
+}
+
+void
+f1 ()
+{
+#pragma omp parallel for default(none) shared(a)
+  for (auto i : a)
+    baz (i);
+}
+
+void
+f2 ()
+{
+#pragma omp parallel for default(none) shared(a)
+  for (auto &i : a)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+void
+f3 ()
+{
+#pragma omp parallel for collapse(3) default(none) shared(b, c)
+  for (auto &i : b)
+    for (int j = 9; j < 10; j++)
+      for (auto k : c)
+	if (&i != &b[i] || i < 0 || i >= 40 || j != 9 || k < 0 || k >= 50)
+	  abort ();
+	else
+	  baz (i * 50 + k);
+}
+
+void
+f4 (J<int> j)
+{
+#pragma omp parallel for default(none) shared(j, a)
+  for (auto &i : j)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+void
+f5 ()
+{
+#pragma omp parallel for simd default(none) shared(d, results)
+  for (auto i : d)
+    results[i % 1024] += 2 * ((unsigned) i >> 10) + 1;
+}
+
+void
+f6 (J<K<int>> j)
+{
+#pragma omp parallel for default(none) shared(j, e)
+  for (auto & [k, l, m] : j)
+    if (&k != &e[m].c || &l != &e[m].b || &m != &e[m].a || k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+void
+f7 (J<L<int>> j)
+{
+#pragma omp parallel for default(none) shared(j, f)
+  for (auto & [k, l, m] : j)
+    if (&k != &f[k].a || &l != &f[k].b || &m != &f[k].c || l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+void
+f8 (J<K<int>> j)
+{
+#pragma omp parallel for default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+void
+f9 (J<L<int>> j)
+{
+#pragma omp parallel for default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+template <int N>
+void
+f10 ()
+{
+#pragma omp parallel for default(none) shared(a)
+  for (auto i : a)
+    baz (i);
+}
+
+template <int N>
+void
+f11 ()
+{
+#pragma omp parallel for default(none) shared(a)
+  for (auto &i : a)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+template <int N>
+void
+f12 ()
+{
+#pragma omp parallel for collapse(3) default(none) shared(a, b, c)
+  for (auto &i : b)
+    for (I<int> j = I<int> (&a[9]); j < I<int> (&a[10]); j++)
+      for (auto k : c)
+	if (&i != &b[i] || i < 0 || i >= 40 || *j != 9 || k < 0 || k >= 50)
+	  abort ();
+	else
+	  baz (i * 50 + k);
+}
+
+template <typename T>
+void
+f13 (J<T> j)
+{
+#pragma omp parallel for default(none) shared(j, a)
+  for (auto &i : j)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+template <int N>
+void
+f14 ()
+{
+#pragma omp parallel for simd default(none) shared(d, results)
+  for (auto i : d)
+    results[i % N] += 2 * ((unsigned) i >> 10) + 1;
+}
+
+template <typename T>
+void
+f15 (J<K<T>> j)
+{
+#pragma omp parallel for default(none) shared(j, e)
+  for (auto & [k, l, m] : j)
+    if (&k != &e[m].c || &l != &e[m].b || &m != &e[m].a || k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+template <typename T>
+void
+f16 (J<L<T>> j)
+{
+#pragma omp parallel for default(none) shared(j, f)
+  for (auto & [k, l, m] : j)
+    if (&k != &f[k].a || &l != &f[k].b || &m != &f[k].c || l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+template <int N>
+void
+f17 (J<K<int>> j)
+{
+#pragma omp parallel for default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+template <int N>
+void
+f18 (J<L<int>> j)
+{
+#pragma omp parallel for default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)			\
+    if (expr)						\
+      {							\
+	if (results[i] != 1)				\
+	  abort ();					\
+	results[i] = 0;					\
+      }							\
+    else if (results[i])				\
+      abort ()
+
+int
+main ()
+{
+  for (int i = 0; i < 2000; i++)
+    a[i] = i;
+  for (int i = 0; i < 40; i++)
+    b[i] = i;
+  for (int i = 0; i < 50; i++)
+    c[i] = i;
+  for (int i = 0; i < 1024; i++)
+    d[i] = i;
+  for (int i = 0; i < 1089; i++)
+    {
+      e[i].a = i;
+      e[i].b = 2 * i;
+      e[i].c = 3 * i;
+    }
+  for (int i = 0; i < 1093; i++)
+    {
+      f[i].a = i;
+      f[i].b = 4 * i;
+      f[i].c = 5 * i;
+    }
+  f1 ();
+  check (1);
+  f2 ();
+  check (1);
+  f3 ();
+  check (1);
+  f4 (J<int> (&a[14], &a[1803]));
+  check (i >= 14 && i < 1803);
+  f5 ();
+  check (i >= 0 && i < 1024);
+  f6 (J<K<int>> (&e[19], &e[1029]));
+  check (i >= 19 && i < 1029);
+  f7 (J<L<int>> (&f[15], &f[1091]));
+  check (i >= 15 && i < 1091);
+  f8 (J<K<int>> (&e[27], &e[1037]));
+  check (i >= 27 && i < 1037);
+  f9 (J<L<int>> (&f[1], &f[1012]));
+  check (i >= 1 && i < 1012);
+  f10 <0> ();
+  check (1);
+  f11 <1> ();
+  check (1);
+  f12 <2> ();
+  check (1);
+  f13 (J<int> (&a[24], &a[1703]));
+  check (i >= 24 && i < 1703);
+  f14 <1024> ();
+  check (i >= 0 && i < 1024);
+  f15 (J<K<int>> (&e[39], &e[929]));
+  check (i >= 39 && i < 929);
+  f16 (J<L<int>> (&f[17], &f[1071]));
+  check (i >= 17 && i < 1071);
+  f17 <3> (J<K<int>> (&e[7], &e[1017]));
+  check (i >= 7 && i < 1017);
+  f18 <5> (J<L<int>> (&f[121], &f[1010]));
+  check (i >= 121 && i < 1010);
+}
--- libgomp/testsuite/libgomp.c++/for-24.C.jj	2018-07-17 17:24:39.962318578 +0200
+++ libgomp/testsuite/libgomp.c++/for-24.C	2018-07-17 17:24:39.962318578 +0200
@@ -0,0 +1,427 @@
+// { dg-do run }
+// { dg-additional-options "-std=c++17" }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+#pragma omp declare target
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+  T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+  J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+  const I<T> &begin ();
+  const I<T> &end ();
+private:
+  I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+struct K
+{
+  template <int N> int &get () { if (N == 0) return c; else if (N == 1) return b; return a; }
+  int a, b, c;
+};
+
+template <> struct std::tuple_size<K> { static constexpr int value = 3; };
+template <int N> struct std::tuple_element<N, K> { using type = int; };
+
+struct L
+{
+  int a, b, c;
+};
+
+int a[2000];
+long b[40];
+short c[50];
+int d[1024];
+K e[1089];
+L f[1093];
+#pragma omp end declare target
+
+int results[2000];
+
+#pragma omp declare target
+template <typename T>
+void
+baz (I<T> &i)
+{
+  if (*i < 0 || *i >= 2000)
+    abort ();
+  results[*i]++;
+}
+
+void
+baz (int i)
+{
+  if (i < 0 || i >= 2000)
+    abort ();
+  results[i]++;
+}
+
+void
+f1 ()
+{
+#pragma omp distribute parallel for default(none) shared(a)
+  for (auto i : a)
+    baz (i);
+}
+
+void
+f2 ()
+{
+#pragma omp distribute parallel for default(none) shared(a)
+  for (auto &i : a)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+void
+f3 ()
+{
+#pragma omp distribute parallel for collapse(3) default(none) shared(b, c)
+  for (auto &i : b)
+    for (int j = 9; j < 10; j++)
+      for (auto k : c)
+	if (&i != &b[i] || i < 0 || i >= 40 || j != 9 || k < 0 || k >= 50)
+	  abort ();
+	else
+	  baz (i * 50 + k);
+}
+
+void
+f4 (J<int> j)
+{
+#pragma omp distribute parallel for default(none) shared(j, a)
+  for (auto &i : j)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+void
+f5 ()
+{
+#pragma omp distribute parallel for simd default(none) shared(d, results)
+  for (auto i : d)
+    results[i % 1024] += 2 * ((unsigned) i >> 10) + 1;
+}
+
+void
+f6 (J<K> j)
+{
+#pragma omp distribute parallel for default(none) shared(j, e)
+  for (auto & [k, l, m] : j)
+    if (&k != &e[m].c || &l != &e[m].b || &m != &e[m].a || k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+void
+f7 (J<L> j)
+{
+#pragma omp distribute parallel for default(none) shared(j, f)
+  for (auto & [k, l, m] : j)
+    if (&k != &f[k].a || &l != &f[k].b || &m != &f[k].c || l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+void
+f8 (J<K> j)
+{
+#pragma omp distribute parallel for default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+void
+f9 (J<L> j)
+{
+#pragma omp distribute parallel for default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+template <int N>
+void
+f10 ()
+{
+#pragma omp distribute parallel for default(none) shared(a)
+  for (auto i : a)
+    baz (i);
+}
+
+template <int N>
+void
+f11 ()
+{
+#pragma omp distribute parallel for default(none) shared(a)
+  for (auto &i : a)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+template <int N>
+void
+f12 ()
+{
+#pragma omp distribute parallel for collapse(3) default(none) shared(a, b, c)
+  for (auto &i : b)
+    for (I<int> j = I<int> (&a[9]); j < I<int> (&a[10]); j++)
+      for (auto k : c)
+	if (&i != &b[i] || i < 0 || i >= 40 || *j != 9 || k < 0 || k >= 50)
+	  abort ();
+	else
+	  baz (i * 50 + k);
+}
+
+template <typename T>
+void
+f13 (J<T> j)
+{
+#pragma omp distribute parallel for default(none) shared(j, a)
+  for (auto &i : j)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+template <int N>
+void
+f14 ()
+{
+#pragma omp distribute parallel for simd default(none) shared(d, results)
+  for (auto i : d)
+    results[i % N] += 2 * ((unsigned) i >> 10) + 1;
+}
+
+template <typename T>
+void
+f15 (J<T> j)
+{
+#pragma omp distribute parallel for default(none) shared(j, e)
+  for (auto & [k, l, m] : j)
+    if (&k != &e[m].c || &l != &e[m].b || &m != &e[m].a || k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+template <typename T>
+void
+f16 (J<T> j)
+{
+#pragma omp distribute parallel for default(none) shared(j, f)
+  for (auto & [k, l, m] : j)
+    if (&k != &f[k].a || &l != &f[k].b || &m != &f[k].c || l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+template <int N>
+void
+f17 (J<K> j)
+{
+#pragma omp distribute parallel for default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+template <int N>
+void
+f18 (J<L> j)
+{
+#pragma omp distribute parallel for default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+#pragma omp end declare target
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)			\
+    if (expr)						\
+      {							\
+	if (results[i] != 1)				\
+	  abort ();					\
+	results[i] = 0;					\
+      }							\
+    else if (results[i])				\
+      abort ()
+
+int
+main ()
+{
+  for (int i = 0; i < 2000; i++)
+    a[i] = i;
+  for (int i = 0; i < 40; i++)
+    b[i] = i;
+  for (int i = 0; i < 50; i++)
+    c[i] = i;
+  for (int i = 0; i < 1024; i++)
+    d[i] = i;
+  for (int i = 0; i < 1089; i++)
+    {
+      e[i].a = i;
+      e[i].b = 2 * i;
+      e[i].c = 3 * i;
+    }
+  for (int i = 0; i < 1093; i++)
+    {
+      f[i].a = i;
+      f[i].b = 4 * i;
+      f[i].c = 5 * i;
+    }
+  #pragma omp target update to (a, b, c, d, e, f)
+  #pragma omp target teams map (tofrom: results)
+  f1 ();
+  check (1);
+  #pragma omp target teams map (tofrom: results)
+  f2 ();
+  check (1);
+  #pragma omp target teams map (tofrom: results)
+  f3 ();
+  check (1);
+  #pragma omp target teams map (tofrom: results)
+  f4 (J<int> (&a[14], &a[1803]));
+  check (i >= 14 && i < 1803);
+  #pragma omp target teams map (tofrom: results)
+  f5 ();
+  check (i >= 0 && i < 1024);
+  #pragma omp target teams map (tofrom: results)
+  f6 (J<K> (&e[19], &e[1029]));
+  check (i >= 19 && i < 1029);
+  #pragma omp target teams map (tofrom: results)
+  f7 (J<L> (&f[15], &f[1091]));
+  check (i >= 15 && i < 1091);
+  #pragma omp target teams map (tofrom: results)
+  f8 (J<K> (&e[27], &e[1037]));
+  check (i >= 27 && i < 1037);
+  #pragma omp target teams map (tofrom: results)
+  f9 (J<L> (&f[1], &f[1012]));
+  check (i >= 1 && i < 1012);
+  #pragma omp target teams map (tofrom: results)
+  f10 <0> ();
+  check (1);
+  #pragma omp target teams map (tofrom: results)
+  f11 <1> ();
+  check (1);
+  #pragma omp target teams map (tofrom: results)
+  f12 <2> ();
+  check (1);
+  #pragma omp target teams map (tofrom: results)
+  f13 (J<int> (&a[24], &a[1703]));
+  check (i >= 24 && i < 1703);
+  #pragma omp target teams map (tofrom: results)
+  f14 <1024> ();
+  check (i >= 0 && i < 1024);
+  #pragma omp target teams map (tofrom: results)
+  f15 (J<K> (&e[39], &e[929]));
+  check (i >= 39 && i < 929);
+  #pragma omp target teams map (tofrom: results)
+  f16 (J<L> (&f[17], &f[1071]));
+  check (i >= 17 && i < 1071);
+  #pragma omp target teams map (tofrom: results)
+  f17 <3> (J<K> (&e[7], &e[1017]));
+  check (i >= 7 && i < 1017);
+  #pragma omp target teams map (tofrom: results)
+  f18 <5> (J<L> (&f[121], &f[1010]));
+  check (i >= 121 && i < 1010);
+}
--- libgomp/testsuite/libgomp.c++/for-25.C.jj	2018-07-17 17:24:39.963318579 +0200
+++ libgomp/testsuite/libgomp.c++/for-25.C	2018-07-17 17:24:39.963318579 +0200
@@ -0,0 +1,420 @@
+// { dg-do run }
+// { dg-additional-options "-std=c++17" }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+  T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+  J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+  const I<T> &begin ();
+  const I<T> &end ();
+private:
+  I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+template <typename T>
+class K
+{
+public:
+  K ();
+  ~K ();
+  template <int N> T &get () { if (N == 0) return c; else if (N == 1) return b; return a; }
+  T a, b, c;
+};
+
+template <typename T> K<T>::K () : a {}, b {}, c {} {}
+template <typename T> K<T>::~K () {}
+template <typename T> struct std::tuple_size<K<T>> { static constexpr int value = 3; };
+template <typename T, int N> struct std::tuple_element<N, K<T>> { using type = T; };
+
+template <typename T>
+class L
+{
+public:
+  L ();
+  ~L ();
+  T a, b, c;
+};
+
+template <typename T> L<T>::L () : a {}, b {}, c {} {}
+template <typename T> L<T>::~L () {}
+
+int a[2000];
+long b[40];
+short c[50];
+int d[1024];
+K<int> e[1089];
+L<int> f[1093];
+int results[2000];
+
+template <typename T>
+void
+baz (I<T> &i)
+{
+  if (*i < 0 || *i >= 2000)
+    abort ();
+  results[*i]++;
+}
+
+void
+baz (int i)
+{
+  if (i < 0 || i >= 2000)
+    abort ();
+  results[i]++;
+}
+
+void
+f1 ()
+{
+#pragma omp taskloop default(none) shared(a)
+  for (auto i : a)
+    baz (i);
+}
+
+void
+f2 ()
+{
+#pragma omp taskloop default(none) shared(a)
+  for (auto &i : a)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+void
+f3 ()
+{
+#pragma omp taskloop collapse(3) default(none) shared(b, c)
+  for (auto &i : b)
+    for (int j = 9; j < 10; j++)
+      for (auto k : c)
+	if (&i != &b[i] || i < 0 || i >= 40 || j != 9 || k < 0 || k >= 50)
+	  abort ();
+	else
+	  baz (i * 50 + k);
+}
+
+void
+f4 (J<int> j)
+{
+#pragma omp taskloop default(none) shared(j, a)
+  for (auto &i : j)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+void
+f5 ()
+{
+#pragma omp taskloop simd default(none) shared(d, results)
+  for (auto i : d)
+    results[i % 1024] += 2 * ((unsigned) i >> 10) + 1;
+}
+
+void
+f6 (J<K<int>> j)
+{
+#pragma omp taskloop default(none) shared(j, e)
+  for (auto & [k, l, m] : j)
+    if (&k != &e[m].c || &l != &e[m].b || &m != &e[m].a || k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+void
+f7 (J<L<int>> j)
+{
+#pragma omp taskloop default(none) shared(j, f)
+  for (auto & [k, l, m] : j)
+    if (&k != &f[k].a || &l != &f[k].b || &m != &f[k].c || l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+void
+f8 (J<K<int>> j)
+{
+#pragma omp taskloop default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+void
+f9 (J<L<int>> j)
+{
+#pragma omp taskloop default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+template <int N>
+void
+f10 ()
+{
+#pragma omp taskloop default(none) shared(a)
+  for (auto i : a)
+    baz (i);
+}
+
+template <int N>
+void
+f11 ()
+{
+#pragma omp taskloop default(none) shared(a)
+  for (auto &i : a)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+template <int N>
+void
+f12 ()
+{
+#pragma omp taskloop collapse(3) default(none) shared(a, b, c)
+  for (auto &i : b)
+    for (I<int> j = I<int> (&a[9]); j < I<int> (&a[10]); j++)
+      for (auto k : c)
+	if (&i != &b[i] || i < 0 || i >= 40 || *j != 9 || k < 0 || k >= 50)
+	  abort ();
+	else
+	  baz (i * 50 + k);
+}
+
+template <typename T>
+void
+f13 (J<T> j)
+{
+#pragma omp taskloop default(none) shared(j, a)
+  for (auto &i : j)
+    if (&i != &a[i])
+      abort ();
+    else
+      baz (i);
+}
+
+template <int N>
+void
+f14 ()
+{
+#pragma omp taskloop simd default(none) shared(d, results)
+  for (auto i : d)
+    results[i % N] += 2 * ((unsigned) i >> 10) + 1;
+}
+
+template <typename T>
+void
+f15 (J<K<T>> j)
+{
+#pragma omp taskloop default(none) shared(j, e)
+  for (auto & [k, l, m] : j)
+    if (&k != &e[m].c || &l != &e[m].b || &m != &e[m].a || k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+template <typename T>
+void
+f16 (J<L<T>> j)
+{
+#pragma omp taskloop default(none) shared(j, f)
+  for (auto & [k, l, m] : j)
+    if (&k != &f[k].a || &l != &f[k].b || &m != &f[k].c || l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+template <int N>
+void
+f17 (J<K<int>> j)
+{
+#pragma omp taskloop default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (k != m * 3 || l != m * 2)
+      abort ();
+    else
+      baz (m);
+}
+
+template <int N>
+void
+f18 (J<L<int>> j)
+{
+#pragma omp taskloop default(none) shared(j)
+  for (auto [k, l, m] : j)
+    if (l != k * 4 || m != k * 5)
+      abort ();
+    else
+      baz (k);
+}
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)			\
+    if (expr)						\
+      {							\
+	if (results[i] != 1)				\
+	  abort ();					\
+	results[i] = 0;					\
+      }							\
+    else if (results[i])				\
+      abort ()
+
+int
+main ()
+{
+  for (int i = 0; i < 2000; i++)
+    a[i] = i;
+  for (int i = 0; i < 40; i++)
+    b[i] = i;
+  for (int i = 0; i < 50; i++)
+    c[i] = i;
+  for (int i = 0; i < 1024; i++)
+    d[i] = i;
+  for (int i = 0; i < 1089; i++)
+    {
+      e[i].a = i;
+      e[i].b = 2 * i;
+      e[i].c = 3 * i;
+    }
+  for (int i = 0; i < 1093; i++)
+    {
+      f[i].a = i;
+      f[i].b = 4 * i;
+      f[i].c = 5 * i;
+    }
+  #pragma omp parallel
+  #pragma omp single
+  {
+    f1 ();
+    check (1);
+    f2 ();
+    check (1);
+    f3 ();
+    check (1);
+    f4 (J<int> (&a[14], &a[1803]));
+    check (i >= 14 && i < 1803);
+    f5 ();
+    check (i >= 0 && i < 1024);
+    f6 (J<K<int>> (&e[19], &e[1029]));
+    check (i >= 19 && i < 1029);
+    f7 (J<L<int>> (&f[15], &f[1091]));
+    check (i >= 15 && i < 1091);
+    f8 (J<K<int>> (&e[27], &e[1037]));
+    check (i >= 27 && i < 1037);
+    f9 (J<L<int>> (&f[1], &f[1012]));
+    check (i >= 1 && i < 1012);
+    f10 <0> ();
+    check (1);
+    f11 <1> ();
+    check (1);
+    f12 <2> ();
+    check (1);
+    f13 (J<int> (&a[24], &a[1703]));
+    check (i >= 24 && i < 1703);
+    f14 <1024> ();
+    check (i >= 0 && i < 1024);
+    f15 (J<K<int>> (&e[39], &e[929]));
+    check (i >= 39 && i < 929);
+    f16 (J<L<int>> (&f[17], &f[1071]));
+    check (i >= 17 && i < 1071);
+    f17 <3> (J<K<int>> (&e[7], &e[1017]));
+    check (i >= 7 && i < 1017);
+    f18 <5> (J<L<int>> (&f[121], &f[1010]));
+    check (i >= 121 && i < 1010);
+  }
+}

	Jakub



More information about the Gcc-patches mailing list