[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