OpenMP: lvalue parsing for map/to/from clauses (C)

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

2024-01-11  Julian Brown  <julian@codesourcery.com>

gcc/c-family/
	* c-pretty-print.cc (c_pretty_printer::postfix_expression,
	c_pretty_printer::expression): Add OMP_ARRAY_SECTION support.

gcc/c/
	* 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.cc (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/
	* libgomp.texi: C/C++ lvalues are supported now for map/to/from.
	* testsuite/libgomp.c-c++-common/ind-base-4.c: New test.
	* testsuite/libgomp.c-c++-common/unary-ptr-1.c: New test.
This commit is contained in:
Julian Brown 2021-11-15 02:23:49 -08:00
parent 61b493f17e
commit b5476e4c88
15 changed files with 465 additions and 38 deletions

View File

@ -1650,6 +1650,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;
@ -2699,6 +2710,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:

View File

@ -6146,6 +6146,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)
@ -6184,6 +6186,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)
{
@ -9149,6 +9152,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 ());
@ -9156,6 +9160,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
@ -9208,6 +9213,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;
}
{
@ -9254,6 +9260,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;
}
@ -10705,6 +10712,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);
@ -10721,6 +10729,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;
@ -10731,6 +10740,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
{
@ -12480,7 +12490,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[6], comp_loc;
tree sizeof_arg[6];
unsigned int literal_zero_mask;
@ -12499,12 +12509,29 @@ 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;
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;
expr.value = build_omp_array_section (op_loc, expr.value, idx,
len);
}
else
expr.value = build_array_ref (op_loc, expr.value, idx);
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;
@ -12829,6 +12856,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)
@ -12882,6 +12911,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;
}
@ -15126,7 +15156,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;
@ -15137,6 +15167,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)
@ -15217,8 +15249,96 @@ 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 indirection of a pointer "*foo" into "foo[0:1]". */
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)
@ -15269,8 +15389,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;
@ -15371,9 +15490,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++)
{
@ -15385,7 +15502,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)
@ -15433,6 +15552,8 @@ c_parser_omp_variable_list (c_parser *parser,
parser->tokens = saved_tokens;
parser->tokens_avail = tokens_avail;
}
next_item:
if (c_parser_next_token_is_not (parser, CPP_COMMA))
break;
@ -15449,7 +15570,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;
@ -15470,7 +15591,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;
@ -15541,7 +15662,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);
@ -17221,13 +17342,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)

View File

@ -737,6 +737,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;
@ -777,6 +778,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);

View File

@ -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;
@ -1987,6 +1990,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;
}
@ -2899,6 +2909,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 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))
sectype = TREE_TYPE (array);
else
{
tree idxtype = NULL_TREE;
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);
gcc_assert (!error_operand_p (idxtype));
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
@ -2938,7 +2995,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))
@ -13762,7 +13823,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;
@ -13787,7 +13848,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),
@ -13835,14 +13898,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;
@ -14035,7 +14098,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;
}
}
@ -14066,14 +14129,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),
@ -14096,7 +14160,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);
@ -14159,10 +14223,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
@ -14587,8 +14651,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)
{
@ -14696,7 +14760,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))
{
@ -15317,7 +15381,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;
@ -15427,7 +15491,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);
@ -15597,6 +15661,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)]);
@ -15827,7 +15894,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;

View File

@ -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-error {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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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-error {pointer/integer type mismatch in conditional expression} "" { target *-*-* } .-2 } */
/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-3 } */
{ }
return 0;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -242,7 +242,7 @@ The OpenMP 4.5 specification is fully supported.
@item Discontiguous array section with @code{target update} construct
@tab N @tab
@item C/C++'s lvalue expressions in @code{to}, @code{from}
and @code{map} clauses @tab N @tab
and @code{map} clauses @tab Y @tab
@item C/C++'s lvalue expressions in @code{depend} clauses @tab Y @tab
@item Nested @code{declare target} directive @tab Y @tab
@item Combined @code{master} constructs @tab Y @tab

View File

@ -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;
}

View File

@ -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;
}