diff options
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 87 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 1256 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 452 |
3 files changed, 1618 insertions, 177 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 708ef5d..04f667b 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,90 @@ +2018-11-08 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c: Include memmode.h. + (c_parser_omp_depobj, c_parser_omp_requires): New functions. + (c_parser_pragma): Handle PRAGMA_OMP_DEPOBJ and PRAGMA_OMP_REQUIRES. + (c_parser_omp_clause_name): Handle nontemporal, in_reduction and + task_reduction clauses. + (c_parser_omp_variable_list): Handle OMP_CLAUSE_{IN,TASK}_REDUCTION. + For OMP_CLAUSE_DEPEND, parse clause operands as either an array + section, or lvalue assignment expression. + (c_parser_omp_clause_if): Handle cancel and simd modifiers. + (c_parser_omp_clause_lastprivate): Parse optional + conditional: modifier. + (c_parser_omp_clause_hint): Require constant integer expression rather + than just integer expression. + (c_parser_omp_clause_defaultmap): Parse new kinds of defaultmap + clause. + (c_parser_omp_clause_reduction): Add IS_OMP and KIND arguments. + Parse reduction modifiers. Pass KIND to c_parser_omp_variable_list. + (c_parser_omp_clause_nontemporal, c_parser_omp_iterators): New + functions. + (c_parser_omp_clause_depend): Parse iterator modifier and handle + iterators. Parse mutexinoutset and depobj kinds. + (c_parser_oacc_all_clauses): Adjust c_parser_omp_clause_reduction + callers. + (c_parser_omp_all_clauses): Likewise. Handle + PRAGMA_OMP_CLAUSE_NONTEMPORAL and + PRAGMA_OMP_CLAUSE_{IN,TASK}_REDUCTION. + (c_parser_omp_atomic): Parse hint and memory order clauses. Handle + default memory order from requires directive if any. Adjust + c_finish_omp_atomic caller. + (c_parser_omp_critical): Allow comma in between (name) and hint clause. + (c_parser_omp_flush): Parse flush with memory-order-clause. + (c_parser_omp_for_loop): Allow NE_EXPR even in + OpenMP loops, adjust c_finish_omp_for caller. + (OMP_SIMD_CLAUSE_MASK): Add if and nontemporal clauses. + (c_parser_omp_master): Add p_name, mask and cclauses arguments. + Allow to be called while parsing combined parallel master. + Parse combined master taskloop{, simd}. + (c_parser_omp_parallel): Parse combined + parallel master{, taskloop{, simd}} constructs. + (OMP_TASK_CLAUSE_MASK): Add in_reduction clause. + (OMP_TASKGROUP_CLAUSE_MASK): Define. + (c_parser_omp_taskgroup): Add LOC argument. Parse taskgroup clauses. + (OMP_TASKWAIT_CLAUSE_MASK): Define. + (c_parser_omp_taskwait): Handle taskwait with depend clauses. + (c_parser_omp_teams): Force a BIND_EXPR with BLOCK + around teams body. Use SET_EXPR_LOCATION. + (c_parser_omp_target_data): Allow target data + with only use_device_ptr clauses. + (c_parser_omp_target): Use SET_EXPR_LOCATION. Set + OMP_REQUIRES_TARGET_USED bit in omp_requires_mask. + (c_parser_omp_requires): New function. + (c_finish_taskloop_clauses): New function. + (OMP_TASKLOOP_CLAUSE_MASK): Add reduction and in_reduction clauses. + (c_parser_omp_taskloop): Use c_finish_taskloop_clauses. Add forward + declaration. Disallow in_reduction clause when combined with parallel + master. + (c_parser_omp_construct): Adjust c_parser_omp_master and + c_parser_omp_taskgroup callers. + * c-typeck.c (c_finish_omp_cancel): Diagnose if clause with modifier + other than cancel. + (handle_omp_array_sections_1): Handle OMP_CLAUSE_{IN,TASK}_REDUCTION + like OMP_CLAUSE_REDUCTION. + (handle_omp_array_sections): Likewise. Call save_expr on array + reductions before calling build_index_type. Handle depend clauses + with iterators. + (struct c_find_omp_var_s): New type. + (c_find_omp_var_r, c_omp_finish_iterators): New functions. + (c_finish_omp_clauses): Don't diagnose nonmonotonic clause + with static, runtime or auto schedule kinds. Call save_expr for whole + array reduction sizes. Diagnose reductions with zero sized elements + or variable length structures. Diagnose nogroup clause used with + reduction clause(s). Handle depend clause with + OMP_CLAUSE_DEPEND_DEPOBJ. Diagnose bit-fields. Require + omp_depend_t type for OMP_CLAUSE_DEPEND_DEPOBJ kinds and + some different type for other kinds. Use build_unary_op with + ADDR_EXPR and build_indirect_ref instead of c_mark_addressable. + Handle depend clauses with iterators. Remove no longer needed special + case that predetermined const qualified vars may be specified in + firstprivate clause. Complain if const qualified vars are mentioned + in data-sharing clauses other than firstprivate or shared. Use + error_at with OMP_CLAUSE_LOCATION (c) as first argument instead of + error. Formatting fix. Handle OMP_CLAUSE_NONTEMPORAL and + OMP_CLAUSE_{IN,TASK}_REDUCTION. Allow any lvalue as + OMP_CLAUSE_DEPEND operand (besides array section), adjust diagnostics. + 2018-10-29 David Malcolm <dmalcolm@redhat.com> * c-decl.c (implicit_decl_warning): Update "is there a suggestion" diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index b36fca9..624d5a3 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -68,6 +68,7 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "c-family/name-hint.h" #include "tree-iterator.h" +#include "memmodel.h" /* We need to walk over decls with incomplete struct/union/enum types after parsing the whole translation unit. @@ -1450,6 +1451,7 @@ static void c_parser_oacc_update (c_parser *); static void c_parser_omp_construct (c_parser *, bool *); static void c_parser_omp_threadprivate (c_parser *); static void c_parser_omp_barrier (c_parser *); +static void c_parser_omp_depobj (c_parser *); static void c_parser_omp_flush (c_parser *); static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, tree, tree *, bool *); @@ -1464,6 +1466,7 @@ static void c_parser_omp_cancellation_point (c_parser *, enum pragma_context); static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); static void c_parser_omp_end_declare_target (c_parser *); static void c_parser_omp_declare (c_parser *, enum pragma_context); +static void c_parser_omp_requires (c_parser *); static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); static void c_parser_oacc_routine (c_parser *, enum pragma_context); @@ -11168,6 +11171,15 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) c_parser_omp_barrier (parser); return false; + case PRAGMA_OMP_DEPOBJ: + if (context != pragma_compound) + { + construct = "omp depobj"; + goto in_compound; + } + c_parser_omp_depobj (parser); + return false; + case PRAGMA_OMP_FLUSH: if (context != pragma_compound) { @@ -11230,6 +11242,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) c_parser_omp_declare (parser, context); return false; + case PRAGMA_OMP_REQUIRES: + c_parser_omp_requires (parser); + return false; + case PRAGMA_OMP_ORDERED: return c_parser_omp_ordered (parser, context, if_p); @@ -11452,6 +11468,8 @@ c_parser_omp_clause_name (c_parser *parser) case 'i': if (!strcmp ("if_present", p)) result = PRAGMA_OACC_CLAUSE_IF_PRESENT; + else if (!strcmp ("in_reduction", p)) + result = PRAGMA_OMP_CLAUSE_IN_REDUCTION; else if (!strcmp ("inbranch", p)) result = PRAGMA_OMP_CLAUSE_INBRANCH; else if (!strcmp ("independent", p)) @@ -11476,6 +11494,8 @@ c_parser_omp_clause_name (c_parser *parser) case 'n': if (!strcmp ("nogroup", p)) result = PRAGMA_OMP_CLAUSE_NOGROUP; + else if (!strcmp ("nontemporal", p)) + result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; else if (!strcmp ("notinbranch", p)) result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; else if (!strcmp ("nowait", p)) @@ -11544,7 +11564,9 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_SIMDLEN; break; case 't': - if (!strcmp ("taskgroup", p)) + if (!strcmp ("task_reduction", p)) + result = PRAGMA_OMP_CLAUSE_TASK_REDUCTION; + else if (!strcmp ("taskgroup", p)) result = PRAGMA_OMP_CLAUSE_TASKGROUP; else if (!strcmp ("thread_limit", p)) result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; @@ -11671,13 +11693,87 @@ c_parser_omp_variable_list (c_parser *parser, location_t clause_loc, enum omp_clause_code kind, tree list) { - if (c_parser_next_token_is_not (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID) + auto_vec<c_token> tokens; + unsigned int tokens_avail = 0; + + if (kind != OMP_CLAUSE_DEPEND + && (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID)) c_parser_error (parser, "expected identifier"); - while (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID) + while (kind == OMP_CLAUSE_DEPEND + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID)) { + bool array_section_p = false; + if (kind == OMP_CLAUSE_DEPEND) + { + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + struct c_expr expr = c_parser_expr_no_commas (parser, NULL); + if (expr.value != error_mark_node) + { + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = expr.value; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + continue; + } + + tokens.truncate (0); + unsigned int nesting_depth = 0; + while (1) + { + c_token *token = c_parser_peek_token (parser); + switch (token->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + break; + case CPP_OPEN_BRACE: + case CPP_OPEN_PAREN: + case CPP_OPEN_SQUARE: + ++nesting_depth; + goto add; + case CPP_CLOSE_BRACE: + case CPP_CLOSE_PAREN: + case CPP_CLOSE_SQUARE: + if (nesting_depth-- == 0) + break; + goto add; + case CPP_COMMA: + if (nesting_depth == 0) + break; + goto add; + default: + add: + tokens.safe_push (*token); + c_parser_consume_token (parser); + continue; + } + break; + } + + /* Make sure nothing tries to read past the end of the tokens. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + tokens.safe_push (eof_token); + tokens.safe_push (eof_token); + + tokens_avail = parser->tokens_avail; + gcc_assert (parser->tokens == &parser->tokens_buf[0]); + parser->tokens = tokens.address (); + parser->tokens_avail = tokens.length (); + } + tree t = lookup_name (c_parser_peek_token (parser)->value); if (t == NULL_TREE) @@ -11728,6 +11824,8 @@ c_parser_omp_variable_list (c_parser *parser, /* FALLTHROUGH */ case OMP_CLAUSE_DEPEND: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_IN_REDUCTION: + case OMP_CLAUSE_TASK_REDUCTION: while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) { tree low_bound = NULL_TREE, length = NULL_TREE; @@ -11753,6 +11851,7 @@ c_parser_omp_variable_list (c_parser *parser, t = error_mark_node; break; } + array_section_p = true; if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) { location_t expr_loc @@ -11773,6 +11872,30 @@ c_parser_omp_variable_list (c_parser *parser, t = tree_cons (low_bound, length, t); } + if (kind == OMP_CLAUSE_DEPEND + && t != error_mark_node + && parser->tokens_avail != 2) + { + if (array_section_p) + { + error_at (c_parser_peek_token (parser)->location, + "expected %<)%> or %<,%>"); + t = error_mark_node; + } + else + { + parser->tokens = tokens.address (); + parser->tokens_avail = tokens.length (); + + t = c_parser_expr_no_commas (parser, NULL).value; + if (t != error_mark_node && parser->tokens_avail != 2) + { + error_at (c_parser_peek_token (parser)->location, + "expected %<)%> or %<,%>"); + t = error_mark_node; + } + } + } break; default: break; @@ -11789,6 +11912,11 @@ c_parser_omp_variable_list (c_parser *parser, else list = tree_cons (t, NULL_TREE, list); + if (kind == OMP_CLAUSE_DEPEND) + { + parser->tokens = &parser->tokens_buf[0]; + parser->tokens_avail = tokens_avail; + } if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; @@ -12080,7 +12208,11 @@ c_parser_omp_clause_final (c_parser *parser, tree list) directive-name-modifier: parallel | task | taskloop | target data | target | target update - | target enter data | target exit data */ + | target enter data | target exit data + + OpenMP 5.0: + directive-name-modifier: + ... | simd | cancel */ static tree c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) @@ -12096,8 +12228,12 @@ c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); int n = 2; - if (strcmp (p, "parallel") == 0) + if (strcmp (p, "cancel") == 0) + if_modifier = VOID_CST; + else if (strcmp (p, "parallel") == 0) if_modifier = OMP_PARALLEL; + else if (strcmp (p, "simd") == 0) + if_modifier = OMP_SIMD; else if (strcmp (p, "task") == 0) if_modifier = OMP_TASK; else if (strcmp (p, "taskloop") == 0) @@ -12181,7 +12317,9 @@ c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) const char *p = NULL; switch (if_modifier) { + case VOID_CST: p = "cancel"; break; case OMP_PARALLEL: p = "parallel"; break; + case OMP_SIMD: p = "simd"; break; case OMP_TASK: p = "task"; break; case OMP_TASKLOOP: p = "taskloop"; break; case OMP_TARGET_DATA: p = "target data"; break; @@ -12220,12 +12358,41 @@ c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) } /* OpenMP 2.5: - lastprivate ( variable-list ) */ + lastprivate ( variable-list ) + + OpenMP 5.0: + lastprivate ( [ lastprivate-modifier : ] variable-list ) */ static tree c_parser_omp_clause_lastprivate (c_parser *parser, tree list) { - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list); + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + bool conditional = false; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "conditional") == 0) + { + conditional = true; + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + } + tree nlist = c_parser_omp_variable_list (parser, loc, + OMP_CLAUSE_LASTPRIVATE, list); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (conditional) + for (tree c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 1; + return nlist; + } + return list; } /* OpenMP 3.1: @@ -12465,9 +12632,10 @@ c_parser_omp_clause_hint (c_parser *parser, tree list) parens.skip_until_found_close (parser); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + || TREE_CODE (t) != INTEGER_CST) { - c_parser_error (parser, "expected integer expression"); + c_parser_error (parser, "expected constant integer expression"); return list; } @@ -12483,7 +12651,10 @@ c_parser_omp_clause_hint (c_parser *parser, tree list) } /* OpenMP 4.5: - defaultmap ( tofrom : scalar ) */ + defaultmap ( tofrom : scalar ) + + OpenMP 5.0: + defaultmap ( implicit-behavior [ : variable-category ] ) */ static tree c_parser_omp_clause_defaultmap (c_parser *parser, tree list) @@ -12491,39 +12662,155 @@ c_parser_omp_clause_defaultmap (c_parser *parser, tree list) location_t loc = c_parser_peek_token (parser)->location; tree c; const char *p; + enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; + enum omp_clause_defaultmap_kind category + = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; matching_parens parens; if (!parens.require_open (parser)) return list; - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected %<tofrom%>"); + if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) + p = "default"; + else if (!c_parser_next_token_is (parser, CPP_NAME)) + { + invalid_behavior: + c_parser_error (parser, "expected %<alloc%>, %<to%>, %<from%>, " + "%<tofrom%>, %<firstprivate%>, %<none%> " + "or %<default%>"); goto out_err; } - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "tofrom") != 0) + else + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) { - c_parser_error (parser, "expected %<tofrom%>"); - goto out_err; + case 'a': + if (strcmp ("alloc", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC; + else + goto invalid_behavior; + break; + + case 'd': + if (strcmp ("default", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; + else + goto invalid_behavior; + break; + + case 'f': + if (strcmp ("firstprivate", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE; + else if (strcmp ("from", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_FROM; + else + goto invalid_behavior; + break; + + case 'n': + if (strcmp ("none", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_NONE; + else + goto invalid_behavior; + break; + + case 't': + if (strcmp ("tofrom", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM; + else if (strcmp ("to", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_TO; + else + goto invalid_behavior; + break; + + default: + goto invalid_behavior; } c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - goto out_err; - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected %<scalar%>"); - goto out_err; - } - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "scalar") != 0) + + if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { - c_parser_error (parser, "expected %<scalar%>"); - goto out_err; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto out_err; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + invalid_category: + c_parser_error (parser, "expected %<scalar%>, %<aggregate%> or " + "%<pointer%>"); + goto out_err; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + switch (p[0]) + { + case 'a': + if (strcmp ("aggregate", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; + else + goto invalid_category; + break; + + case 'p': + if (strcmp ("pointer", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER; + else + goto invalid_category; + break; + + case 's': + if (strcmp ("scalar", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR; + else + goto invalid_category; + break; + + default: + goto invalid_category; + } + + c_parser_consume_token (parser); } - c_parser_consume_token (parser); parens.skip_until_found_close (parser); - check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULTMAP, "defaultmap"); + + for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP + && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED + || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category + || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) + == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) + { + enum omp_clause_defaultmap_kind cat = category; + location_t loc = OMP_CLAUSE_LOCATION (c); + if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) + cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); + p = NULL; + switch (cat) + { + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: + p = NULL; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: + p = "aggregate"; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: + p = "pointer"; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: + p = "scalar"; + break; + default: + gcc_unreachable (); + } + if (p) + error_at (loc, "too many %<defaultmap%> clauses with %qs category", + p); + else + error_at (loc, "too many %<defaultmap%> clauses with unspecified " + "category"); + break; + } + c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP); + OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category); OMP_CLAUSE_CHAIN (c) = list; return c; @@ -12957,18 +13244,51 @@ c_parser_omp_clause_private (c_parser *parser, tree list) reduction-operator: One of: + * - & ^ | && || - identifier */ + identifier + + OpenMP 5.0: + reduction ( reduction-modifier, reduction-operator : variable-list ) + in_reduction ( reduction-operator : variable-list ) + task_reduction ( reduction-operator : variable-list ) */ static tree -c_parser_omp_clause_reduction (c_parser *parser, tree list) +c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, + bool is_omp, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; matching_parens parens; if (parens.require_open (parser)) { + bool task = false; + bool inscan = false; enum tree_code code = ERROR_MARK; tree reduc_id = NULL_TREE; + if (kind == OMP_CLAUSE_REDUCTION && is_omp) + { + if (c_parser_next_token_is_keyword (parser, RID_DEFAULT) + && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "task") == 0) + task = true; + else if (strcmp (p, "inscan") == 0) + inscan = true; + if (task || inscan) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + } + } + switch (c_parser_peek_token (parser)->type) { case CPP_PLUS: @@ -13025,8 +13345,7 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) { tree nl, c; - nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_REDUCTION, list); + nl = c_parser_omp_variable_list (parser, clause_loc, kind, list); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { tree d = OMP_CLAUSE_DECL (c), type; @@ -13051,6 +13370,10 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) while (TREE_CODE (type) == ARRAY_TYPE) type = TREE_TYPE (type); OMP_CLAUSE_REDUCTION_CODE (c) = code; + if (task) + OMP_CLAUSE_REDUCTION_TASK (c) = 1; + else if (inscan) + OMP_CLAUSE_REDUCTION_INSCAN (c) = 1; if (code == ERROR_MARK || !(INTEGRAL_TYPE_P (type) || TREE_CODE (type) == REAL_TYPE @@ -13510,6 +13833,15 @@ c_parser_omp_clause_linear (c_parser *parser, tree list) return nl; } +/* OpenMP 5.0: + nontemporal ( variable-list ) */ + +static tree +c_parser_omp_clause_nontemporal (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_NONTEMPORAL, list); +} + /* OpenMP 4.0: safelen ( constant-expression ) */ @@ -13670,6 +14002,106 @@ c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc, return u; } +/* OpenMP 5.0: + iterators ( iterators-definition ) + + iterators-definition: + iterator-specifier + iterator-specifier , iterators-definition + + iterator-specifier: + identifier = range-specification + iterator-type identifier = range-specification + + range-specification: + begin : end + begin : end : step */ + +static tree +c_parser_omp_iterators (c_parser *parser) +{ + tree ret = NULL_TREE, *last = &ret; + c_parser_consume_token (parser); + + push_scope (); + + matching_parens parens; + if (!parens.require_open (parser)) + return error_mark_node; + + do + { + tree iter_type = NULL_TREE, type_expr = NULL_TREE; + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + if (type != NULL) + iter_type = groktypename (type, &type_expr, NULL); + } + if (iter_type == NULL_TREE) + iter_type = integer_type_node; + + location_t loc = c_parser_peek_token (parser)->location; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + break; + + location_t eloc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + tree begin = expr.value; + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + break; + + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + tree end = expr.value; + + tree step = integer_one_node; + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + step = expr.value; + } + + tree iter_var = build_decl (loc, VAR_DECL, id, iter_type); + DECL_ARTIFICIAL (iter_var) = 1; + DECL_CONTEXT (iter_var) = current_function_decl; + pushdecl (iter_var); + + *last = make_tree_vec (6); + TREE_VEC_ELT (*last, 0) = iter_var; + TREE_VEC_ELT (*last, 1) = begin; + TREE_VEC_ELT (*last, 2) = end; + TREE_VEC_ELT (*last, 3) = step; + last = &TREE_CHAIN (*last); + + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + continue; + } + break; + } + while (1); + + parens.skip_until_found_close (parser); + return ret ? ret : error_mark_node; +} + /* OpenMP 4.0: depend ( depend-kind: variable-list ) @@ -13679,40 +14111,71 @@ c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc, OpenMP 4.5: depend ( source ) - depend ( sink : vec ) */ + depend ( sink : vec ) + + OpenMP 5.0: + depend ( depend-modifier , depend-kind: variable-list ) + + depend-kind: + in | out | inout | mutexinoutset | depobj + + depend-modifier: + iterator ( iterators-definition ) */ static tree c_parser_omp_clause_depend (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; - tree nl, c; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST; + tree nl, c, iterators = NULL_TREE; matching_parens parens; if (!parens.require_open (parser)) return list; - if (c_parser_next_token_is (parser, CPP_NAME)) + do { + if (c_parser_next_token_is_not (parser, CPP_NAME)) + goto invalid_kind; + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE) + { + iterators = c_parser_omp_iterators (parser); + c_parser_require (parser, CPP_COMMA, "expected %<,%>"); + continue; + } if (strcmp ("in", p) == 0) kind = OMP_CLAUSE_DEPEND_IN; else if (strcmp ("inout", p) == 0) kind = OMP_CLAUSE_DEPEND_INOUT; + else if (strcmp ("mutexinoutset", p) == 0) + kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; else if (strcmp ("out", p) == 0) kind = OMP_CLAUSE_DEPEND_OUT; - else if (strcmp ("source", p) == 0) - kind = OMP_CLAUSE_DEPEND_SOURCE; + else if (strcmp ("depobj", p) == 0) + kind = OMP_CLAUSE_DEPEND_DEPOBJ; else if (strcmp ("sink", p) == 0) kind = OMP_CLAUSE_DEPEND_SINK; + else if (strcmp ("source", p) == 0) + kind = OMP_CLAUSE_DEPEND_SOURCE; else goto invalid_kind; + break; } - else - goto invalid_kind; + while (1); c_parser_consume_token (parser); + if (iterators + && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) + { + pop_scope (); + error_at (clause_loc, "%<iterator%> modifier incompatible with %qs", + kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + iterators = NULL_TREE; + } + if (kind == OMP_CLAUSE_DEPEND_SOURCE) { c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); @@ -13733,8 +14196,22 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_DEPEND, list); + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_DEPEND_KIND (c) = kind; + { + OMP_CLAUSE_DEPEND_KIND (c) = kind; + if (iterators) + OMP_CLAUSE_DECL (c) + = build_tree_list (iterators, OMP_CLAUSE_DECL (c)); + } } parens.skip_until_found_close (parser); @@ -13744,6 +14221,8 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) c_parser_error (parser, "invalid depend kind"); resync_fail: parens.skip_until_found_close (parser); + if (iterators) + pop_scope (); return list; } @@ -14169,12 +14648,14 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, c_name = "private"; break; case PRAGMA_OACC_CLAUSE_REDUCTION: - clauses = c_parser_omp_clause_reduction (parser, clauses); + clauses + = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, + false, clauses); c_name = "reduction"; break; case PRAGMA_OACC_CLAUSE_SEQ: clauses = c_parser_oacc_simple_clause (parser, OMP_CLAUSE_SEQ, - clauses); + clauses); c_name = "seq"; break; case PRAGMA_OACC_CLAUSE_TILE: @@ -14295,6 +14776,12 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_if (parser, clauses, true); c_name = "if"; break; + case PRAGMA_OMP_CLAUSE_IN_REDUCTION: + clauses + = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_IN_REDUCTION, + true, clauses); + c_name = "in_reduction"; + break; case PRAGMA_OMP_CLAUSE_LASTPRIVATE: clauses = c_parser_omp_clause_lastprivate (parser, clauses); c_name = "lastprivate"; @@ -14328,7 +14815,9 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, c_name = "private"; break; case PRAGMA_OMP_CLAUSE_REDUCTION: - clauses = c_parser_omp_clause_reduction (parser, clauses); + clauses + = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION, + true, clauses); c_name = "reduction"; break; case PRAGMA_OMP_CLAUSE_SCHEDULE: @@ -14339,6 +14828,12 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_shared (parser, clauses); c_name = "shared"; break; + case PRAGMA_OMP_CLAUSE_TASK_REDUCTION: + clauses + = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_TASK_REDUCTION, + true, clauses); + c_name = "task_reduction"; + break; case PRAGMA_OMP_CLAUSE_UNTIED: clauses = c_parser_omp_clause_untied (parser, clauses); c_name = "untied"; @@ -14348,6 +14843,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses); c_name = "inbranch"; break; + case PRAGMA_OMP_CLAUSE_NONTEMPORAL: + clauses = c_parser_omp_clause_nontemporal (parser, clauses); + c_name = "nontemporal"; + break; case PRAGMA_OMP_CLAUSE_NOTINBRANCH: clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH, clauses); @@ -15252,62 +15751,157 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; - enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; + enum tree_code code = ERROR_MARK, opcode = NOP_EXPR; + enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED; struct c_expr expr; location_t eloc; bool structured_block = false; bool swapped = false; - bool seq_cst = false; bool non_lvalue_p; + bool first = true; + tree clauses = NULL_TREE; - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (!strcmp (p, "seq_cst")) - { - seq_cst = true; - c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_COMMA) - && c_parser_peek_2nd_token (parser)->type == CPP_NAME) - c_parser_consume_token (parser); - } - } - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - - if (!strcmp (p, "read")) - code = OMP_ATOMIC_READ; - else if (!strcmp (p, "write")) - code = NOP_EXPR; - else if (!strcmp (p, "update")) - code = OMP_ATOMIC; - else if (!strcmp (p, "capture")) - code = OMP_ATOMIC_CAPTURE_NEW; - else - p = NULL; - if (p) - c_parser_consume_token (parser); - } - if (!seq_cst) + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) { - if (c_parser_next_token_is (parser, CPP_COMMA) - && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + if (!first && c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); + first = false; + if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (!strcmp (p, "seq_cst")) + location_t cloc = c_parser_peek_token (parser)->location; + enum tree_code new_code = ERROR_MARK; + enum omp_memory_order new_memory_order + = OMP_MEMORY_ORDER_UNSPECIFIED; + + if (!strcmp (p, "read")) + new_code = OMP_ATOMIC_READ; + else if (!strcmp (p, "write")) + new_code = NOP_EXPR; + else if (!strcmp (p, "update")) + new_code = OMP_ATOMIC; + else if (!strcmp (p, "capture")) + new_code = OMP_ATOMIC_CAPTURE_NEW; + else if (!strcmp (p, "seq_cst")) + new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; + else if (!strcmp (p, "acq_rel")) + new_memory_order = OMP_MEMORY_ORDER_ACQ_REL; + else if (!strcmp (p, "release")) + new_memory_order = OMP_MEMORY_ORDER_RELEASE; + else if (!strcmp (p, "acquire")) + new_memory_order = OMP_MEMORY_ORDER_ACQUIRE; + else if (!strcmp (p, "relaxed")) + new_memory_order = OMP_MEMORY_ORDER_RELAXED; + else if (!strcmp (p, "hint")) + { + c_parser_consume_token (parser); + clauses = c_parser_omp_clause_hint (parser, clauses); + continue; + } + else + { + p = NULL; + error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " + "%<capture%>, %<seq_cst%>, %<acq_rel%>, " + "%<release%>, %<relaxed%> or %<hint%> clause"); + } + if (p) { - seq_cst = true; + if (new_code != ERROR_MARK) + { + if (code != ERROR_MARK) + error_at (cloc, "too many atomic clauses"); + else + code = new_code; + } + else if (new_memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) + { + if (memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) + error_at (cloc, "too many memory order clauses"); + else + memory_order = new_memory_order; + } c_parser_consume_token (parser); + continue; } } + break; } c_parser_skip_to_pragma_eol (parser); + if (code == ERROR_MARK) + code = OMP_ATOMIC; + if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) + { + omp_requires_mask + = (enum omp_requires) (omp_requires_mask + | OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED); + switch ((enum omp_memory_order) + (omp_requires_mask & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER)) + { + case OMP_MEMORY_ORDER_UNSPECIFIED: + case OMP_MEMORY_ORDER_RELAXED: + memory_order = OMP_MEMORY_ORDER_RELAXED; + break; + case OMP_MEMORY_ORDER_SEQ_CST: + memory_order = OMP_MEMORY_ORDER_SEQ_CST; + break; + case OMP_MEMORY_ORDER_ACQ_REL: + switch (code) + { + case OMP_ATOMIC_READ: + memory_order = OMP_MEMORY_ORDER_ACQUIRE; + break; + case NOP_EXPR: /* atomic write */ + case OMP_ATOMIC: + memory_order = OMP_MEMORY_ORDER_RELEASE; + break; + default: + memory_order = OMP_MEMORY_ORDER_ACQ_REL; + break; + } + break; + default: + gcc_unreachable (); + } + } + else + switch (code) + { + case OMP_ATOMIC_READ: + if (memory_order == OMP_MEMORY_ORDER_ACQ_REL + || memory_order == OMP_MEMORY_ORDER_RELEASE) + { + error_at (loc, "%<#pragma omp atomic read%> incompatible with " + "%<acq_rel%> or %<release%> clauses"); + memory_order = OMP_MEMORY_ORDER_SEQ_CST; + } + break; + case NOP_EXPR: /* atomic write */ + if (memory_order == OMP_MEMORY_ORDER_ACQ_REL + || memory_order == OMP_MEMORY_ORDER_ACQUIRE) + { + error_at (loc, "%<#pragma omp atomic write%> incompatible with " + "%<acq_rel%> or %<acquire%> clauses"); + memory_order = OMP_MEMORY_ORDER_SEQ_CST; + } + break; + case OMP_ATOMIC: + if (memory_order == OMP_MEMORY_ORDER_ACQ_REL + || memory_order == OMP_MEMORY_ORDER_ACQUIRE) + { + error_at (loc, "%<#pragma omp atomic update%> incompatible with " + "%<acq_rel%> or %<acquire%> clauses"); + memory_order = OMP_MEMORY_ORDER_SEQ_CST; + } + break; + default: + break; + } + switch (code) { case OMP_ATOMIC_READ: @@ -15624,7 +16218,7 @@ done: } else stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, - swapped, seq_cst); + swapped, memory_order); if (stmt != error_mark_node) add_stmt (stmt); @@ -15676,6 +16270,10 @@ c_parser_omp_critical (location_t loc, c_parser *parser, bool *if_p) else c_parser_error (parser, "expected identifier"); + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + clauses = c_parser_omp_all_clauses (parser, OMP_CRITICAL_CLAUSE_MASK, "#pragma omp critical"); @@ -15691,24 +16289,159 @@ c_parser_omp_critical (location_t loc, c_parser *parser, bool *if_p) return c_finish_omp_critical (loc, stmt, name, clauses); } +/* OpenMP 5.0: + # pragma omp depobj ( depobj ) depobj-clause new-line + + depobj-clause: + depend (dependence-type : locator) + destroy + update (dependence-type) + + dependence-type: + in + out + inout + mutexinout */ + +static void +c_parser_omp_depobj (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + c_parser_skip_to_pragma_eol (parser); + return; + } + + tree depobj = c_parser_expr_no_commas (parser, NULL).value; + if (depobj != error_mark_node) + { + if (!lvalue_p (depobj)) + { + error_at (EXPR_LOC_OR_LOC (depobj, loc), + "%<depobj%> expression is not lvalue expression"); + depobj = error_mark_node; + } + else + { + tree addr = build_unary_op (EXPR_LOC_OR_LOC (depobj, loc), ADDR_EXPR, + depobj, false); + if (addr == error_mark_node) + depobj = error_mark_node; + else + depobj = build_indirect_ref (EXPR_LOC_OR_LOC (depobj, loc), + addr, RO_UNARY_STAR); + } + } + + parens.skip_until_found_close (parser); + tree clause = NULL_TREE; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE; + location_t c_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + c_parser_consume_token (parser); + if (!strcmp ("depend", p)) + { + clause = c_parser_omp_clause_depend (parser, NULL_TREE); + clause = c_finish_omp_clauses (clause, C_ORT_OMP); + if (!clause) + clause = error_mark_node; + } + else if (!strcmp ("destroy", p)) + kind = OMP_CLAUSE_DEPEND_LAST; + else if (!strcmp ("update", p)) + { + matching_parens c_parens; + if (c_parens.require_open (parser)) + { + location_t c2_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p2 + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + c_parser_consume_token (parser); + if (!strcmp ("in", p2)) + kind = OMP_CLAUSE_DEPEND_IN; + else if (!strcmp ("out", p2)) + kind = OMP_CLAUSE_DEPEND_OUT; + else if (!strcmp ("inout", p2)) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (!strcmp ("mutexinoutset", p2)) + kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; + } + if (kind == OMP_CLAUSE_DEPEND_SOURCE) + { + clause = error_mark_node; + error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%> or " + "%<mutexinoutset%>"); + } + c_parens.skip_until_found_close (parser); + } + else + clause = error_mark_node; + } + } + if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE) + { + clause = error_mark_node; + error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause"); + } + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_depobj (loc, depobj, kind, clause); +} + + /* OpenMP 2.5: # pragma omp flush flush-vars[opt] new-line flush-vars: - ( variable-list ) */ + ( variable-list ) + + OpenMP 5.0: + # pragma omp flush memory-order-clause new-line */ static void c_parser_omp_flush (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_pragma (parser); + enum memmodel mo = MEMMODEL_LAST; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (!strcmp (p, "acq_rel")) + mo = MEMMODEL_ACQ_REL; + else if (!strcmp (p, "release")) + mo = MEMMODEL_RELEASE; + else if (!strcmp (p, "acquire")) + mo = MEMMODEL_ACQUIRE; + else + error_at (c_parser_peek_token (parser)->location, + "expected %<acq_rel%>, %<release%> or %<acquire%>"); + c_parser_consume_token (parser); + } if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) - c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + { + if (mo != MEMMODEL_LAST) + error_at (c_parser_peek_token (parser)->location, + "%<flush%> list specified together with memory order " + "clause"); + c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + } else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) c_parser_error (parser, "expected %<(%> or end of line"); c_parser_skip_to_pragma_eol (parser); - c_finish_omp_flush (loc); + c_finish_omp_flush (loc, mo); } /* Parse the restricted form of loop statements allowed by OpenACC and OpenMP. @@ -15880,6 +16613,10 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, case LT_EXPR: case LE_EXPR: break; + case NE_EXPR: + if (code != OACC_LOOP) + break; + /* FALLTHRU. */ default: /* Can't be cond = error_mark_node, because we want to preserve the location until c_finish_omp_for. */ @@ -16011,7 +16748,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, if (!fail) { stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv, - incrv, body, pre_body); + incrv, body, pre_body, true); /* Check for iterators appearing in lb, b or incr expressions. */ if (stmt && !c_omp_check_loop_iv (stmt, declv, NULL)) @@ -16108,7 +16845,9 @@ omp_split_clauses (location_t loc, enum tree_code code, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL)) static tree c_parser_omp_simd (location_t loc, c_parser *parser, @@ -16236,6 +16975,9 @@ c_parser_omp_for (location_t loc, c_parser *parser, return ret; } +static tree c_parser_omp_taskloop (location_t, c_parser *, char *, + omp_clause_mask, tree *, bool *); + /* OpenMP 2.5: # pragma omp master new-line structured-block @@ -16244,9 +16986,52 @@ c_parser_omp_for (location_t loc, c_parser *parser, */ static tree -c_parser_omp_master (location_t loc, c_parser *parser, bool *if_p) +c_parser_omp_master (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) { - c_parser_skip_to_pragma_eol (parser); + tree block, clauses, ret; + + strcat (p_name, " master"); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = c_finish_omp_master (loc, block); + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + if (cclauses) + { + clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); + omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses); + } + else + c_parser_skip_to_pragma_eol (parser); + return c_finish_omp_master (loc, c_parser_omp_structured_block (parser, if_p)); } @@ -16508,19 +17293,38 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, c_parser_skip_to_pragma_eol (parser); return NULL_TREE; } - else if (!flag_openmp) /* flag_openmp_simd */ - { - c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; - } else if (cclauses == NULL && c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "sections") == 0) + if (strcmp (p, "master") == 0) { tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; - if (cclauses == NULL) - cclauses = cclauses_buf; + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_master (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_omp_parallel (); + tree ret = c_parser_omp_master (loc, parser, p_name, mask, cclauses, + if_p); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + if (ret == NULL) + return ret; + return stmt; + } + else if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + else if (strcmp (p, "sections") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; c_parser_consume_token (parser); block = c_begin_omp_parallel (); @@ -16532,6 +17336,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, return stmt; } } + else if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); if (cclauses) @@ -16591,7 +17400,8 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) static tree c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) @@ -16608,16 +17418,35 @@ c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) /* OpenMP 3.0: # pragma omp taskwait new-line + + OpenMP 5.0: + # pragma omp taskwait taskwait-clause[optseq] new-line */ +#define OMP_TASKWAIT_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + static void c_parser_omp_taskwait (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; c_parser_consume_pragma (parser); - c_parser_skip_to_pragma_eol (parser); - c_finish_omp_taskwait (loc); + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK, + "#pragma omp taskwait"); + + if (clauses) + { + tree stmt = make_node (OMP_TASK); + TREE_TYPE (stmt) = void_node; + OMP_TASK_CLAUSES (stmt) = clauses; + OMP_TASK_BODY (stmt) = NULL_TREE; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + } + else + c_finish_omp_taskwait (loc); } /* OpenMP 3.1: @@ -16636,15 +17465,22 @@ c_parser_omp_taskyield (c_parser *parser) /* OpenMP 4.0: # pragma omp taskgroup new-line + + OpenMP 5.0: + # pragma omp taskgroup taskgroup-clause[optseq] new-line */ +#define OMP_TASKGROUP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION)) + static tree -c_parser_omp_taskgroup (c_parser *parser, bool *if_p) +c_parser_omp_taskgroup (location_t loc, c_parser *parser, bool *if_p) { - location_t loc = c_parser_peek_token (parser)->location; - c_parser_skip_to_pragma_eol (parser); - return c_finish_omp_taskgroup (loc, c_parser_omp_structured_block (parser, - if_p)); + tree clauses = c_parser_omp_all_clauses (parser, OMP_TASKGROUP_CLAUSE_MASK, + "#pragma omp taskgroup"); + + tree body = c_parser_omp_structured_block (parser, if_p); + return c_finish_omp_taskgroup (loc, body, clauses); } /* OpenMP 4.0: @@ -16850,7 +17686,7 @@ c_parser_omp_teams (location_t loc, c_parser *parser, if (!flag_openmp) /* flag_openmp_simd */ return c_parser_omp_distribute (loc, parser, p_name, mask, cclauses, if_p); - block = c_begin_compound_stmt (true); + block = c_begin_omp_parallel (); ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses, if_p); block = c_end_compound_stmt (loc, block, true); @@ -16862,6 +17698,7 @@ c_parser_omp_teams (location_t loc, c_parser *parser, OMP_TEAMS_CLAUSES (ret) = clauses; OMP_TEAMS_BODY (ret) = block; OMP_TEAMS_COMBINED (ret) = 1; + SET_EXPR_LOCATION (ret, loc); return add_stmt (ret); } } @@ -16881,7 +17718,10 @@ c_parser_omp_teams (location_t loc, c_parser *parser, tree stmt = make_node (OMP_TEAMS); TREE_TYPE (stmt) = void_type_node; OMP_TEAMS_CLAUSES (stmt) = clauses; - OMP_TEAMS_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); + block = c_begin_omp_parallel (); + add_stmt (c_parser_omp_structured_block (parser, if_p)); + OMP_TEAMS_BODY (stmt) = c_end_compound_stmt (loc, block, true); + SET_EXPR_LOCATION (stmt, loc); return add_stmt (stmt); } @@ -16929,6 +17769,8 @@ c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p) *pc = OMP_CLAUSE_CHAIN (*pc); continue; } + else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR) + map_seen = 3; pc = &OMP_CLAUSE_CHAIN (*pc); } @@ -16937,7 +17779,7 @@ c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p) if (map_seen == 0) error_at (loc, "%<#pragma omp target data%> must contain at least " - "one %<map%> clause"); + "one %<map%> or %<use_device_ptr%> clause"); return NULL_TREE; } @@ -17196,6 +18038,10 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) return false; } + if (flag_openmp) + omp_requires_mask + = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); + if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); @@ -17296,6 +18142,7 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; OMP_TARGET_BODY (stmt) = block; OMP_TARGET_COMBINED (stmt) = 1; + SET_EXPR_LOCATION (stmt, loc); add_stmt (stmt); pc = &OMP_TARGET_CLAUSES (stmt); goto check_clauses; @@ -18082,6 +18929,176 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) c_parser_skip_to_pragma_eol (parser); } +/* OpenMP 5.0 + #pragma omp requires clauses[optseq] new-line */ + +static void +c_parser_omp_requires (c_parser *parser) +{ + bool first = true; + enum omp_requires new_req = (enum omp_requires) 0; + + c_parser_consume_pragma (parser); + + location_t loc = c_parser_peek_token (parser)->location; + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + if (!first && c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + + first = false; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + location_t cloc = c_parser_peek_token (parser)->location; + enum omp_requires this_req = (enum omp_requires) 0; + + if (!strcmp (p, "unified_address")) + this_req = OMP_REQUIRES_UNIFIED_ADDRESS; + else if (!strcmp (p, "unified_shared_memory")) + this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY; + else if (!strcmp (p, "dynamic_allocators")) + this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS; + else if (!strcmp (p, "reverse_offload")) + this_req = OMP_REQUIRES_REVERSE_OFFLOAD; + else if (!strcmp (p, "atomic_default_mem_order")) + { + c_parser_consume_token (parser); + + matching_parens parens; + if (parens.require_open (parser)) + { + if (c_parser_next_token_is (parser, CPP_NAME)) + { + tree v = c_parser_peek_token (parser)->value; + p = IDENTIFIER_POINTER (v); + + if (!strcmp (p, "seq_cst")) + this_req + = (enum omp_requires) OMP_MEMORY_ORDER_SEQ_CST; + else if (!strcmp (p, "relaxed")) + this_req + = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED; + else if (!strcmp (p, "acq_rel")) + this_req + = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL; + } + if (this_req == 0) + { + error_at (c_parser_peek_token (parser)->location, + "expected %<seq_cst%>, %<relaxed%> or " + "%<acq_rel%>"); + if (c_parser_peek_2nd_token (parser)->type + == CPP_CLOSE_PAREN) + c_parser_consume_token (parser); + } + else + c_parser_consume_token (parser); + + parens.skip_until_found_close (parser); + if (this_req == 0) + { + c_parser_skip_to_pragma_eol (parser, false); + return; + } + } + p = NULL; + } + else + { + error_at (cloc, "expected %<unified_address%>, " + "%<unified_shared_memory%>, " + "%<dynamic_allocators%>, " + "%<reverse_offload%> " + "or %<atomic_default_mem_order%> clause"); + c_parser_skip_to_pragma_eol (parser, false); + return; + } + if (p) + c_parser_consume_token (parser); + if (this_req) + { + if ((this_req & ~OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) + { + if ((this_req & new_req) != 0) + error_at (cloc, "too many %qs clauses", p); + if (this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS + && (omp_requires_mask & OMP_REQUIRES_TARGET_USED) != 0) + error_at (cloc, "%qs clause used lexically after first " + "target construct or offloading API", p); + } + else if ((new_req & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) + { + error_at (cloc, "too many %qs clauses", + "atomic_default_mem_order"); + this_req = (enum omp_requires) 0; + } + else if ((omp_requires_mask + & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) + { + error_at (cloc, "more than one %<atomic_default_mem_order%>" + " clause in a single compilation unit"); + this_req + = (enum omp_requires) + (omp_requires_mask + & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER); + } + else if ((omp_requires_mask + & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED) != 0) + error_at (cloc, "%<atomic_default_mem_order%> clause used " + "lexically after first %<atomic%> construct " + "without memory order clause"); + new_req = (enum omp_requires) (new_req | this_req); + omp_requires_mask + = (enum omp_requires) (omp_requires_mask | this_req); + continue; + } + } + break; + } + c_parser_skip_to_pragma_eol (parser); + + if (new_req == 0) + error_at (loc, "%<pragma omp requires%> requires at least one clause"); +} + +/* Helper function for c_parser_omp_taskloop. + Disallow zero sized or potentially zero sized task reductions. */ + +static tree +c_finish_taskloop_clauses (tree clauses) +{ + tree *pc = &clauses; + for (tree c = clauses; c; c = *pc) + { + bool remove = false; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + tree type = strip_array_types (TREE_TYPE (OMP_CLAUSE_DECL (c))); + if (integer_zerop (TYPE_SIZE_UNIT (type))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero sized type %qT in %<reduction%> clause", type); + remove = true; + } + else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "variable sized type %qT in %<reduction%> clause", + type); + remove = true; + } + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + return clauses; +} + /* OpenMP 4.5: #pragma omp taskloop taskloop-clause[optseq] new-line for-loop @@ -18103,7 +19120,9 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) static tree c_parser_omp_taskloop (location_t loc, c_parser *parser, @@ -18114,6 +19133,10 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser, strcat (p_name, " taskloop"); mask |= OMP_TASKLOOP_CLAUSE_MASK; + /* #pragma omp parallel master taskloop{, simd} disallow in_reduction + clause. */ + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION); if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -18124,7 +19147,6 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser, tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; if (cclauses == NULL) cclauses = cclauses_buf; - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION); c_parser_consume_token (parser); if (!flag_openmp) /* flag_openmp_simd */ return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, @@ -18138,6 +19160,8 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser, TREE_TYPE (ret) = void_type_node; OMP_FOR_BODY (ret) = block; OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; + OMP_FOR_CLAUSES (ret) + = c_finish_taskloop_clauses (OMP_FOR_CLAUSES (ret)); SET_EXPR_LOCATION (ret, loc); add_stmt (ret); return ret; @@ -18156,6 +19180,7 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser, clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; } + clauses = c_finish_taskloop_clauses (clauses); block = c_begin_compound_stmt (true); ret = c_parser_omp_for_loop (loc, parser, OMP_TASKLOOP, clauses, NULL, if_p); block = c_end_compound_stmt (loc, block, true); @@ -18223,7 +19248,8 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL, if_p); break; case PRAGMA_OMP_MASTER: - stmt = c_parser_omp_master (loc, parser, if_p); + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p); break; case PRAGMA_OMP_PARALLEL: strcpy (p_name, "#pragma omp"); @@ -18244,7 +19270,7 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) stmt = c_parser_omp_task (loc, parser, if_p); break; case PRAGMA_OMP_TASKGROUP: - stmt = c_parser_omp_taskgroup (parser, if_p); + stmt = c_parser_omp_taskgroup (loc, parser, if_p); break; case PRAGMA_OMP_TASKLOOP: strcpy (p_name, "#pragma omp"); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 9d09b8d..144977e 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -12525,6 +12525,11 @@ c_finish_omp_cancel (location_t loc, tree clauses) tree ifc = omp_find_clause (clauses, OMP_CLAUSE_IF); if (ifc != NULL_TREE) { + if (OMP_CLAUSE_IF_MODIFIER (ifc) != ERROR_MARK + && OMP_CLAUSE_IF_MODIFIER (ifc) != VOID_CST) + error_at (OMP_CLAUSE_LOCATION (ifc), + "expected %<cancel%> %<if%> clause modifier"); + tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc)); ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR, boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc), @@ -12717,7 +12722,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, if (!integer_nonzerop (length)) { if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) { if (integer_zerop (length)) { @@ -12783,7 +12790,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, if (tree_int_cst_equal (size, low_bound)) { if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) { error_at (OMP_CLAUSE_LOCATION (c), "zero length array section in %qs clause", @@ -12802,7 +12811,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, else if (length == NULL_TREE) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; @@ -12838,7 +12849,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, else if (length == NULL_TREE) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_IN_REDUCTION + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TASK_REDUCTION) maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; @@ -12910,7 +12923,13 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) bool maybe_zero_len = false; unsigned int first_non_one = 0; auto_vec<tree, 10> types; - tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, + tree *tp = &OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && TREE_CODE (*tp) == TREE_LIST + && TREE_PURPOSE (*tp) + && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) + tp = &TREE_VALUE (*tp); + tree first = handle_omp_array_sections_1 (c, *tp, types, maybe_zero_len, first_non_one, ort); if (first == error_mark_node) @@ -12919,7 +12938,7 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) return false; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) { - tree t = OMP_CLAUSE_DECL (c); + tree t = *tp; tree tem = NULL_TREE; /* Need to evaluate side effects in the length expressions if any. */ @@ -12938,7 +12957,7 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if (tem) first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); first = c_fully_fold (first, false, NULL, true); - OMP_CLAUSE_DECL (c) = first; + *tp = first; } else { @@ -13010,7 +13029,9 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if (i > first_non_one && ((length && integer_nonzerop (length)) - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION)) continue; if (length) l = fold_convert (sizetype, length); @@ -13038,7 +13059,9 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) tree eltype = TREE_TYPE (types[num - 1]); while (TREE_CODE (eltype) == ARRAY_TYPE) eltype = TREE_TYPE (eltype); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) { if (integer_zerop (size) || integer_zerop (size_in_bytes (eltype))) @@ -13062,10 +13085,13 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) } if (side_effects) size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION) { size = size_binop (MINUS_EXPR, size, size_one_node); size = c_fully_fold (size, false, NULL); + size = save_expr (size); tree index_type = build_index_type (size); tree eltype = TREE_TYPE (first); while (TREE_CODE (eltype) == ARRAY_TYPE) @@ -13195,6 +13221,178 @@ c_find_omp_placeholder_r (tree *tp, int *, void *data) return NULL_TREE; } +/* Similarly, but also walk aggregate fields. */ + +struct c_find_omp_var_s { tree var; hash_set<tree> *pset; }; + +static tree +c_find_omp_var_r (tree *tp, int *, void *data) +{ + if (*tp == ((struct c_find_omp_var_s *) data)->var) + return *tp; + if (RECORD_OR_UNION_TYPE_P (*tp)) + { + tree field; + hash_set<tree> *pset = ((struct c_find_omp_var_s *) data)->pset; + + for (field = TYPE_FIELDS (*tp); field; + field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + { + tree ret = walk_tree (&DECL_FIELD_OFFSET (field), + c_find_omp_var_r, data, pset); + if (ret) + return ret; + ret = walk_tree (&DECL_SIZE (field), c_find_omp_var_r, data, pset); + if (ret) + return ret; + ret = walk_tree (&DECL_SIZE_UNIT (field), c_find_omp_var_r, data, + pset); + if (ret) + return ret; + ret = walk_tree (&TREE_TYPE (field), c_find_omp_var_r, data, pset); + if (ret) + return ret; + } + } + else if (INTEGRAL_TYPE_P (*tp)) + return walk_tree (&TYPE_MAX_VALUE (*tp), c_find_omp_var_r, data, + ((struct c_find_omp_var_s *) data)->pset); + return NULL_TREE; +} + +/* Finish OpenMP iterators ITER. Return true if they are errorneous + and clauses containing them should be removed. */ + +static bool +c_omp_finish_iterators (tree iter) +{ + bool ret = false; + for (tree it = iter; it; it = TREE_CHAIN (it)) + { + tree var = TREE_VEC_ELT (it, 0); + tree begin = TREE_VEC_ELT (it, 1); + tree end = TREE_VEC_ELT (it, 2); + tree step = TREE_VEC_ELT (it, 3); + tree orig_step; + tree type = TREE_TYPE (var); + location_t loc = DECL_SOURCE_LOCATION (var); + if (type == error_mark_node) + { + ret = true; + continue; + } + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) + { + error_at (loc, "iterator %qD has neither integral nor pointer type", + var); + ret = true; + continue; + } + else if (TYPE_ATOMIC (type)) + { + error_at (loc, "iterator %qD has %<_Atomic%> qualified type", var); + ret = true; + continue; + } + else if (TYPE_READONLY (type)) + { + error_at (loc, "iterator %qD has const qualified type", var); + ret = true; + continue; + } + else if (step == error_mark_node + || TREE_TYPE (step) == error_mark_node) + { + ret = true; + continue; + } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) + { + error_at (EXPR_LOC_OR_LOC (step, loc), + "iterator step with non-integral type"); + ret = true; + continue; + } + begin = c_fully_fold (build_c_cast (loc, type, begin), false, NULL); + end = c_fully_fold (build_c_cast (loc, type, end), false, NULL); + orig_step = save_expr (c_fully_fold (step, false, NULL)); + tree stype = POINTER_TYPE_P (type) ? sizetype : type; + step = c_fully_fold (build_c_cast (loc, stype, orig_step), false, NULL); + if (POINTER_TYPE_P (type)) + { + begin = save_expr (begin); + step = pointer_int_sum (loc, PLUS_EXPR, begin, step); + step = fold_build2_loc (loc, MINUS_EXPR, sizetype, + fold_convert (sizetype, step), + fold_convert (sizetype, begin)); + step = fold_convert (ssizetype, step); + } + if (integer_zerop (step)) + { + error_at (loc, "iterator %qD has zero step", var); + ret = true; + continue; + } + + if (begin == error_mark_node + || end == error_mark_node + || step == error_mark_node + || orig_step == error_mark_node) + { + ret = true; + continue; + } + hash_set<tree> pset; + tree it2; + for (it2 = TREE_CHAIN (it); it2; it2 = TREE_CHAIN (it2)) + { + tree var2 = TREE_VEC_ELT (it2, 0); + tree begin2 = TREE_VEC_ELT (it2, 1); + tree end2 = TREE_VEC_ELT (it2, 2); + tree step2 = TREE_VEC_ELT (it2, 3); + tree type2 = TREE_TYPE (var2); + location_t loc2 = DECL_SOURCE_LOCATION (var2); + struct c_find_omp_var_s data = { var, &pset }; + if (walk_tree (&type2, c_find_omp_var_r, &data, &pset)) + { + error_at (loc2, + "type of iterator %qD refers to outer iterator %qD", + var2, var); + break; + } + else if (walk_tree (&begin2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (begin2, loc2), + "begin expression refers to outer iterator %qD", var); + break; + } + else if (walk_tree (&end2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (end2, loc2), + "end expression refers to outer iterator %qD", var); + break; + } + else if (walk_tree (&step2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (step2, loc2), + "step expression refers to outer iterator %qD", var); + break; + } + } + if (it2) + { + ret = true; + continue; + } + TREE_VEC_ELT (it, 1) = begin; + TREE_VEC_ELT (it, 2) = end; + TREE_VEC_ELT (it, 3) = step; + TREE_VEC_ELT (it, 4) = orig_step; + } + return ret; +} + /* For all elements of CLAUSES, validate them against their constraints. Remove any elements from the list that are invalid. */ @@ -13212,14 +13410,20 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bool ordered_seen = false; tree schedule_clause = NULL_TREE; bool oacc_async = false; + tree last_iterators = NULL_TREE; + bool last_iterators_remove = false; + tree *nogroup_seen = NULL; + bool reduction_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); bitmap_initialize (&aligned_head, &bitmap_default_obstack); + /* If ort == C_ORT_OMP_DECLARE_SIMD used as uniform_head instead. */ bitmap_initialize (&map_head, &bitmap_default_obstack); bitmap_initialize (&map_field_head, &bitmap_default_obstack); + /* If ort == C_ORT_OMP used as nontemporal_head instead. */ bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack); if (ort & C_ORT_ACC) @@ -13248,6 +13452,10 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) goto check_dup_generic; case OMP_CLAUSE_REDUCTION: + reduction_seen = true; + /* FALLTHRU */ + case OMP_CLAUSE_IN_REDUCTION: + case OMP_CLAUSE_TASK_REDUCTION: need_implicitly_determined = true; t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST) @@ -13296,6 +13504,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; } size = size_binop (MINUS_EXPR, size, size_one_node); + size = save_expr (size); tree index_type = build_index_type (size); tree atype = build_array_type (type, index_type); tree ptype = build_pointer_type (type); @@ -13311,6 +13520,28 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; break; } + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_REDUCTION_TASK (c)) + { + /* Disallow zero sized or potentially zero sized task + reductions. */ + if (integer_zerop (TYPE_SIZE_UNIT (type))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero sized type %qT in %qs clause", type, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + break; + } + else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "variable sized type %qT in %qs clause", type, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + break; + } + } if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE && (FLOAT_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)) @@ -13512,7 +13743,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (TYPE_ATOMIC (TREE_TYPE (t))) { error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qD in %<linear%> clause", t); + "%<_Atomic%> %qD in %<linear%> clause", t); remove = true; break; } @@ -13570,7 +13801,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) { - error ("%qD appears more than once in reduction clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in reduction clauses", + t); remove = true; } else @@ -13588,9 +13821,11 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) && bitmap_bit_p (&map_head, DECL_UID (t))) { if (ort == C_ORT_ACC) - error ("%qD appears more than once in data clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); else - error ("%qD appears both in data and map clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears both in data and map clauses", t); remove = true; } else @@ -13617,9 +13852,11 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) else if (bitmap_bit_p (&map_head, DECL_UID (t))) { if (ort == C_ORT_ACC) - error ("%qD appears more than once in data clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); else - error ("%qD appears both in data and map clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears both in data and map clauses", t); remove = true; } else @@ -13681,6 +13918,25 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bitmap_set_bit (&aligned_head, DECL_UID (t)); break; + case OMP_CLAUSE_NONTEMPORAL: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %<nontemporal%> clause", t); + remove = true; + } + else if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in %<nontemporal%> " + "clauses", t); + remove = true; + } + else + bitmap_set_bit (&oacc_reduction_head, DECL_UID (t)); + break; + case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); if (t == NULL_TREE) @@ -13717,22 +13973,89 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } break; } + if (TREE_CODE (t) == TREE_LIST + && TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + { + if (TREE_PURPOSE (t) != last_iterators) + last_iterators_remove + = c_omp_finish_iterators (TREE_PURPOSE (t)); + last_iterators = TREE_PURPOSE (t); + t = TREE_VALUE (t); + if (last_iterators_remove) + t = error_mark_node; + } + else + last_iterators = NULL_TREE; if (TREE_CODE (t) == TREE_LIST) { if (handle_omp_array_sections (c, ort)) remove = true; + else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<depend%> clause with %<depobj%> dependence " + "type on array section"); + remove = true; + } break; } if (t == error_mark_node) remove = true; - else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + else if (!lvalue_p (t)) { error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in %<depend%> clause", t); + "%qE is not lvalue expression nor array section in " + "%<depend%> clause", t); remove = true; } - else if (!c_mark_addressable (t)) - remove = true; + else if (TREE_CODE (t) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", t, "depend"); + remove = true; + } + else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_DEPOBJ) + { + if (!c_omp_depend_t_p (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have %<omp_depend_t%> type in " + "%<depend%> clause with %<depobj%> dependence " + "type", t); + remove = true; + } + } + else if (c_omp_depend_t_p (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE should not have %<omp_depend_t%> type in " + "%<depend%> clause with dependence type other than " + "%<depobj%>", t); + remove = true; + } + if (!remove) + { + tree addr = build_unary_op (OMP_CLAUSE_LOCATION (c), ADDR_EXPR, + t, false); + if (addr == error_mark_node) + remove = true; + else + { + t = build_indirect_ref (OMP_CLAUSE_LOCATION (c), addr, + RO_UNARY_STAR); + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == TREE_LIST + && TREE_PURPOSE (OMP_CLAUSE_DECL (c)) + && (TREE_CODE (TREE_PURPOSE (OMP_CLAUSE_DECL (c))) + == TREE_VEC)) + TREE_VALUE (OMP_CLAUSE_DECL (c)) = t; + else + OMP_CLAUSE_DECL (c) = t; + } + } break; case OMP_CLAUSE_MAP: @@ -13774,14 +14097,17 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (bitmap_bit_p (&map_head, DECL_UID (t))) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) - error ("%qD appears more than once in motion" - " clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in motion " + "clauses", t); else if (ort == C_ORT_ACC) - error ("%qD appears more than once in data" - " clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data " + "clauses", t); else - error ("%qD appears more than once in map" - " clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in map " + "clauses", t); remove = true; } else @@ -13891,15 +14217,18 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (bitmap_bit_p (&generic_head, DECL_UID (t)) || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) { - error ("%qD appears more than once in data clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); remove = true; } else if (bitmap_bit_p (&map_head, DECL_UID (t))) { if (ort == C_ORT_ACC) - error ("%qD appears more than once in data clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); else - error ("%qD appears both in data and map clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears both in data and map clauses", t); remove = true; } else @@ -13908,20 +14237,25 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) else if (bitmap_bit_p (&map_head, DECL_UID (t))) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) - error ("%qD appears more than once in motion clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in motion clauses", t); else if (ort == C_ORT_ACC) - error ("%qD appears more than once in data clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); else - error ("%qD appears more than once in map clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in map clauses", t); remove = true; } else if (bitmap_bit_p (&generic_head, DECL_UID (t)) || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) { if (ort == C_ORT_ACC) - error ("%qD appears more than once in data clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears more than once in data clauses", t); else - error ("%qD appears both in data and map clauses", t); + error_at (OMP_CLAUSE_LOCATION (c), + "%qD appears both in data and map clauses", t); remove = true; } else @@ -14041,7 +14375,6 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_PRIORITY: case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: - case OMP_CLAUSE_NOGROUP: case OMP_CLAUSE_THREADS: case OMP_CLAUSE_SIMD: case OMP_CLAUSE_HINT: @@ -14063,30 +14396,12 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) pc = &OMP_CLAUSE_CHAIN (c); continue; + case OMP_CLAUSE_NOGROUP: + nogroup_seen = pc; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + case OMP_CLAUSE_SCHEDULE: - if (OMP_CLAUSE_SCHEDULE_KIND (c) & OMP_CLAUSE_SCHEDULE_NONMONOTONIC) - { - const char *p = NULL; - switch (OMP_CLAUSE_SCHEDULE_KIND (c) & OMP_CLAUSE_SCHEDULE_MASK) - { - case OMP_CLAUSE_SCHEDULE_STATIC: p = "static"; break; - case OMP_CLAUSE_SCHEDULE_DYNAMIC: break; - case OMP_CLAUSE_SCHEDULE_GUIDED: break; - case OMP_CLAUSE_SCHEDULE_AUTO: p = "auto"; break; - case OMP_CLAUSE_SCHEDULE_RUNTIME: p = "runtime"; break; - default: gcc_unreachable (); - } - if (p) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<nonmonotonic%> modifier specified for %qs " - "schedule kind", p); - OMP_CLAUSE_SCHEDULE_KIND (c) - = (enum omp_clause_schedule_kind) - (OMP_CLAUSE_SCHEDULE_KIND (c) - & ~OMP_CLAUSE_SCHEDULE_NONMONOTONIC); - } - } schedule_clause = c; pc = &OMP_CLAUSE_CHAIN (c); continue; @@ -14145,10 +14460,6 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_DEFAULT_UNSPECIFIED: break; case OMP_CLAUSE_DEFAULT_SHARED: - /* const vars may be specified in firstprivate clause. */ - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE - && TREE_READONLY (t)) - break; share_name = "shared"; break; case OMP_CLAUSE_DEFAULT_PRIVATE: @@ -14165,6 +14476,15 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + else if (TREE_READONLY (t) + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SHARED + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<const%> qualified %qE may appear only in " + "%<shared%> or %<firstprivate%> clauses", t); + remove = true; + } } } @@ -14222,6 +14542,14 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) pc = &OMP_CLAUSE_CHAIN (c); } + if (nogroup_seen && reduction_seen) + { + error_at (OMP_CLAUSE_LOCATION (*nogroup_seen), + "%<nogroup%> clause must not be used together with " + "%<reduction%> clause"); + *nogroup_seen = OMP_CLAUSE_CHAIN (*nogroup_seen); + } + bitmap_obstack_release (NULL); return clauses; } |