[Patch] C++: Handle OpenMP/OpenACC array sections [: / :] with C++26
Tobias Burnus <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
OpenMP/OpenACC supports array sections of the form:
map ( var[start_idx : length] )
where either can be left out (the start index is then 0
and the length is taken from the type, if available.)
Hence, 'var[:n]', var[:], and 'var[3:]' might appear. While with
a space before and after the ':', there is no issue, this changes
when there is no space and C++26 is used. C++26 adds a splicer for
reflections - and uses the for slicer [: and :]. And those get now
lexed as CPP_OPEN_SPLICE and CPP_CLOSE_SPLICE; with C++23 or with
space they are lexed as CPP_OPEN/CLOSE_SQUARE and CPP_COLON.
At least currently, there should be no ambiguity as the C++26
use for splicers with reflections and OpenMP/OpenACC's use of
array sections - as the usage is orthogonal. Therefore, this patch
just handles the new tokens for the array sections.
Once committed, I intent to revert the following commit as follow up:
r16-5330-gedc821b60ce94b OpenMP/OpenACC tests. vs C++26
Comments, remarks, concerns before I commit the patch?ß
And before I revert r16-5330?
Tobias
PS: On the spec side, the issue has been discussed but no action taken;
on the parser-side related (and tracked in the same spec issues) is
'var[::std::max(1,5):::std::min(1,5)]'.
omp-cxx26.diff
(text/x-patch, 13.1 KB)
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_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.
gcc/cp/parser.cc | 79 +++++++++++++++++++++++-----
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 | 16 ++++++
5 files changed, 104 insertions(+), 19 deletions(-)
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index a4cfcfa480e..d274320725f 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,
@@ -9425,12 +9452,18 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
"section");
index = error_mark_node;
}
+
+post_colon_parsing:
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);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ cp_lexer_consume_token (parser->lexer);
tree length = NULL_TREE;
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE)
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SPLICE))
{
if (cxx_dialect >= cxx23)
{
@@ -9469,6 +9502,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
cp_parser_skip_to_closing_square_bracket (parser);
return error_mark_node;
}
+ else if (!open_splice
+ && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SPLICE))
+ cp_lexer_consume_token (parser->lexer);
else
cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
@@ -41847,7 +41883,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;
@@ -41882,25 +41919,34 @@ 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_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))
+ if (!open_splice
+ && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
{
length = integer_one_node;
no_colon = true;
@@ -41908,7 +41954,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))
@@ -41919,7 +41967,8 @@ 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,
+ if (!close_splice &&
+ !cp_lexer_next_token_is (parser->lexer,
CPP_CLOSE_SQUARE))
{
length = cp_parser_expression (parser);
@@ -41928,8 +41977,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 78bd21d1a6f..9a2d678bc10 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 00000000000..9c6ca229501
--- /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 0303b55fa25..e778314f07e 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 00000000000..784d6632422
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/array-section-3.C
@@ -0,0 +1,16 @@
+// { 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];
+
+ #pragma omp target map(to: a1[:], a2[:2], a3[2:], b[1:2], c1[ : ], c2[ : 2], c3[2: ])
+ ;
+}
+
+// { dg-final { scan-tree-dump "#pragma omp target.* 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" } }