Re: [PATCH 2/5] openmp: Support pointer indirection in array-shaping casts and array sections

Paul-Antoine Arras <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
Here is a follow-up patch to the C++ front end that handles ambiguous 
syntaxes implying colons in array sections with strides, including the 
scope and splice notations.
-- 
PA
0001-C-Disambiguate-colon-syntaxes-in-array-sections.patch (text/x-patch, 20.2 KB)
From c628cdfbcea159549d0349bf07abb49fae458fd2 Mon Sep 17 00:00:00 2001
From: Paul-Antoine Arras <[email protected]>
Date: Thu, 6 Aug 2026 20:03:30 +0200
Subject: [PATCH] C++: Disambiguate colon syntaxes in array sections
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The general syntax for array sections is: '[index:length:stride]'; any of the
three components may be omitted. Runs of adjacent colons in this syntax (e.g.
'[::', '[:::', '[::::', trailing '::]') can ambiguously refer to the splice
([:/:]) and scope (::) notations, as well as component separators of the array
section.

While awaiting clarification from the OpenMP committe, this patch adopts the
following stance: "In an intra-clause-specification, if a sequence of two or
more colons appears without separating whitespace, they are treated as follows:
the trailing :: is treated as nested-name-specifier or being part of a
nested-name-specifier – the other colons, if any, as separators according to the
OpenMP syntax."

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_new): Rename omp_array_section_p to
	omp_array_section_kind.
	(cp_parser_statement_expr): Likewise.
	(cp_parser_postfix_expression): Likewise.
	(cp_parser_postfix_open_square_expression): Support scope (::) and
	splice ([:/:]) syntaxes in combination with strides in array sections.
	(cp_parser_parenthesized_expression_list): Rename
	omp_array_section_p to omp_array_section_kind.
	(cp_parser_cast_expression): Likewise.
	(cp_parser_lambda_expression): Likewise.
	(cp_parser_braced_list): Likewise.
	(cp_parser_skip_up_to_closing_square_bracket): Likewise.
	(cp_parser_omp_var_list_no_open): Pass
	OMP_ARRAY_SECTION_STRIDED for 'to'/'from' clauses and
	OMP_ARRAY_SECTION_UNSTRIDED for 'map' clauses, instead of a
	single boolean.
	* parser.h (omp_array_section_p): Replace bool with...
	(omp_array_section_kind): ...this unsigned char.
	(OMP_ARRAY_SECTION_NONE, OMP_ARRAY_SECTION_UNSTRIDED)
	(OMP_ARRAY_SECTION_STRIDED): New macros.

gcc/testsuite/ChangeLog:

	* g++.dg/gomp/array-section-7.C: New test.
	* g++.dg/gomp/array-section-8.C: New test.
---
 gcc/cp/parser.cc                            | 116 +++++++++++++-------
 gcc/cp/parser.h                             |   6 +-
 gcc/testsuite/g++.dg/gomp/array-section-7.C |  36 ++++++
 gcc/testsuite/g++.dg/gomp/array-section-8.C |  57 ++++++++++
 4 files changed, 173 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/gomp/array-section-7.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/array-section-8.C

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 2d5b3c0ed3c..ab672aed649 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -4777,7 +4777,7 @@ cp_parser_new (cp_lexer *lexer)
   parser->oacc_routine = NULL;
 
   /* Disallow OpenMP array sections in expressions.  */
-  parser->omp_array_section_p = false;
+  parser->omp_array_section_kind = false;
 
   /* Disallow OpenMP array-shaping operator in expressions.  */
   parser->omp_array_shaping_op_p = false;
@@ -5815,7 +5815,7 @@ static cp_expr
 cp_parser_statement_expr (cp_parser *parser)
 {
   cp_token_position start = cp_parser_start_tentative_firewall (parser);
-  auto oas = make_temp_override (parser->omp_array_section_p, false);
+  auto oas = make_temp_override (parser->omp_array_section_kind, false);
   auto aso = make_temp_override (parser->omp_array_shaping_op_p, false);
 
   /* Consume the '('.  */
@@ -8926,9 +8926,9 @@ 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)
+	  if (!parser->omp_array_section_kind)
 	    goto default_case;
-	  /* Parse '[: length]' array section.  */
+	  /* Parse '[: length :]' array section.  */
 	  postfix_expression
 	    = cp_parser_postfix_open_square_expression (parser,
 							postfix_expression,
@@ -9289,9 +9289,10 @@ cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
    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.  */
+   array sections of the type [ index : length : stride ] where index,
+   length and stride are optional. Note that an absent index
+   might be lexed as CPP_OPEN_SPLICE ('[:') and an absent stride
+   might be lexed as CPP_CLOSE_SPLICE (':]') since C++26.  */
 
 static tree
 cp_parser_postfix_open_square_expression (cp_parser *parser,
@@ -9310,11 +9311,17 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
   /* Consume the `[' token - or with open_splice the '[:' token.  */
   cp_lexer_consume_token (parser->lexer);
 
+  bool double_scope = cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)
+		      && cp_lexer_nth_token_is (parser->lexer, 2, CPP_SCOPE);
+  bool double_colon_only
+    = cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)
+      && cp_lexer_nth_token_is (parser->lexer, 2, CPP_CLOSE_SQUARE);
+
   saved_greater_than_is_operator_p = parser->greater_than_is_operator_p;
   parser->greater_than_is_operator_p = true;
 
   saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
-  if (parser->omp_array_section_p)
+  if (parser->omp_array_section_kind)
     parser->colon_corrects_to_scope_p = false;
 
   if (open_splice)
@@ -9330,7 +9337,12 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
      constant expressions here.  */
   if (for_offsetof)
     index = cp_parser_constant_expression (parser);
-  else if (!parser->omp_array_section_p
+  else if (parser->omp_array_section_kind == OMP_ARRAY_SECTION_STRIDED
+	   && (double_scope || double_colon_only))
+    {
+      /* Handle '[::::' and '[::]' in post_colon_parsing.  */
+    }
+  else if (!parser->omp_array_section_kind
 	   || (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)
 	       && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SPLICE)))
     {
@@ -9393,6 +9405,14 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
 	  maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
 	  index = cp_parser_braced_list (parser);
 	}
+      else if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)
+	       && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+	{
+	  /* The lexer greedily tokenizes '[:::' as '[ :: :'.
+	     It should be '[ : ::'. Let's swap the last two.  */
+	  cp_lexer_peek_token (parser->lexer)->type = CPP_COLON;
+	  cp_lexer_peek_nth_token (parser->lexer, 2)->type = CPP_SCOPE;
+	}
       else
 	index = cp_parser_expression (parser, NULL, /*cast_p=*/false,
 				      /*decltype_p=*/false,
@@ -9402,8 +9422,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
 post_colon_parsing:
   parser->greater_than_is_operator_p = saved_greater_than_is_operator_p;
 
-  if (cxx_dialect >= cxx23
-      && parser->omp_array_section_p
+  if (cxx_dialect >= cxx23 && parser->omp_array_section_kind
       && expression_list.get () != NULL
       && vec_safe_length (expression_list) > 1)
     {
@@ -9412,15 +9431,16 @@ post_colon_parsing:
       index = error_mark_node;
     }
 
-  if (parser->omp_array_section_p
-      && (open_splice
-	  || cp_lexer_next_token_is (parser->lexer, CPP_COLON)
-	  || cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SPLICE)))
+  if (parser->omp_array_section_kind
+      && (open_splice || cp_lexer_next_token_is (parser->lexer, CPP_COLON)
+	  || cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SPLICE)
+	  || (parser->omp_array_section_kind == OMP_ARRAY_SECTION_STRIDED
+	      && (double_scope || double_colon_only))))
     {
       tree length = NULL_TREE, stride = NULL_TREE;
       bool close_splice = cp_lexer_next_token_is (parser->lexer,
 						  CPP_CLOSE_SPLICE);
-      if (!open_splice)
+      if (!open_splice && !double_scope)
 	cp_lexer_consume_token (parser->lexer);
       if (open_splice && close_splice)
 	{
@@ -9428,19 +9448,24 @@ post_colon_parsing:
 				    UNKNOWN_LOCATION);
 	  length = error_mark_node;
 	}
+      else if (open_splice && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)
+	       && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+	{
+	  /* The lexer greedily tokenizes '[::::' as '[: :: :'.
+	     It should be '[ : : ::'. Let's swap the last two.  */
+	  cp_lexer_peek_token (parser->lexer)->type = CPP_COLON;
+	  cp_lexer_peek_nth_token (parser->lexer, 2)->type = CPP_SCOPE;
+	}
       else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE)
-	       && !close_splice)
+	       && !close_splice && !double_scope)
 	{
 	  if (cxx_dialect >= cxx23)
 	    {
-	      cp_expr expr
-		= cp_parser_parenthesized_expression_list_elt (parser,
-							       /*cast_p=*/
-							       false,
-							       /*allow_exp_p=*/
-							       true,
-							       /*non_cst_p=*/
-							       NULL);
+	      cp_expr expr = cp_parser_parenthesized_expression_list_elt (
+		parser,
+		/*cast_p=*/false,
+		/*allow_exp_p=*/true,
+		/*non_cst_p=*/NULL);
 
 	      if (expr == error_mark_node)
 		length = error_mark_node;
@@ -9450,7 +9475,7 @@ post_colon_parsing:
 	      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 		{
 		  error_at (loc, "cannot use multidimensional subscript in "
-			    "OpenMP array section");
+				 "OpenMP array section");
 		  length = error_mark_node;
 		}
 	    }
@@ -9461,7 +9486,9 @@ post_colon_parsing:
 				      /*warn_comma_p=*/warn_comma_subscript);
 	}
 
-      if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+      if (parser->omp_array_section_kind == OMP_ARRAY_SECTION_STRIDED
+	  && (cp_lexer_next_token_is (parser->lexer, CPP_COLON)
+	      || double_scope))
 	{
 	  cp_lexer_consume_token (parser->lexer);
 	  /* We could check for C++-23 multidimensional/comma-separated
@@ -9482,7 +9509,13 @@ post_colon_parsing:
 	  cp_parser_skip_to_closing_square_bracket (parser);
 	  return error_mark_node;
 	}
-      else if (!close_splice)
+      else if (parser->omp_array_section_kind == OMP_ARRAY_SECTION_STRIDED
+	       && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SPLICE))
+	cp_lexer_consume_token (parser->lexer);
+      else if (!close_splice
+	       && (OMP_ARRAY_SECTION_UNSTRIDED
+		   || cp_lexer_next_token_is_not (parser->lexer,
+						  CPP_CLOSE_SPLICE)))
 	cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
 
       return grok_omp_array_section (input_location, postfix_expression, index,
@@ -9888,9 +9921,9 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
     = parser->greater_than_is_operator_p;
   parser->greater_than_is_operator_p = true;
 
-  saved_omp_array_section_p = parser->omp_array_section_p;
+  saved_omp_array_section_p = parser->omp_array_section_kind;
   saved_omp_array_shaping_op_p = parser->omp_array_shaping_op_p;
-  parser->omp_array_section_p = false;
+  parser->omp_array_section_kind = false;
   parser->omp_array_shaping_op_p = false;
 
   cp_expr expr (NULL_TREE);
@@ -9985,7 +10018,7 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
 	{
 	  parser->greater_than_is_operator_p
 	    = saved_greater_than_is_operator_p;
-	  parser->omp_array_section_p = saved_omp_array_section_p;
+	  parser->omp_array_section_kind = saved_omp_array_section_p;
 	  parser->omp_array_shaping_op_p = saved_omp_array_shaping_op_p;
 	  return NULL;
 	}
@@ -9993,7 +10026,7 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
 
   parser->greater_than_is_operator_p
     = saved_greater_than_is_operator_p;
-  parser->omp_array_section_p = saved_omp_array_section_p;
+  parser->omp_array_section_kind = saved_omp_array_section_p;
   parser->omp_array_shaping_op_p = saved_omp_array_shaping_op_p;
 
   return expression_list;
@@ -11542,7 +11575,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
       else if (parser->omp_array_shaping_op_p
 	       && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
 	{
-	  auto oas = make_temp_override (parser->omp_array_section_p, false);
+	  auto oas = make_temp_override (parser->omp_array_section_kind, false);
 	  auto aso = make_temp_override (parser->omp_array_shaping_op_p, false);
 
 	  while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
@@ -12929,7 +12962,7 @@ cp_parser_lambda_expression (cp_parser* parser,
     cp_binding_level* implicit_template_scope = parser->implicit_template_scope;
     bool auto_is_implicit_function_template_parm_p
         = parser->auto_is_implicit_function_template_parm_p;
-    bool saved_omp_array_section_p = parser->omp_array_section_p;
+    bool saved_omp_array_section_p = parser->omp_array_section_kind;
     bool saved_omp_array_shaping_op_p = parser->omp_array_shaping_op_p;
     bool saved_in_targ = parser->in_template_argument_list_p;
     bool saved_in_declarator_p = parser->in_declarator_p;
@@ -12943,7 +12976,7 @@ cp_parser_lambda_expression (cp_parser* parser,
     parser->implicit_template_parms = 0;
     parser->implicit_template_scope = 0;
     parser->auto_is_implicit_function_template_parm_p = false;
-    parser->omp_array_section_p = false;
+    parser->omp_array_section_kind = false;
     parser->omp_array_shaping_op_p = false;
     parser->in_template_argument_list_p = false;
     parser->in_declarator_p = false;
@@ -13012,7 +13045,7 @@ cp_parser_lambda_expression (cp_parser* parser,
     parser->implicit_template_scope = implicit_template_scope;
     parser->auto_is_implicit_function_template_parm_p
 	= auto_is_implicit_function_template_parm_p;
-    parser->omp_array_section_p = saved_omp_array_section_p;
+    parser->omp_array_section_kind = saved_omp_array_section_p;
     parser->omp_array_shaping_op_p = saved_omp_array_shaping_op_p;
     parser->in_template_argument_list_p = saved_in_targ;
     parser->in_declarator_p = saved_in_declarator_p;
@@ -29194,7 +29227,7 @@ cp_parser_braced_list (cp_parser *parser, bool *non_constant_p /*=nullptr*/)
 {
   tree initializer;
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
-  auto oas = make_temp_override (parser->omp_array_section_p, false);
+  auto oas = make_temp_override (parser->omp_array_section_kind, false);
   auto aso = make_temp_override (parser->omp_array_shaping_op_p, false);
 
   /* Within a brace-enclosed initializer list, a `>' token is always the
@@ -29271,7 +29304,7 @@ cp_parser_skip_up_to_closing_square_bracket (cp_parser *parser)
 	  return false;
 
 	case CPP_OPEN_SPLICE:
-	  if (!parser->omp_array_section_p)
+	  if (!parser->omp_array_section_kind)
 	    break;
 	  /* FALLTHRU */
 
@@ -29280,7 +29313,7 @@ cp_parser_skip_up_to_closing_square_bracket (cp_parser *parser)
           break;
 
 	case CPP_CLOSE_SPLICE:
-	  if (!parser->omp_array_section_p)
+	  if (!parser->omp_array_section_kind)
 	    break;
 	  /* FALLTHRU */
         case CPP_CLOSE_SQUARE:
@@ -41680,7 +41713,10 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 		   || kind == OMP_CLAUSE_TO
 		   || kind == OMP_CLAUSE_FROM))
 	{
-	  auto s = make_temp_override (parser->omp_array_section_p, true);
+	  auto s = make_temp_override (parser->omp_array_section_kind,
+				       kind == OMP_CLAUSE_MAP
+					 ? OMP_ARRAY_SECTION_UNSTRIDED
+					 : OMP_ARRAY_SECTION_STRIDED);
 	  auto o = make_temp_override (parser->omp_array_shaping_op_p,
 				       (kind == OMP_CLAUSE_TO
 					|| kind == OMP_CLAUSE_FROM));
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 2f696502246..19dc0154372 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -425,8 +425,10 @@ struct GTY(()) cp_parser {
      appear.  */
   bool omp_attrs_forbidden_p;
 
-  /* TRUE if an OpenMP array section is allowed.  */
-  bool omp_array_section_p;
+#define OMP_ARRAY_SECTION_NONE 0
+#define OMP_ARRAY_SECTION_UNSTRIDED 1
+#define OMP_ARRAY_SECTION_STRIDED 2
+  unsigned char omp_array_section_kind;
 
   /* TRUE if an OpenMP array-shaping operator is allowed.  */
   bool omp_array_shaping_op_p;
diff --git a/gcc/testsuite/g++.dg/gomp/array-section-7.C b/gcc/testsuite/g++.dg/gomp/array-section-7.C
new file mode 100644
index 00000000000..622e100be29
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/array-section-7.C
@@ -0,0 +1,36 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -fdump-tree-original" }
+
+// Check that the OpenMP stride array-section notation
+// '[ lower : length : stride ]' is not confused with C++26's splice specifier,
+// including when the latter is used to supply one of the section's components.
+
+constexpr int lb0 = 4;
+constexpr auto rlb = ^^lb0;
+constexpr int s0 = 2;
+constexpr auto rs = ^^s0;
+
+void f() {
+  int arr[128];
+  int lb = 4, len = 16, s = 2;
+
+  // baseline: all three components explicit, nothing splice-shaped.
+#pragma omp target update to(arr[lb:len:s])
+
+  // splice-expression supplying the lower bound.
+#pragma omp target update to(arr[[:rlb:]:len:s])
+
+  // splice-expression supplying the stride.
+#pragma omp target update to(arr[lb:len:[:rs:]])
+
+  // Stride left empty: the trailing ':' + ']' is lexed as a single
+  // CPP_CLOSE_SPLICE token.
+#pragma omp target update to(arr[lb:len:])
+#pragma omp target update to(arr[:len:])
+}
+
+// { dg-final { scan-tree-dump "map\\(to_grid:arr \\\[len: 4\\\]\\) map\\(grid_dim:SAVE_EXPR <lb> \\\[len: len\\\]\\) map\\(grid_stride:s\\)" "original" } }
+// { dg-final { scan-tree-dump "map\\(to_grid:arr \\\[len: 4\\\]\\) map\\(grid_dim:4 \\\[len: len\\\]\\) map\\(grid_stride:s\\)" "original" } }
+// { dg-final { scan-tree-dump "map\\(to_grid:arr \\\[len: 4\\\]\\) map\\(grid_dim:SAVE_EXPR <lb> \\\[len: len\\\]\\) map\\(grid_stride:2\\)" "original" } }
+// { dg-final { scan-tree-dump "to\\(arr\\\[SAVE_EXPR <lb>\\\] \\\[len: \\(sizetype\\) len \\* 4\\\]\\)" "original" } }
+// { dg-final { scan-tree-dump "to\\(arr\\\[0\\\] \\\[len: \\(sizetype\\) len \\* 4\\\]\\)" "original" } }
diff --git a/gcc/testsuite/g++.dg/gomp/array-section-8.C b/gcc/testsuite/g++.dg/gomp/array-section-8.C
new file mode 100644
index 00000000000..08f07e000de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/array-section-8.C
@@ -0,0 +1,57 @@
+// { dg-do compile }
+// { dg-additional-options "-fdump-tree-original" }
+
+// Check parsing of double colon (::). In case of ambiguity between the scope
+// resolution operator and the array section syntax, spaces are required.
+
+int lb2 = 4;
+int len2 = 16;
+int s2 = 2;
+
+void g() {
+  int arr[128];
+  int lb = 4, len = 16, s = 2;
+
+#pragma omp target update to(arr[lb::s])
+// { dg-error "34: 'lb' is not a class" "" { target *-*-* } .-1 }
+// { dg-error "must contain at least one" "" { target *-*-* } .-2 }
+
+#pragma omp target update to(arr[::s])
+// { dg-error "36: '::s' has not been declared" "" { target *-*-* } .-1 }
+// { dg-error "must contain at least one" "" { target *-*-* } .-2 }
+
+#pragma omp target update to(arr[lb::])
+// { dg-error "34: 'lb' is not a class" "" { target *-*-* } .-1 }
+// { dg-error "38: expected unqualified-id before '\\\]' token" "" { target *-*-* } .-2 }
+// { dg-error "must contain at least one" "" { target *-*-* } .-3 }
+
+  // Valid: default values.
+#pragma omp target update to(arr[::])
+// { dg-final { scan-tree-dump "to\\(arr\\\[0\\\] \\\[len: 512\\\]\\)" "original" } }
+
+  // Valid: len2 is looked up in the global namespace and forms the length of the
+  // array section.
+#pragma omp target update to(arr[:::len2])
+#pragma omp target update to(arr[:::len2:])
+// { dg-final { scan-tree-dump-times "to\\(arr\\\[0\\\] \\\[len: \\(sizetype\\) len2 \\* 4\\\]\\)" 2 "original" } }
+
+  // Valid: s2 is looked up in the global namespace and forms the stride of the
+  // array section.
+#pragma omp target update to(arr[::::s2])
+// { dg-final { scan-tree-dump "map\\(to_grid:arr \\\[len: 4\\\]\\) map\\(grid_dim:0 \\\[len: 1\\\]\\) map\\(grid_stride:s2\\)" "original" } }
+
+  // Valid: lb2 is looked up in the global namespace and forms the lower bound
+  // of the array section.
+#pragma omp target update to(arr[::lb2:])
+// { dg-final { scan-tree-dump "to\\(arr\\\[SAVE_EXPR <lb2>\\\] \\\[len: \\(128 - \\(sizetype\\) SAVE_EXPR <lb2>\\) \\* 4\\\]\\)" "original" } }
+
+#pragma omp target update to(arr[::lb2::])
+// { dg-error "36: '::lb2' is not a class" "" { target *-*-* } .-1 }
+// { dg-error "41: expected unqualified-id before '\\\]' token" "" { target *-*-* } .-2 }
+// { dg-error "must contain at least one" "" { target *-*-* } .-3 }
+
+#pragma omp target update to(arr[::lb2::s2])
+// { dg-error "36: '::lb2' is not a class" "" { target *-*-* } .-1 }
+// { dg-error "must contain at least one" "" { target *-*-* } .-2 }
+
+}
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.