Hi! Another thing being voted into OpenMP 5.0 these days are clarifications for iterators - step must be integral, and whether it is > 0 determines if it iterates up or down, so one can use downward iterators even with unsigned iterator type, either just use signed negative step constant, or some signed negative expression. Wrap-around, both signed and unsigned, of the iterator is unspecified behavior, which simplifies things.
Tested on x86_64-linux, committed to gomp-5_0-branch. 2018-08-02 Jakub Jelinek <ja...@redhat.com> * gimplify.c (gimplify_omp_depend): Load block from elt 5 instead of 4, in 4 expect to find original step expression, gimplify it and use it to determine if iterating upwards or downwards. When iterating downwards with unsigned iterator type, negate both the difference and step before division. gcc/c/ * c-parser.c (c_parser_omp_iterators): Build vector with 6 elts instead of 5. (c_parser_omp_clause_depend): Put block into elt 5 instead of 4. * c-typeck.c (c_omp_finish_iterators): Remove iterator if step is errorneous, diagnose if step doesn't have integral type. Remember original step expression wrapped with save_expr and store that to elt 4. gcc/cp/ * parser.c (cp_parser_omp_iterators): Build vector with 6 elts instead of 5. (cp_parser_omp_clause_depend): Put block into elt 5 instead of 4. * semantics.c (cp_omp_finish_iterators): Remove iterator if step is errorneous, diagnose if step doesn't have integral type. Remember original step expression wrapped with save_expr and store that to elt 4. If processing_template_decl, punt earlier if begin/end/step are type dependent expression, and only update step to the orig_step. * pt.c (tsubst_omp_clause_decl): Put block into elt 5 instead of 4. gcc/testsuite/ * c-c++-common/gomp/depend-iterator-2.c (f1): Adjust expected diagnostics, split the test with step 3.5 into one where only begin/end are floating point, and one where only step is floating point. * g++.dg/gomp/depend-iterator-2.C (f1, f3): Likewise. libgomp/ * testsuite/libgomp.c-c++-common/depend-iterator-1.c: Add tests for unsigned iterators, add gaps in between different arr2 bits. * testsuite/libgomp.c++/depend-iterator-1.C: Likewise. --- gcc/gimplify.c.jj 2018-08-01 16:36:33.391000517 +0200 +++ gcc/gimplify.c 2018-08-02 17:59:48.980047042 +0200 @@ -7572,7 +7572,9 @@ gimplify_omp_depend (tree *list_p, gimpl is_gimple_val, fb_rvalue) == GS_ERROR || gimplify_expr (&TREE_VEC_ELT (it, 2), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR - || (gimplify_expr (&TREE_VEC_ELT (it, 3), pre_p, NULL, + || gimplify_expr (&TREE_VEC_ELT (it, 3), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR + || (gimplify_expr (&TREE_VEC_ELT (it, 4), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR)) return 2; @@ -7580,12 +7582,13 @@ gimplify_omp_depend (tree *list_p, gimpl tree begin = TREE_VEC_ELT (it, 1); tree end = TREE_VEC_ELT (it, 2); tree step = TREE_VEC_ELT (it, 3); + tree orig_step = TREE_VEC_ELT (it, 4); tree type = TREE_TYPE (var); tree stype = TREE_TYPE (step); location_t loc = DECL_SOURCE_LOCATION (var); tree endmbegin; /* Compute count for this iterator as - step > 0 + orig_step > 0 ? (begin < end ? (end - begin + (step - 1)) / step : 0) : (begin > end ? (end - begin + (step + 1)) / step : 0) and compute product of those for the entire depend @@ -7608,8 +7611,14 @@ gimplify_omp_depend (tree *list_p, gimpl pos, step); tree neg = fold_build2_loc (loc, PLUS_EXPR, stype, endmbegin, stepp1); + if (TYPE_UNSIGNED (stype)) + { + neg = fold_build1_loc (loc, NEGATE_EXPR, stype, neg); + step = fold_build1_loc (loc, NEGATE_EXPR, stype, step); + } neg = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, neg, step); + step = NULL_TREE; tree cond = fold_build2_loc (loc, LT_EXPR, boolean_type_node, begin, end); @@ -7619,8 +7628,10 @@ gimplify_omp_depend (tree *list_p, gimpl end, begin); neg = fold_build3_loc (loc, COND_EXPR, stype, cond, neg, build_int_cst (stype, 0)); + tree osteptype = TREE_TYPE (orig_step); cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - step, build_int_cst (stype, 0)); + orig_step, + build_int_cst (osteptype, 0)); tree cnt = fold_build3_loc (loc, COND_EXPR, stype, cond, pos, neg); cnt = fold_convert_loc (loc, sizetype, cnt); @@ -7779,7 +7790,7 @@ gimplify_omp_depend (tree *list_p, gimpl { if (last_bind) gimplify_and_add (last_bind, pre_p); - tree block = TREE_VEC_ELT (TREE_PURPOSE (t), 4); + tree block = TREE_VEC_ELT (TREE_PURPOSE (t), 5); last_bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block), NULL, block); TREE_SIDE_EFFECTS (last_bind) = 1; @@ -7791,8 +7802,8 @@ gimplify_omp_depend (tree *list_p, gimpl tree begin = TREE_VEC_ELT (it, 1); tree end = TREE_VEC_ELT (it, 2); tree step = TREE_VEC_ELT (it, 3); + tree orig_step = TREE_VEC_ELT (it, 4); tree type = TREE_TYPE (var); - tree stype = TREE_TYPE (step); location_t loc = DECL_SOURCE_LOCATION (var); /* Emit: var = begin; @@ -7801,7 +7812,7 @@ gimplify_omp_depend (tree *list_p, gimpl ... var = var + step; cond_label: - if (step > 0) { + if (orig_step > 0) { if (var < end) goto beg_label; } else { if (var > end) goto beg_label; @@ -7846,8 +7857,10 @@ gimplify_omp_depend (tree *list_p, gimpl = fold_build3_loc (loc, COND_EXPR, void_type_node, cond, build_and_jump (&beg_label), void_node); + tree osteptype = TREE_TYPE (orig_step); cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - step, build_int_cst (stype, 0)); + orig_step, + build_int_cst (osteptype, 0)); tem = fold_build3_loc (loc, COND_EXPR, void_type_node, cond, pos, neg); append_to_statement_list_force (tem, p); --- gcc/c/c-parser.c.jj 2018-08-01 17:27:10.069513226 +0200 +++ gcc/c/c-parser.c 2018-08-02 14:14:40.138818877 +0200 @@ -13911,7 +13911,7 @@ c_parser_omp_iterators (c_parser *parser DECL_CONTEXT (iter_var) = current_function_decl; pushdecl (iter_var); - *last = make_tree_vec (5); + *last = make_tree_vec (6); TREE_VEC_ELT (*last, 0) = iter_var; TREE_VEC_ELT (*last, 1) = begin; TREE_VEC_ELT (*last, 2) = end; @@ -14031,7 +14031,7 @@ c_parser_omp_clause_depend (c_parser *pa if (iterators == error_mark_node) iterators = NULL_TREE; else - TREE_VEC_ELT (iterators, 4) = block; + TREE_VEC_ELT (iterators, 5) = block; } for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) --- gcc/c/c-typeck.c.jj 2018-08-01 17:00:46.329549760 +0200 +++ gcc/c/c-typeck.c 2018-08-02 18:57:31.969477582 +0200 @@ -13112,6 +13112,7 @@ c_omp_finish_iterators (tree iter) tree begin = TREE_VEC_ELT (it, 1); tree end = TREE_VEC_ELT (it, 2); tree step = TREE_VEC_ELT (it, 3); + tree orig_step; tree type = TREE_TYPE (var); location_t loc = DECL_SOURCE_LOCATION (var); if (type == error_mark_node) @@ -13138,11 +13139,24 @@ c_omp_finish_iterators (tree iter) ret = true; continue; } - + else if (step == error_mark_node + || TREE_TYPE (step) == error_mark_node) + { + ret = true; + continue; + } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) + { + error_at (EXPR_LOC_OR_LOC (step, loc), + "iterator step with non-integral type"); + ret = true; + continue; + } begin = c_fully_fold (build_c_cast (loc, type, begin), false, NULL); end = c_fully_fold (build_c_cast (loc, type, end), false, NULL); + orig_step = save_expr (c_fully_fold (step, false, NULL)); tree stype = POINTER_TYPE_P (type) ? sizetype : type; - step = c_fully_fold (build_c_cast (loc, stype, step), false, NULL); + step = c_fully_fold (build_c_cast (loc, stype, orig_step), false, NULL); if (POINTER_TYPE_P (type)) { begin = save_expr (begin); @@ -13161,7 +13175,8 @@ c_omp_finish_iterators (tree iter) if (begin == error_mark_node || end == error_mark_node - || step == error_mark_node) + || step == error_mark_node + || orig_step == error_mark_node) { ret = true; continue; @@ -13211,6 +13226,7 @@ c_omp_finish_iterators (tree iter) TREE_VEC_ELT (it, 1) = begin; TREE_VEC_ELT (it, 2) = end; TREE_VEC_ELT (it, 3) = step; + TREE_VEC_ELT (it, 4) = orig_step; } return ret; } --- gcc/cp/parser.c.jj 2018-08-01 17:37:54.378605484 +0200 +++ gcc/cp/parser.c 2018-08-02 15:12:57.043831778 +0200 @@ -33733,7 +33733,7 @@ cp_parser_omp_iterators (cp_parser *pars DECL_CONTEXT (iter_var) = current_function_decl; pushdecl (iter_var); - *last = make_tree_vec (5); + *last = make_tree_vec (6); TREE_VEC_ELT (*last, 0) = iter_var; TREE_VEC_ELT (*last, 1) = begin; TREE_VEC_ELT (*last, 2) = end; @@ -33867,7 +33867,7 @@ cp_parser_omp_clause_depend (cp_parser * if (iterators == error_mark_node) iterators = NULL_TREE; else - TREE_VEC_ELT (iterators, 4) = block; + TREE_VEC_ELT (iterators, 5) = block; } for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) --- gcc/cp/semantics.c.jj 2018-08-01 17:16:25.767685638 +0200 +++ gcc/cp/semantics.c 2018-08-02 18:57:07.374400371 +0200 @@ -5868,6 +5868,7 @@ cp_omp_finish_iterators (tree iter) tree begin = TREE_VEC_ELT (it, 1); tree end = TREE_VEC_ELT (it, 2); tree step = TREE_VEC_ELT (it, 3); + tree orig_step; tree type = TREE_TYPE (var); location_t loc = DECL_SOURCE_LOCATION (var); if (type == error_mark_node) @@ -5890,12 +5891,31 @@ cp_omp_finish_iterators (tree iter) ret = true; continue; } + if (type_dependent_expression_p (begin) + || type_dependent_expression_p (end) + || type_dependent_expression_p (step)) + continue; + else if (error_operand_p (step)) + { + ret = true; + continue; + } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) + { + error_at (EXPR_LOC_OR_LOC (step, loc), + "iterator step with non-integral type"); + ret = true; + continue; + } begin = mark_rvalue_use (begin); end = mark_rvalue_use (end); step = mark_rvalue_use (step); begin = cp_build_c_cast (type, begin, tf_warning_or_error); end = cp_build_c_cast (type, end, tf_warning_or_error); + orig_step = step; + if (!processing_template_decl) + step = orig_step = save_expr (step); tree stype = POINTER_TYPE_P (type) ? sizetype : type; step = cp_build_c_cast (stype, step, tf_warning_or_error); if (POINTER_TYPE_P (type) && !processing_template_decl) @@ -5912,6 +5932,7 @@ cp_omp_finish_iterators (tree iter) begin = maybe_constant_value (begin); end = maybe_constant_value (end); step = maybe_constant_value (step); + orig_step = maybe_constant_value (orig_step); } if (integer_zerop (step)) { @@ -5922,7 +5943,8 @@ cp_omp_finish_iterators (tree iter) if (begin == error_mark_node || end == error_mark_node - || step == error_mark_node) + || step == error_mark_node + || orig_step == error_mark_node) { ret = true; continue; @@ -5933,6 +5955,8 @@ cp_omp_finish_iterators (tree iter) begin = fold_build_cleanup_point_expr (TREE_TYPE (begin), begin); end = fold_build_cleanup_point_expr (TREE_TYPE (end), end); step = fold_build_cleanup_point_expr (TREE_TYPE (step), step); + orig_step = fold_build_cleanup_point_expr (TREE_TYPE (orig_step), + orig_step); } hash_set<tree> pset; tree it2; @@ -5969,7 +5993,13 @@ cp_omp_finish_iterators (tree iter) } TREE_VEC_ELT (it, 1) = begin; TREE_VEC_ELT (it, 2) = end; - TREE_VEC_ELT (it, 3) = step; + if (processing_template_decl) + TREE_VEC_ELT (it, 3) = orig_step; + else + { + TREE_VEC_ELT (it, 3) = step; + TREE_VEC_ELT (it, 4) = orig_step; + } } return ret; } --- gcc/cp/pt.c.jj 2018-08-01 17:39:48.853977209 +0200 +++ gcc/cp/pt.c 2018-08-02 16:05:50.445344053 +0200 @@ -15983,7 +15983,7 @@ tsubst_omp_clause_decl (tree decl, tree TREE_CHAIN (*tp) = NULL_TREE; tp = &TREE_CHAIN (*tp); } - TREE_VEC_ELT (ret, 4) = poplevel (1, 1, 0); + TREE_VEC_ELT (ret, 5) = poplevel (1, 1, 0); iterator_cache[0] = TREE_PURPOSE (decl); iterator_cache[1] = ret; } --- gcc/testsuite/c-c++-common/gomp/depend-iterator-2.c.jj 2018-08-01 18:47:11.000000000 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-2.c 2018-08-02 19:26:13.142704860 +0200 @@ -52,10 +52,11 @@ f1 (void) ; /* { dg-error "invalid cast from type 'S' to type 'int'" "" { target c++ } .-1 } */ #pragma omp task depend (iterator (i = 2:*d:2) , in : a) /* { dg-error "aggregate value used where an integer was expected" "" { target c } } */ ; /* { dg-error "invalid cast from type 'S' to type 'int'" "" { target c++ } .-1 } */ - #pragma omp task depend (iterator (i = 2:4:*d) , in : a) /* { dg-error "aggregate value used where an integer was expected" "" { target c } } */ - ; /* { dg-error "invalid cast from type 'S' to type 'int'" "" { target c++ } .-1 } */ - /* { dg-error "iterator 'i' has zero step" "" { target c } .-2 } */ - #pragma omp task depend (iterator (i = 1.25:2.5:3.5) , in : a) + #pragma omp task depend (iterator (i = 2:4:*d) , in : a) /* { dg-error "iterator step with non-integral type" } */ + ; + #pragma omp task depend (iterator (i = 1.25:2.5:3) , in : a) + ; + #pragma omp task depend (iterator (i = 1:2:3.5) , in : a) /* { dg-error "iterator step with non-integral type" } */ ; #pragma omp task depend (iterator (int *p = 23 : h) , in : a) ; --- gcc/testsuite/g++.dg/gomp/depend-iterator-2.C.jj 2018-08-01 18:47:23.250933990 +0200 +++ gcc/testsuite/g++.dg/gomp/depend-iterator-2.C 2018-08-02 19:37:21.773080622 +0200 @@ -43,7 +43,9 @@ f1 () ; #pragma omp task depend (iterator (i = 0:4, j = 2:8:i) , in : a) // { dg-error "step expression refers to outer iterator 'i'" } ; - #pragma omp task depend (iterator (i = 1.25:2.5:3.5) , in : a) + #pragma omp task depend (iterator (i = 1.25:2.5:3) , in : a) + ; + #pragma omp task depend (iterator (i = 1:2:3.5) , in : a) // { dg-error "iterator step with non-integral type" } ; #pragma omp task depend (iterator (W *p = 23 : h) , in : a) ; @@ -81,9 +83,11 @@ f3 () ; #pragma omp task depend (iterator (i = 2:*d:2) , in : a) // { dg-error "invalid cast from type 'S' to type 'int'" } ; - #pragma omp task depend (iterator (i = 2:4:*d) , in : a) // { dg-error "invalid cast from type 'S' to type 'int'" } + #pragma omp task depend (iterator (i = 2:4:*d) , in : a) // { dg-error "iterator step with non-integral type" } + ; + #pragma omp task depend (iterator (i = 1.25:2.5:3) , in : a) ; - #pragma omp task depend (iterator (i = 1.25:2.5:3.5) , in : a) + #pragma omp task depend (iterator (i = 1:2:3.5) , in : a) // { dg-error "iterator step with non-integral type" } ; #pragma omp task depend (iterator (W *p = 23 : h) , in : a) ; --- libgomp/testsuite/libgomp.c-c++-common/depend-iterator-1.c.jj 2018-08-01 18:03:26.037649407 +0200 +++ libgomp/testsuite/libgomp.c-c++-common/depend-iterator-1.c 2018-08-02 18:25:16.409444294 +0200 @@ -24,26 +24,43 @@ foo (int x, int y, long z) if (y < 0 || y > 60 || (y & 3) || z < 0 || z >= 4) abort (); #pragma omp atomic - arr2[y + z] = arr2[y + z] + 2; + arr2[y + z] = arr2[y + z] + 4; return &arr[y + z]; case 3: if (z < 0 || z > 60 || (z & 3) || y < 0 || y >= 4) abort (); #pragma omp atomic - arr2[y + z] = arr2[y + z] + 4; + arr2[y + z] = arr2[y + z] + 16; return &arr[y + z]; case 4: if (y != 0 || z > 64 || z <= 0) abort (); #pragma omp atomic - arr2[z - 1] = arr2[z - 1] + 8; + arr2[z - 1] = arr2[z - 1] + 64; return &arr[z - 1]; + case 5: + if ((y & 3) != 0 || y < 64 || y >= 96 + || (z & 127) != 0 || z < 512 || z >= 1024) + abort (); + y = (y - 64) + (z - 512) / 128; + #pragma omp atomic + arr2[y] = arr2[y] + 256; + return &arr[y]; + case 6: + if ((y & 3) != 0 || y <= 64 || y > 96 + || (z & 127) != 1 || z <= 513 || z > 1025) + abort (); + y = (y - 68) + (z - 641) / 128; + #pragma omp atomic + arr2[y] = arr2[y] + 1024; + return &arr[y]; default: abort (); } } -volatile int beg, end, step; +volatile int beg, end, step, step2; +volatile unsigned int begu, endu; int main () @@ -52,6 +69,9 @@ main () beg = 60; end = -4; step = -4; + step2 = 4; + begu = -64U; + endu = -32U; #pragma omp parallel #pragma omp master { @@ -66,16 +86,30 @@ main () abort (); else arr[i] = arr[i] + 1; - #pragma omp task depend (iterator (int *p=&arr3[64]:&arr3[0]:-1) , in : \ + #pragma omp task depend (iterator (int *p=&arr3[64]:&arr3[0]:-1) , inout : \ foo (4, 0, p - &arr3[0])[0]) depend (in : beg) for (i = 0; i < 64; i++) if (arr[i] != i + 1) abort (); else arr[i] = arr[i] + 2; + #pragma omp task depend (iterator (unsigned n=begu:endu:step2, unsigned int o = 512: 1024U: (unsigned char) 128), inout : \ + foo (5, n + 128, o)[0]) + for (i = 0; i < 64; i++) + if (arr[i] != i + 3) + abort (); + else + arr[i] = arr[i] + 4; + #pragma omp task depend (iterator (int unsigned p=endu:begu:step,unsigned q= 1025U:513U:(signed char) -128), in : \ + foo (6, p + 128, q)[0]) + for (i = 0; i < 64; i++) + if (arr[i] != i + 7) + abort (); + else + arr[i] = arr[i] + 8; } for (m = 0; m < 64; m++) - if (arr[m] != m + 3 || arr2[m] != 15) + if (arr[m] != m + 15 || arr2[m] != (m < 32 ? 1365 : 85)) abort (); return 0; } --- libgomp/testsuite/libgomp.c++/depend-iterator-1.C.jj 2018-08-01 18:05:47.080082763 +0200 +++ libgomp/testsuite/libgomp.c++/depend-iterator-1.C 2018-08-02 18:38:14.372092577 +0200 @@ -21,26 +21,43 @@ foo (int x, int y, long z) if (y < 0 || y > 60 || (y & 3) || z < 0 || z >= 4) abort (); #pragma omp atomic - arr2[y + z] = arr2[y + z] + 2; + arr2[y + z] = arr2[y + z] + 4; return &arr[y + z]; case 3: if (z < 0 || z > 60 || (z & 3) || y < 0 || y >= 4) abort (); #pragma omp atomic - arr2[y + z] = arr2[y + z] + 4; + arr2[y + z] = arr2[y + z] + 16; return &arr[y + z]; case 4: if (y != 0 || z > 64 || z <= 0) abort (); #pragma omp atomic - arr2[z - 1] = arr2[z - 1] + 8; + arr2[z - 1] = arr2[z - 1] + 64; return &arr[z - 1]; + case 5: + if ((y & 3) != 0 || y < 64 || y >= 96 + || (z & 127) != 0 || z < 512 || z >= 1024) + abort (); + y = (y - 64) + (z - 512) / 128; + #pragma omp atomic + arr2[y] = arr2[y] + 256; + return &arr[y]; + case 6: + if ((y & 3) != 0 || y <= 64 || y > 96 + || (z & 127) != 1 || z <= 513 || z > 1025) + abort (); + y = (y - 68) + (z - 641) / 128; + #pragma omp atomic + arr2[y] = arr2[y] + 1024; + return &arr[y]; default: abort (); } } -volatile int beg, end, step; +volatile int beg, end, step, step2; +volatile unsigned int begu, endu; template <int N> void @@ -60,19 +77,33 @@ bar () abort (); else arr[i] = arr[i] + 1; - #pragma omp task depend (iterator (int *p=&arr3[64]:&arr3[0]:-1), in : \ + #pragma omp task depend (iterator (int *p=&arr3[64]:&arr3[0]:-1), inout : \ foo (4, 0, p - &arr3[0])[0]) depend (in : beg) for (i = 0; i < 64; i++) if (arr[i] != i + 1) abort (); else arr[i] = arr[i] + 2; + #pragma omp task depend (iterator (unsigned n=begu:endu:step2, unsigned int o = 512: 1024U: (unsigned char) 128), inout : \ + foo (5, n + 128, o)[0]) + for (i = 0; i < 64; i++) + if (arr[i] != i + 3) + abort (); + else + arr[i] = arr[i] + 4; + #pragma omp task depend (iterator (int unsigned p=endu:begu:step,unsigned q= 1025U:513U:(signed char) -128), in : \ + foo (6, p + 128, q)[0]) + for (i = 0; i < 64; i++) + if (arr[i] != i + 7) + abort (); + else + arr[i] = arr[i] + 8; } } -template <typename A, typename B, typename C> +template <typename A, typename B, typename C, typename D, typename E, typename F> void -baz (A beg, A end, A step) +baz (A beg, A end, A step, D begu, D endu, A step2) { #pragma omp parallel #pragma omp master @@ -95,6 +126,20 @@ baz (A beg, A end, A step) abort (); else arr[i] = arr[i] + 2; + #pragma omp task depend (iterator (D n=begu:endu:step2, D o = 512: 1024U:(E) 128), inout : \ + foo (5, n + 128, o)[0]) + for (i = 0; i < 64; i++) + if (arr[i] != i + 3) + abort (); + else + arr[i] = arr[i] + 4; + #pragma omp task depend (iterator (D p=endu:begu:step,D q= 1025U:513U:(F) -128), in : \ + foo (6, p + 128, q)[0]) + for (i = 0; i < 64; i++) + if (arr[i] != i + 7) + abort (); + else + arr[i] = arr[i] + 8; } } @@ -105,15 +150,18 @@ main () beg = 60; end = -4; step = -4; + step2 = 4; + begu = -64U; + endu = -32U; bar<0> (); for (m = 0; m < 64; m++) - if (arr[m] != m + 3 || arr2[m] != 15) + if (arr[m] != m + 15 || arr2[m] != (m < 32 ? 1365 : 85)) abort (); else arr[m] = arr2[m] = 0; - baz<int, long int, int *> (beg, end, step); + baz<int, long int, int *, unsigned int, unsigned char, signed char> (beg, end, step, begu, endu, step2); for (m = 0; m < 64; m++) - if (arr[m] != m + 3 || arr2[m] != 15) + if (arr[m] != m + 15 || arr2[m] != (m < 32 ? 1365 : 85)) abort (); return 0; } Jakub