From b5476e4c881b0d2bfbbfb84ee38d791123acf8e1 Mon Sep 17 00:00:00 2001 From: Julian Brown <julian@codesourcery.com> Date: Mon, 15 Nov 2021 02:23:49 -0800 Subject: [PATCH] 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. --- gcc/c-family/c-pretty-print.cc | 12 ++ gcc/c/c-parser.cc | 155 ++++++++++++++++-- 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/libgomp.texi | 2 +- .../libgomp.c-c++-common/ind-base-4.c | 50 ++++++ .../libgomp.c-c++-common/unary-ptr-1.c | 16 ++ 15 files changed, 465 insertions(+), 38 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 diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc index 51c8856b8630..45045fb2242f 100644 --- a/gcc/c-family/c-pretty-print.cc +++ b/gcc/c-family/c-pretty-print.cc @@ -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: diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 878f323dd2f7..c31349dae2ff 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -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; + + /* 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); + } - tree t = NULL_TREE; + 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) diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 182315108a57..cf29534c0915 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -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); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 2b90fa7f82b9..774dc1b3e6b4 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; @@ -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; 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..36b2426de97c --- /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-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; +} 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..2880d171abba --- /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-error {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/libgomp.texi b/libgomp/libgomp.texi index 30f69ee412b6..74d4ef34c437 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -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 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; +} -- GitLab