diff mbox series

[2/8] OpenMP: lvalue parsing for map/to/from clauses (C)

Message ID 78fa6c4dae60578a8feffe204bfe24d85d19520c.1693941293.git.julian@codesourcery.com
State New
Headers show
Series OpenMP: lvalue parsing and "declare mapper" support | expand

Commit Message

Julian Brown Sept. 5, 2023, 7:28 p.m. UTC
This patch adds support for parsing general lvalues ("locator list item
types") for OpenMP "map", "to" and "from" clauses to the C front-end,
similar to the previously-posted patch for C++.  Such syntax is permitted
for OpenMP 5.0 and above.  It was previously posted for mainline here:

  https://gcc.gnu.org/pipermail/gcc-patches/2022-December/609038.html

and for the og13 branch here:

  https://gcc.gnu.org/pipermail/gcc-patches/2023-June/623355.html

2023-09-05  Julian Brown  <julian@codesourcery.com>

gcc/c/
	* c-pretty-print.cc (c_pretty_printer::postfix_expression,
	c_pretty_printer::expression): Add OMP_ARRAY_SECTION support.
	* c-parser.cc (c_parser_braced_init, c_parser_conditional_expression):
	Don't allow OpenMP array section.
	(c_parser_postfix_expression): Don't allow array section in statement
	expression.
	(c_parser_postfix_expression_after_primary): Add support for OpenMP
	array section parsing.
	(c_parser_expr_list): Don't allow OpenMP array section here.
	(c_parser_omp_variable_list): Change ALLOW_DEREF parameter to
	MAP_LVALUE.  Support parsing of general lvalues in "map", "to" and
	"from" 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): Update calls to
	c_parser_omp_var_list_parens.
	(c_parser_omp_clause_reduction): Use OMP_ARRAY_SECTION tree node
	instead of TREE_LIST for array sections.
	(c_parser_omp_target): Allow GOMP_MAP_ATTACH.
	* c-tree.h (c_omp_array_section_p): Add extern declaration.
	(build_omp_array_section): Add prototype.
	* c-typeck.c (c_omp_array_section_p): Add flag.
	(mark_exp_read): Support OMP_ARRAY_SECTION.
	(build_omp_array_section): Add function.
	(build_external_ref): Tweak error path for OpenMP array sections.
	(handle_omp_array_sections_1): Use OMP_ARRAY_SECTION tree code instead
	of TREE_LIST.  Handle more kinds of expressions.
	(c_oacc_check_attachments): Use OMP_ARRAY_SECTION instead of TREE_LIST
	for array sections.
	(c_finish_omp_clauses): Use OMP_ARRAY_SECTION instead of TREE_LIST.
	Check for supported expression types.

gcc/testsuite/
	* gcc.dg/gomp/bad-array-section-c-1.c: New test.
	* gcc.dg/gomp/bad-array-section-c-2.c: New test.
	* gcc.dg/gomp/bad-array-section-c-3.c: New test.
	* gcc.dg/gomp/bad-array-section-c-4.c: New test.
	* gcc.dg/gomp/bad-array-section-c-5.c: New test.
	* gcc.dg/gomp/bad-array-section-c-6.c: New test.
	* gcc.dg/gomp/bad-array-section-c-7.c: New test.
	* gcc.dg/gomp/bad-array-section-c-8.c: New test.

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-family/c-pretty-print.cc                |  12 ++
 gcc/c/c-parser.cc                             | 181 +++++++++++++++---
 gcc/c/c-tree.h                                |   2 +
 gcc/c/c-typeck.cc                             | 109 +++++++++--
 .../gcc.dg/gomp/bad-array-section-c-1.c       |  16 ++
 .../gcc.dg/gomp/bad-array-section-c-2.c       |  13 ++
 .../gcc.dg/gomp/bad-array-section-c-3.c       |  24 +++
 .../gcc.dg/gomp/bad-array-section-c-4.c       |  26 +++
 .../gcc.dg/gomp/bad-array-section-c-5.c       |  15 ++
 .../gcc.dg/gomp/bad-array-section-c-6.c       |  16 ++
 .../gcc.dg/gomp/bad-array-section-c-7.c       |  26 +++
 .../gcc.dg/gomp/bad-array-section-c-8.c       |  21 ++
 .../libgomp.c-c++-common/ind-base-4.c         |  50 +++++
 .../libgomp.c-c++-common/unary-ptr-1.c        |  16 ++
 14 files changed, 482 insertions(+), 45 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-6.c
 create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-7.c
 create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-8.c
 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

Comments

Tobias Burnus Jan. 10, 2024, 9:31 p.m. UTC | #1
Julian Brown wrote:
> This patch adds support for parsing general lvalues ("locator list item
> types") for OpenMP "map", "to" and "from" clauses to the C front-end,
> similar to the previously-posted patch for C++.  Such syntax is permitted
> for OpenMP 5.0 and above.  It was previously posted for mainline here

...

In libgomp/libgomp.texi, the following can now be set to 'Y':

@item C/C++'s lvalue expressions in @code{to}, @code{from}
       and @code{map} clauses @tab N @tab

> @@ -11253,16 +11263,41 @@ 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;
> -	  expr.m_decimal = 0;
> +	  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 %<]%>");
> +
> +	      start = expr.get_start ();
> +	      finish = parser->tokens_buf[0].location;
> +	      expr.value = build_omp_array_section (op_loc, 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;
> +	      expr.m_decimal = 0;
> +	    }

I think that's more readable when moving everything but the expr.value 
assignment after the if/else (obviously for "if" also everything until 
"len =" has to remain). That also adds the missing "m_decimal = 0" for 
the "if" case.

> @@ -13915,8 +13955,97 @@ c_parser_omp_variable_list (c_parser *parser,
...
> +	  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 = build_omp_array_section (loc, decl, integer_zero_node,
> +					      integer_one_node);
> +	    }

I wonder whether we shouldn't use the C++ wording, i.e.

               /* If we have "*foo" and
                  - it's an indirection of a reference, "unconvert" it,
                    i.e. strip the indirection (to just "foo").
                  - it's an indirection of a pointer, turn it into
                    "foo[0:1]".  */

* * *

As remarked for cp/typecheck.cc's build_omp_array_section:

> +tree
> +build_omp_array_section (location_t loc, tree array, tree index, tree length)
> +{
> +  tree idxtype;
> +
> +  if (index != NULL_TREE
> +      && length != NULL_TREE
> +      && INTEGRAL_TYPE_P (TREE_TYPE (index))
> +      && INTEGRAL_TYPE_P (TREE_TYPE (length)))
> +    {
> +      tree low = fold_convert (sizetype, index);
> +      tree high = fold_convert (sizetype, length);
> +      high = size_binop (PLUS_EXPR, low, high);
> +      high = size_binop (MINUS_EXPR, high, size_one_node);
> +      idxtype = build_range_type (sizetype, low, high);
> +    }
> +  else if ((index == NULL_TREE || integer_zerop (index))
> +	   && length != NULL_TREE
> +	   && INTEGRAL_TYPE_P (TREE_TYPE (length)))
> +    idxtype = build_index_type (length);
> +  else
> +    idxtype = NULL_TREE;
> +
> +  tree type = TREE_TYPE (array);
> +  gcc_assert (type);
> +
> +  tree sectype, eltype = TREE_TYPE (type);
> +
> +  /* It's not an array or pointer type.  Just reuse the type of the original
> +     expression as the type of the array section (an error will be raised
> +     anyway, later).  */
> +  if (eltype == NULL_TREE
> +      || error_operand_p (eltype)
> +      || error_operand_p (idxtype))
> +    sectype = TREE_TYPE (array);
> +  else
> +    sectype = build_array_type (eltype, idxtype);
> +
> +  return build3_loc (loc, OMP_ARRAY_SECTION, sectype, array, index, length);
> +}

I think that's more readable when having that if condition at the top
and moving everything before into the else branch.


Otherwise, LGTM.

Thanks for the patch!

Tobias
diff mbox series

Patch

diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc
index 7536a7c471ff..225ac7ef2851 100644
--- a/gcc/c-family/c-pretty-print.cc
+++ b/gcc/c-family/c-pretty-print.cc
@@ -1615,6 +1615,17 @@  c_pretty_printer::postfix_expression (tree e)
       pp_c_right_bracket (this);
       break;
 
+    case OMP_ARRAY_SECTION:
+      postfix_expression (TREE_OPERAND (e, 0));
+      pp_c_left_bracket (this);
+      if (TREE_OPERAND (e, 1))
+	expression (TREE_OPERAND (e, 1));
+      pp_colon (this);
+      if (TREE_OPERAND (e, 2))
+	expression (TREE_OPERAND (e, 2));
+      pp_c_right_bracket (this);
+      break;
+
     case CALL_EXPR:
       {
 	call_expr_arg_iterator iter;
@@ -2664,6 +2675,7 @@  c_pretty_printer::expression (tree e)
     case POSTINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
     case ARRAY_REF:
+    case OMP_ARRAY_SECTION:
     case CALL_EXPR:
     case COMPONENT_REF:
     case BIT_FIELD_REF:
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index ae3a25737151..36215096af4c 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -5767,6 +5767,8 @@  c_parser_braced_init (c_parser *parser, tree type, bool nested_p,
   location_t brace_loc = c_parser_peek_token (parser)->location;
   gcc_obstack_init (&braced_init_obstack);
   gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
+  bool save_c_omp_array_section_p = c_omp_array_section_p;
+  c_omp_array_section_p = false;
   matching_braces braces;
   braces.consume_open (parser);
   if (nested_p)
@@ -5805,6 +5807,7 @@  c_parser_braced_init (c_parser *parser, tree type, bool nested_p,
 	    break;
 	}
     }
+  c_omp_array_section_p = save_c_omp_array_section_p;
   c_token *next_tok = c_parser_peek_token (parser);
   if (next_tok->type != CPP_CLOSE_BRACE)
     {
@@ -8194,6 +8197,7 @@  c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
 {
   struct c_expr cond, exp1, exp2, ret;
   location_t start, cond_loc, colon_loc;
+  bool save_c_omp_array_section_p = c_omp_array_section_p;
 
   gcc_assert (!after || c_dialect_objc ());
 
@@ -8201,6 +8205,7 @@  c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
 
   if (c_parser_next_token_is_not (parser, CPP_QUERY))
     return cond;
+  c_omp_array_section_p = false;
   if (cond.value != error_mark_node)
     start = cond.get_start ();
   else
@@ -8253,6 +8258,7 @@  c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
       ret.set_error ();
       ret.original_code = ERROR_MARK;
       ret.original_type = NULL;
+      c_omp_array_section_p = save_c_omp_array_section_p;
       return ret;
     }
   {
@@ -8299,6 +8305,7 @@  c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
     }
   set_c_expr_source_range (&ret, start, exp2.get_finish ());
   ret.m_decimal = 0;
+  c_omp_array_section_p = save_c_omp_array_section_p;
   return ret;
 }
 
@@ -9750,6 +9757,7 @@  c_parser_postfix_expression (c_parser *parser)
 	  /* A statement expression.  */
 	  tree stmt;
 	  location_t brace_loc;
+	  bool save_c_omp_array_section_p = c_omp_array_section_p;
 	  c_parser_consume_token (parser);
 	  brace_loc = c_parser_peek_token (parser)->location;
 	  c_parser_consume_token (parser);
@@ -9766,6 +9774,7 @@  c_parser_postfix_expression (c_parser *parser)
 	      expr.set_error ();
 	      break;
 	    }
+	  c_omp_array_section_p = false;
 	  stmt = c_begin_stmt_expr ();
 	  c_parser_compound_statement_nostart (parser);
 	  location_t close_loc = c_parser_peek_token (parser)->location;
@@ -9776,6 +9785,7 @@  c_parser_postfix_expression (c_parser *parser)
 	  expr.value = c_finish_stmt_expr (brace_loc, stmt);
 	  set_c_expr_source_range (&expr, loc, close_loc);
 	  mark_exp_read (expr.value);
+	  c_omp_array_section_p = save_c_omp_array_section_p;
 	}
       else
 	{
@@ -11234,7 +11244,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;
@@ -11253,16 +11263,41 @@  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;
-	  expr.m_decimal = 0;
+	  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 %<]%>");
+
+	      start = expr.get_start ();
+	      finish = parser->tokens_buf[0].location;
+	      expr.value = build_omp_array_section (op_loc, 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;
+	      expr.m_decimal = 0;
+	    }
 	  break;
 	case CPP_OPEN_PAREN:
 	  /* Function call.  */
@@ -11545,6 +11580,8 @@  c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
   vec<tree, va_gc> *orig_types;
   struct c_expr expr;
   unsigned int idx = 0;
+  bool save_c_omp_array_section_p = c_omp_array_section_p;
+  c_omp_array_section_p = false;
 
   ret = make_tree_vector ();
   if (p_orig_types == NULL)
@@ -11598,6 +11635,7 @@  c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
     }
   if (orig_types)
     *p_orig_types = orig_types;
+  c_omp_array_section_p = save_c_omp_array_section_p;
   return ret;
 }
 
@@ -13825,7 +13863,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<omp_dim> dims;
   bool array_section_p;
@@ -13835,6 +13873,8 @@  c_parser_omp_variable_list (c_parser *parser,
 
   while (1)
     {
+      tree t = NULL_TREE;
+
       if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
 	{
 	  if (c_parser_next_token_is_not (parser, CPP_NAME)
@@ -13915,8 +13955,97 @@  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
+		   || kind == OMP_CLAUSE_TO
+		   || kind == OMP_CLAUSE_FROM))
+	{
+	  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;
+	 /* This code rewrites a parsed expression containing various tree
+	    codes used to represent array accesses into a more uniform nest of
+	    OMP_ARRAY_SECTION nodes before it is processed by
+	    c-typeck.cc:handle_omp_array_sections_1.  It might be more
+	    efficient to move this logic to that function instead, analysing
+	    the parsed expression directly rather than this preprocessed
+	    form.  (See also equivalent code in cp/parser.cc,
+	    cp/semantics.cc).  */
+	  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 = build_omp_array_section (loc,  decl, dims[i].low_bound,
+						dims[i].length);
+	    }
+	  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 = build_omp_array_section (loc, decl, integer_zero_node,
+					      integer_one_node);
+	    }
+	  else if (TREE_CODE (decl) == ARRAY_REF)
+	    {
+	      tree idx = TREE_OPERAND (decl, 1);
+
+	      decl = TREE_OPERAND (decl, 0);
+	      STRIP_NOPS (decl);
+
+	      decl = build_omp_array_section (loc, decl, idx, integer_one_node);
+	    }
+	  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)
@@ -13967,8 +14096,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;
 		  location_t arrow_loc = UNKNOWN_LOCATION;
@@ -14069,9 +14197,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++)
 			{
@@ -14083,7 +14209,9 @@  c_parser_omp_variable_list (c_parser *parser,
 		    }
 		  else
 		    for (unsigned i = 0; i < dims.length (); i++)
-		      t = tree_cons (dims[i].low_bound, dims[i].length, t);
+		      t = build_omp_array_section (clause_loc, t,
+						   dims[i].low_bound,
+						   dims[i].length);
 		}
 
 	      if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
@@ -14131,6 +14259,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;
 
@@ -14147,7 +14277,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;
@@ -14155,7 +14285,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;
@@ -14224,7 +14354,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, false);
 
   for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
     OMP_CLAUSE_SET_MAP_KIND (c, kind);
@@ -15814,13 +15944,15 @@  c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind,
 	  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
 	    {
 	      tree d = OMP_CLAUSE_DECL (c), type;
-	      if (TREE_CODE (d) != TREE_LIST)
+	      if (TREE_CODE (d) != OMP_ARRAY_SECTION)
 		type = TREE_TYPE (d);
 	      else
 		{
 		  int cnt = 0;
 		  tree t;
-		  for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t))
+		  for (t = d;
+		      TREE_CODE (t) == OMP_ARRAY_SECTION;
+		      t = TREE_OPERAND (t, 0))
 		    cnt++;
 		  type = TREE_TYPE (t);
 		  while (cnt > 0)
@@ -22479,6 +22611,7 @@  check_clauses:
 	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	  case GOMP_MAP_ALWAYS_POINTER:
 	  case GOMP_MAP_ATTACH_DETACH:
+	  case GOMP_MAP_ATTACH:
 	    break;
 	  default:
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 7c5234e80fd9..5cd507563695 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -726,6 +726,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;
@@ -764,6 +765,7 @@  extern tree composite_type (tree, tree);
 extern tree build_component_ref (location_t, tree, tree, location_t,
 				 location_t);
 extern tree build_array_ref (location_t, tree, tree);
+extern tree build_omp_array_section (location_t, tree, tree, tree);
 extern tree build_external_ref (location_t, tree, bool, tree *);
 extern void pop_maybe_used (bool);
 extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 597b77181dc2..b399341084d2 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -76,6 +76,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;
@@ -2001,6 +2004,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;
     }
@@ -2878,6 +2888,53 @@  build_array_ref (location_t loc, tree array, tree index)
       return ret;
     }
 }
+
+/* Build an OpenMP array section reference, creating an exact type for the
+   resulting expression based on the element type and bounds if possible.  If
+   we have variable bounds, create an incomplete array type for the result
+   instead.  */
+
+tree
+build_omp_array_section (location_t loc, tree array, tree index, tree length)
+{
+  tree idxtype;
+
+  if (index != NULL_TREE
+      && length != NULL_TREE
+      && INTEGRAL_TYPE_P (TREE_TYPE (index))
+      && INTEGRAL_TYPE_P (TREE_TYPE (length)))
+    {
+      tree low = fold_convert (sizetype, index);
+      tree high = fold_convert (sizetype, length);
+      high = size_binop (PLUS_EXPR, low, high);
+      high = size_binop (MINUS_EXPR, high, size_one_node);
+      idxtype = build_range_type (sizetype, low, high);
+    }
+  else if ((index == NULL_TREE || integer_zerop (index))
+	   && length != NULL_TREE
+	   && INTEGRAL_TYPE_P (TREE_TYPE (length)))
+    idxtype = build_index_type (length);
+  else
+    idxtype = NULL_TREE;
+
+  tree type = TREE_TYPE (array);
+  gcc_assert (type);
+
+  tree sectype, eltype = TREE_TYPE (type);
+
+  /* It's not an array or pointer type.  Just reuse the type of the original
+     expression as the type of the array section (an error will be raised
+     anyway, later).  */
+  if (eltype == NULL_TREE
+      || error_operand_p (eltype)
+      || error_operand_p (idxtype))
+    sectype = TREE_TYPE (array);
+  else
+    sectype = build_array_type (eltype, idxtype);
+
+  return build3_loc (loc, OMP_ARRAY_SECTION, sectype, array, index, length);
+}
+
 
 /* Build an external reference to identifier ID.  FUN indicates
    whether this will be used for a function call.  LOC is the source
@@ -2917,7 +2974,11 @@  build_external_ref (location_t loc, tree id, bool fun, tree *type)
       return error_mark_node;
     }
 
-  if (TREE_TYPE (ref) == error_mark_node)
+  /* For an OpenMP map clause, we can get better diagnostics for decls with
+     unmappable types if we return the decl with an error_mark_node type,
+     rather than returning error_mark_node for the decl itself.  */
+  if (TREE_TYPE (ref) == error_mark_node
+      && !c_omp_array_section_p)
     return error_mark_node;
 
   if (TREE_UNAVAILABLE (ref))
@@ -13635,7 +13696,7 @@  handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 {
   tree ret, low_bound, length, type;
   bool openacc = (ort & C_ORT_ACC) != 0;
-  if (TREE_CODE (t) != TREE_LIST)
+  if (TREE_CODE (t) != OMP_ARRAY_SECTION)
     {
       if (error_operand_p (t))
 	return error_mark_node;
@@ -13660,7 +13721,9 @@  handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 	t = ai.unconverted_ref_origin ();
       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),
@@ -13708,14 +13771,14 @@  handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
       return ret;
     }
 
-  ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
+  ret = handle_omp_array_sections_1 (c, TREE_OPERAND (t, 0), types,
 				     maybe_zero_len, first_non_one, ort);
   if (ret == error_mark_node || ret == NULL_TREE)
     return ret;
 
   type = TREE_TYPE (ret);
-  low_bound = TREE_PURPOSE (t);
-  length = TREE_VALUE (t);
+  low_bound = TREE_OPERAND (t, 1);
+  length = TREE_OPERAND (t, 2);
 
   if (low_bound == error_mark_node || length == error_mark_node)
     return error_mark_node;
@@ -13908,7 +13971,7 @@  handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 	  tree lb = save_expr (low_bound);
 	  if (lb != low_bound)
 	    {
-	      TREE_PURPOSE (t) = lb;
+	      TREE_OPERAND (t, 1) = lb;
 	      low_bound = lb;
 	    }
 	}
@@ -13939,14 +14002,15 @@  handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 	 array-section-subscript, the array section could be non-contiguous.  */
       if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
 	  && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY
-	  && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST)
+	  && TREE_CODE (TREE_OPERAND (t, 0)) == OMP_ARRAY_SECTION)
 	{
 	  /* If any prior dimension has a non-one length, then deem this
 	     array section as non-contiguous.  */
-	  for (tree d = TREE_CHAIN (t); TREE_CODE (d) == TREE_LIST;
-	       d = TREE_CHAIN (d))
+	  for (tree d = TREE_OPERAND (t, 0);
+	       TREE_CODE (d) == OMP_ARRAY_SECTION;
+	       d = TREE_OPERAND (d, 0))
 	    {
-	      tree d_length = TREE_VALUE (d);
+	      tree d_length = TREE_OPERAND (d, 2);
 	      if (d_length == NULL_TREE || !integer_onep (d_length))
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
@@ -13969,7 +14033,7 @@  handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
   tree lb = save_expr (low_bound);
   if (lb != low_bound)
     {
-      TREE_PURPOSE (t) = lb;
+      TREE_OPERAND (t, 1) = lb;
       low_bound = lb;
     }
   ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound);
@@ -14032,10 +14096,10 @@  handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 	maybe_zero_len = true;
 
       for (i = num, t = OMP_CLAUSE_DECL (c); i > 0;
-	   t = TREE_CHAIN (t))
+	   t = TREE_OPERAND (t, 0))
 	{
-	  tree low_bound = TREE_PURPOSE (t);
-	  tree length = TREE_VALUE (t);
+	  tree low_bound = TREE_OPERAND (t, 1);
+	  tree length = TREE_OPERAND (t, 2);
 
 	  i--;
 	  if (low_bound
@@ -14441,8 +14505,8 @@  c_oacc_check_attachments (tree c)
     {
       tree t = OMP_CLAUSE_DECL (c);
 
-      while (TREE_CODE (t) == TREE_LIST)
-	t = TREE_CHAIN (t);
+      while (TREE_CODE (t) == OMP_ARRAY_SECTION)
+	t = TREE_OPERAND (t, 0);
 
       if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
 	{
@@ -14550,7 +14614,7 @@  c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	case OMP_CLAUSE_TASK_REDUCTION:
 	  need_implicitly_determined = true;
 	  t = OMP_CLAUSE_DECL (c);
-	  if (TREE_CODE (t) == TREE_LIST)
+	  if (TREE_CODE (t) == OMP_ARRAY_SECTION)
 	    {
 	      if (handle_omp_array_sections (c, ort))
 		{
@@ -15171,7 +15235,7 @@  c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  else
 	    last_iterators = NULL_TREE;
-	  if (TREE_CODE (t) == TREE_LIST)
+	  if (TREE_CODE (t) == OMP_ARRAY_SECTION)
 	    {
 	      if (handle_omp_array_sections (c, ort))
 		remove = true;
@@ -15281,7 +15345,7 @@  c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    auto_vec<omp_addr_token *, 10> addr_tokens;
 
 	    t = OMP_CLAUSE_DECL (c);
-	    if (TREE_CODE (t) == TREE_LIST)
+	    if (TREE_CODE (t) == OMP_ARRAY_SECTION)
 	      {
 		grp_start_p = pc;
 		grp_sentinel = OMP_CLAUSE_CHAIN (c);
@@ -15449,6 +15513,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)]);
@@ -15677,7 +15744,7 @@  c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 
 	case OMP_CLAUSE_HAS_DEVICE_ADDR:
 	  t = OMP_CLAUSE_DECL (c);
-	  if (TREE_CODE (t) == TREE_LIST)
+	  if (TREE_CODE (t) == OMP_ARRAY_SECTION)
 	    {
 	      if (handle_omp_array_sections (c, ort))
 		remove = true;
diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-1.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-1.c
new file mode 100644
index 000000000000..a2226ebf6429
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-1.c
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+
+int foo (int *ptr);
+
+int main()
+{
+  int arr[20];
+  /* Reject array section as function argument.  */
+#pragma omp target map(foo(arr[3:5]))
+/* { dg-error {expected '\]' before ':' token} "" { target *-*-* } .-1 } */
+/* { dg-warning {passing argument 1 of 'foo' makes pointer from integer without a cast} "" { target *-*-* } .-2 } */
+/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-3 } */
+  { }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-2.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-2.c
new file mode 100644
index 000000000000..449487ad55d6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-2.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+
+int main()
+{
+  int arr[20];
+  /* Reject array section in statement expression.  */
+#pragma omp target map( ({ int x = 5; arr[0:x]; }) )
+/* { dg-error {expected '\]' before ':' token} "" { target *-*-* } .-1 } */
+/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-2 } */
+  { }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-3.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-3.c
new file mode 100644
index 000000000000..8be15ced8c06
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-3.c
@@ -0,0 +1,24 @@ 
+/* { dg-do compile } */
+
+struct S {
+  int *ptr;
+};
+
+int main()
+{
+  int arr[20];
+
+  /* Reject array section in compound initialiser.  */
+#pragma omp target map( (struct S) { .ptr = (int *) arr[5:5] } )
+/* { dg-error {expected '\]' before ':' token} "" { target *-*-* } .-1 } */
+/* { dg-warning {cast to pointer from integer of different size} "" { target *-*-* } .-2 } */
+/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-3 } */
+  { }
+
+  /* ...and this is unsupported too (probably not useful anyway).  */
+#pragma omp target map( (struct S) { .ptr = &arr[5] } )
+/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-1 } */
+  { }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-4.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-4.c
new file mode 100644
index 000000000000..b78cdfc8a13e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-4.c
@@ -0,0 +1,26 @@ 
+/* { dg-do compile } */
+
+int x;
+
+int main()
+{
+  int arr[20];
+  int *ptr;
+  /* "arr[1:10]" looks like it might be an expression of array type, hence
+     able to be indexed (again).  This isn't allowed, though.  */
+#pragma omp target map(arr[1:10][2])
+/* { dg-error {'arr\[1\]' does not have pointer or array type} "" { target *-*-* } .-1 } */
+  { }
+#pragma omp target map(arr[1:x][2])
+/* { dg-error {'arr\[1\]' does not have pointer or array type} "" { target *-*-* } .-1 } */
+  { }
+  /* ...and nor is this.  */
+#pragma omp target map(ptr[1:10][2])
+/* { dg-error {'\*\(ptr \+ [0-9]+\)' does not have pointer or array type} "" { target *-*-* } .-1 } */
+  { }
+#pragma omp target map(ptr[1:x][2])
+/* { dg-error {'\*\(ptr \+ [0-9]+\)' does not have pointer or array type} "" { target *-*-* } .-1 } */
+  { }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-5.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-5.c
new file mode 100644
index 000000000000..ae343464a19a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-5.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+
+int partly = 0;
+
+int main()
+{
+  int arr[20];
+#pragma omp target map(partly ? arr[5:5] : arr)
+/* { dg-error {expected '\]' before ':' token} "" { target *-*-* } .-1 } */
+/* { dg-warning {pointer/integer type mismatch in conditional expression} "" { target *-*-* } .-2 } */
+/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-3 } */
+  { }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-6.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-6.c
new file mode 100644
index 000000000000..bfca4f0fca3f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-6.c
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+
+int x;
+
+int main()
+{
+  int arr[20];
+#pragma omp target map(arr[5:5] * 2)
+/* { dg-error {invalid operands to binary \*} "" { target *-*-* } .-1 } */
+  { }
+#pragma omp target map(arr[x:5] * 2)
+/* { dg-error {invalid operands to binary \*} "" { target *-*-* } .-1 } */
+  { }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-7.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-7.c
new file mode 100644
index 000000000000..1fd9e2b383a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-7.c
@@ -0,0 +1,26 @@ 
+/* { dg-do compile } */
+
+int x;
+
+struct T {
+  int arr[20];
+};
+
+struct S {
+  struct T *tvec;
+};
+
+int main()
+{
+  struct S *s;
+  /* You can't use an array section like this.  Make sure sensible errors are
+     reported.  */
+#pragma omp target map(s->tvec[3:5].arr[0:20])
+/* { dg-error {'\(struct T \*\)&s->tvec\[3:5\]' is a pointer; did you mean to use '->'\?} "" { target *-*-* } .-1 } */
+  { }
+#pragma omp target map(s->tvec[5:x].arr[0:20])
+/* { dg-error {'\(struct T \*\)&s->tvec\[5:x\]' is a pointer; did you mean to use '->'\?} "" { target *-*-* } .-1 } */
+  { }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-8.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-8.c
new file mode 100644
index 000000000000..f90eca1fa9fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-8.c
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+
+int x;
+
+int main()
+{
+  int arr1[40];
+  int arr2[40];
+#pragma omp target map(arr1[arr2[4:5]:arr2[6:7]])
+/* { dg-error {low bound 'arr2\[4:5\]' of array section does not have integral type} "" { target *-*-* } .-1 } */
+  { }
+#pragma omp target map(arr1[arr2[:1]:arr2[6:1]])
+/* { dg-error {low bound 'arr2\[:1\]' of array section does not have integral type} "" { target *-*-* } .-1 } */
+  { }
+#pragma omp target map(arr1[x:arr2[6:1]])
+/* { dg-error {length 'arr2\[6:1\]' of array section does not have integral type} "" { target *-*-* } .-1 } */
+  { }
+
+  return 0;
+}
+
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 000000000000..91549ac4d245
--- /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 000000000000..3623b2695763
--- /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;
+}