[gcc r17-2993] C++: Handle OpenMP/OpenACC array sections [: / :] with C++26
Tobias Burnus via Gcc-cvs <[email protected]> Wed, 5 Aug 2026 20:38:49 +0000 (GMT)
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:8f43cf55107e34bc10ed0ee8461d0551bc7e3817 commit r17-2993-g8f43cf55107e34bc10ed0ee8461d0551bc7e3817 Author: Tobias Burnus <[email protected]> Date: Wed Aug 5 22:37:41 2026 +0200 C++: Handle OpenMP/OpenACC array sections [: / :] with C++26 OpenMP and OpenACC have array sections of the form '[ lower : size ]' where the lower bound and/or the size bound can be left out, i.e. '[:n]', '[idx:]', and '[:]'. However, since C++26, '[:' and ':]' are parsed as CPP_OPEN_SPLICE and CPP_CLOSE_SPLICE, respectively - to implement the splicer as added for reflections (see https://wg21.link/P2996). At least as currently specified in C++ and in OpenMP/OpenACC, there should be no ambiguity between splicing and array sections. Therefore, this commit just handles the new token types to process OpenMP/OpenACC array sections as it did in C++ until C++23. On the OpenMP specification side, this and related ':' issues are tracked in Issue 4740 - and, on the OpenACC side, in Issue 557. Note: This commit permits to revert the commit r16-5330-gedc821b60ce94b OpenMP/OpenACC tests. vs C++26 that is planned to be done as follow up. The added/modified testcases ensure that also '[:' etc. is tested before the revert - and adds some '[ :' tests for C++29 for after the revert. After the revert, the hope is that -std= < C++26 and >= C++26 will together span the full testspace, even if with C++26 not all OPEN_SQUARE + COLON cases are tested for. gcc/cp/ChangeLog: * parser.cc (cp_parser_postfix_expression, cp_parser_postfix_open_square_expression, cp_parser_skip_up_to_closing_square_bracket, cp_parser_omp_var_list_no_open): Handle OpenMP/OpenACC array sections that are lexed since C++26 as CPP_OPEN_SPLICE and CPP_CLOSE_SPLICE. gcc/testsuite/ChangeLog: * c-c++-common/gomp/affinity-2.c: Also run with C++ > 23 and add some '[ :' and ': ]' tests. * g++.dg/gomp/allocate-3.C: Remove 'dg-skip-if' for c++26. * g++.dg/goacc/cache-4.C: New test. * g++.dg/gomp/array-section-3.C: New test. * g++.dg/gomp/array-section-4.C: New test. * g++.dg/gomp/array-section-5.C: New test. * g++.dg/gomp/array-section-6.C: New test. Diff: --- gcc/cp/parser.cc | 121 ++++++++++++++++++++++----- gcc/testsuite/c-c++-common/gomp/affinity-2.c | 12 ++- gcc/testsuite/g++.dg/goacc/cache-4.C | 12 +++ gcc/testsuite/g++.dg/gomp/allocate-3.C | 4 - gcc/testsuite/g++.dg/gomp/array-section-3.C | 44 ++++++++++ gcc/testsuite/g++.dg/gomp/array-section-4.C | 43 ++++++++++ gcc/testsuite/g++.dg/gomp/array-section-5.C | 96 +++++++++++++++++++++ gcc/testsuite/g++.dg/gomp/array-section-6.C | 85 +++++++++++++++++++ 8 files changed, 391 insertions(+), 26 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 85c5030acbb4..b1a1157afda4 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -8968,6 +8968,22 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, switch (token->type) { + case CPP_OPEN_SPLICE: + if (!parser->omp_array_section_p) + goto default_case; + /* Parse '[: length]' array section. */ + postfix_expression + = cp_parser_postfix_open_square_expression (parser, + postfix_expression, + false, + decltype_p); + postfix_expression.set_range (start_loc, + postfix_expression.get_location ()); + + idk = CP_ID_KIND_NONE; + is_member_access = false; + break; + case CPP_OPEN_SQUARE: if (cp_next_tokens_can_be_std_attribute_p (parser)) { @@ -9243,6 +9259,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, break; default: + default_case: if (pidk_return != NULL) * pidk_return = idk; if (member_access_only_p) @@ -9312,7 +9329,12 @@ cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p, postfix-expression [ expression-list[opt] ] (C++23) FOR_OFFSETOF is set if we're being called in that context, which - changes how we deal with integer constant expressions. */ + changes how we deal with integer constant expressions. + + With parser->omp_array_section_p, it also handles OpenMP + array sections of the type [ index : length ] where both + index and length are optional. Note that an absent index + might be lexed as CPP_OPEN_SPLICE ('[:') since C++26. */ static tree cp_parser_postfix_open_square_expression (cp_parser *parser, @@ -9326,7 +9348,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, bool saved_greater_than_is_operator_p; bool saved_colon_corrects_to_scope_p; - /* Consume the `[' token. */ + bool open_splice = cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SPLICE); + + /* Consume the `[' token - or with open_splice the '[:' token. */ cp_lexer_consume_token (parser->lexer); saved_greater_than_is_operator_p = parser->greater_than_is_operator_p; @@ -9336,6 +9360,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, if (parser->omp_array_section_p) parser->colon_corrects_to_scope_p = false; + if (open_splice) + goto post_colon_parsing; + /* Parse the index expression. */ /* ??? For offsetof, there is a question of what to allow here. If offsetof is not being used in an integral constant expression context, @@ -9347,7 +9374,8 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, if (for_offsetof) index = cp_parser_constant_expression (parser); else if (!parser->omp_array_section_p - || cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) + || (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON) + && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SPLICE))) { if (cxx_dialect >= cxx23 && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) @@ -9414,6 +9442,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, /*warn_comma_p=*/warn_comma_subscript); } +post_colon_parsing: parser->greater_than_is_operator_p = saved_greater_than_is_operator_p; if (cxx_dialect >= cxx23 @@ -9425,12 +9454,25 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, "section"); index = error_mark_node; } + if (parser->omp_array_section_p - && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + && (open_splice + || cp_lexer_next_token_is (parser->lexer, CPP_COLON) + || cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SPLICE))) { - cp_lexer_consume_token (parser->lexer); tree length = NULL_TREE; - if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE)) + bool close_splice = cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SPLICE); + if (!open_splice) + cp_lexer_consume_token (parser->lexer); + if (open_splice && close_splice) + { + cp_parser_required_error (parser, RT_CLOSE_SQUARE, /*keyword=*/false, + UNKNOWN_LOCATION); + length = error_mark_node; + } + else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE) + && !close_splice) { if (cxx_dialect >= cxx23) { @@ -9469,7 +9511,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, cp_parser_skip_to_closing_square_bracket (parser); return error_mark_node; } - else + else if (!close_splice) cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); return grok_omp_array_section (input_location, postfix_expression, index, @@ -29190,7 +29232,10 @@ cp_parser_braced_list (cp_parser *parser, bool *non_constant_p /*=nullptr*/) } /* Consume tokens up to, but not including, the next non-nested closing `]'. - Returns true iff we found a closing `]'. */ + Returns true iff we found a closing `]'. + When OpenMP array sections are permitted, the open and close splice, '[:' + and ':]', are are treated as '[' and ']' - because an absent lower or size + value in '[ lower : size ]' might get parsed as open or closed splice. */ static bool cp_parser_skip_up_to_closing_square_bracket (cp_parser *parser) @@ -29212,10 +29257,19 @@ cp_parser_skip_up_to_closing_square_bracket (cp_parser *parser) /* If we've run out of tokens, then there is no closing `]'. */ return false; + case CPP_OPEN_SPLICE: + if (!parser->omp_array_section_p) + break; + /* FALLTHRU */ + case CPP_OPEN_SQUARE: ++square_depth; break; + case CPP_CLOSE_SPLICE: + if (!parser->omp_array_section_p) + break; + /* FALLTHRU */ case CPP_CLOSE_SQUARE: if (!square_depth--) return true; @@ -41851,7 +41905,8 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, case OMP_CLAUSE__CACHE_: /* The OpenACC cache directive explicitly only allows "array elements or subarrays". */ - if (cp_lexer_peek_token (parser->lexer)->type != CPP_OPEN_SQUARE) + if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE) + && !cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SPLICE)) { error_at (token->location, "expected %<[%>"); decl = error_mark_node; @@ -41886,25 +41941,44 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, case OMP_CLAUSE_HAS_DEVICE_ADDR: array_section_p = false; dims.truncate (0); - while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE) + || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SPLICE)) { location_t loc = UNKNOWN_LOCATION; tree low_bound = NULL_TREE, length = NULL_TREE; bool no_colon = false; - + bool open_splice = cp_lexer_next_token_is (parser->lexer, + CPP_OPEN_SPLICE); parser->colon_corrects_to_scope_p = false; cp_lexer_consume_token (parser->lexer); - if (!cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + bool close_splice = cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SPLICE); + if (open_splice && close_splice) + { + cp_parser_required_error (parser, RT_CLOSE_SQUARE, + /*keyword=*/false, loc); + if ((kind == OMP_CLAUSE_DEPEND + || kind == OMP_CLAUSE_AFFINITY) + && cp_parser_simulate_error (parser)) + goto depend_lvalue; + goto skip_comma; + } + if (!open_splice + && !close_splice + && !cp_lexer_next_token_is (parser->lexer, CPP_COLON)) { loc = cp_lexer_peek_token (parser->lexer)->location; low_bound = cp_parser_expression (parser); /* Later handling is not prepared to see through these. */ gcc_checking_assert (!location_wrapper_p (low_bound)); + close_splice = cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SPLICE); } - if (!colon) - parser->colon_corrects_to_scope_p - = saved_colon_corrects_to_scope_p; - if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + if (!open_splice + && cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SQUARE)) { length = integer_one_node; no_colon = true; @@ -41912,7 +41986,9 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, else { /* Look for `:'. */ - if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + if (!open_splice + && !close_splice + && !cp_parser_require (parser, CPP_COLON, RT_COLON)) { if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) @@ -41923,8 +41999,9 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, cp_parser_commit_to_tentative_parse (parser); else array_section_p = true; - if (!cp_lexer_next_token_is (parser->lexer, - CPP_CLOSE_SQUARE)) + if (!close_splice + && !cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SQUARE)) { length = cp_parser_expression (parser); /* Later handling is not prepared to see through these. */ @@ -41932,8 +42009,10 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, } } /* Look for the closing `]'. */ - if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, - RT_CLOSE_SQUARE)) + if (close_splice) + cp_lexer_consume_token (parser->lexer); + else if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, + RT_CLOSE_SQUARE)) { if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) diff --git a/gcc/testsuite/c-c++-common/gomp/affinity-2.c b/gcc/testsuite/c-c++-common/gomp/affinity-2.c index 78bd21d1a6f1..9a2d678bc10d 100644 --- a/gcc/testsuite/c-c++-common/gomp/affinity-2.c +++ b/gcc/testsuite/c-c++-common/gomp/affinity-2.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { c || c++23_down } } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ extern int a[][10], a2[][10]; @@ -32,14 +32,24 @@ foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], ; #pragma omp task affinity( b[-1:]) /* { dg-error "negative low bound in array section" } */ ; + #pragma omp task affinity( b[-1: ]) /* { dg-error "negative low bound in array section" } */ + ; #pragma omp task affinity( c[:-3][1:1]) /* { dg-error "negative length in array section" } */ ; + #pragma omp task affinity( c[ :-3][1:1]) /* { dg-error "negative length in array section" } */ + ; + #pragma omp task affinity( d[11: ]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + ; #pragma omp task affinity( d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ ; #pragma omp task affinity( e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */ ; #pragma omp task affinity( f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ ; + #pragma omp task affinity( g[: ][2:4]) /* { dg-error "for array function parameter length expression must be specified" } */ + ; + #pragma omp task affinity( g[ :][2:4]) /* { dg-error "for array function parameter length expression must be specified" } */ + ; #pragma omp task affinity( g[:][2:4]) /* { dg-error "for array function parameter length expression must be specified" } */ ; #pragma omp task affinity( h[2:2][-1:]) /* { dg-error "negative low bound in array section" } */ diff --git a/gcc/testsuite/g++.dg/goacc/cache-4.C b/gcc/testsuite/g++.dg/goacc/cache-4.C new file mode 100644 index 000000000000..9c6ca229501e --- /dev/null +++ b/gcc/testsuite/g++.dg/goacc/cache-4.C @@ -0,0 +1,12 @@ +int l[10]; + +void +foo () +{ + #pragma acc cache(l) /* { dg-error "expected '\\\['" } */ + ; + #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma acc cache(l[ :7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; +} diff --git a/gcc/testsuite/g++.dg/gomp/allocate-3.C b/gcc/testsuite/g++.dg/gomp/allocate-3.C index 0303b55fa256..e778314f07e7 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-3.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-3.C @@ -1,7 +1,3 @@ -// Array sections without spaces between [ and : or : and ] are incompatible -// with C++26. -// { dg-skip-if "array sections vs. C++26" { c++26 } } - template <typename T> void foo (T &x, T (&y)[4], T *&z, int &u, int (&v)[4], int *&w) diff --git a/gcc/testsuite/g++.dg/gomp/array-section-3.C b/gcc/testsuite/g++.dg/gomp/array-section-3.C new file mode 100644 index 000000000000..170405fba875 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/array-section-3.C @@ -0,0 +1,44 @@ +// { dg-additional-options "-fdump-tree-original" } + +// Check that OpenMP array sections with [: and :] do not get mixed up with C++26's splice specifier, +// used for reflection. +// +// See also OpenMP spec Issue 4740. + +void f() { + char a1[4], a2[4], a3[4], b[5]; + char c1[4], c2[4], c3[4], c4[4]; + + #pragma omp target map(to: a1[:], a2[:2], a3[2:], b[1:2], c1[ : ], c2[ : 2], c3[2: ], c4[ :]) + ; + + #pragma omp task affinity(a1[:]) + ; + #pragma omp task affinity(a2[:2]) + ; + #pragma omp task affinity(a3[2:]) + ; + #pragma omp task affinity(b[1:2]) + ; + #pragma omp task affinity(c1[ : ]) + ; + #pragma omp task affinity(c2[ : 2]) + ; + #pragma omp task affinity(c3[2: ]) + ; + #pragma omp task affinity(c4[ :]) + ; + +} + +// { dg-final { scan-tree-dump "#pragma omp target.* map\\(to:c4\\\[0\\\] \\\[len: 4\\\]\\).* map\\(to:c3\\\[2\\\] \\\[len: 2\\\]\\).* map\\(to:c2\\\[0\\\] \\\[len: 2\\\]\\).* map\\(to:c1\\\[0\\\] \\\[len: 4\\\]\\).* map\\(to:b\\\[1\\\] \\\[len: 2\\\]\\).* map\\(to:a3\\\[2\\\] \\\[len: 2\\\]\\).* map\\(to:a2\\\[0\\\] \\\[len: 2\\\]\\).* map\\(to:a1\\\[0\\\] \\\[len: 4\\\]\\)" "original" } } + +// { dg-final { scan-tree-dump "#pragma omp task affinity\\(a1\\\[0\\\]\\)" "original" } } +// { dg-final { scan-tree-dump "#pragma omp task affinity\\(a2\\\[0\\\]\\)" "original" } } +// { dg-final { scan-tree-dump "#pragma omp task affinity\\(a3\\\[2\\\]\\)" "original" } } +// { dg-final { scan-tree-dump "#pragma omp task affinity\\(b\\\[1\\\]\\)" "original" } } +// { dg-final { scan-tree-dump "#pragma omp task affinity\\(c1\\\[0\\\]\\)" "original" } } +// { dg-final { scan-tree-dump "#pragma omp task affinity\\(c2\\\[0\\\]\\)" "original" } } +// { dg-final { scan-tree-dump "#pragma omp task affinity\\(c3\\\[2\\\]\\)" "original" } } +// { dg-final { scan-tree-dump "#pragma omp task affinity\\(c4\\\[0\\\]\\)" "original" } } + diff --git a/gcc/testsuite/g++.dg/gomp/array-section-4.C b/gcc/testsuite/g++.dg/gomp/array-section-4.C new file mode 100644 index 000000000000..2ece1ac9e610 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/array-section-4.C @@ -0,0 +1,43 @@ +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection -fdump-tree-original" } + +void f() +{ + constexpr int a = 42; + constexpr auto b = ^^a; + int c[128]; + + #pragma omp target enter data map(to : c[[:b:]]) + + #pragma omp target enter data map(to : c[[:b:]:]) + + #pragma omp target enter data map(to : c[:[:b:]]) + + #pragma omp target enter data map(to : c[[:b:]:2]) + + #pragma omp target enter data map(to : c[2:[:b:]]) + + + #pragma omp task affinity( c[[:b:]]) + ; + + #pragma omp task affinity( c[[:b:]:2]) + ; + #pragma omp task affinity( c[2:[:b:]]) + ; + + #pragma omp task affinity( c[[:b:]:]) + ; + #pragma omp task affinity( c[:[:b:]]) + ; +} + +// { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(to:c\\\[42\\\] \\\[len: 4\\\]\\)" 1 "original" } } +// { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(to:c\\\[42\\\] \\\[len: 344\\\]\\)" 1 "original" } } +// { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(to:c\\\[0\\\] \\\[len: 168\\\]\\)" 1 "original" } } +// { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(to:c\\\[42\\\] \\\[len: 8\\\]\\)" 1 "original" } } +// { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(to:c\\\[2\\\] \\\[len: 168\\\]\\)" 1 "original" } } + +// { dg-final { scan-tree-dump-times "#pragma omp task affinity\\(c\\\[42\\\]\\)" 3 "original" } } +// { dg-final { scan-tree-dump-times "#pragma omp task affinity\\(c\\\[2\\\]\\)" 1 "original" } } +// { dg-final { scan-tree-dump-times "#pragma omp task affinity\\(c\\\[0\\\]\\)" 1 "original" } } diff --git a/gcc/testsuite/g++.dg/gomp/array-section-5.C b/gcc/testsuite/g++.dg/gomp/array-section-5.C new file mode 100644 index 000000000000..80075e6dabfd --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/array-section-5.C @@ -0,0 +1,96 @@ +// { dg-do compile { target c++23_down } } + +// See 'array-section-6.C' for C++26 and higher +// Same test but slightly different error messages. + + +// Check that OpenMP array sections with [: and :] do not get mixed up with C++26's splice specifier, +// used for reflection. +// +// See also OpenMP spec Issue 4740. + + +// The following checks that an additional ':' is diagnosed. +// +// NOTE: When STRIDES are permitted (e.g. for target update) that's actually +// valid but not yet implemented (at the time this test was written) - and +// it is still not valid for 'target enter data' or affinity - as used here. + +void f() { + char a1[4], a2[4], a3[4], a4[5], a5[5], b; + char c1[4], c2[4], c3[4], c4[4], c5[4]; + + #pragma omp target enter data map(b) map(to: a1[::]) // { dg-error "52: expected id-expression before '\\\]' token" } + #pragma omp target enter data map(b) map(to: a2[: :]) // { dg-error "52: expected primary-expression before ':' token" } + #pragma omp target enter data map(b) map(to: a3[ ::]) // { dg-error "53: expected id-expression before '\\\]' token" } + #pragma omp target enter data map(b) map(to: a4[:: ]) // { dg-error "53: expected id-expression before '\\\]' token" } + #pragma omp target enter data map(b) map(to: a5[ :: ]) // { dg-error "54: expected id-expression before '\\\]' token" } + + #pragma omp target enter data map(b) map(to: a1[1::]) + // { dg-error "51: expected '\\\]' before '::' token" "" { target *-*-* } .-1 } + // { dg-error "51: expected '\\)' before '::' token" "" { target *-*-* } .-2 } + // { dg-error "53: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + + #pragma omp target enter data map(b) map(to: a2[1:: ]) + // { dg-error "51: expected '\\\]' before '::' token" "" { target *-*-* } .-1 } + // { dg-error "51: expected '\\)' before '::' token" "" { target *-*-* } .-2 } + // { dg-error "54: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + #pragma omp target enter data map(b) map(to: a3[:1:]) + // { dg-error "52: expected '\\\]' before ':' token" "" { target *-*-* } .-1 } + // { dg-error "52: expected '\\)' before ':' token" "" { target *-*-* } .-2 } + // { dg-error "53: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + #pragma omp target enter data map(b) map(to: a4[ :1: ]) + // { dg-error "53: expected '\\\]' before ':' token" "" { target *-*-* } .-1 } + // { dg-error "53: expected '\\)' before ':' token" "" { target *-*-* } .-2 } + // { dg-error "55: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + #pragma omp target enter data map(b) map(to: a5[ :1:]) + // { dg-error "53: expected '\\\]' before ':' token" "" { target *-*-* } .-1 } + // { dg-error "53: expected '\\)' before ':' token" "" { target *-*-* } .-2 } + // { dg-error "54: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + + + #pragma omp task affinity(c1[::]) // { dg-error "28: expected '\\)' before 'c1'" } + ; + + #pragma omp task affinity(c2[: :]) + ; + // { dg-error "33: expected primary-expression before ':' token" "" { target *-*-* } .-2 } + // { dg-error "32: expected '\\\]' before ':' token" "" { target *-*-* } .-3 } + // { dg-error "34: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-4 } + + #pragma omp task affinity(c3[ ::]) // { dg-error "28: expected '\\)' before 'c3'" } + ; + + #pragma omp task affinity(c4[:: ]) // { dg-error "28: expected '\\)' before 'c4'" } + ; + + #pragma omp task affinity(c5[ :: ]) // { dg-error "28: expected '\\)' before 'c5'" } + ; + + #pragma omp task affinity(c1[1::]) + ; + // { dg-error "32: expected '\\\]' before '::' token" "" { target *-*-* } .-2 } + // { dg-error "32: expected '\\)' before '::' token" "" { target *-*-* } .-3 } + // { dg-error "34: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-4 } + + #pragma omp task affinity(c2[1:: ]) + ; + // { dg-error "32: expected '\\\]' before '::' token" "" { target *-*-* } .-2 } + // { dg-error "32: expected '\\)' before '::' token" "" { target *-*-* } .-3 } + // { dg-error "35: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-4 } + + #pragma omp task affinity(c3[:1:]) + ; + // { dg-error "33: expected '\\\]' before ':' token" "" { target *-*-* } .-2 } + // { dg-error "34: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + + #pragma omp task affinity(c4[ :1: ]) + ; + // { dg-error "34: expected '\\\]' before ':' token" "" { target *-*-* } .-2 } + // { dg-error "36: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + + #pragma omp task affinity(c5[ :1:]) + ; + // { dg-error "34: expected '\\\]' before ':' token" "" { target *-*-* } .-2 } + // { dg-error "35: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } +} diff --git a/gcc/testsuite/g++.dg/gomp/array-section-6.C b/gcc/testsuite/g++.dg/gomp/array-section-6.C new file mode 100644 index 000000000000..163560779835 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/array-section-6.C @@ -0,0 +1,85 @@ +// { dg-do compile { target c++26 } } + +// See 'array-section-5.C' for C++23 and lower +// Same test but slightly different error messages. + + +// Check that OpenMP array sections with [: and :] do not get mixed up with C++26's splice specifier, +// used for reflection. +// +// See also OpenMP spec Issue 4740. + + +// The following checks that an additional ':' is diagnosed. +// +// NOTE: When STRIDES are permitted (e.g. for target update) that's actually +// valid but not yet implemented (at the time this test was written) - and +// it is still not valid for 'target enter data' or affinity - as used here. + +void f() { + char a1[4], a2[4], a3[4], a4[5], a5[5], b; + char c1[4], c2[4], c3[4], c4[4], c5[4]; + + #pragma omp target enter data map(b) map(to: a1[::]) // { dg-error "52: expected id-expression before '\\\]' token" } + #pragma omp target enter data map(b) map(to: a2[: :]) // { dg-error "51: expected '\\\]' before ':\\\]' token" } + #pragma omp target enter data map(b) map(to: a3[ ::]) // { dg-error "53: expected id-expression before '\\\]' token" } + #pragma omp target enter data map(b) map(to: a4[:: ]) // { dg-error "53: expected id-expression before '\\\]' token" } + #pragma omp target enter data map(b) map(to: a5[ :: ]) // { dg-error "54: expected id-expression before '\\\]' token" } + + #pragma omp target enter data map(b) map(to: a1[1::]) + // { dg-error "51: expected '\\\]' before '::' token" "" { target *-*-* } .-1 } + // { dg-error "51: expected '\\)' before '::' token" "" { target *-*-* } .-2 } + // { dg-error "53: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + + #pragma omp target enter data map(b) map(to: a2[1:: ]) + // { dg-error "51: expected '\\\]' before '::' token" "" { target *-*-* } .-1 } + // { dg-error "51: expected '\\)' before '::' token" "" { target *-*-* } .-2 } + // { dg-error "54: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + + #pragma omp target enter data map(b) map(to: a3[:1:]) + // { dg-error "52: expected '\\\]' before ':\\\]' token" "" { target *-*-* } .-1 } + // { dg-error "52: expected '\\)' before ':\\\]' token" "" { target *-*-* } .-2 } + + #pragma omp target enter data map(b) map(to: a4[ :1: ]) + // { dg-error "53: expected '\\\]' before ':' token" "" { target *-*-* } .-1 } + // { dg-error "53: expected '\\)' before ':' token" "" { target *-*-* } .-2 } + // { dg-error "55: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + + #pragma omp target enter data map(b) map(to: a5[ :1:]) + // { dg-error "53: expected '\\\]' before ':\\\]' token" "" { target *-*-* } .-1 } + // { dg-error "53: expected '\\)' before ':\\\]' token" "" { target *-*-* } .-2 } + + #pragma omp task affinity(c1[::]) // { dg-error "28: expected '\\)' before 'c1'" } + ; + #pragma omp task affinity(c2[: :]) // { dg-error "30: expected '\\)' before '\\\[:' token" } + ; + #pragma omp task affinity(c3[ ::]) // { dg-error "28: expected '\\)' before 'c3'" } + ; + #pragma omp task affinity(c4[:: ]) // { dg-error "28: expected '\\)' before 'c4'" } + ; + #pragma omp task affinity(c5[ :: ]) // { dg-error "28: expected '\\)' before 'c5'" } + ; + + #pragma omp task affinity(c1[1::]) + ; + // { dg-error "32: expected '\\\]' before '::' token" "" { target *-*-* } .-2 } + // { dg-error "32: expected '\\)' before '::' token" "" { target *-*-* } .-3 } + // { dg-error "34: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-4 } + + #pragma omp task affinity(c2[1:: ]) + ; + // { dg-error "32: expected '\\\]' before '::' token" "" { target *-*-* } .-2 } + // { dg-error "32: expected '\\)' before '::' token" "" { target *-*-* } .-3 } + // { dg-error "35: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-4 } + + #pragma omp task affinity(c3[:1:]) // { dg-error "33: expected '\\\]' before ':\\\]' token" } + ; + + #pragma omp task affinity(c4[ :1: ]) + ; + // { dg-error "34: expected '\\\]' before ':' token" "" { target *-*-* } .-2 } + // { dg-error "36: expected an OpenMP clause before '\\\]' token" "" { target *-*-* } .-3 } + + #pragma omp task affinity(c5[ :1:]) // { dg-error "34: expected '\\\]' before ':\\\]' token" } + ; +}