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" }
+  ;
+}

Reply via email to