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 <ja...@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