public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 15/16] OpenMP: lvalue parsing for map clauses (C++)
@ 2021-11-25 14:11 Julian Brown
  2021-11-25 14:11 ` [PATCH 16/16] OpenMP: lvalue parsing for map clauses (C) Julian Brown
  0 siblings, 1 reply; 2+ messages in thread
From: Julian Brown @ 2021-11-25 14:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jakub Jelinek, Thomas Schwinge

This patch changes parsing for OpenMP map clauses in C++ to use the
generic expression parser, hence adds support for parsing general
lvalues (as required by OpenMP 5.0+).  So far only a few new types of
expression are actually supported throughout compilation (including
everything in the testsuite of course, and newly-added tests), and we
attempt to reject unsupported expressions in order to avoid surprises
for the user.

This version of the patch adds a number of additional tests for various
expressions accepted as lvalues in C++, many of which are currently
rejected as not yet supported -- and really only a handful of the
rejected cases would be plausible in the context of an OpenMP "map"
clause anyway, IMO.

OK?

Thanks,

Julian

2021-11-24  Julian Brown  <julian@codesourcery.com>

gcc/c-family/
	* c-omp.c (c_omp_decompose_attachable_address): Handle
	more types of expressions.

gcc/cp/
	* error.c (dump_expr): Handle OMP_ARRAY_SECTION.
	* parser.c (cp_parser_new): Initialize parser->omp_array_section_p.
	(cp_parser_postfix_open_square_expression): Support OMP_ARRAY_SECTION
	parsing.
	(cp_parser_omp_var_list_no_open): Remove ALLOW_DEREF parameter, add
	MAP_LVALUE in its place.  Supported generalised lvalue parsing for map
	clauses.
	(cp_parser_omp_var_list): Remove ALLOW_DEREF parameter, add MAP_LVALUE.
	Pass to cp_parser_omp_var_list_no_open.
	(cp_parser_oacc_data_clause, cp_parser_omp_all_clauses): Update calls
	to cp_parser_omp_var_list.
	* parser.h (cp_parser): Add omp_array_section_p field.
	* semantics.c (handle_omp_array_sections_1): Handle more types of map
	expression.
	(handle_omp_array_section): Handle non-DECL_P attachment points.
	(finish_omp_clauses): Check for supported types of expression.

gcc/
	* gimplify.c (build_struct_group): Handle reference-typed component
	accesses.  Fix support for non-DECL_P struct bases.
	(omp_build_struct_sibling_lists): Support length-two group for
	synthesized inner struct mapping.
	* tree-pretty-print.c (dump_generic_node): Support OMP_ARRAY_SECTION.
	* tree.def (OMP_ARRAY_SECTION): New tree code.

gcc/testsuite/
	* c-c++-common/gomp/map-6.c: Update expected output.
	* g++.dg/gomp/pr67522.C: Likewise.
	* g++.dg/gomp/ind-base-3.C: New test.
	* g++.dg/gomp/map-assignment-1.C: New test.
	* g++.dg/gomp/map-inc-1.C: New test.
	* g++.dg/gomp/map-lvalue-ref-1.C: New test.
	* g++.dg/gomp/map-ptrmem-1.C: New test.
	* g++.dg/gomp/map-ptrmem-2.C: New test.
	* g++.dg/gomp/map-static-cast-lvalue-1.C: New test.
	* g++.dg/gomp/map-ternary-1.C: New test.
	* g++.dg/gomp/member-array-2.C: New test.

libgomp/
	* testsuite/libgomp.c++/ind-base-1.C: New test.
	* testsuite/libgomp.c++/ind-base-2.C: New test.
	* testsuite/libgomp.c++/map-comma-1.C: New test.
	* testsuite/libgomp.c++/map-rvalue-ref-1.C: New test.
	* testsuite/libgomp.c++/member-array-1.C: New test.
	* testsuite/libgomp.c++/struct-ref-1.C: New test.
---
 gcc/c-family/c-omp.c                          |  25 ++-
 gcc/cp/error.c                                |   9 +
 gcc/cp/parser.c                               | 141 +++++++++++++--
 gcc/cp/parser.h                               |   3 +
 gcc/cp/semantics.c                            |  35 +++-
 gcc/gimplify.c                                |  37 +++-
 gcc/testsuite/c-c++-common/gomp/map-6.c       |   4 +-
 gcc/testsuite/g++.dg/gomp/ind-base-3.C        |  38 ++++
 gcc/testsuite/g++.dg/gomp/map-assignment-1.C  |  12 ++
 gcc/testsuite/g++.dg/gomp/map-inc-1.C         |  10 ++
 gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C  |  19 ++
 gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C      |  36 ++++
 gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C      |  39 +++++
 .../g++.dg/gomp/map-static-cast-lvalue-1.C    |  17 ++
 gcc/testsuite/g++.dg/gomp/map-ternary-1.C     |  20 +++
 gcc/testsuite/g++.dg/gomp/member-array-2.C    |  86 ++++++++++
 gcc/testsuite/g++.dg/gomp/pr67522.C           |   2 +-
 gcc/tree-pretty-print.c                       |  14 ++
 gcc/tree.def                                  |   3 +
 libgomp/testsuite/libgomp.c++/ind-base-1.C    | 162 ++++++++++++++++++
 libgomp/testsuite/libgomp.c++/ind-base-2.C    |  49 ++++++
 libgomp/testsuite/libgomp.c++/map-comma-1.C   |  15 ++
 .../testsuite/libgomp.c++/map-rvalue-ref-1.C  |  22 +++
 .../testsuite/libgomp.c++/member-array-1.C    |  89 ++++++++++
 libgomp/testsuite/libgomp.c++/struct-ref-1.C  |  97 +++++++++++
 25 files changed, 956 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/gomp/ind-base-3.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/map-assignment-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/map-inc-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/map-ternary-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/member-array-2.C
 create mode 100644 libgomp/testsuite/libgomp.c++/ind-base-1.C
 create mode 100644 libgomp/testsuite/libgomp.c++/ind-base-2.C
 create mode 100644 libgomp/testsuite/libgomp.c++/map-comma-1.C
 create mode 100644 libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C
 create mode 100644 libgomp/testsuite/libgomp.c++/member-array-1.C
 create mode 100644 libgomp/testsuite/libgomp.c++/struct-ref-1.C

diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index 5b2fbf6809b..808688cac8c 100644
--- a/gcc/c-family/c-omp.c
+++ b/gcc/c-family/c-omp.c
@@ -3265,12 +3265,18 @@ c_omp_decompose_attachable_address (tree t, tree *virtbase)
 {
   *virtbase = t;
 
-  /* It's already a pointer.  Just use that.  */
-  if (POINTER_TYPE_P (TREE_TYPE (t)))
+  /* It's already a non-offset pointer.  Just use that.  */
+  if (POINTER_TYPE_P (TREE_TYPE (t))
+      && (DECL_P (t)
+	  || TREE_CODE (t) == COMPONENT_REF
+	  || TREE_CODE (t) == ARRAY_REF))
     return NULL_TREE;
 
   /* Otherwise, look for a base pointer deeper within the expression.  */
 
+  while (TREE_CODE (t) == COMPOUND_EXPR)
+    t = TREE_OPERAND (t, 1);
+
   while (TREE_CODE (t) == COMPONENT_REF
 	 && (TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF
 	     || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF))
@@ -3280,9 +3286,24 @@ c_omp_decompose_attachable_address (tree t, tree *virtbase)
 	t = TREE_OPERAND (t, 0);
     }
 
+  if (TREE_CODE (t) == POINTER_PLUS_EXPR)
+    {
+      t = TREE_OPERAND (t, 0);
+      if (TREE_CODE (t) == SAVE_EXPR)
+	t = TREE_OPERAND (t, 0);
+    }
+
+  if (TREE_CODE (t) == INDIRECT_REF
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == REFERENCE_TYPE)
+    t = TREE_OPERAND (t, 0);
 
   *virtbase = t;
 
+  /* If we have a pointer now (e.g. after we've stripped POINTER_PLUS_EXPR),
+     we have an offset pointer.  That's the attachment point.  */
+  if (POINTER_TYPE_P (TREE_TYPE (t)))
+    return t;
+
   if (TREE_CODE (t) != COMPONENT_REF)
     return NULL_TREE;
 
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 012a4ecddf4..141c959d1bb 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2415,6 +2415,15 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
       pp_cxx_right_bracket (pp);
       break;
 
+    case OMP_ARRAY_SECTION:
+      dump_expr (pp, TREE_OPERAND (t, 0), flags);
+      pp_cxx_left_bracket (pp);
+      dump_expr (pp, TREE_OPERAND (t, 1), flags);
+      pp_colon (pp);
+      dump_expr (pp, TREE_OPERAND (t, 2), flags);
+      pp_cxx_right_bracket (pp);
+      break;
+
     case UNARY_PLUS_EXPR:
       dump_unary_op (pp, "+", t, flags);
       break;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ed047022c40..8954e50e065 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4241,6 +4241,9 @@ cp_parser_new (cp_lexer *lexer)
   parser->omp_declare_simd = NULL;
   parser->oacc_routine = NULL;
 
+  /* Allow array slice in expression.  */
+  parser->omp_array_section_p = false;
+
   /* Not declaring an implicit function template.  */
   parser->auto_is_implicit_function_template_parm_p = false;
   parser->fully_implicit_function_template_p = false;
@@ -7901,6 +7904,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
   tree index = NULL_TREE;
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
   bool saved_greater_than_is_operator_p;
+  bool saved_colon_corrects_to_scope_p;
 
   /* Consume the `[' token.  */
   cp_lexer_consume_token (parser->lexer);
@@ -7908,6 +7912,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
   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;
+  parser->colon_corrects_to_scope_p = false;
+
   /* 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,
@@ -7918,7 +7925,8 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
      constant expressions here.  */
   if (for_offsetof)
     index = cp_parser_constant_expression (parser);
-  else
+  else if (!parser->omp_array_section_p
+	   || cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
     {
       if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
 	{
@@ -7935,6 +7943,32 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
 
   parser->greater_than_is_operator_p = saved_greater_than_is_operator_p;
 
+  if (parser->omp_array_section_p
+      && 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))
+	length = cp_parser_expression (parser);
+
+      parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+
+      if ((index && error_operand_p (index))
+	  || (length && error_operand_p (length)))
+	return error_mark_node;
+
+      cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+
+      /* NOTE: We are reusing using the type of the whole array as the type of
+	 the array section here, which isn't necessarily entirely correct.
+	 Might need revisiting.  */
+      return build3_loc (input_location, OMP_ARRAY_SECTION,
+			 TREE_TYPE (postfix_expression),
+			 postfix_expression, index, length);
+    }
+
+  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+
   /* Look for the closing `]'.  */
   cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
 
@@ -36335,7 +36369,7 @@ struct omp_dim
 static tree
 cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 				tree list, bool *colon,
-				bool allow_deref = false)
+				bool map_lvalue = false)
 {
   auto_vec<omp_dim> dims;
   bool array_section_p;
@@ -36346,12 +36380,95 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
       parser->colon_corrects_to_scope_p = false;
       *colon = false;
     }
+  begin_scope (sk_omp, NULL);
   while (1)
     {
       tree name, decl;
 
       if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
 	cp_parser_parse_tentatively (parser);
+      else if (map_lvalue && kind == OMP_CLAUSE_MAP)
+	{
+	  auto s = make_temp_override (parser->omp_array_section_p, true);
+	  token = cp_lexer_peek_token (parser->lexer);
+	  location_t loc = token->location;
+	  decl = cp_parser_assignment_expression (parser);
+
+	  dims.truncate (0);
+	  if (TREE_CODE (decl) == OMP_ARRAY_SECTION)
+	    {
+	      while (TREE_CODE (decl) == OMP_ARRAY_SECTION)
+		{
+		  tree low_bound = TREE_OPERAND (decl, 1);
+		  tree length = TREE_OPERAND (decl, 2);
+		  dims.safe_push (omp_dim (low_bound, length, loc, false));
+		  decl = TREE_OPERAND (decl, 0);
+		}
+
+	      while (TREE_CODE (decl) == ARRAY_REF
+		     || TREE_CODE (decl) == INDIRECT_REF
+		     || TREE_CODE (decl) == COMPOUND_EXPR)
+		{
+		  if (REFERENCE_REF_P (decl))
+		    break;
+
+		  if (TREE_CODE (decl) == COMPOUND_EXPR)
+		    {
+		      decl = TREE_OPERAND (decl, 1);
+		      STRIP_NOPS (decl);
+		    }
+		  else if (TREE_CODE (decl) == INDIRECT_REF)
+		    {
+		      dims.safe_push (omp_dim (integer_zero_node,
+					       integer_one_node, loc, true));
+		      decl = TREE_OPERAND (decl, 0);
+		    }
+		  else  /* ARRAY_REF. */
+		    {
+		      tree index = TREE_OPERAND (decl, 1);
+		      dims.safe_push (omp_dim (index, integer_one_node, loc,
+					       true));
+		      decl = TREE_OPERAND (decl, 0);
+		    }
+		}
+
+	      /* Bare references have their own special handling, so remove
+		 the explicit dereference added by convert_from_reference.  */
+	      if (REFERENCE_REF_P (decl))
+		decl = TREE_OPERAND (decl, 0);
+
+	      for (int i = dims.length () - 1; i >= 0; i--)
+		decl = tree_cons (dims[i].low_bound, dims[i].length, decl);
+	    }
+	  else if (TREE_CODE (decl) == INDIRECT_REF)
+	    {
+	      bool ref_p = REFERENCE_REF_P (decl);
+
+	      /* Turn *foo into the representation previously used for
+		 foo[0].  */
+	      decl = TREE_OPERAND (decl, 0);
+	      STRIP_NOPS (decl);
+
+	      /* ...but don't add the [0:1] representation for references
+		 (because they have special handling elsewhere).  */
+	      if (!ref_p)
+		decl = tree_cons (integer_zero_node, integer_one_node, decl);
+	    }
+	  else if (TREE_CODE (decl) == ARRAY_REF)
+	    {
+	      tree idx = TREE_OPERAND (decl, 1);
+
+	      decl = TREE_OPERAND (decl, 0);
+	      STRIP_NOPS (decl);
+
+	      decl = tree_cons (idx, integer_one_node, decl);
+	    }
+	  else if (TREE_CODE (decl) == NON_LVALUE_EXPR
+		   || CONVERT_EXPR_P (decl))
+	    decl = TREE_OPERAND (decl, 0);
+
+	  goto build_clause;
+	}
       token = cp_lexer_peek_token (parser->lexer);
       if (kind != 0
 	  && cp_parser_is_keyword (token, RID_THIS))
@@ -36421,8 +36538,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 	    case OMP_CLAUSE_TO:
 	    start_component_ref:
 	      while (cp_lexer_next_token_is (parser->lexer, CPP_DOT)
-		     || (allow_deref
-			 && cp_lexer_next_token_is (parser->lexer, CPP_DEREF)))
+		     || cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
 		{
 		  cpp_ttype ttype
 		    = cp_lexer_next_token_is (parser->lexer, CPP_DOT)
@@ -36508,9 +36624,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 		   || kind == OMP_CLAUSE_TO)
 		  && !array_section_p
 		  && (cp_lexer_next_token_is (parser->lexer, CPP_DOT)
-		      || (allow_deref
-			  && cp_lexer_next_token_is (parser->lexer,
-						     CPP_DEREF))))
+		      || cp_lexer_next_token_is (parser->lexer, CPP_DEREF)))
 		{
 		  for (unsigned i = 0; i < dims.length (); i++)
 		    {
@@ -36546,6 +36660,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 		cp_parser_parse_definitely (parser);
 	    }
 
+	build_clause:
 	  tree u = build_omp_clause (token->location, kind);
 	  OMP_CLAUSE_DECL (u) = decl;
 	  OMP_CLAUSE_CHAIN (u) = list;
@@ -36567,6 +36682,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
     {
       *colon = true;
       cp_parser_require (parser, CPP_COLON, RT_COLON);
+      finish_scope ();
       return list;
     }
 
@@ -36587,6 +36703,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 	goto get_comma;
     }
 
+  finish_scope ();
   return list;
 }
 
@@ -36595,11 +36712,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 
 static tree
 cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list,
-			bool allow_deref = false)
+			bool map_lvalue = false)
 {
   if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
     return cp_parser_omp_var_list_no_open (parser, kind, list, NULL,
-					   allow_deref);
+					   map_lvalue);
   return list;
 }
 
@@ -36666,7 +36783,7 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind,
       gcc_unreachable ();
     }
   tree nl, c;
-  nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, true);
+  nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, false);
 
   for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
     OMP_CLAUSE_SET_MAP_KIND (c, kind);
@@ -40028,12 +40145,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
 					      clauses);
 	  else
 	    clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses,
-					      true);
+					      false);
 	  c_name = "to";
 	  break;
 	case PRAGMA_OMP_CLAUSE_FROM:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses,
-					    true);
+					    false);
 	  c_name = "from";
 	  break;
 	case PRAGMA_OMP_CLAUSE_UNIFORM:
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 3669587cebd..bebf8e6b16a 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -404,6 +404,9 @@ struct GTY(()) cp_parser {
   /* TRUE if omp::directive or omp::sequence attributes may not appear.  */
   bool omp_attrs_forbidden_p;
 
+  /* TRUE if an OpenMP array section is allowed.  */
+  bool omp_array_section_p;
+
   /* Tracks the function's template parameter list when declaring a function
      using generic type parameters.  This is either a new chain in the case of a
      fully implicit function template or an extension of the function's existing
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index a95eb1adcb5..34e0d84c534 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5073,7 +5073,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
       ret = t_insp.get_deref_toplevel ();
       if (TREE_CODE (t) == FIELD_DECL)
 	ret = finish_non_static_data_member (t, NULL_TREE, NULL_TREE);
-      else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+      else if (!VAR_P (t)
+	       && (ort == C_ORT_ACC || !EXPR_P (t))
+	       && TREE_CODE (t) != PARM_DECL)
 	{
 	  if (processing_template_decl && TREE_CODE (t) != OVERLOAD)
 	    return NULL_TREE;
@@ -5647,7 +5649,9 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 	  bool reference_always_pointer = true;
 	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
 				      OMP_CLAUSE_MAP);
-	  if (TREE_CODE (t) == COMPONENT_REF)
+	  if (TREE_CODE (t) == COMPONENT_REF
+	      || (TREE_CODE (t) == POINTER_PLUS_EXPR
+		  && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF))
 	    {
 	      OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
 
@@ -5677,6 +5681,13 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 		}
 	      OMP_CLAUSE_SET_MAP_KIND (c2, k);
 	    }
+	  else if (ort != C_ORT_ACC && attach_pt && !DECL_P (attach_pt))
+	    {
+	      if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+		return false;
+
+	      OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
+	    }
 	  else
 	    OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER);
 	  OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c);
@@ -7909,6 +7920,15 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		    {
 		      t = t_insp.analyze_components (false);
 
+		      if (!t_insp.map_supported_p ())
+			{
+			  sorry_at (OMP_CLAUSE_LOCATION (c),
+				    "unsupported map expression %qE",
+				    OMP_CLAUSE_DECL (c));
+			  remove = true;
+			  break;
+			}
+
 		      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 			  && OMP_CLAUSE_MAP_IMPLICIT (c)
 			  && (bitmap_bit_p (&map_head, DECL_UID (t))
@@ -7990,6 +8010,14 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      OMP_CLAUSE_DECL (c) = t_insp.get_deref_toplevel ();
 	    if (type_dependent_expression_p (t_insp.get_deref_toplevel ()))
 	      break;
+	    if (!t_insp.map_supported_p ())
+	      {
+		sorry_at (OMP_CLAUSE_LOCATION (c),
+			  "unsupported map expression %qE",
+			  OMP_CLAUSE_DECL (c));
+		remove = true;
+		break;
+	      }
 	    if (t == error_mark_node)
 	      {
 		remove = true;
@@ -8019,7 +8047,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 		  && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
 		      || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER
-		      || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH))
+		      || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH
+		      || (ort != C_ORT_ACC && EXPR_P (t))))
 		break;
 	      if (DECL_P (t))
 		error_at (OMP_CLAUSE_LOCATION (c),
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 8f07da8a991..c9f66be3119 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -9812,6 +9812,7 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code,
     {
       tree l = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), OMP_CLAUSE_MAP);
       gomp_map_kind k = attach ? GOMP_MAP_FORCE_PRESENT : GOMP_MAP_STRUCT;
+      tree *tail_chain;
 
       OMP_CLAUSE_SET_MAP_KIND (l, k);
 
@@ -9840,9 +9841,13 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code,
 	    {
 	      OMP_CLAUSE_CHAIN (extra_node) = *insert_node_pos;
 	      OMP_CLAUSE_CHAIN (alloc_node) = extra_node;
+	      tail_chain = &OMP_CLAUSE_CHAIN (extra_node);
 	    }
 	  else
-	    OMP_CLAUSE_CHAIN (alloc_node) = *insert_node_pos;
+	    {
+	      OMP_CLAUSE_CHAIN (alloc_node) = *insert_node_pos;
+	      tail_chain = &OMP_CLAUSE_CHAIN (alloc_node);
+	    }
 
 	  *insert_node_pos = l;
 	}
@@ -9850,6 +9855,7 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code,
 	{
 	  gcc_assert (*grp_start_p == grp_end);
 	  grp_start_p = insert_node_after (l, grp_start_p);
+	  tail_chain = &OMP_CLAUSE_CHAIN (*grp_start_p);
 	}
 
       tree noind = strip_indirections (base);
@@ -9914,8 +9920,7 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code,
 	     || TREE_CODE (sdecl) == POINTER_PLUS_EXPR)
 	sdecl = TREE_OPERAND (sdecl, 0);
 
-      if (DECL_P (sdecl)
-	  && POINTER_TYPE_P (TREE_TYPE (sdecl))
+      if (POINTER_TYPE_P (TREE_TYPE (sdecl))
 	  && (region_type & ORT_TARGET))
 	{
 	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end),
@@ -9929,8 +9934,12 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code,
 		       && (TREE_CODE (TREE_TYPE (TREE_OPERAND
 						  (TREE_OPERAND (base, 0), 0)))
 			   == REFERENCE_TYPE))));
-	  enum gomp_map_kind mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE
-					      : GOMP_MAP_FIRSTPRIVATE_POINTER;
+	  enum gomp_map_kind mkind;
+	  if (DECL_P (sdecl))
+	    mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE
+			     : GOMP_MAP_FIRSTPRIVATE_POINTER;
+	  else
+	    mkind = GOMP_MAP_ATTACH;
 	  OMP_CLAUSE_SET_MAP_KIND (c2, mkind);
 	  OMP_CLAUSE_DECL (c2) = sdecl;
 	  tree baddr = build_fold_addr_expr (base);
@@ -9946,9 +9955,21 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code,
 	  OMP_CLAUSE_SIZE (c2)
 	    = fold_build2_loc (OMP_CLAUSE_LOCATION (grp_end), MINUS_EXPR,
 			       ptrdiff_type_node, baddr, decladdr);
-	  /* Insert after struct node.  */
-	  OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l);
-	  OMP_CLAUSE_CHAIN (l) = c2;
+	  if (mkind == GOMP_MAP_FIRSTPRIVATE_POINTER
+	      || mkind == GOMP_MAP_FIRSTPRIVATE_REFERENCE)
+	    {
+	      /* Insert after struct node.  */
+	      OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l);
+	      OMP_CLAUSE_CHAIN (l) = c2;
+	    }
+	  else  /* GOMP_MAP_ATTACH.  */
+	    {
+	      /* Insert after struct group.  */
+	      OMP_CLAUSE_CHAIN (c2) = *tail_chain;
+	      *tail_chain = c2;
+	      if (*grp_start_p == grp_end)
+		return &OMP_CLAUSE_CHAIN (*tail_chain);
+	    }
 	}
 
       return NULL;
diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c
index 6ee59714847..c749db845b0 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-6.c
@@ -20,12 +20,12 @@ foo (void)
   ;
 
   #pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */ 
-  /* { dg-error "'close' has not been declared" "" { target c++ } .-1 } */ 
+  /* { dg-error "'close' was not declared in this scope" "" { target c++ } .-1 } */ 
   /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */
   ;
 
   #pragma omp target map (always a) /* { dg-error "'always' undeclared" "" { target c } } */
-  /* { dg-error "'always' has not been declared" "" { target c++ } .-1 } */ 
+  /* { dg-error "'always' was not declared in this scope" "" { target c++ } .-1 } */ 
   /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */
   ;
 
diff --git a/gcc/testsuite/g++.dg/gomp/ind-base-3.C b/gcc/testsuite/g++.dg/gomp/ind-base-3.C
new file mode 100644
index 00000000000..dbabaf7680c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/ind-base-3.C
@@ -0,0 +1,38 @@
+#include <cassert>
+
+struct S {
+  int x[10];
+};
+
+S *
+choose (S *a, S *b, int c)
+{
+  if (c < 5)
+    return a;
+  else
+    return b; 
+}
+
+int main (int argc, char *argv[])
+{
+  S a, b;
+
+  for (int i = 0; i < 10; i++)
+    a.x[i] = b.x[i] = 0;
+
+  for (int i = 0; i < 10; i++)
+    {
+#pragma omp target map(choose(&a, &b, i)->x[:10])
+/* { dg-message {sorry, unimplemented: unsupported map expression 'choose\(\(& a\), \(& b\), i\)->S::x\[0\]'} "" { target *-*-* } .-1 } */
+/* { dg-message {sorry, unimplemented: unsupported map expression 'choose\(\(& a\), \(& b\), i\)'} "" { target *-*-* } .-2 } */
+      for (int j = 0; j < 10; j++)
+        choose (&a, &b, i)->x[j]++;
+    }
+
+  for (int i = 0; i < 10; i++)
+    assert (a.x[i] == 5 && b.x[i] == 5);
+
+  return 0;
+}
+
+
diff --git a/gcc/testsuite/g++.dg/gomp/map-assignment-1.C b/gcc/testsuite/g++.dg/gomp/map-assignment-1.C
new file mode 100644
index 00000000000..5979ec379f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-assignment-1.C
@@ -0,0 +1,12 @@
+#include <cassert>
+
+int main (int argc, char *argv[])
+{
+  int a = 5, b = 2;
+#pragma omp target map(a += b)
+  /* { dg-message {sorry, unimplemented: unsupported map expression '\(a = \(a \+ b\)\)'} "" { target *-*-* } .-1 } */
+  {
+    a++;
+  }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-inc-1.C b/gcc/testsuite/g++.dg/gomp/map-inc-1.C
new file mode 100644
index 00000000000..b469a4bd548
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-inc-1.C
@@ -0,0 +1,10 @@
+int main (int argc, char *argv[])
+{
+  int a = 5;
+#pragma omp target map(++a)
+  /* { dg-message {sorry, unimplemented: unsupported map expression '\+\+ a'} "" { target *-*-* } .-1 } */
+  {
+    a++;
+  }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C b/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C
new file mode 100644
index 00000000000..d720d4318ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C
@@ -0,0 +1,19 @@
+#include <cassert>
+
+int glob = 10;
+
+int& foo ()
+{
+  return glob;
+}
+
+int main (int argc, char *argv[])
+{
+#pragma omp target map(foo())
+  /* { dg-message {sorry, unimplemented: unsupported map expression 'foo\(\)'} "" { target *-*-* } .-1 } */
+  {
+    foo()++;
+  }
+  assert (glob == 11);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C b/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C
new file mode 100644
index 00000000000..f5f5949a1ca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C
@@ -0,0 +1,36 @@
+#include <cassert>
+
+struct S {
+  int x;
+  int *ptr;
+};
+
+int
+main (int argc, char *argv[])
+{
+  S s;
+  int S::* xp = &S::x;
+  int* S::* ptrp = &S::ptr;
+
+  s.ptr = new int[64];
+
+  s.*xp = 6;
+  for (int i = 0; i < 64; i++)
+    (s.*ptrp)[i] = i;
+
+#pragma omp target map(s.*xp, s.*ptrp, (s.*ptrp)[:64])
+  /* { dg-message {sorry, unimplemented: unsupported map expression '\(int\*\*\)\(& s\)'} "" { target *-*-* } .-1 } */
+  /* { dg-message {sorry, unimplemented: unsupported map expression '\(int\*\)\(& s\)'} "" { target *-*-* } .-2 } */
+#pragma omp teams distribute parallel for
+  for (int i = 0; i < 64; i++)
+    {
+      (s.*xp)++;
+      (s.*ptrp)[i]++;
+    }
+
+  assert (s.*xp == 70);
+  for (int i = 0; i < 64; i++)
+    assert ((s.*ptrp)[i] == i + 1);
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C b/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C
new file mode 100644
index 00000000000..7fdf742b2ca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C
@@ -0,0 +1,39 @@
+#include <cassert>
+
+struct S {
+  int x;
+  int *ptr;
+};
+
+int
+main (int argc, char *argv[])
+{
+  S *s = new S;
+  int S::* xp = &S::x;
+  int* S::* ptrp = &S::ptr;
+
+  s->ptr = new int[64];
+
+  s->*xp = 4;
+  for (int i = 0; i < 64; i++)
+    (s->*ptrp)[i] = i;
+
+#pragma omp target map(s->*xp, s->*ptrp, (s->*ptrp)[:64])
+  /* { dg-message {sorry, unimplemented: unsupported map expression '\(int\*\*\)s'} "" { target *-*-* } .-1 } */
+  /* { dg-message {sorry, unimplemented: unsupported map expression '\(int\*\)s'} "" { target *-*-* } .-2 } */
+#pragma omp teams distribute parallel for
+  for (int i = 0; i < 64; i++)
+    {
+      (s->*xp)++;
+      (s->*ptrp)[i]++;
+    }
+
+  assert (s->*xp == 68);
+  for (int i = 0; i < 64; i++)
+    assert ((s->*ptrp)[i] == i + 1);
+
+  delete s->ptr;
+  delete s;
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C b/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C
new file mode 100644
index 00000000000..3af9668202c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C
@@ -0,0 +1,17 @@
+#include <cassert>
+
+int foo (int x)
+{
+#pragma omp target map(static_cast<int&>(x))
+  /* { dg-message {sorry, unimplemented: unsupported map expression '& x'} "" { target *-*-* } .-1 } */
+  {
+    x += 3;
+  }
+  return x;
+}
+
+int main (int argc, char *argv[])
+{
+  assert (foo (5) == 8);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-ternary-1.C b/gcc/testsuite/g++.dg/gomp/map-ternary-1.C
new file mode 100644
index 00000000000..7b365a909bb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-ternary-1.C
@@ -0,0 +1,20 @@
+#include <cassert>
+
+int foo (bool yesno)
+{
+  int x = 5, y = 7;
+#pragma omp target map(yesno ? x : y)
+  /* { dg-message {sorry, unimplemented: unsupported map expression '\(yesno \?  x :  y\)'} "" { target *-*-* } .-1 } */
+  {
+    x += 3;
+    y += 5;
+  }
+  return yesno ? x : y;
+}
+
+int main (int argc, char *argv[])
+{
+  assert (foo (true) == 8);
+  assert (foo (false) == 12);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/member-array-2.C b/gcc/testsuite/g++.dg/gomp/member-array-2.C
new file mode 100644
index 00000000000..ba931bd585e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/member-array-2.C
@@ -0,0 +1,86 @@
+#include <cassert>
+
+typedef int intarr100[100];
+
+class C {
+  int arr[100];
+  int *ptr;
+
+public:
+  C();
+  ~C();
+  void zero ();
+  void do_operation ();
+  void check (int, int);
+  intarr100 &get_arr () { return arr; }
+  int *get_ptr() { return ptr; }
+};
+
+C::C()
+{
+  ptr = new int[100];
+  for (int i = 0; i < 100; i++)
+    arr[i] = 0;
+}
+
+C::~C()
+{
+  delete ptr;
+}
+
+void
+C::zero ()
+{
+  for (int i = 0; i < 100; i++)
+    arr[i] = ptr[i] = 0;
+}
+
+void
+C::do_operation ()
+{
+#pragma omp target map(arr, ptr, ptr[:100])
+#pragma omp teams distribute parallel for
+  for (int i = 0; i < 100; i++)
+    {
+      arr[i] = arr[i] + 3;
+      ptr[i] = ptr[i] + 5;
+    }
+}
+
+void
+C::check (int arrval, int ptrval)
+{
+  for (int i = 0; i < 100; i++)
+    {
+      assert (arr[i] == arrval);
+      assert (ptr[i] == ptrval);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  C c;
+
+  c.zero ();
+  c.do_operation ();
+  c.check (3, 5);
+
+  #pragma omp target map(c.get_arr()[:100])
+  #pragma omp teams distribute parallel for
+    for (int i = 0; i < 100; i++)
+      c.get_arr()[i] += 2;
+
+  c.check (5, 5);
+
+  #pragma omp target map(c.get_ptr(), c.get_ptr()[:100])
+  /* { dg-message {sorry, unimplemented: unsupported map expression 'c\.C::get_ptr\(\)'} "" { target *-*-* } .-1 } */
+  #pragma omp teams distribute parallel for
+    for (int i = 0; i < 100; i++)
+      c.get_ptr()[i] += 3;
+
+  c.check (5, 8);
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/gomp/pr67522.C b/gcc/testsuite/g++.dg/gomp/pr67522.C
index da8cb74d1fa..4a901ba68c7 100644
--- a/gcc/testsuite/g++.dg/gomp/pr67522.C
+++ b/gcc/testsuite/g++.dg/gomp/pr67522.C
@@ -12,7 +12,7 @@ foo (void)
   for (int i = 0; i < 16; i++)
     ;
 
-  #pragma omp target map (S[0:10])		// { dg-error "is not a variable in" }
+  #pragma omp target map (S[0:10])		// { dg-error "expected primary-expression before '\\\[' token" }
   ;
 
   #pragma omp task depend (inout: S[0:10])	// { dg-error "is not a variable in" }
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 13b64fd52e1..387fc3e132c 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -2516,6 +2516,20 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
 	}
       break;
 
+    case OMP_ARRAY_SECTION:
+      op0 = TREE_OPERAND (node, 0);
+      if (op_prio (op0) < op_prio (node))
+	pp_left_paren (pp);
+      dump_generic_node (pp, op0, spc, flags, false);
+      if (op_prio (op0) < op_prio (node))
+	pp_right_paren (pp);
+      pp_left_bracket (pp);
+      dump_generic_node (pp, TREE_OPERAND (node, 1), spc, flags, false);
+      pp_colon (pp);
+      dump_generic_node (pp, TREE_OPERAND (node, 2), spc, flags, false);
+      pp_right_bracket (pp);
+      break;
+
     case CONSTRUCTOR:
       {
 	unsigned HOST_WIDE_INT ix;
diff --git a/gcc/tree.def b/gcc/tree.def
index e27bc3e2b1f..9824840ec00 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -1304,6 +1304,9 @@ DEFTREECODE (OMP_ATOMIC_CAPTURE_NEW, "omp_atomic_capture_new", tcc_statement, 2)
 /* OpenMP clauses.  */
 DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0)
 
+/* An OpenMP array section.  */
+DEFTREECODE (OMP_ARRAY_SECTION, "omp_array_section", tcc_expression, 3)
+
 /* TRANSACTION_EXPR tree code.
    Operand 0: BODY: contains body of the transaction.  */
 DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 1)
diff --git a/libgomp/testsuite/libgomp.c++/ind-base-1.C b/libgomp/testsuite/libgomp.c++/ind-base-1.C
new file mode 100644
index 00000000000..4566854e60a
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/ind-base-1.C
@@ -0,0 +1,162 @@
+// { dg-do run }
+// { dg-options "-fopenmp" }
+
+#include <cassert>
+
+struct S
+{
+  int x[10];
+};
+
+struct T
+{
+  struct S *s;
+};
+
+struct U
+{
+  struct T *t;
+};
+
+void
+foo_siblist (void)
+{
+  U *u = new U;
+  u->t = new T;
+  u->t->s = new S;
+  for (int i = 0; i < 10; i++)
+    u->t->s->x[i] = 0;
+#pragma omp target map(u->t, *(u->t), u->t->s, *u->t->s)
+  for (int i = 0; i < 10; i++)
+    u->t->s->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert (u->t->s->x[i] == i * 3);
+  delete u->t->s;
+  delete u->t;
+  delete u;
+}
+
+void
+foo (void)
+{
+  U *u = new U;
+  u->t = new T;
+  u->t->s = new S;
+  for (int i = 0; i < 10; i++)
+    u->t->s->x[i] = 0;
+#pragma omp target map(*u, u->t, *(u->t), u->t->s, *u->t->s)
+  for (int i = 0; i < 10; i++)
+    u->t->s->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert (u->t->s->x[i] == i * 3);
+  delete u->t->s;
+  delete u->t;
+  delete u;
+}
+
+void
+foo_tofrom (void)
+{
+  U *u = new U;
+  u->t = new T;
+  u->t->s = new S;
+  for (int i = 0; i < 10; i++)
+    u->t->s->x[i] = 0;
+#pragma omp target map(u, *u, u->t, *(u->t), u->t->s, *u->t->s)
+  for (int i = 0; i < 10; i++)
+    u->t->s->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert (u->t->s->x[i] == i * 3);
+  delete u->t->s;
+  delete u->t;
+  delete u;
+}
+
+void
+bar (void)
+{
+  U *u = new U;
+  U **up = &u;
+  u->t = new T;
+  u->t->s = new S;
+  for (int i = 0; i < 10; i++)
+    (*up)->t->s->x[i] = 0;
+#pragma omp target map(*up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s)
+  for (int i = 0; i < 10; i++)
+    (*up)->t->s->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert ((*up)->t->s->x[i] == i * 3);
+  delete u->t->s;
+  delete u->t;
+  delete u;
+}
+
+void
+bar_pp (void)
+{
+  U *u = new U;
+  U **up = &u;
+  u->t = new T;
+  u->t->s = new S;
+  for (int i = 0; i < 10; i++)
+    (*up)->t->s->x[i] = 0;
+#pragma omp target map(*up, **up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s)
+  for (int i = 0; i < 10; i++)
+    (*up)->t->s->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert ((*up)->t->s->x[i] == i * 3);
+  delete u->t->s;
+  delete u->t;
+  delete u;
+}
+
+void
+bar_tofrom (void)
+{
+  U *u = new U;
+  U **up = &u;
+  u->t = new T;
+  u->t->s = new S;
+  for (int i = 0; i < 10; i++)
+    (*up)->t->s->x[i] = 0;
+#pragma omp target map(*up, up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s)
+  for (int i = 0; i < 10; i++)
+    (*up)->t->s->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert ((*up)->t->s->x[i] == i * 3);
+  delete u->t->s;
+  delete u->t;
+  delete u;
+}
+
+void
+bar_tofrom_pp (void)
+{
+  U *u = new U;
+  U **up = &u;
+  u->t = new T;
+  u->t->s = new S;
+  for (int i = 0; i < 10; i++)
+    (*up)->t->s->x[i] = 0;
+#pragma omp target map(**up, *up, up, (*up)->t, *(*up)->t, (*up)->t->s, \
+		       *(*up)->t->s)
+  for (int i = 0; i < 10; i++)
+    (*up)->t->s->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert ((*up)->t->s->x[i] == i * 3);
+  delete u->t->s;
+  delete u->t;
+  delete u;
+}
+
+int main (int argc, char *argv[])
+{
+  foo_siblist ();
+  foo ();
+  foo_tofrom ();
+  bar ();
+  bar_pp ();
+  bar_tofrom ();
+  bar_tofrom_pp ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/ind-base-2.C b/libgomp/testsuite/libgomp.c++/ind-base-2.C
new file mode 100644
index 00000000000..706a1205c00
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/ind-base-2.C
@@ -0,0 +1,49 @@
+// { dg-do run }
+// { dg-options "-fopenmp" }
+
+#include <cassert>
+
+struct S
+{
+  int x[10];
+};
+
+struct T
+{
+  struct S ***s;
+};
+
+struct U
+{
+  struct T **t;
+};
+
+void
+foo (void)
+{
+  U *u = new U;
+  T *real_t = new T;
+  S *real_s = new S;
+  T **t_pp = &real_t;
+  S **s_pp = &real_s;
+  S ***s_ppp = &s_pp;
+  u->t = t_pp;
+  (*u->t)->s = s_ppp;
+  for (int i = 0; i < 10; i++)
+    (**((*u->t)->s))->x[i] = 0;
+#pragma omp target map(u->t, *u->t, (*u->t)->s, *(*u->t)->s, **(*u->t)->s, \
+		       (**(*u->t)->s)->x[0:10])
+  for (int i = 0; i < 10; i++)
+    (**((*u->t)->s))->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert ((**((*u->t)->s))->x[i] == i * 3);
+  delete real_s;
+  delete real_t;
+  delete u;
+}
+
+int main (int argc, char *argv[])
+{
+  foo ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/map-comma-1.C b/libgomp/testsuite/libgomp.c++/map-comma-1.C
new file mode 100644
index 00000000000..ee03c5ac1aa
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/map-comma-1.C
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+
+#include <cassert>
+
+int main (int argc, char *argv[])
+{
+  int a = 5, b = 7;
+#pragma omp target map((a, b))
+  {
+    a++;
+    b++;
+  }
+  assert (a == 5 && b == 8);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C b/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C
new file mode 100644
index 00000000000..93811da4000
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+
+#include <cassert>
+
+int foo (int &&x)
+{
+  int y;
+#pragma omp target map(x, y)
+  {
+    x++;
+    y = x;
+  }
+  return y;
+}
+
+int main (int argc, char *argv[])
+{
+  int y = 5;
+  y = foo (y + 3);
+  assert (y == 9);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/member-array-1.C b/libgomp/testsuite/libgomp.c++/member-array-1.C
new file mode 100644
index 00000000000..ee11d45562e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/member-array-1.C
@@ -0,0 +1,89 @@
+/* { dg-do run } */
+
+#include <cassert>
+
+typedef int intarr100[100];
+
+class C {
+  int arr[100];
+  int *ptr;
+
+public:
+  C();
+  ~C();
+  void zero ();
+  void do_operation ();
+  void check (int, int);
+  intarr100 &get_arr () { return arr; }
+  int *get_ptr() { return ptr; }
+};
+
+C::C()
+{
+  ptr = new int[100];
+  for (int i = 0; i < 100; i++)
+    arr[i] = 0;
+}
+
+C::~C()
+{
+  delete ptr;
+}
+
+void
+C::zero ()
+{
+  for (int i = 0; i < 100; i++)
+    arr[i] = ptr[i] = 0;
+}
+
+void
+C::do_operation ()
+{
+#pragma omp target map(arr, ptr, ptr[:100])
+#pragma omp teams distribute parallel for
+  for (int i = 0; i < 100; i++)
+    {
+      arr[i] = arr[i] + 3;
+      ptr[i] = ptr[i] + 5;
+    }
+}
+
+void
+C::check (int arrval, int ptrval)
+{
+  for (int i = 0; i < 100; i++)
+    {
+      assert (arr[i] == arrval);
+      assert (ptr[i] == ptrval);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  C c;
+
+  c.zero ();
+  c.do_operation ();
+  c.check (3, 5);
+
+  #pragma omp target map(c.get_arr()[:100])
+  #pragma omp teams distribute parallel for
+    for (int i = 0; i < 100; i++)
+      c.get_arr()[i] += 2;
+
+  c.check (5, 5);
+
+  /* This is currently not supported. See also:
+      gcc/testsuite/g++.dg/gomp/member-array-2.C.  */
+  //#pragma omp target map(c.get_ptr(), c.get_ptr()[:100])
+  //#pragma omp teams distribute parallel for
+    for (int i = 0; i < 100; i++)
+      c.get_ptr()[i] += 3;
+
+  c.check (5, 8);
+
+  return 0;
+}
+
diff --git a/libgomp/testsuite/libgomp.c++/struct-ref-1.C b/libgomp/testsuite/libgomp.c++/struct-ref-1.C
new file mode 100644
index 00000000000..d3874650017
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/struct-ref-1.C
@@ -0,0 +1,97 @@
+// { dg-do run }
+// { dg-options "-fopenmp" }
+
+#include <cassert>
+
+struct S
+{
+  int x[10];
+};
+
+void
+foo (S *s, int x)
+{
+  S *&r = s;
+  for (int i = 0; i < x; i++)
+    s[0].x[i] = s[1].x[i] = 0;
+  #pragma omp target map (s, x)
+    ;
+  #pragma omp target map (s[0], x)
+  for (int i = 0; i < x; i++)
+    s[0].x[i] = i;
+  #pragma omp target map (s[1], x)
+  for (int i = 0; i < x; i++)
+    s[1].x[i] = i * 2;
+  for (int i = 0; i < x; i++)
+    {
+      assert (s[0].x[i] == i);
+      assert (s[1].x[i] == i * 2);
+      s[0].x[i] = 0;
+      s[1].x[i] = 0;
+    }
+  #pragma omp target map (r, x)
+    ;
+  #pragma omp target map (r[0], x)
+  for (int i = 0; i < x; i++)
+    r[0].x[i] = i;
+  #pragma omp target map (r[1], x)
+  for (int i = 0; i < x; i++)
+    r[1].x[i] = i * 2;
+  for (int i = 0; i < x; i++)
+    {
+      assert (r[0].x[i] == i);
+      assert (r[1].x[i] == i * 2);
+    }
+}
+
+template <int N>
+struct T
+{
+  int x[N];
+};
+
+template <int N>
+void
+bar (T<N> *t, int x)
+{
+  T<N> *&r = t;
+  for (int i = 0; i < x; i++)
+    t[0].x[i] = t[1].x[i] = 0;
+  #pragma omp target map (t, x)
+    ;
+  #pragma omp target map (t[0], x)
+  for (int i = 0; i < x; i++)
+    t[0].x[i] = i;
+  #pragma omp target map (t[1], x)
+  for (int i = 0; i < x; i++)
+    t[1].x[i] = i * 2;
+  for (int i = 0; i < x; i++)
+    {
+      assert (t[0].x[i] == i);
+      assert (t[1].x[i] == i * 2);
+      t[0].x[i] = 0;
+      t[1].x[i] = 0;
+    }
+  #pragma omp target map (r, x)
+    ;
+  #pragma omp target map (r[0], x)
+  for (int i = 0; i < x; i++)
+    r[0].x[i] = i;
+  #pragma omp target map (r[1], x)
+  for (int i = 0; i < x; i++)
+    r[1].x[i] = i * 2;
+  for (int i = 0; i < x; i++)
+    {
+      assert (r[0].x[i] == i);
+      assert (r[1].x[i] == i * 2);
+    }
+}
+
+int main (int argc, char *argv[])
+{
+  S s[2];
+  foo (s, 10);
+  T<10> t[2];
+  bar (t, 10);
+  return 0;
+}
-- 
2.29.2


^ permalink raw reply	[flat|nested] 2+ messages in thread

* [PATCH 16/16] OpenMP: lvalue parsing for map clauses (C)
  2021-11-25 14:11 [PATCH 15/16] OpenMP: lvalue parsing for map clauses (C++) Julian Brown
@ 2021-11-25 14:11 ` Julian Brown
  0 siblings, 0 replies; 2+ messages in thread
From: Julian Brown @ 2021-11-25 14:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jakub Jelinek, Thomas Schwinge

This patch adds support for parsing general lvalues for OpenMP "map"
clauses to the C front-end, similar to the previous patch for C++.

This version of the patch fixes several omissions regarding non-DECL_P
root terms in map clauses (i.e. "*foo" in "(*foo)->ptr->arr[:N]") --
similar to the cp/semantics.c changes in the previous patch -- and adds
a couple of new tests.

OK?

Thanks,

Julian

2021-11-24  Julian Brown  <julian@codesourcery.com>

gcc/c/
	* c-parser.c (c_parser_postfix_expression_after_primary): Add support
	for OpenMP array section parsing.
	(c_parser_omp_variable_list): Change ALLOW_DEREF parameter to
	MAP_LVALUE.  Support parsing of general lvalues in "map" clauses.
	(c_parser_omp_var_list_parens): Change ALLOW_DEREF parameter to
	MAP_LVALUE.  Update call to c_parser_omp_variable_list.
	(c_parser_oacc_data_clause, c_parser_omp_clause_to,
	c_parser_omp_clause_from): Update calls to
	c_parser_omp_var_list_parens.
	* c-tree.h (c_omp_array_section_p): Add extern declaration.
	* c-typeck.c (c_omp_array_section_p): Add flag.
	(mark_exp_read): Support OMP_ARRAY_SECTION.
	(handle_omp_array_sections_1): Handle more kinds of expressions.
	(handle_omp_array_sections): Handle non-DECL_P attachment points.
	(c_finish_omp_clauses): Check for supported expression types.  Support
	non-DECL_P root term for map clauses.

gcc/testsuite/
	* c-c++-common/gomp/map-1.c: Adjust expected output.
	* c-c++-common/gomp/map-6.c: Likewise.

libgomp/
	* testsuite/libgomp.c-c++-common/ind-base-4.c: New test.
	* testsuite/libgomp.c-c++-common/unary-ptr-1.c: New test.
---
 gcc/c/c-parser.c                              | 150 +++++++++++++++---
 gcc/c/c-tree.h                                |   1 +
 gcc/c/c-typeck.c                              |  45 +++++-
 gcc/testsuite/c-c++-common/gomp/map-1.c       |   3 +-
 gcc/testsuite/c-c++-common/gomp/map-6.c       |   2 +
 .../libgomp.c-c++-common/ind-base-4.c         |  50 ++++++
 .../libgomp.c-c++-common/unary-ptr-1.c        |  16 ++
 7 files changed, 243 insertions(+), 24 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 322f30c90b4..702a0b7d8a9 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -10460,7 +10460,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
 					   struct c_expr expr)
 {
   struct c_expr orig_expr;
-  tree ident, idx;
+  tree ident, idx, len;
   location_t sizeof_arg_loc[3], comp_loc;
   tree sizeof_arg[3];
   unsigned int literal_zero_mask;
@@ -10479,15 +10479,44 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
 	case CPP_OPEN_SQUARE:
 	  /* Array reference.  */
 	  c_parser_consume_token (parser);
-	  idx = c_parser_expression (parser).value;
-	  c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
-				     "expected %<]%>");
-	  start = expr.get_start ();
-	  finish = parser->tokens_buf[0].location;
-	  expr.value = build_array_ref (op_loc, expr.value, idx);
-	  set_c_expr_source_range (&expr, start, finish);
-	  expr.original_code = ERROR_MARK;
-	  expr.original_type = NULL;
+	  idx = len = NULL_TREE;
+	  if (!c_omp_array_section_p
+	      || c_parser_next_token_is_not (parser, CPP_COLON))
+	    idx = c_parser_expression (parser).value;
+
+	  if (c_omp_array_section_p
+	      && c_parser_next_token_is (parser, CPP_COLON))
+	    {
+	      c_parser_consume_token (parser);
+	      if (c_parser_next_token_is_not (parser, CPP_CLOSE_SQUARE))
+		len = c_parser_expression (parser).value;
+
+	      c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+					 "expected %<]%>");
+
+	     /* NOTE: We are reusing using the type of the whole array as the
+		type of the array section here, which isn't necessarily
+		entirely correct.  Might need revisiting.  */
+	      start = expr.get_start ();
+	      finish = parser->tokens_buf[0].location;
+	      expr.value = build3_loc (op_loc, OMP_ARRAY_SECTION,
+				       TREE_TYPE (expr.value), expr.value,
+				       idx, len);
+	      set_c_expr_source_range (&expr, start, finish);
+	      expr.original_code = ERROR_MARK;
+	      expr.original_type = NULL;
+	    }
+	  else
+	    {
+	      c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+					 "expected %<]%>");
+	      start = expr.get_start ();
+	      finish = parser->tokens_buf[0].location;
+	      expr.value = build_array_ref (op_loc, expr.value, idx);
+	      set_c_expr_source_range (&expr, start, finish);
+	      expr.original_code = ERROR_MARK;
+	      expr.original_type = NULL;
+	    }
 	  break;
 	case CPP_OPEN_PAREN:
 	  /* Function call.  */
@@ -12983,7 +13012,7 @@ static tree
 c_parser_omp_variable_list (c_parser *parser,
 			    location_t clause_loc,
 			    enum omp_clause_code kind, tree list,
-			    bool allow_deref = false)
+			    bool map_lvalue = false)
 {
   auto_vec<c_token> tokens;
   unsigned int tokens_avail = 0;
@@ -12993,6 +13022,8 @@ c_parser_omp_variable_list (c_parser *parser,
     {
       auto_vec<omp_dim> dims;
       bool array_section_p = false;
+      tree t = NULL_TREE;
+
       if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
 	{
 	  if (c_parser_next_token_is_not (parser, CPP_NAME)
@@ -13061,8 +13092,84 @@ c_parser_omp_variable_list (c_parser *parser,
 	  parser->tokens = tokens.address ();
 	  parser->tokens_avail = tokens.length ();
 	}
+      else if (map_lvalue && kind == OMP_CLAUSE_MAP)
+	{
+	  location_t loc = c_parser_peek_token (parser)->location;
+	  bool save_c_omp_array_section_p = c_omp_array_section_p;
+	  c_omp_array_section_p = true;
+	  c_expr expr = c_parser_expr_no_commas (parser, NULL);
+	  if (expr.value != error_mark_node)
+	    mark_exp_read (expr.value);
+	  c_omp_array_section_p = save_c_omp_array_section_p;
+	  tree decl = expr.value;
 
-      tree t = NULL_TREE;
+	  dims.truncate (0);
+	  if (TREE_CODE (decl) == OMP_ARRAY_SECTION)
+	    {
+	      while (TREE_CODE (decl) == OMP_ARRAY_SECTION)
+		{
+		  tree low_bound = TREE_OPERAND (decl, 1);
+		  tree length = TREE_OPERAND (decl, 2);
+		  dims.safe_push (omp_dim (low_bound, length, loc, false));
+		  decl = TREE_OPERAND (decl, 0);
+		}
+
+	      while (TREE_CODE (decl) == ARRAY_REF
+		     || TREE_CODE (decl) == INDIRECT_REF
+		     || TREE_CODE (decl) == COMPOUND_EXPR)
+		{
+		  if (TREE_CODE (decl) == COMPOUND_EXPR)
+		    {
+		      decl = TREE_OPERAND (decl, 1);
+		      STRIP_NOPS (decl);
+		    }
+		  else if (TREE_CODE (decl) == INDIRECT_REF)
+		    {
+		      dims.safe_push (omp_dim (integer_zero_node,
+					       integer_one_node, loc, true));
+		      decl = TREE_OPERAND (decl, 0);
+		    }
+		  else  /* ARRAY_REF. */
+		    {
+		      tree index = TREE_OPERAND (decl, 1);
+		      dims.safe_push (omp_dim (index, integer_one_node, loc,
+					       true));
+		      decl = TREE_OPERAND (decl, 0);
+		    }
+		}
+
+	      for (int i = dims.length () - 1; i >= 0; i--)
+		decl = tree_cons (dims[i].low_bound, dims[i].length, decl);
+	    }
+	  else if (TREE_CODE (decl) == INDIRECT_REF)
+	    {
+	      /* Turn *foo into the representation previously used for
+		 foo[0].  */
+	      decl = TREE_OPERAND (decl, 0);
+	      STRIP_NOPS (decl);
+
+	      decl = tree_cons (integer_zero_node, integer_one_node, decl);
+	    }
+	  else if (TREE_CODE (decl) == ARRAY_REF)
+	    {
+	      tree idx = TREE_OPERAND (decl, 1);
+
+	      decl = TREE_OPERAND (decl, 0);
+	      STRIP_NOPS (decl);
+
+	      decl = tree_cons (idx, integer_one_node, decl);
+	    }
+	  else if (TREE_CODE (decl) == NON_LVALUE_EXPR
+		   || CONVERT_EXPR_P (decl))
+	    decl = TREE_OPERAND (decl, 0);
+
+	  tree u = build_omp_clause (clause_loc, kind);
+	  OMP_CLAUSE_DECL (u) = decl;
+	  OMP_CLAUSE_CHAIN (u) = list;
+	  list = u;
+
+	  goto next_item;
+	}
 
       if (c_parser_next_token_is (parser, CPP_NAME)
 	  && c_parser_peek_token (parser)->id_kind == C_ID_ID)
@@ -13113,8 +13220,7 @@ c_parser_omp_variable_list (c_parser *parser,
 	    case OMP_CLAUSE_TO:
 	    start_component_ref:
 	      while (c_parser_next_token_is (parser, CPP_DOT)
-		     || (allow_deref
-			 && c_parser_next_token_is (parser, CPP_DEREF)))
+		     || c_parser_next_token_is (parser, CPP_DEREF))
 		{
 		  location_t op_loc = c_parser_peek_token (parser)->location;
 		  if (c_parser_next_token_is (parser, CPP_DEREF))
@@ -13201,9 +13307,7 @@ c_parser_omp_variable_list (c_parser *parser,
 		       || kind == OMP_CLAUSE_TO)
 		      && !array_section_p
 		      && (c_parser_next_token_is (parser, CPP_DOT)
-			  || (allow_deref
-			      && c_parser_next_token_is (parser,
-							 CPP_DEREF))))
+			  || c_parser_next_token_is (parser, CPP_DEREF)))
 		    {
 		      for (unsigned i = 0; i < dims.length (); i++)
 			{
@@ -13265,6 +13369,8 @@ c_parser_omp_variable_list (c_parser *parser,
 	  parser->tokens = &parser->tokens_buf[0];
 	  parser->tokens_avail = tokens_avail;
 	}
+
+    next_item:
       if (c_parser_next_token_is_not (parser, CPP_COMMA))
 	break;
 
@@ -13281,7 +13387,7 @@ c_parser_omp_variable_list (c_parser *parser,
 
 static tree
 c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
-			      tree list, bool allow_deref = false)
+			      tree list, bool map_lvalue = false)
 {
   /* The clauses location.  */
   location_t loc = c_parser_peek_token (parser)->location;
@@ -13289,7 +13395,7 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
   matching_parens parens;
   if (parens.require_open (parser))
     {
-      list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref);
+      list = c_parser_omp_variable_list (parser, loc, kind, list, map_lvalue);
       parens.skip_until_found_close (parser);
     }
   return list;
@@ -13358,7 +13464,7 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind,
       gcc_unreachable ();
     }
   tree nl, c;
-  nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, true);
+  nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list);
 
   for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
     OMP_CLAUSE_SET_MAP_KIND (c, kind);
@@ -16466,7 +16572,7 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list)
 static tree
 c_parser_omp_clause_to (c_parser *parser, tree list)
 {
-  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true);
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list);
 }
 
 /* OpenMP 4.0:
@@ -16475,7 +16581,7 @@ c_parser_omp_clause_to (c_parser *parser, tree list)
 static tree
 c_parser_omp_clause_from (c_parser *parser, tree list)
 {
-  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true);
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list);
 }
 
 /* OpenMP 4.0:
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index f1dbbd5d573..cd76ea077b9 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -673,6 +673,7 @@ extern int in_alignof;
 extern int in_sizeof;
 extern int in_typeof;
 extern bool c_in_omp_for;
+extern bool c_omp_array_section_p;
 
 extern tree c_last_sizeof_arg;
 extern location_t c_last_sizeof_loc;
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 3a9f129181b..a27d5e1ef9f 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -75,6 +75,9 @@ int in_typeof;
 /* True when parsing OpenMP loop expressions.  */
 bool c_in_omp_for;
 
+/* True when parsing OpenMP map clause.  */
+bool c_omp_array_section_p;
+
 /* The argument of last parsed sizeof expression, only to be tested
    if expr.original_code == SIZEOF_EXPR.  */
 tree c_last_sizeof_arg;
@@ -2020,6 +2023,13 @@ mark_exp_read (tree exp)
     case C_MAYBE_CONST_EXPR:
       mark_exp_read (TREE_OPERAND (exp, 1));
       break;
+    case OMP_ARRAY_SECTION:
+      mark_exp_read (TREE_OPERAND (exp, 0));
+      if (TREE_OPERAND (exp, 1))
+	mark_exp_read (TREE_OPERAND (exp, 1));
+      if (TREE_OPERAND (exp, 2))
+	mark_exp_read (TREE_OPERAND (exp, 2));
+      break;
     default:
       break;
     }
@@ -13228,7 +13238,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 	t = t_insp.get_outer_virtual_base ();
       if (t == error_mark_node)
 	return error_mark_node;
-      if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+      if (!VAR_P (t)
+	  && (ort == C_ORT_ACC || !EXPR_P (t))
+	  && TREE_CODE (t) != PARM_DECL)
 	{
 	  if (DECL_P (t))
 	    error_at (OMP_CLAUSE_LOCATION (c),
@@ -13792,6 +13804,13 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
       tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
       if (TREE_CODE (t) == COMPONENT_REF)
 	OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
+      else if (ort != C_ORT_ACC && attach_pt && !DECL_P (attach_pt))
+	{
+	  if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+	    return false;
+
+	  OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
+	}
       else
 	OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER);
       OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c);
@@ -14886,6 +14905,15 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		    {
 		      t = t_insp.analyze_components (false);
 
+		      if (!t_insp.map_supported_p ())
+			{
+			  sorry_at (OMP_CLAUSE_LOCATION (c),
+				    "unsupported map expression %qE",
+				    OMP_CLAUSE_DECL (c));
+			  remove = true;
+			  break;
+			}
+
 		      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 			  && OMP_CLAUSE_MAP_IMPLICIT (c)
 			  && (bitmap_bit_p (&map_head, DECL_UID (t))
@@ -14936,6 +14964,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  if (t == error_mark_node)
 	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"unmappable expression in %qs clause",
+			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	      remove = true;
 	      break;
 	    }
@@ -14963,6 +14994,15 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    else
 	      t = t_insp.get_outer_virtual_base ();
 
+	    if (!t_insp.map_supported_p ())
+	      {
+		sorry_at (OMP_CLAUSE_LOCATION (c),
+			  "unsupported map expression %qE",
+			  OMP_CLAUSE_DECL (c));
+		remove = true;
+		break;
+	      }
+
 	    if (t == error_mark_node)
 	      {
 		remove = true;
@@ -14983,6 +15023,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 
 	  if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
 	    {
+	      if (ort != C_ORT_ACC && EXPR_P (t))
+		break;
+
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qE is not a variable in %qs clause", t,
 			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
diff --git a/gcc/testsuite/c-c++-common/gomp/map-1.c b/gcc/testsuite/c-c++-common/gomp/map-1.c
index ed88944da7b..57baa4fd285 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-1.c
@@ -39,7 +39,8 @@ foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
     ;
   #pragma omp target map(alloc: s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
     ;
-  #pragma omp target map(alloc: s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+  #pragma omp target map(alloc: s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" "" { target c++ } } */
+  /* { dg-error "unmappable expression in 'map' clause" "" { target c } .-1 } */
     ;
   #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression must be specified" } */
     bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */
diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c
index c749db845b0..19db264e805 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-6.c
@@ -22,11 +22,13 @@ foo (void)
   #pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */ 
   /* { dg-error "'close' was not declared in this scope" "" { target c++ } .-1 } */ 
   /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */
+  /* { dg-error "unmappable expression in 'map' clause" "" { target c } .-3 } */
   ;
 
   #pragma omp target map (always a) /* { dg-error "'always' undeclared" "" { target c } } */
   /* { dg-error "'always' was not declared in this scope" "" { target c++ } .-1 } */ 
   /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */
+  /* { dg-error "unmappable expression in 'map' clause" "" { target c } .-3 } */
   ;
 
   #pragma omp target map (close to:a)
diff --git a/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c b/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c
new file mode 100644
index 00000000000..91549ac4d24
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c
@@ -0,0 +1,50 @@
+// { dg-do run }
+// { dg-options "-fopenmp" }
+
+#include <assert.h>
+#include <stdlib.h>
+
+typedef struct
+{
+  int x[10];
+} S;
+
+typedef struct
+{
+  S ***s;
+} T;
+
+typedef struct
+{
+  T **t;
+} U;
+
+void
+foo (void)
+{
+  U *u = (U *) malloc (sizeof (U));
+  T *real_t = (T *) malloc (sizeof (T));
+  S *real_s = (S *) malloc (sizeof (S));
+  T **t_pp = &real_t;
+  S **s_pp = &real_s;
+  S ***s_ppp = &s_pp;
+  u->t = t_pp;
+  (*u->t)->s = s_ppp;
+  for (int i = 0; i < 10; i++)
+    (**((*u->t)->s))->x[i] = 0;
+#pragma omp target map(u->t, *u->t, (*u->t)->s, *(*u->t)->s, **(*u->t)->s, \
+		       (**(*u->t)->s)->x[0:10])
+  for (int i = 0; i < 10; i++)
+    (**((*u->t)->s))->x[i] = i * 3;
+  for (int i = 0; i < 10; i++)
+    assert ((**((*u->t)->s))->x[i] == i * 3);
+  free (real_s);
+  free (real_t);
+  free (u);
+}
+
+int main (int argc, char *argv[])
+{
+  foo ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c b/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c
new file mode 100644
index 00000000000..3623b269576
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c
@@ -0,0 +1,16 @@
+#include <assert.h>
+
+int main (int argc, char *argv[])
+{
+  int y = 0;
+  int *x = &y;
+
+#pragma omp target map(*x)
+  {
+    (*x)++;
+  }
+
+  assert (y == 1);
+
+  return 0;
+}
-- 
2.29.2


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-11-25 14:11 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-25 14:11 [PATCH 15/16] OpenMP: lvalue parsing for map clauses (C++) Julian Brown
2021-11-25 14:11 ` [PATCH 16/16] OpenMP: lvalue parsing for map clauses (C) Julian Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).