diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 169 | ||||
-rw-r--r-- | gcc/cp/cp-array-notation.c | 1 | ||||
-rw-r--r-- | gcc/cp/cp-gimplify.c | 25 | ||||
-rw-r--r-- | gcc/cp/cp-objcp-common.h | 2 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 34 | ||||
-rw-r--r-- | gcc/cp/decl.c | 52 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 73 | ||||
-rw-r--r-- | gcc/cp/parser.c | 2569 | ||||
-rw-r--r-- | gcc/cp/parser.h | 18 | ||||
-rw-r--r-- | gcc/cp/pt.c | 293 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 1564 |
11 files changed, 4421 insertions, 379 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b3bde10..da49d12 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,172 @@ +2013-10-11 Jakub Jelinek <jakub@redhat.com> + + * decl.c (duplicate_decls): Error out for redeclaration of UDRs. + (declare_simd_adjust_this): New function. + (grokfndecl): If "omp declare simd" attribute is present, + call declare_simd_adjust_this if needed and + c_omp_declare_simd_clauses_to_numbers. + * cp-array-notation.c (expand_array_notation_exprs): Handle + OMP_TASKGROUP. + * cp-gimplify.c (cp_gimplify_expr): Handle OMP_SIMD and + OMP_DISTRIBUTE. Handle is_invisiref_parm decls in + OMP_CLAUSE_REDUCTION. + (cp_genericize_r): Handle OMP_SIMD and OMP_DISTRIBUTE like + OMP_FOR. + (cxx_omp_privatize_by_reference): Return true for + is_invisiref_parm decls. + (cxx_omp_finish_clause): Adjust cxx_omp_create_clause_info + caller. + * pt.c (apply_late_template_attributes): For "omp declare simd" + attribute call tsubst_omp_clauses, + c_omp_declare_simd_clauses_to_decls, finish_omp_clauses + and c_omp_declare_simd_clauses_to_numbers. + (instantiate_class_template_1): Call cp_check_omp_declare_reduction + for UDRs. + (tsubst_decl): Handle UDRs. + (tsubst_omp_clauses): Add declare_simd argument, if true don't + call finish_omp_clauses. Handle new OpenMP 4.0 clauses. + Handle non-NULL OMP_CLAUSE_REDUCTION_PLACEHOLDER on + OMP_CLAUSE_REDUCTION. + (tsubst_expr): For UDRs call pushdecl and + cp_check_omp_declare_reduction. Adjust tsubst_omp_clauses + callers. Handle OMP_SIMD, OMP_DISTRIBUTE, OMP_TEAMS, + OMP_TARGET_DATA, OMP_TARGET_UPDATE, OMP_TARGET, OMP_TASKGROUP. + Adjust finish_omp_atomic caller. + (tsubst_omp_udr): New function. + (instantiate_decl): For UDRs at block scope, don't call + start_preparsed_function/finish_function. Call tsubst_omp_udr. + * semantics.c (cxx_omp_create_clause_info): Add need_dtor argument, + use it instead of need_default_ctor || need_copy_ctor. + (struct cp_check_omp_declare_reduction_data): New type. + (handle_omp_array_sections_1, handle_omp_array_sections, + omp_reduction_id, omp_reduction_lookup, + cp_remove_omp_priv_cleanup_stmt, cp_check_omp_declare_reduction_r, + cp_check_omp_declare_reduction, clone_omp_udr, + find_omp_placeholder_r, finish_omp_reduction_clause): New functions. + (finish_omp_clauses): Handle new OpenMP 4.0 clauses and user defined + reductions. + (finish_omp_for): Add CODE argument, use it instead of hardcoded + OMP_FOR. Adjust c_finish_omp_for caller. + (finish_omp_atomic): Add seq_cst argument, adjust + c_finish_omp_atomic callers, handle seq_cst and new OpenMP 4.0 + atomic variants. + (finish_omp_cancel, finish_omp_cancellation_point): New functions. + * decl2.c (mark_used): Force immediate instantiation of + DECL_OMP_DECLARE_REDUCTION_P decls. + (is_late_template_attribute): Return true for "omp declare simd" + attribute. + (cp_omp_mappable_type): New function. + (cplus_decl_attributes): Add implicit "omp declare target" attribute + if requested. + * parser.c (cp_debug_parser): Print + parser->colon_doesnt_start_class_def_p. + (cp_ensure_no_omp_declare_simd, cp_finalize_omp_declare_simd): New + functions. + (enum pragma_context): Add pragma_member and pragma_objc_icode. + (cp_parser_binary_expression): Handle no_toplevel_fold_p + even for binary operations other than comparison. + (cp_parser_linkage_specification): Call + cp_ensure_no_omp_declare_simd if needed. + (cp_parser_namespace_definition): Likewise. + (cp_parser_init_declarator): Call cp_finalize_omp_declare_simd. + (cp_parser_direct_declarator): Pass declarator to + cp_parser_late_return_type_opt. + (cp_parser_late_return_type_opt): Add declarator argument, + call cp_parser_late_parsing_omp_declare_simd for declare simd. + (cp_parser_class_specifier_1): Call cp_ensure_no_omp_declare_simd. + Parse UDRs before all other methods. + (cp_parser_member_specification_opt): Use pragma_member instead of + pragma_external. + (cp_parser_member_declaration): Call cp_finalize_omp_declare_simd. + (cp_parser_function_definition_from_specifiers_and_declarator, + cp_parser_save_member_function_body): Likewise. + (cp_parser_late_parsing_for_member): Handle UDRs specially. + (cp_parser_next_token_starts_class_definition_p): Don't allow + CPP_COLON if colon_doesnt_start_class_def_p flag is true. + (cp_parser_objc_interstitial_code): Use pragma_objc_icode + instead of pragma_external. + (cp_parser_omp_clause_name): Parse new OpenMP 4.0 clause names. + (cp_parser_omp_var_list_no_open): Parse array sections for + OMP_CLAUSE_{DEPEND,MAP,TO,FROM} clauses. Add COLON argument, + if non-NULL, allow parsing to end with a colon rather than close + paren. + (cp_parser_omp_var_list): Adjust cp_parser_omp_var_list_no_open + caller. + (cp_parser_omp_clause_reduction): Handle user defined reductions. + (cp_parser_omp_clause_branch, cp_parser_omp_clause_cancelkind, + cp_parser_omp_clause_num_teams, cp_parser_omp_clause_thread_limit, + cp_parser_omp_clause_aligned, cp_parser_omp_clause_linear, + cp_parser_omp_clause_safelen, cp_parser_omp_clause_simdlen, + cp_parser_omp_clause_depend, cp_parser_omp_clause_map, + cp_parser_omp_clause_device, cp_parser_omp_clause_dist_schedule, + cp_parser_omp_clause_proc_bind, cp_parser_omp_clause_to, + cp_parser_omp_clause_from, cp_parser_omp_clause_uniform): New + functions. + (cp_parser_omp_all_clauses): Add finish_p argument. Don't call + finish_omp_clauses if it is false. Handle new OpenMP 4.0 clauses. + (cp_parser_omp_atomic): Parse seq_cst clause, pass + true if it is present to finish_omp_atomic. Handle new OpenMP 4.0 + atomic forms. + (cp_parser_omp_for_loop): Add CODE argument, pass it through + to finish_omp_for. Change last argument to cclauses, + and adjust uses to grab parallel clauses from the array of all + the split clauses. + (cp_omp_split_clauses): New function. + (cp_parser_omp_simd): New function. + (cp_parser_omp_for): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined constructs, + and call c_parser_omp_simd when parsing for simd. + (cp_parser_omp_sections_scope): If section-sequence doesn't start with + #pragma omp section, require exactly one structured-block instead of + sequence of statements. + (cp_parser_omp_sections): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined constructs. + (cp_parser_omp_parallel): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined + constructs. + (cp_parser_omp_taskgroup, cp_parser_omp_cancel, + cp_parser_omp_cancellation_point, cp_parser_omp_distribute, + cp_parser_omp_teams, cp_parser_omp_target_data, + cp_parser_omp_target_update, cp_parser_omp_target, + cp_parser_omp_declare_simd, cp_parser_late_parsing_omp_declare_simd, + cp_parser_omp_declare_target, cp_parser_omp_end_declare_target, + cp_parser_omp_declare_reduction_exprs, cp_parser_omp_declare_reduction, + cp_parser_omp_declare): New functions. + (cp_parser_omp_construct): Add p_name and mask vars. Handle + PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_SIMD, PRAGMA_OMP_TASKGROUP, + PRAGMA_OMP_TEAMS. Adjust cp_parser_omp_for, cp_parser_omp_parallel + and cp_parser_omp_sections callers. + (cp_parser_pragma): Handle PRAGMA_OMP_CANCEL, + PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_DECLARE_REDUCTION, + PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_SIMD, PRAGMA_OMP_TASKGROUP, + PRAGMA_OMP_TEAMS, PRAGMA_OMP_TARGET, PRAGMA_OMP_END_DECLARE_TARGET. + Handle pragma_member and pragma_objc_icode like pragma_external. + (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, + OMP_SINGLE_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. + (OMP_PARALLEL_CLAUSE_MASK): Likewise. Add OMP_CLAUSE_PROC_BIND. + (OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. Add + OMP_CLAUSE_DEPEND. + (OMP_SIMD_CLAUSE_MASK, OMP_CANCEL_CLAUSE_MASK, + OMP_CANCELLATION_POINT_CLAUSE_MASK, OMP_DISTRIBUTE_CLAUSE_MASK, + OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_DATA_CLAUSE_MASK, + OMP_TARGET_UPDATE_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK, + OMP_DECLARE_SIMD_CLAUSE_MASK): Define. + * parser.h (struct cp_omp_declare_simd_data): New type. + (struct cp_parser): Add colon_doesnt_start_class_def_p and + omp_declare_simd fields. + * cp-objcp-common.h (LANG_HOOKS_OMP_MAPPABLE_TYPE): Define. + * cp-tree.h (struct lang_decl_fn): Add omp_declare_reduction_p + bit. + (DECL_OMP_DECLARE_REDUCTION_P): Define. + (OMP_FOR_GIMPLIFYING_P): Use OMP_LOOP_CHECK macro. + (struct saved_scope): Add omp_declare_target_attribute field. + (cp_omp_mappable_type, omp_reduction_id, + cp_remove_omp_priv_cleanup_stmt, cp_check_omp_declare_reduction, + finish_omp_cancel, finish_omp_cancellation_point): New prototypes. + (finish_omp_for): Add CODE argument. + (finish_omp_atomic): Add seq_cst argument. + (cxx_omp_create_clause_info): Add need_dtor argument. + 2013-10-09 Marek Polacek <polacek@redhat.com> PR c++/58635 diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c index f4581f0..c700f58 100644 --- a/gcc/cp/cp-array-notation.c +++ b/gcc/cp/cp-array-notation.c @@ -1193,6 +1193,7 @@ expand_array_notation_exprs (tree t) case OMP_SECTION: case OMP_SECTIONS: case OMP_MASTER: + case OMP_TASKGROUP: case OMP_ORDERED: case OMP_CRITICAL: case OMP_ATOMIC: diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 590d857..53b0ca8 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -669,6 +669,8 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) gcc_unreachable (); case OMP_FOR: + case OMP_SIMD: + case OMP_DISTRIBUTE: ret = cp_gimplify_omp_for (expr_p, pre_p); break; @@ -934,7 +936,19 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) *walk_subtrees = 0; break; case OMP_CLAUSE_REDUCTION: - gcc_assert (!is_invisiref_parm (OMP_CLAUSE_DECL (stmt))); + /* Don't dereference an invisiref in reduction clause's + OMP_CLAUSE_DECL either. OMP_CLAUSE_REDUCTION_{INIT,MERGE} + still needs to be genericized. */ + if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) + { + *walk_subtrees = 0; + if (OMP_CLAUSE_REDUCTION_INIT (stmt)) + cp_walk_tree (&OMP_CLAUSE_REDUCTION_INIT (stmt), + cp_genericize_r, data, NULL); + if (OMP_CLAUSE_REDUCTION_MERGE (stmt)) + cp_walk_tree (&OMP_CLAUSE_REDUCTION_MERGE (stmt), + cp_genericize_r, data, NULL); + } break; default: break; @@ -1116,7 +1130,9 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) genericize_continue_stmt (stmt_p); else if (TREE_CODE (stmt) == BREAK_STMT) genericize_break_stmt (stmt_p); - else if (TREE_CODE (stmt) == OMP_FOR) + else if (TREE_CODE (stmt) == OMP_FOR + || TREE_CODE (stmt) == OMP_SIMD + || TREE_CODE (stmt) == OMP_DISTRIBUTE) genericize_omp_for_stmt (stmt_p, walk_subtrees, data); else if (TREE_CODE (stmt) == SIZEOF_EXPR) { @@ -1402,7 +1418,8 @@ cxx_omp_clause_dtor (tree clause, tree decl) bool cxx_omp_privatize_by_reference (const_tree decl) { - return is_invisiref_parm (decl); + return (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE + || is_invisiref_parm (decl)); } /* Return true if DECL is const qualified var having no mutable member. */ @@ -1505,7 +1522,7 @@ cxx_omp_finish_clause (tree c) for making these queries. */ if (!make_shared && CLASS_TYPE_P (inner_type) - && cxx_omp_create_clause_info (c, inner_type, false, true, false)) + && cxx_omp_create_clause_info (c, inner_type, false, true, false, true)) make_shared = true; if (make_shared) diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 47fb20a..ee22423 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -145,6 +145,8 @@ extern void cp_common_init_ts (void); #define LANG_HOOKS_OMP_FINISH_CLAUSE cxx_omp_finish_clause #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference +#undef LANG_HOOKS_OMP_MAPPABLE_TYPE +#define LANG_HOOKS_OMP_MAPPABLE_TYPE cp_omp_mappable_type #undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP true diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d7840af..b1347e2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -60,7 +60,7 @@ c-common.h, not after. STMT_EXPR_NO_SCOPE (in STMT_EXPR) BIND_EXPR_TRY_BLOCK (in BIND_EXPR) TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) - OMP_FOR_GIMPLIFYING_P (in OMP_FOR) + OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD and OMP_DISTRIBUTE) BASELINK_QUALIFIED_P (in BASELINK) TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR) TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX) @@ -1037,6 +1037,9 @@ struct GTY(()) saved_scope { int unevaluated_operand; int inhibit_evaluation_warnings; + /* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ + int omp_declare_target_attribute; struct stmt_tree_s x_stmt_tree; @@ -1979,7 +1982,8 @@ struct GTY(()) lang_decl_fn { unsigned thunk_p : 1; unsigned this_thunk_p : 1; unsigned hidden_friend_p : 1; - /* 1 spare bit. */ + unsigned omp_declare_reduction_p : 1; + /* No spare bits on 32-bit hosts, 32 on 64-bit hosts. */ /* For a non-thunk function decl, this is a tree list of friendly classes. For a thunk function decl, it is the @@ -3181,6 +3185,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_HIDDEN_FRIEND_P(NODE) \ (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->hidden_friend_p) +/* Nonzero if NODE is an artificial FUNCTION_DECL for + #pragma omp declare reduction. */ +#define DECL_OMP_DECLARE_REDUCTION_P(NODE) \ + (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->omp_declare_reduction_p) + /* Nonzero if DECL has been declared threadprivate by #pragma omp threadprivate. */ #define CP_DECL_THREADPRIVATE_P(DECL) \ @@ -4011,7 +4020,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* Used while gimplifying continue statements bound to OMP_FOR nodes. */ #define OMP_FOR_GIMPLIFYING_P(NODE) \ - (TREE_LANG_FLAG_0 (OMP_FOR_CHECK (NODE))) + (TREE_LANG_FLAG_0 (OMP_LOOP_CHECK (NODE))) /* A language-specific token attached to the OpenMP data clauses to hold code (or code fragments) related to ctors, dtors, and op=. @@ -5299,6 +5308,7 @@ extern bool possibly_inlined_p (tree); extern int parm_index (tree); extern tree vtv_start_verification_constructor_init_function (void); extern tree vtv_finish_verification_constructor_init_function (tree); +extern bool cp_omp_mappable_type (tree); /* in error.c */ extern void init_error (void); @@ -5774,6 +5784,9 @@ extern tree finish_qualified_id_expr (tree, tree, bool, bool, extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree *, tree, tree); extern void note_decl_for_pch (tree); +extern tree omp_reduction_id (enum tree_code, tree, tree); +extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *); +extern void cp_check_omp_declare_reduction (tree); extern tree finish_omp_clauses (tree); extern void finish_omp_threadprivate (tree); extern tree begin_omp_structured_block (void); @@ -5782,18 +5795,23 @@ extern tree begin_omp_parallel (void); extern tree finish_omp_parallel (tree, tree); extern tree begin_omp_task (void); extern tree finish_omp_task (tree, tree); -extern tree finish_omp_for (location_t, tree, tree, - tree, tree, tree, tree, tree); +extern tree finish_omp_for (location_t, enum tree_code, + tree, tree, tree, tree, tree, + tree, tree); extern void finish_omp_atomic (enum tree_code, enum tree_code, - tree, tree, tree, tree, tree); + tree, tree, tree, tree, tree, + bool); extern void finish_omp_barrier (void); extern void finish_omp_flush (void); extern void finish_omp_taskwait (void); +extern void finish_omp_taskyield (void); +extern void finish_omp_cancel (tree); +extern void finish_omp_cancellation_point (tree); extern tree begin_transaction_stmt (location_t, tree *, int); extern void finish_transaction_stmt (tree, tree, int, tree); extern tree build_transaction_expr (location_t, tree, int, tree); -extern void finish_omp_taskyield (void); -extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool); +extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, + bool, bool); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 5f17a05..fe8fe4e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1341,6 +1341,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) } return NULL_TREE; } + else if (DECL_OMP_DECLARE_REDUCTION_P (olddecl)) + { + gcc_assert (DECL_OMP_DECLARE_REDUCTION_P (newdecl)); + error_at (DECL_SOURCE_LOCATION (newdecl), + "redeclaration of %<pragma omp declare reduction%>"); + error_at (DECL_SOURCE_LOCATION (olddecl), + "previous %<pragma omp declare reduction%> declaration"); + return error_mark_node; + } else if (!types_match) { /* Avoid warnings redeclaring built-ins which have not been @@ -7302,6 +7311,22 @@ check_static_quals (tree decl, cp_cv_quals quals) decl); } +/* Helper function. Replace the temporary this parameter injected + during cp_finish_omp_declare_simd with the real this parameter. */ + +static tree +declare_simd_adjust_this (tree *tp, int *walk_subtrees, void *data) +{ + tree this_parm = (tree) data; + if (TREE_CODE (*tp) == PARM_DECL + && DECL_NAME (*tp) == this_identifier + && *tp != this_parm) + *tp = this_parm; + else if (TYPE_P (*tp)) + *walk_subtrees = 0; + return NULL_TREE; +} + /* CTYPE is class type, or null if non-class. TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE or METHOD_TYPE. @@ -7620,6 +7645,33 @@ grokfndecl (tree ctype, if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl)) TREE_NOTHROW (decl) = 1; + if (flag_openmp) + { + /* Adjust "omp declare simd" attributes. */ + tree ods = lookup_attribute ("omp declare simd", *attrlist); + if (ods) + { + tree attr; + for (attr = ods; attr; + attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))) + { + if (TREE_CODE (type) == METHOD_TYPE) + walk_tree (&TREE_VALUE (attr), declare_simd_adjust_this, + DECL_ARGUMENTS (decl), NULL); + if (TREE_VALUE (attr) != NULL_TREE) + { + tree cl = TREE_VALUE (TREE_VALUE (attr)); + cl = c_omp_declare_simd_clauses_to_numbers + (DECL_ARGUMENTS (decl), cl); + if (cl) + TREE_VALUE (TREE_VALUE (attr)) = cl; + else + TREE_VALUE (attr) = NULL_TREE; + } + } + } + } + /* Caller will do the rest of this. */ if (check < 0) return decl; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 53e6bc9..4ebc155 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -101,7 +101,6 @@ static GTY(()) vec<tree, va_gc> *no_linkage_decls; /* Nonzero if we're done parsing and into end-of-file activities. */ int at_eof; - /* Return a member function type (a METHOD_TYPE), given FNTYPE (a @@ -1135,6 +1134,11 @@ is_late_template_attribute (tree attr, tree decl) if (is_attribute_p ("unused", name)) return false; + /* #pragma omp declare simd attribute needs to be always deferred. */ + if (flag_openmp + && is_attribute_p ("omp declare simd", name)) + return true; + /* If any of the arguments are dependent expressions, we can't evaluate the attribute until instantiation time. */ for (arg = args; arg; arg = TREE_CHAIN (arg)) @@ -1336,6 +1340,34 @@ cp_check_const_attributes (tree attributes) } } +/* Return true if TYPE is an OpenMP mappable type. */ +bool +cp_omp_mappable_type (tree type) +{ + /* Mappable type has to be complete. */ + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + return false; + /* Arrays have mappable type if the elements have mappable type. */ + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + /* A mappable type cannot contain virtual members. */ + if (CLASS_TYPE_P (type) && CLASSTYPE_VTABLES (type)) + return false; + /* All data members must be non-static. */ + if (CLASS_TYPE_P (type)) + { + tree field; + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == VAR_DECL) + return false; + /* All fields must have mappable types. */ + else if (TREE_CODE (field) == FIELD_DECL + && !cp_omp_mappable_type (TREE_TYPE (field))) + return false; + } + return true; +} + /* Like decl_attributes, but handle C++ complexity. */ void @@ -1345,6 +1377,30 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) || *decl == error_mark_node) return; + /* Add implicit "omp declare target" attribute if requested. */ + if (scope_chain->omp_declare_target_attribute + && ((TREE_CODE (*decl) == VAR_DECL && TREE_STATIC (*decl)) + || TREE_CODE (*decl) == FUNCTION_DECL)) + { + if (TREE_CODE (*decl) == VAR_DECL + && DECL_CLASS_SCOPE_P (*decl)) + error ("%q+D static data member inside of declare target directive", + *decl); + else if (TREE_CODE (*decl) == VAR_DECL + && (DECL_FUNCTION_SCOPE_P (*decl) + || (current_function_decl && !DECL_EXTERNAL (*decl)))) + error ("%q+D in block scope inside of declare target directive", + *decl); + else if (!processing_template_decl + && TREE_CODE (*decl) == VAR_DECL + && !cp_omp_mappable_type (TREE_TYPE (*decl))) + error ("%q+D in declare target directive does not have mappable type", + *decl); + else + attributes = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, attributes); + } + if (processing_template_decl) { if (check_for_bare_parameter_packs (attributes)) @@ -4623,13 +4679,16 @@ mark_used (tree decl, tsubst_flags_t complain) or a constexpr function, we need it right now because a reference to such a data member or a call to such function is not value-dependent. For a function that uses auto in the return type, we need to instantiate - it to find out its type. */ - if ((decl_maybe_constant_var_p (decl) - || (TREE_CODE (decl) == FUNCTION_DECL - && DECL_DECLARED_CONSTEXPR_P (decl)) - || undeduced_auto_decl (decl)) - && DECL_LANG_SPECIFIC (decl) + it to find out its type. For OpenMP user defined reductions, we need + them instantiated for reduction clauses which inline them by hand + directly. */ + if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) + && (decl_maybe_constant_var_p (decl) + || (TREE_CODE (decl) == FUNCTION_DECL + && (DECL_DECLARED_CONSTEXPR_P (decl) + || DECL_OMP_DECLARE_REDUCTION_P (decl))) + || undeduced_auto_decl (decl)) && !uses_template_parms (DECL_TI_ARGS (decl))) { /* Instantiating a function will result in garbage collection. We diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 90c1775..83fdfab 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -232,6 +232,9 @@ static void cp_parser_initial_pragma static tree cp_literal_operator_id (const char *); +static bool cp_parser_omp_declare_reduction_exprs + (tree, cp_parser *); + /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) #define CP_SAVED_TOKEN_STACK 5 @@ -542,6 +545,8 @@ cp_debug_parser (FILE *file, cp_parser *parser) "local class", parser->in_function_body); cp_debug_print_flag (file, "Auto correct a colon to a scope operator", parser->colon_corrects_to_scope_p); + cp_debug_print_flag (file, "Colon doesn't start a class definition", + parser->colon_doesnt_start_class_def_p); if (parser->type_definition_forbidden_message) fprintf (file, "Error message for forbidden type definitions: %s\n", parser->type_definition_forbidden_message); @@ -1222,6 +1227,40 @@ cp_token_cache_new (cp_token *first, cp_token *last) return cache; } +/* Diagnose if #pragma omp declare simd isn't followed immediately + by function declaration or definition. */ + +static inline void +cp_ensure_no_omp_declare_simd (cp_parser *parser) +{ + if (parser->omp_declare_simd && !parser->omp_declare_simd->error_seen) + { + error ("%<#pragma omp declare simd%> not immediately followed by " + "function declaration or definition"); + parser->omp_declare_simd = NULL; + } +} + +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +static inline void +cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl) +{ + if (__builtin_expect (parser->omp_declare_simd != NULL, 0)) + { + if (fndecl == error_mark_node) + { + parser->omp_declare_simd = NULL; + return; + } + if (TREE_CODE (fndecl) != FUNCTION_DECL) + { + cp_ensure_no_omp_declare_simd (parser); + return; + } + } +} /* Decl-specifiers. */ @@ -2030,7 +2069,7 @@ static cp_virt_specifiers cp_parser_virt_specifier_seq_opt static cp_ref_qualifier cp_parser_ref_qualifier_opt (cp_parser *); static tree cp_parser_late_return_type_opt - (cp_parser *, cp_cv_quals); + (cp_parser *, cp_declarator *, cp_cv_quals); static tree cp_parser_declarator_id (cp_parser *, bool); static tree cp_parser_type_id @@ -2064,6 +2103,9 @@ static vec<constructor_elt, va_gc> *cp_parser_initializer_list static bool cp_parser_ctor_initializer_opt_and_function_body (cp_parser *, bool); +static tree cp_parser_late_parsing_omp_declare_simd + (cp_parser *, tree); + static tree add_implicit_template_parms (cp_parser *, size_t, tree); static tree finish_fully_implicit_template @@ -2211,7 +2253,13 @@ static bool cp_parser_function_transaction static tree cp_parser_transaction_cancel (cp_parser *); -enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +enum pragma_context { + pragma_external, + pragma_member, + pragma_objc_icode, + pragma_stmt, + pragma_compound +}; static bool cp_parser_pragma (cp_parser *, enum pragma_context); @@ -7807,9 +7855,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, */ if (no_toplevel_fold_p && lookahead_prec <= current.prec - && sp == stack - && TREE_CODE_CLASS (current.tree_type) == tcc_comparison) - current.lhs = build2 (current.tree_type, boolean_type_node, + && sp == stack) + current.lhs = build2 (current.tree_type, + TREE_CODE_CLASS (current.tree_type) + == tcc_comparison + ? boolean_type_node : TREE_TYPE (current.lhs), current.lhs, rhs); else current.lhs = build_x_binary_op (current.loc, current.tree_type, @@ -11522,6 +11572,8 @@ cp_parser_linkage_specification (cp_parser* parser) production. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { + cp_ensure_no_omp_declare_simd (parser); + /* Consume the `{' token. */ cp_lexer_consume_token (parser->lexer); /* Parse the declarations. */ @@ -15509,6 +15561,7 @@ cp_parser_namespace_definition (cp_parser* parser) bool has_visibility; bool is_inline; + cp_ensure_no_omp_declare_simd (parser); if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE)) { maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES); @@ -16449,8 +16502,8 @@ cp_parser_init_declarator (cp_parser* parser, decl_specifiers->storage_class = sc_extern; decl = start_decl (declarator, decl_specifiers, range_for_decl_p? SD_INITIALIZED : is_initialized, - attributes, prefix_attributes, - &pushed_scope); + attributes, prefix_attributes, &pushed_scope); + cp_finalize_omp_declare_simd (parser, decl); /* Adjust location of decl if declarator->id_loc is more appropriate: set, and decl wasn't merged with another decl, in which case its location would be different from input_location, and more accurate. */ @@ -16560,6 +16613,7 @@ cp_parser_init_declarator (cp_parser* parser, chainon (attributes, prefix_attributes)); if (decl && TREE_CODE (decl) == FUNCTION_DECL) cp_parser_save_default_args (parser, decl); + cp_finalize_omp_declare_simd (parser, decl); } /* Finish processing the declaration. But, skip member @@ -16871,7 +16925,9 @@ cp_parser_direct_declarator (cp_parser* parser, attrs = cp_parser_std_attribute_spec_seq (parser); late_return = (cp_parser_late_return_type_opt - (parser, memfn ? cv_quals : -1)); + (parser, declarator, + memfn ? cv_quals : -1)); + /* Parse the virt-specifier-seq. */ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); @@ -17575,24 +17631,28 @@ parsing_nsdmi (void) Returns the type indicated by the type-id. + In addition to this this parses any queued up omp declare simd + clauses. + QUALS is either a bitmask of cv_qualifiers or -1 for a non-member function. */ static tree -cp_parser_late_return_type_opt (cp_parser* parser, cp_cv_quals quals) +cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator, + cp_cv_quals quals) { cp_token *token; - tree type; + tree type = NULL_TREE; + bool declare_simd_p = (parser->omp_declare_simd + && declarator + && declarator->kind == cdk_id); /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); /* A late-specified return type is indicated by an initial '->'. */ - if (token->type != CPP_DEREF) + if (token->type != CPP_DEREF && !declare_simd_p) return NULL_TREE; - /* Consume the ->. */ - cp_lexer_consume_token (parser->lexer); - tree save_ccp = current_class_ptr; tree save_ccr = current_class_ref; if (quals >= 0) @@ -17601,7 +17661,18 @@ cp_parser_late_return_type_opt (cp_parser* parser, cp_cv_quals quals) inject_this_parameter (current_class_type, quals); } - type = cp_parser_trailing_type_id (parser); + if (token->type == CPP_DEREF) + { + /* Consume the ->. */ + cp_lexer_consume_token (parser->lexer); + + type = cp_parser_trailing_type_id (parser); + } + + if (declare_simd_p) + declarator->std_attributes + = cp_parser_late_parsing_omp_declare_simd (parser, + declarator->std_attributes); if (quals >= 0) { @@ -18856,6 +18927,8 @@ cp_parser_class_specifier_1 (cp_parser* parser) return error_mark_node; } + cp_ensure_no_omp_declare_simd (parser); + /* Issue an error message if type-definitions are forbidden here. */ cp_parser_check_type_definition (parser); /* Remember that we are defining one more class. */ @@ -19083,8 +19156,19 @@ cp_parser_class_specifier_1 (cp_parser* parser) if (pushed_scope) pop_scope (pushed_scope); /* Now parse the body of the functions. */ - FOR_EACH_VEC_SAFE_ELT (unparsed_funs_with_definitions, ix, decl) - cp_parser_late_parsing_for_member (parser, decl); + if (flag_openmp) + { + /* OpenMP UDRs need to be parsed before all other functions. */ + FOR_EACH_VEC_SAFE_ELT (unparsed_funs_with_definitions, ix, decl) + if (DECL_OMP_DECLARE_REDUCTION_P (decl)) + cp_parser_late_parsing_for_member (parser, decl); + FOR_EACH_VEC_SAFE_ELT (unparsed_funs_with_definitions, ix, decl) + if (!DECL_OMP_DECLARE_REDUCTION_P (decl)) + cp_parser_late_parsing_for_member (parser, decl); + } + else + FOR_EACH_VEC_SAFE_ELT (unparsed_funs_with_definitions, ix, decl) + cp_parser_late_parsing_for_member (parser, decl); vec_safe_truncate (unparsed_funs_with_definitions, 0); } @@ -19631,7 +19715,7 @@ cp_parser_member_specification_opt (cp_parser* parser) /* Accept #pragmas at class scope. */ if (token->type == CPP_PRAGMA) { - cp_parser_pragma (parser, pragma_external); + cp_parser_pragma (parser, pragma_member); break; } @@ -20087,15 +20171,16 @@ cp_parser_member_declaration (cp_parser* parser) else if (declarator->kind == cdk_function) declarator->id_loc = token->location; - /* Create the declaration. */ - decl = grokfield (declarator, &decl_specifiers, - initializer, /*init_const_expr_p=*/true, - asm_specification, - attributes); + /* Create the declaration. */ + decl = grokfield (declarator, &decl_specifiers, + initializer, /*init_const_expr_p=*/true, + asm_specification, attributes); if (parser->fully_implicit_function_template_p) decl = finish_fully_implicit_template (parser, decl); } + cp_finalize_omp_declare_simd (parser, decl); + /* Reset PREFIX_ATTRIBUTES. */ while (attributes && TREE_CHAIN (attributes) != first_attribute) attributes = TREE_CHAIN (attributes); @@ -22244,6 +22329,12 @@ cp_parser_function_definition_from_specifiers_and_declarator might be a friend. */ perform_deferred_access_checks (tf_warning_or_error); + if (success_p) + { + cp_finalize_omp_declare_simd (parser, current_function_decl); + parser->omp_declare_simd = NULL; + } + if (!success_p) { /* Skip the entire function. */ @@ -22775,6 +22866,7 @@ cp_parser_save_member_function_body (cp_parser* parser, /* Create the FUNCTION_DECL. */ fn = grokmethod (decl_specifiers, declarator, attributes); + cp_finalize_omp_declare_simd (parser, fn); /* If something went badly wrong, bail out now. */ if (fn == error_mark_node) { @@ -23001,9 +23093,18 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) if (processing_template_decl) push_deferring_access_checks (dk_no_check); - /* Now, parse the body of the function. */ - cp_parser_function_definition_after_declarator (parser, - /*inline_p=*/true); + /* #pragma omp declare reduction needs special parsing. */ + if (DECL_OMP_DECLARE_REDUCTION_P (member_function)) + { + parser->lexer->in_pragma = true; + cp_parser_omp_declare_reduction_exprs (member_function, parser); + finish_function (0); + cp_check_omp_declare_reduction (member_function); + } + else + /* Now, parse the body of the function. */ + cp_parser_function_definition_after_declarator (parser, + /*inline_p=*/true); if (processing_template_decl) pop_deferring_access_checks (); @@ -23923,7 +24024,9 @@ cp_parser_next_token_starts_class_definition_p (cp_parser *parser) cp_token *token; token = cp_lexer_peek_token (parser->lexer); - return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON); + return (token->type == CPP_OPEN_BRACE + || (token->type == CPP_COLON + && !parser->colon_doesnt_start_class_def_p)); } /* Returns TRUE iff the next token is the "," or ">" (or `>>', in @@ -25176,7 +25279,7 @@ cp_parser_objc_interstitial_code (cp_parser* parser) cp_parser_linkage_specification (parser); /* Handle #pragma, if any. */ else if (token->type == CPP_PRAGMA) - cp_parser_pragma (parser, pragma_external); + cp_parser_pragma (parser, pragma_objc_icode); /* Allow stray semicolons. */ else if (token->type == CPP_SEMICOLON) cp_lexer_consume_token (parser->lexer); @@ -26341,7 +26444,7 @@ cp_parser_objc_at_dynamic_declaration (cp_parser *parser) } -/* OpenMP 2.5 parsing routines. */ +/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */ /* Returns name of the next clause. If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and @@ -26359,6 +26462,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_DEFAULT; else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_PRIVATE)) result = PRAGMA_OMP_CLAUSE_PRIVATE; + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + result = PRAGMA_OMP_CLAUSE_FOR; else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -26366,6 +26471,10 @@ cp_parser_omp_clause_name (cp_parser *parser) switch (p[0]) { + case 'a': + if (!strcmp ("aligned", p)) + result = PRAGMA_OMP_CLAUSE_ALIGNED; + break; case 'c': if (!strcmp ("collapse", p)) result = PRAGMA_OMP_CLAUSE_COLLAPSE; @@ -26374,23 +26483,45 @@ cp_parser_omp_clause_name (cp_parser *parser) else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; break; + case 'd': + if (!strcmp ("depend", p)) + result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("device", p)) + result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("dist_schedule", p)) + result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + break; case 'f': if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("firstprivate", p)) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + else if (!strcmp ("from", p)) + result = PRAGMA_OMP_CLAUSE_FROM; + break; + case 'i': + if (!strcmp ("inbranch", p)) + result = PRAGMA_OMP_CLAUSE_INBRANCH; break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + else if (!strcmp ("linear", p)) + result = PRAGMA_OMP_CLAUSE_LINEAR; break; case 'm': - if (!strcmp ("mergeable", p)) + if (!strcmp ("map", p)) + result = PRAGMA_OMP_CLAUSE_MAP; + else if (!strcmp ("mergeable", p)) result = PRAGMA_OMP_CLAUSE_MERGEABLE; break; case 'n': - if (!strcmp ("nowait", p)) + if (!strcmp ("notinbranch", p)) + result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; + else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_teams", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; break; @@ -26398,18 +26529,40 @@ cp_parser_omp_clause_name (cp_parser *parser) if (!strcmp ("ordered", p)) result = PRAGMA_OMP_CLAUSE_ORDERED; break; + case 'p': + if (!strcmp ("parallel", p)) + result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("proc_bind", p)) + result = PRAGMA_OMP_CLAUSE_PROC_BIND; + break; case 'r': if (!strcmp ("reduction", p)) result = PRAGMA_OMP_CLAUSE_REDUCTION; break; case 's': - if (!strcmp ("schedule", p)) + if (!strcmp ("safelen", p)) + result = PRAGMA_OMP_CLAUSE_SAFELEN; + else if (!strcmp ("schedule", p)) result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("sections", p)) + result = PRAGMA_OMP_CLAUSE_SECTIONS; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simdlen", p)) + result = PRAGMA_OMP_CLAUSE_SIMDLEN; + break; + case 't': + if (!strcmp ("taskgroup", p)) + result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("thread_limit", p)) + result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; + else if (!strcmp ("to", p)) + result = PRAGMA_OMP_CLAUSE_TO; break; case 'u': - if (!strcmp ("untied", p)) + if (!strcmp ("uniform", p)) + result = PRAGMA_OMP_CLAUSE_UNIFORM; + else if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; break; } @@ -26442,20 +26595,30 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code, identifier variable-list , identifier - In addition, we match a closing parenthesis. An opening parenthesis - will have been consumed by the caller. + In addition, we match a closing parenthesis (or, if COLON is non-NULL, + colon). An opening parenthesis will have been consumed by the caller. If KIND is nonzero, create the appropriate node and install the decl in OMP_CLAUSE_DECL and add the node to the head of the list. If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; - return the list created. */ + return the list created. + + COLON can be NULL if only closing parenthesis should end the list, + or pointer to bool which will receive false if the list is terminated + by closing parenthesis or true if the list is terminated by colon. */ static tree cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, - tree list) + tree list, bool *colon) { cp_token *token; + bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + if (colon) + { + parser->colon_corrects_to_scope_p = false; + *colon = false; + } while (1) { tree name, decl; @@ -26475,6 +26638,48 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, token->location); else if (kind != 0) { + switch (kind) + { + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_DEPEND: + while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + { + tree low_bound = NULL_TREE, length = NULL_TREE; + + parser->colon_corrects_to_scope_p = false; + cp_lexer_consume_token (parser->lexer); + if (!cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + low_bound = cp_parser_expression (parser, /*cast_p=*/false, + NULL); + if (!colon) + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) + length = integer_one_node; + else + { + /* Look for `:'. */ + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto skip_comma; + if (!cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SQUARE)) + length = cp_parser_expression (parser, + /*cast_p=*/false, + NULL); + } + /* Look for the closing `]'. */ + if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, + RT_CLOSE_SQUARE)) + goto skip_comma; + decl = tree_cons (low_bound, length, decl); + } + break; + default: + break; + } + tree u = build_omp_clause (token->location, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; @@ -26489,6 +26694,16 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, cp_lexer_consume_token (parser->lexer); } + if (colon) + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + + if (colon != NULL && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + *colon = true; + cp_parser_require (parser, CPP_COLON, RT_COLON); + return list; + } + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) { int ending; @@ -26496,6 +26711,8 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /* Try to resync to an unnested comma. Copied from cp_parser_parenthesized_expression_list. */ skip_comma: + if (colon) + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; ending = cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/true, @@ -26514,7 +26731,7 @@ static tree cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list) { if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) - return cp_parser_omp_var_list_no_open (parser, kind, list); + return cp_parser_omp_var_list_no_open (parser, kind, list, NULL); return list; } @@ -26762,77 +26979,102 @@ cp_parser_omp_clause_ordered (cp_parser * /*parser*/, OpenMP 3.1: reduction-operator: - One of: + * - & ^ | && || min max */ + One of: + * - & ^ | && || min max + + OpenMP 4.0: + + reduction-operator: + One of: + * - & ^ | && || + id-expression */ static tree cp_parser_omp_clause_reduction (cp_parser *parser, tree list) { - enum tree_code code; - tree nlist, c; + enum tree_code code = ERROR_MARK; + tree nlist, c, id = NULL_TREE; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; switch (cp_lexer_peek_token (parser->lexer)->type) { - case CPP_PLUS: - code = PLUS_EXPR; - break; - case CPP_MULT: - code = MULT_EXPR; - break; - case CPP_MINUS: - code = MINUS_EXPR; - break; - case CPP_AND: - code = BIT_AND_EXPR; - break; - case CPP_XOR: - code = BIT_XOR_EXPR; - break; - case CPP_OR: - code = BIT_IOR_EXPR; - break; - case CPP_AND_AND: - code = TRUTH_ANDIF_EXPR; - break; - case CPP_OR_OR: - code = TRUTH_ORIF_EXPR; - break; - case CPP_NAME: - { - tree id = cp_lexer_peek_token (parser->lexer)->u.value; - const char *p = IDENTIFIER_POINTER (id); + case CPP_PLUS: code = PLUS_EXPR; break; + case CPP_MULT: code = MULT_EXPR; break; + case CPP_MINUS: code = MINUS_EXPR; break; + case CPP_AND: code = BIT_AND_EXPR; break; + case CPP_XOR: code = BIT_XOR_EXPR; break; + case CPP_OR: code = BIT_IOR_EXPR; break; + case CPP_AND_AND: code = TRUTH_ANDIF_EXPR; break; + case CPP_OR_OR: code = TRUTH_ORIF_EXPR; break; + default: break; + } - if (strcmp (p, "min") == 0) - { + if (code != ERROR_MARK) + cp_lexer_consume_token (parser->lexer); + else + { + bool saved_colon_corrects_to_scope_p; + saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + parser->colon_corrects_to_scope_p = false; + id = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + if (identifier_p (id)) + { + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "min") == 0) code = MIN_EXPR; - break; - } - if (strcmp (p, "max") == 0) - { + else if (strcmp (p, "max") == 0) code = MAX_EXPR; - break; - } - } - /* FALLTHROUGH */ - default: - cp_parser_error (parser, "expected %<+%>, %<*%>, %<-%>, %<&%>, %<^%>, " - "%<|%>, %<&&%>, %<||%>, %<min%> or %<max%>"); - resync_fail: - cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, - /*or_comma=*/false, - /*consume_paren=*/true); - return list; + else if (id == ansi_opname (PLUS_EXPR)) + code = PLUS_EXPR; + else if (id == ansi_opname (MULT_EXPR)) + code = MULT_EXPR; + else if (id == ansi_opname (MINUS_EXPR)) + code = MINUS_EXPR; + else if (id == ansi_opname (BIT_AND_EXPR)) + code = BIT_AND_EXPR; + else if (id == ansi_opname (BIT_IOR_EXPR)) + code = BIT_IOR_EXPR; + else if (id == ansi_opname (BIT_XOR_EXPR)) + code = BIT_XOR_EXPR; + else if (id == ansi_opname (TRUTH_ANDIF_EXPR)) + code = TRUTH_ANDIF_EXPR; + else if (id == ansi_opname (TRUTH_ORIF_EXPR)) + code = TRUTH_ORIF_EXPR; + id = omp_reduction_id (code, id, NULL_TREE); + tree scope = parser->scope; + if (scope) + id = build_qualified_name (NULL_TREE, scope, id, false); + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + } + else + { + error ("invalid reduction-identifier"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } } - cp_lexer_consume_token (parser->lexer); if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) goto resync_fail; - nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list); + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list, + NULL); for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_REDUCTION_CODE (c) = code; + { + OMP_CLAUSE_REDUCTION_CODE (c) = code; + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = id; + } return nlist; } @@ -26945,13 +27187,468 @@ cp_parser_omp_clause_untied (cp_parser * /*parser*/, return c; } +/* OpenMP 4.0: + inbranch + notinbranch */ + +static tree +cp_parser_omp_clause_branch (cp_parser * /*parser*/, enum omp_clause_code code, + tree list, location_t location) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code], location); + tree c = build_omp_clause (location, code); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + parallel + for + sections + taskgroup */ + +static tree +cp_parser_omp_clause_cancelkind (cp_parser * /*parser*/, + enum omp_clause_code code, + tree list, location_t location) +{ + tree c = build_omp_clause (location, code); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + num_teams ( expression ) */ + +static tree +cp_parser_omp_clause_num_teams (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, + "num_teams", location); + + c = build_omp_clause (location, OMP_CLAUSE_NUM_TEAMS); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + thread_limit ( expression ) */ + +static tree +cp_parser_omp_clause_thread_limit (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT, + "thread_limit", location); + + c = build_omp_clause (location, OMP_CLAUSE_THREAD_LIMIT); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + aligned ( variable-list ) + aligned ( variable-list : constant-expression ) */ + +static tree +cp_parser_omp_clause_aligned (cp_parser *parser, tree list) +{ + tree nlist, c, alignment = NULL_TREE; + bool colon; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ALIGNED, list, + &colon); + + if (colon) + { + alignment = cp_parser_constant_expression (parser, false, NULL); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (alignment == error_mark_node) + alignment = NULL_TREE; + } + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; + + return nlist; +} + +/* OpenMP 4.0: + linear ( variable-list ) + linear ( variable-list : expression ) */ + +static tree +cp_parser_omp_clause_linear (cp_parser *parser, tree list) +{ + tree nlist, c, step = integer_one_node; + bool colon; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_LINEAR, list, + &colon); + + if (colon) + { + step = cp_parser_expression (parser, false, NULL); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (step == error_mark_node) + return list; + } + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_LINEAR_STEP (c) = step; + + return nlist; +} + +/* OpenMP 4.0: + safelen ( constant-expression ) */ + +static tree +cp_parser_omp_clause_safelen (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_constant_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen", location); + + c = build_omp_clause (location, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + simdlen ( constant-expression ) */ + +static tree +cp_parser_omp_clause_simdlen (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_constant_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen", location); + + c = build_omp_clause (location, OMP_CLAUSE_SIMDLEN); + OMP_CLAUSE_SIMDLEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + depend ( depend-kind : variable-list ) + + depend-kind: + in | out | inout */ + +static tree +cp_parser_omp_clause_depend (cp_parser *parser, tree list) +{ + tree nlist, c; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp ("in", p) == 0) + kind = OMP_CLAUSE_DEPEND_IN; + else if (strcmp ("inout", p) == 0) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (strcmp ("out", p) == 0) + kind = OMP_CLAUSE_DEPEND_OUT; + else + goto invalid_kind; + } + else + goto invalid_kind; + + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto resync_fail; + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND, list, + NULL); + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DEPEND_KIND (c) = kind; + + return nlist; + + invalid_kind: + cp_parser_error (parser, "invalid depend kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + +/* OpenMP 4.0: + map ( map-kind : variable-list ) + map ( variable-list ) + + map-kind: + alloc | to | from | tofrom */ + +static tree +cp_parser_omp_clause_map (cp_parser *parser, tree list) +{ + tree nlist, c; + enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp ("alloc", p) == 0) + kind = OMP_CLAUSE_MAP_ALLOC; + else if (strcmp ("to", p) == 0) + kind = OMP_CLAUSE_MAP_TO; + else if (strcmp ("from", p) == 0) + kind = OMP_CLAUSE_MAP_FROM; + else if (strcmp ("tofrom", p) == 0) + kind = OMP_CLAUSE_MAP_TOFROM; + else + { + cp_parser_error (parser, "invalid map kind"); + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_MAP, list, + NULL); + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_MAP_KIND (c) = kind; + + return nlist; +} + +/* OpenMP 4.0: + device ( expression ) */ + +static tree +cp_parser_omp_clause_device (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, + "device", location); + + c = build_omp_clause (location, OMP_CLAUSE_DEVICE); + OMP_CLAUSE_DEVICE_ID (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + dist_schedule ( static ) + dist_schedule ( static , expression ) */ + +static tree +cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, + location_t location) +{ + tree c, t; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + c = build_omp_clause (location, OMP_CLAUSE_DIST_SCHEDULE); + + if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC)) + goto invalid_kind; + cp_lexer_consume_token (parser->lexer); + + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + cp_lexer_consume_token (parser->lexer); + + t = cp_parser_assignment_expression (parser, false, NULL); + + if (t == error_mark_node) + goto resync_fail; + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + goto resync_fail; + } + else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN)) + goto resync_fail; + + check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, "dist_schedule", + location); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + cp_parser_error (parser, "invalid dist_schedule kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + +/* OpenMP 4.0: + proc_bind ( proc-bind-kind ) + + proc-bind-kind: + master | close | spread */ + +static tree +cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, + location_t location) +{ + tree c; + enum omp_clause_proc_bind_kind kind; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp ("master", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_MASTER; + else if (strcmp ("close", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_CLOSE; + else if (strcmp ("spread", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_SPREAD; + else + goto invalid_kind; + } + else + goto invalid_kind; + + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN)) + goto resync_fail; + + c = build_omp_clause (location, OMP_CLAUSE_PROC_BIND); + check_no_duplicate_clause (list, OMP_CLAUSE_PROC_BIND, "proc_bind", + location); + OMP_CLAUSE_PROC_BIND_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + cp_parser_error (parser, "invalid depend kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + /* Parse all OpenMP clauses. The set clauses allowed by the directive is a bitmask in MASK. Return the list of clauses found; the result of clause default goes in *pdefault. */ static tree -cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, - const char *where, cp_token *pragma_tok) +cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, + const char *where, cp_token *pragma_tok, + bool finish_p = true) { tree clauses = NULL; bool first = true; @@ -26968,7 +27665,6 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, token = cp_lexer_peek_token (parser->lexer); c_kind = cp_parser_omp_clause_name (parser); - first = false; switch (c_kind) { @@ -27050,13 +27746,125 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, case PRAGMA_OMP_CLAUSE_UNTIED: clauses = cp_parser_omp_clause_untied (parser, clauses, token->location); - c_name = "nowait"; + c_name = "untied"; + break; + case PRAGMA_OMP_CLAUSE_INBRANCH: + clauses = cp_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH, + clauses, token->location); + c_name = "inbranch"; + break; + case PRAGMA_OMP_CLAUSE_NOTINBRANCH: + clauses = cp_parser_omp_clause_branch (parser, + OMP_CLAUSE_NOTINBRANCH, + clauses, token->location); + c_name = "notinbranch"; + break; + case PRAGMA_OMP_CLAUSE_PARALLEL: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, + clauses, token->location); + c_name = "parallel"; + if (!first) + { + clause_not_first: + error_at (token->location, "%qs must be the first clause of %qs", + c_name, where); + clauses = prev; + } + break; + case PRAGMA_OMP_CLAUSE_FOR: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, + clauses, token->location); + c_name = "for"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_SECTIONS: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, + clauses, token->location); + c_name = "sections"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_TASKGROUP: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, + clauses, token->location); + c_name = "taskgroup"; + if (!first) + goto clause_not_first; + break; + case PRAGMA_OMP_CLAUSE_TO: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, + clauses); + c_name = "to"; + break; + case PRAGMA_OMP_CLAUSE_FROM: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, + clauses); + c_name = "from"; + break; + case PRAGMA_OMP_CLAUSE_UNIFORM: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_UNIFORM, + clauses); + c_name = "uniform"; + break; + case PRAGMA_OMP_CLAUSE_NUM_TEAMS: + clauses = cp_parser_omp_clause_num_teams (parser, clauses, + token->location); + c_name = "num_teams"; + break; + case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: + clauses = cp_parser_omp_clause_thread_limit (parser, clauses, + token->location); + c_name = "thread_limit"; + break; + case PRAGMA_OMP_CLAUSE_ALIGNED: + clauses = cp_parser_omp_clause_aligned (parser, clauses); + c_name = "aligned"; + break; + case PRAGMA_OMP_CLAUSE_LINEAR: + clauses = cp_parser_omp_clause_linear (parser, clauses); + c_name = "linear"; + break; + case PRAGMA_OMP_CLAUSE_DEPEND: + clauses = cp_parser_omp_clause_depend (parser, clauses); + c_name = "depend"; + break; + case PRAGMA_OMP_CLAUSE_MAP: + clauses = cp_parser_omp_clause_map (parser, clauses); + c_name = "map"; + break; + case PRAGMA_OMP_CLAUSE_DEVICE: + clauses = cp_parser_omp_clause_device (parser, clauses, + token->location); + c_name = "device"; + break; + case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: + clauses = cp_parser_omp_clause_dist_schedule (parser, clauses, + token->location); + c_name = "dist_schedule"; + break; + case PRAGMA_OMP_CLAUSE_PROC_BIND: + clauses = cp_parser_omp_clause_proc_bind (parser, clauses, + token->location); + c_name = "proc_bind"; + break; + case PRAGMA_OMP_CLAUSE_SAFELEN: + clauses = cp_parser_omp_clause_safelen (parser, clauses, + token->location); + c_name = "safelen"; + break; + case PRAGMA_OMP_CLAUSE_SIMDLEN: + clauses = cp_parser_omp_clause_simdlen (parser, clauses, + token->location); + c_name = "simdlen"; break; default: cp_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; } + first = false; + if (((mask >> c_kind) & 1) == 0) { /* Remove the invalid clause(s) from the list to avoid @@ -27067,7 +27875,9 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, } saw_error: cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return finish_omp_clauses (clauses); + if (finish_p) + return finish_omp_clauses (clauses); + return clauses; } /* OpenMP 2.5: @@ -27152,10 +27962,18 @@ cp_parser_omp_structured_block (cp_parser *parser) update-stmt: expression-stmt | x = x binop expr capture-stmt: - v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x + v = expression-stmt capture-block: { v = x; update-stmt; } | { update-stmt; v = x; } + OpenMP 4.0: + update-stmt: + expression-stmt | x = x binop expr | x = expr binop x + capture-stmt: + v = update-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } + where x and v are lvalue expressions with scalar type. */ static void @@ -27165,6 +27983,7 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) tree rhs1 = NULL_TREE, orig_lhs; enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; bool structured_block = false; + bool seq_cst = false; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -27184,6 +28003,18 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) if (p) cp_lexer_consume_token (parser->lexer); } + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + cp_lexer_consume_token (parser->lexer); + } + } cp_parser_require_pragma_eol (parser, pragma_tok); switch (code) @@ -27322,75 +28153,139 @@ restart: opcode = BIT_XOR_EXPR; break; case CPP_EQ: - if (structured_block || code == OMP_ATOMIC) + enum cp_parser_prec oprec; + cp_token *token; + cp_lexer_consume_token (parser->lexer); + cp_parser_parse_tentatively (parser); + rhs1 = cp_parser_simple_cast_expression (parser); + if (rhs1 == error_mark_node) { - enum cp_parser_prec oprec; - cp_token *token; - cp_lexer_consume_token (parser->lexer); - rhs1 = cp_parser_unary_expression (parser, /*address_p=*/false, - /*cast_p=*/false, NULL); - if (rhs1 == error_mark_node) - goto saw_error; - token = cp_lexer_peek_token (parser->lexer); - switch (token->type) + cp_parser_abort_tentative_parse (parser); + cp_parser_simple_cast_expression (parser); + goto saw_error; + } + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_SEMICOLON && !cp_tree_equal (lhs, rhs1)) + { + cp_parser_abort_tentative_parse (parser); + cp_parser_parse_tentatively (parser); + rhs = cp_parser_binary_expression (parser, false, true, + PREC_NOT_OPERATOR, NULL); + if (rhs == error_mark_node) + { + cp_parser_abort_tentative_parse (parser); + cp_parser_binary_expression (parser, false, true, + PREC_NOT_OPERATOR, NULL); + goto saw_error; + } + switch (TREE_CODE (rhs)) { - case CPP_SEMICOLON: - if (code == OMP_ATOMIC_CAPTURE_NEW) + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (cp_tree_equal (lhs, TREE_OPERAND (rhs, 1))) { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; - lhs1 = rhs1; - rhs1 = NULL_TREE; - cp_lexer_consume_token (parser->lexer); - goto restart; + if (cp_parser_parse_definitely (parser)) + { + opcode = TREE_CODE (rhs); + rhs1 = TREE_OPERAND (rhs, 0); + rhs = TREE_OPERAND (rhs, 1); + goto stmt_done; + } + else + goto saw_error; } - cp_parser_error (parser, - "invalid form of %<#pragma omp atomic%>"); - goto saw_error; - case CPP_MULT: - opcode = MULT_EXPR; - break; - case CPP_DIV: - opcode = TRUNC_DIV_EXPR; - break; - case CPP_PLUS: - opcode = PLUS_EXPR; - break; - case CPP_MINUS: - opcode = MINUS_EXPR; - break; - case CPP_LSHIFT: - opcode = LSHIFT_EXPR; - break; - case CPP_RSHIFT: - opcode = RSHIFT_EXPR; - break; - case CPP_AND: - opcode = BIT_AND_EXPR; - break; - case CPP_OR: - opcode = BIT_IOR_EXPR; - break; - case CPP_XOR: - opcode = BIT_XOR_EXPR; break; default: - cp_parser_error (parser, - "invalid operator for %<#pragma omp atomic%>"); - goto saw_error; + break; } - oprec = TOKEN_PRECEDENCE (token); - gcc_assert (oprec != PREC_NOT_OPERATOR); - if (commutative_tree_code (opcode)) - oprec = (enum cp_parser_prec) (oprec - 1); - cp_lexer_consume_token (parser->lexer); - rhs = cp_parser_binary_expression (parser, false, false, - oprec, NULL); - if (rhs == error_mark_node) - goto saw_error; - goto stmt_done; + cp_parser_abort_tentative_parse (parser); + if (structured_block && code == OMP_ATOMIC_CAPTURE_OLD) + { + rhs = cp_parser_expression (parser, /*cast_p=*/false, NULL); + if (rhs == error_mark_node) + goto saw_error; + opcode = NOP_EXPR; + rhs1 = NULL_TREE; + goto stmt_done; + } + cp_parser_error (parser, + "invalid form of %<#pragma omp atomic%>"); + goto saw_error; } + if (!cp_parser_parse_definitely (parser)) + goto saw_error; + switch (token->type) + { + case CPP_SEMICOLON: + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + lhs1 = rhs1; + rhs1 = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + goto restart; + } + else if (structured_block) + { + opcode = NOP_EXPR; + rhs = rhs1; + rhs1 = NULL_TREE; + goto stmt_done; + } + cp_parser_error (parser, + "invalid form of %<#pragma omp atomic%>"); + goto saw_error; + case CPP_MULT: + opcode = MULT_EXPR; + break; + case CPP_DIV: + opcode = TRUNC_DIV_EXPR; + break; + case CPP_PLUS: + opcode = PLUS_EXPR; + break; + case CPP_MINUS: + opcode = MINUS_EXPR; + break; + case CPP_LSHIFT: + opcode = LSHIFT_EXPR; + break; + case CPP_RSHIFT: + opcode = RSHIFT_EXPR; + break; + case CPP_AND: + opcode = BIT_AND_EXPR; + break; + case CPP_OR: + opcode = BIT_IOR_EXPR; + break; + case CPP_XOR: + opcode = BIT_XOR_EXPR; + break; + default: + cp_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + oprec = TOKEN_PRECEDENCE (token); + gcc_assert (oprec != PREC_NOT_OPERATOR); + if (commutative_tree_code (opcode)) + oprec = (enum cp_parser_prec) (oprec - 1); + cp_lexer_consume_token (parser->lexer); + rhs = cp_parser_binary_expression (parser, false, false, + oprec, NULL); + if (rhs == error_mark_node) + goto saw_error; + goto stmt_done; /* FALLTHROUGH */ default: cp_parser_error (parser, @@ -27426,7 +28321,7 @@ stmt_done: cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); } done: - finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1); + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, seq_cst); if (!structured_block) cp_parser_consume_semicolon_at_end_of_statement (parser); return; @@ -27635,7 +28530,8 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) /* Parse the restricted form of the for statement allowed by OpenMP. */ static tree -cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) +cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, + tree *cclauses) { tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret; tree real_decl, initv, condv, incrv, declv; @@ -27845,10 +28741,12 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) if (decl) real_decl = decl; - if (par_clauses != NULL && real_decl != NULL_TREE) + if (cclauses != NULL + && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL + && real_decl != NULL_TREE) { tree *c; - for (c = par_clauses; *c ; ) + for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE && OMP_CLAUSE_DECL (*c) == real_decl) { @@ -27994,7 +28892,7 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) if (declv == NULL_TREE) ret = NULL_TREE; else - ret = finish_omp_for (loc_first, declv, initv, condv, incrv, body, + ret = finish_omp_for (loc_first, code, declv, initv, condv, incrv, body, pre_body, clauses); while (nbraces) @@ -28027,33 +28925,137 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) return ret; } +/* Helper function for OpenMP parsing, split clauses and call + finish_omp_clauses on each of the set of clauses afterwards. */ + +static void +cp_omp_split_clauses (location_t loc, enum tree_code code, + omp_clause_mask mask, tree clauses, tree *cclauses) +{ + int i; + c_omp_split_clauses (loc, code, mask, clauses, cclauses); + for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) + if (cclauses[i]) + cclauses[i] = finish_omp_clauses (cclauses[i]); +} + +/* OpenMP 4.0: + #pragma omp simd simd-clause[optseq] new-line + for-loop */ + +#define OMP_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (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)) + +static tree +cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " simd"); + mask |= OMP_SIMD_CLAUSE_MASK; + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + } + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, cclauses); + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + + return ret; +} + /* OpenMP 2.5: #pragma omp for for-clause[optseq] new-line + for-loop + + OpenMP 4.0: + #pragma omp for simd for-simd-clause[optseq] new-line for-loop */ -#define OMP_FOR_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ - | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT) \ - | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE)) +#define OMP_FOR_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree -cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree clauses, sb, ret; unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; - clauses = cp_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, - "#pragma omp for", pragma_tok); + strcat (p_name, " for"); + mask |= OMP_FOR_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "simd") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, + cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = make_node (OMP_FOR); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = body; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + } sb = begin_omp_structured_block (); save = cp_parser_begin_omp_structured_block (parser); - ret = cp_parser_omp_for_loop (parser, clauses, NULL); + ret = cp_parser_omp_for_loop (parser, OMP_FOR, clauses, cclauses); cp_parser_end_omp_structured_block (parser, save); add_stmt (finish_omp_structured_block (sb)); @@ -28108,26 +29110,7 @@ cp_parser_omp_sections_scope (cp_parser *parser) if (cp_lexer_peek_token (parser->lexer)->pragma_kind != PRAGMA_OMP_SECTION) { - unsigned save; - - substmt = begin_omp_structured_block (); - save = cp_parser_begin_omp_structured_block (parser); - - while (1) - { - cp_parser_statement (parser, NULL_TREE, false, NULL); - - tok = cp_lexer_peek_token (parser->lexer); - if (tok->pragma_kind == PRAGMA_OMP_SECTION) - break; - if (tok->type == CPP_CLOSE_BRACE) - break; - if (tok->type == CPP_EOF) - break; - } - - cp_parser_end_omp_structured_block (parser, save); - substmt = finish_omp_structured_block (substmt); + substmt = cp_parser_omp_structured_block (parser); substmt = build1 (OMP_SECTION, void_type_node, substmt); add_stmt (substmt); } @@ -28172,20 +29155,32 @@ cp_parser_omp_sections_scope (cp_parser *parser) # pragma omp sections sections-clause[optseq] newline sections-scope */ -#define OMP_SECTIONS_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree clauses, ret; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; - clauses = cp_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, - "#pragma omp sections", pragma_tok); + strcat (p_name, " sections"); + mask |= OMP_SECTIONS_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; + } ret = cp_parser_omp_sections_scope (parser); if (ret) @@ -28197,35 +29192,54 @@ cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok) /* OpenMP 2.5: # pragma parallel parallel-clause new-line # pragma parallel for parallel-for-clause new-line - # pragma parallel sections parallel-sections-clause new-line */ - -#define OMP_PARALLEL_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + # pragma parallel sections parallel-sections-clause new-line + + OpenMP 4.0: + # pragma parallel for simd parallel-for-simd-clause new-line */ + +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) static tree -cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { - enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; - const char *p_name = "#pragma omp parallel"; - tree stmt, clauses, par_clause, ws_clause, block; - unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + tree stmt, clauses, block; unsigned int save; location_t loc = cp_lexer_peek_token (parser->lexer)->location; + strcat (p_name, " parallel"); + mask |= OMP_PARALLEL_CLAUSE_MASK; + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + cp_lexer_consume_token (parser->lexer); - p_kind = PRAGMA_OMP_PARALLEL_FOR; - p_name = "#pragma omp parallel for"; - mask |= OMP_FOR_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses) + { + error_at (loc, "expected %<for%> after %qs", p_name); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; } else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -28233,45 +29247,28 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) const char *p = IDENTIFIER_POINTER (id); if (strcmp (p, "sections") == 0) { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + cp_lexer_consume_token (parser->lexer); - p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; - p_name = "#pragma omp parallel sections"; - mask |= OMP_SECTIONS_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_omp_sections (parser, pragma_tok, p_name, mask, cclauses); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; } } clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok); + block = begin_omp_parallel (); save = cp_parser_begin_omp_structured_block (parser); - - switch (p_kind) - { - case PRAGMA_OMP_PARALLEL: - cp_parser_statement (parser, NULL_TREE, false, NULL); - par_clause = clauses; - break; - - case PRAGMA_OMP_PARALLEL_FOR: - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - cp_parser_omp_for_loop (parser, ws_clause, &par_clause); - break; - - case PRAGMA_OMP_PARALLEL_SECTIONS: - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - stmt = cp_parser_omp_sections_scope (parser); - if (stmt) - OMP_SECTIONS_CLAUSES (stmt) = ws_clause; - break; - - default: - gcc_unreachable (); - } - + cp_parser_statement (parser, NULL_TREE, false, NULL); cp_parser_end_omp_structured_block (parser, save); - stmt = finish_omp_parallel (par_clause, block); - if (p_kind != PRAGMA_OMP_PARALLEL) - OMP_PARALLEL_COMBINED (stmt) = 1; + stmt = finish_omp_parallel (clauses, block); return stmt; } @@ -28279,11 +29276,11 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) # pragma omp single single-clause[optseq] new-line structured-block */ -#define OMP_SINGLE_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SINGLE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) @@ -28303,15 +29300,16 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) # pragma omp task task-clause[optseq] new-line structured-block */ -#define OMP_TASK_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_FINAL) \ - | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE)) +#define OMP_TASK_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)) static tree cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok) @@ -28348,6 +29346,19 @@ cp_parser_omp_taskyield (cp_parser *parser, cp_token *pragma_tok) finish_omp_taskyield (); } +/* OpenMP 4.0: + # pragma omp taskgroup new-line + structured-block */ + +static tree +cp_parser_omp_taskgroup (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_require_pragma_eol (parser, pragma_tok); + return c_finish_omp_taskgroup (input_location, + cp_parser_omp_structured_block (parser)); +} + + /* OpenMP 2.5: # pragma omp threadprivate (variable-list) */ @@ -28362,12 +29373,957 @@ cp_parser_omp_threadprivate (cp_parser *parser, cp_token *pragma_tok) finish_omp_threadprivate (vars); } +/* OpenMP 4.0: + # pragma omp cancel cancel-clause[optseq] new-line */ + +#define OMP_CANCEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static void +cp_parser_omp_cancel (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses = cp_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, + "#pragma omp cancel", pragma_tok); + finish_omp_cancel (clauses); +} + +/* OpenMP 4.0: + # pragma omp cancellation point cancelpt-clause[optseq] new-line */ + +#define OMP_CANCELLATION_POINT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) + +static void +cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses; + bool point_seen = false; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "point") == 0) + { + cp_lexer_consume_token (parser->lexer); + point_seen = true; + } + } + if (!point_seen) + { + cp_parser_error (parser, "expected %<point%>"); + cp_parser_require_pragma_eol (parser, pragma_tok); + return; + } + + clauses = cp_parser_omp_all_clauses (parser, + OMP_CANCELLATION_POINT_CLAUSE_MASK, + "#pragma omp cancellation point", + pragma_tok); + finish_omp_cancellation_point (clauses); +} + +/* OpenMP 4.0: + #pragma omp distribute distribute-clause[optseq] new-line + for-loop */ + +#define OMP_DISTRIBUTE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " distribute"); + mask |= OMP_DISTRIBUTE_CLAUSE_MASK; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + bool simd = false; + bool parallel = false; + + if (strcmp (p, "simd") == 0) + simd = true; + else + parallel = strcmp (p, "parallel") == 0; + if (parallel || simd) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + cp_lexer_consume_token (parser->lexer); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + if (simd) + ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, + cclauses); + else + ret = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, + cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = make_node (OMP_DISTRIBUTE); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = body; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + } + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser, OMP_DISTRIBUTE, clauses, NULL); + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + + return ret; +} + +/* OpenMP 4.0: + # pragma omp teams teams-clause[optseq] new-line + structured-block */ + +#define OMP_TEAMS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) + +static tree +cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " teams"); + mask |= OMP_TEAMS_CLAUSE_MASK; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + if (strcmp (p, "distribute") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, + cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + ret = make_node (OMP_TEAMS); + TREE_TYPE (ret) = void_type_node; + OMP_TEAMS_CLAUSES (ret) = clauses; + OMP_TEAMS_BODY (ret) = body; + return add_stmt (ret); + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + } + + tree stmt = make_node (OMP_TEAMS); + TREE_TYPE (stmt) = void_type_node; + OMP_TEAMS_CLAUSES (stmt) = clauses; + OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target data target-data-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static tree +cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt = make_node (OMP_TARGET_DATA); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_DATA_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, + "#pragma omp target data", pragma_tok); + keep_next_level (true); + OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser); + + SET_EXPR_LOCATION (stmt, pragma_tok->location); + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target update target-update-clause[optseq] new-line */ + +#define OMP_TARGET_UPDATE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static bool +cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + if (context == pragma_stmt) + { + error_at (pragma_tok->location, + "%<#pragma omp target update%> may only be " + "used in compound statements"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return false; + } + + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK, + "#pragma omp target update", pragma_tok); + if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE + && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE) + { + error_at (pragma_tok->location, + "%<#pragma omp target update must contain at least one " + "%<from%> or %<to%> clauses"); + return false; + } + + tree stmt = make_node (OMP_TARGET_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + return false; +} + +/* OpenMP 4.0: + # pragma omp target target-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static bool +cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + if (context != pragma_stmt && context != pragma_compound) + { + cp_parser_error (parser, "expected declaration specifiers"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return false; + } + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "data") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_target_data (parser, pragma_tok); + return true; + } + else if (strcmp (p, "update") == 0) + { + cp_lexer_consume_token (parser->lexer); + return cp_parser_omp_target_update (parser, pragma_tok, context); + } + else if (strcmp (p, "teams") == 0) + { + tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; + char p_name[sizeof ("#pragma omp target teams distribute " + "parallel for simd")]; + + cp_lexer_consume_token (parser->lexer); + strcpy (p_name, "#pragma omp target"); + keep_next_level (true); + tree sb = begin_omp_structured_block (); + unsigned save = cp_parser_begin_omp_structured_block (parser); + tree ret = cp_parser_omp_teams (parser, pragma_tok, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + OMP_TARGET_BODY (stmt) = body; + add_stmt (stmt); + return true; + } + } + + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, + "#pragma omp target", pragma_tok); + keep_next_level (true); + OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser); + + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + return true; +} + +/* OpenMP 4.0: + # pragma omp declare simd declare-simd-clauses[optseq] new-line */ + +#define OMP_DECLARE_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) + +static void +cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + bool first_p = parser->omp_declare_simd == NULL; + cp_omp_declare_simd_data data; + if (first_p) + { + data.error_seen = false; + data.fndecl_seen = false; + data.tokens = vNULL; + parser->omp_declare_simd = &data; + } + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) + && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + parser->omp_declare_simd->error_seen = true; + cp_parser_require_pragma_eol (parser, pragma_tok); + struct cp_token_cache *cp + = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer)); + parser->omp_declare_simd->tokens.safe_push (cp); + if (first_p) + { + while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) + cp_parser_pragma (parser, context); + switch (context) + { + case pragma_external: + cp_parser_declaration (parser); + break; + case pragma_member: + cp_parser_member_declaration (parser); + break; + case pragma_objc_icode: + cp_parser_block_declaration (parser, /*statement_p=*/false); + break; + default: + cp_parser_declaration_statement (parser); + break; + } + if (parser->omp_declare_simd + && !parser->omp_declare_simd->error_seen + && !parser->omp_declare_simd->fndecl_seen) + error_at (pragma_tok->location, + "%<#pragma omp declare simd%> not immediately followed by " + "function declaration or definition"); + data.tokens.release (); + parser->omp_declare_simd = NULL; + } +} + +/* Finalize #pragma omp declare simd clauses after direct declarator has + been parsed, and put that into "omp declare simd" attribute. */ + +static tree +cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) +{ + struct cp_token_cache *ce; + cp_omp_declare_simd_data *data = parser->omp_declare_simd; + int i; + + if (!data->error_seen && data->fndecl_seen) + { + error ("%<#pragma omp declare simd%> not immediately followed by " + "a single function declaration or definition"); + data->error_seen = true; + return attrs; + } + if (data->error_seen) + return attrs; + + FOR_EACH_VEC_ELT (data->tokens, i, ce) + { + tree c, cl; + + cp_parser_push_lexer_for_tokens (parser, ce); + parser->lexer->in_pragma = true; + gcc_assert (cp_lexer_peek_token (parser->lexer)->type == CPP_PRAGMA); + cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd", pragma_tok); + cp_parser_pop_lexer (parser); + if (cl) + cl = tree_cons (NULL_TREE, cl, NULL_TREE); + c = build_tree_list (get_identifier ("omp declare simd"), cl); + TREE_CHAIN (c) = attrs; + if (processing_template_decl) + ATTR_IS_DEPENDENT (c) = 1; + attrs = c; + } + + data->fndecl_seen = true; + return attrs; +} + + +/* OpenMP 4.0: + # pragma omp declare target new-line + declarations and definitions + # pragma omp end declare target new-line */ + +static void +cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + scope_chain->omp_declare_target_attribute++; +} + +static void +cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) +{ + const char *p = ""; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + } + if (strcmp (p, "declare") == 0) + { + cp_lexer_consume_token (parser->lexer); + p = ""; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + } + if (strcmp (p, "target") == 0) + cp_lexer_consume_token (parser->lexer); + else + { + cp_parser_error (parser, "expected %<target%>"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return; + } + } + else + { + cp_parser_error (parser, "expected %<declare%>"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return; + } + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + if (!scope_chain->omp_declare_target_attribute) + error_at (pragma_tok->location, + "%<#pragma omp end declare target%> without corresponding " + "%<#pragma omp declare target%>"); + else + scope_chain->omp_declare_target_attribute--; +} + +/* Helper function of cp_parser_omp_declare_reduction. Parse the combiner + expression and optional initializer clause of + #pragma omp declare reduction. We store the expression(s) as + either 3, 6 or 7 special statements inside of the artificial function's + body. The first two statements are DECL_EXPRs for the artificial + OMP_OUT resp. OMP_IN variables, followed by a statement with the combiner + expression that uses those variables. + If there was any INITIALIZER clause, this is followed by further statements, + the fourth and fifth statements are DECL_EXPRs for the artificial + OMP_PRIV resp. OMP_ORIG variables. If the INITIALIZER clause wasn't the + constructor variant (first token after open paren is not omp_priv), + then the sixth statement is a statement with the function call expression + that uses the OMP_PRIV and optionally OMP_ORIG variable. + Otherwise, the sixth statement is whatever statement cp_finish_decl emits + to initialize the OMP_PRIV artificial variable and there is seventh + statement, a DECL_EXPR of the OMP_PRIV statement again. */ + +static bool +cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser) +{ + tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); + gcc_assert (TREE_CODE (type) == REFERENCE_TYPE); + type = TREE_TYPE (type); + tree omp_out = build_lang_decl (VAR_DECL, get_identifier ("omp_out"), type); + DECL_ARTIFICIAL (omp_out) = 1; + pushdecl (omp_out); + add_decl_expr (omp_out); + tree omp_in = build_lang_decl (VAR_DECL, get_identifier ("omp_in"), type); + DECL_ARTIFICIAL (omp_in) = 1; + pushdecl (omp_in); + add_decl_expr (omp_in); + tree combiner; + tree omp_priv = NULL_TREE, omp_orig = NULL_TREE, initializer = NULL_TREE; + + keep_next_level (true); + tree block = begin_omp_structured_block (); + combiner = cp_parser_expression (parser, false, NULL); + finish_expr_stmt (combiner); + block = finish_omp_structured_block (block); + add_stmt (block); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + return false; + + const char *p = ""; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + } + + if (strcmp (p, "initializer") == 0) + { + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return false; + + p = ""; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + } + + omp_priv = build_lang_decl (VAR_DECL, get_identifier ("omp_priv"), type); + DECL_ARTIFICIAL (omp_priv) = 1; + pushdecl (omp_priv); + add_decl_expr (omp_priv); + omp_orig = build_lang_decl (VAR_DECL, get_identifier ("omp_orig"), type); + DECL_ARTIFICIAL (omp_orig) = 1; + pushdecl (omp_orig); + add_decl_expr (omp_orig); + + keep_next_level (true); + block = begin_omp_structured_block (); + + bool ctor = false; + if (strcmp (p, "omp_priv") == 0) + { + bool is_direct_init, is_non_constant_init; + ctor = true; + cp_lexer_consume_token (parser->lexer); + /* Reject initializer (omp_priv) and initializer (omp_priv ()). */ + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN) + || (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type + == CPP_CLOSE_PAREN + && cp_lexer_peek_nth_token (parser->lexer, 3)->type + == CPP_CLOSE_PAREN)) + { + finish_omp_structured_block (block); + error ("invalid initializer clause"); + return false; + } + initializer = cp_parser_initializer (parser, &is_direct_init, + &is_non_constant_init); + cp_finish_decl (omp_priv, initializer, !is_non_constant_init, + NULL_TREE, LOOKUP_ONLYCONVERTING); + } + else + { + cp_parser_parse_tentatively (parser); + tree fn_name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + vec<tree, va_gc> *args; + if (fn_name == error_mark_node + || cp_parser_error_occurred (parser) + || !cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN) + || ((args = cp_parser_parenthesized_expression_list + (parser, non_attr, /*cast_p=*/false, + /*allow_expansion_p=*/true, + /*non_constant_p=*/NULL)), + cp_parser_error_occurred (parser))) + { + finish_omp_structured_block (block); + cp_parser_abort_tentative_parse (parser); + cp_parser_error (parser, "expected id-expression (arguments)"); + return false; + } + unsigned int i; + tree arg; + FOR_EACH_VEC_SAFE_ELT (args, i, arg) + if (arg == omp_priv + || (TREE_CODE (arg) == ADDR_EXPR + && TREE_OPERAND (arg, 0) == omp_priv)) + break; + cp_parser_abort_tentative_parse (parser); + if (arg == NULL_TREE) + error ("one of the initializer call arguments should be %<omp_priv%>" + " or %<&omp_priv%>"); + initializer = cp_parser_postfix_expression (parser, false, false, false, + false, NULL); + finish_expr_stmt (initializer); + } + + block = finish_omp_structured_block (block); + cp_walk_tree (&block, cp_remove_omp_priv_cleanup_stmt, omp_priv, NULL); + finish_expr_stmt (block); + + if (ctor) + add_decl_expr (omp_orig); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + return false; + } + + if (!cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL)) + cp_parser_required_error (parser, RT_PRAGMA_EOL, /*keyword=*/false); + + return true; +} + +/* OpenMP 4.0 + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + initializer-clause[opt] new-line + + initializer-clause: + initializer (omp_priv initializer) + initializer (function-name (argument-list)) */ + +static void +cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context) +{ + vec<tree> types = vNULL; + enum tree_code reduc_code = ERROR_MARK; + tree reduc_id = NULL_TREE, orig_reduc_id = NULL_TREE, type; + unsigned int i; + cp_token *first_token; + cp_token_cache *cp; + int errs; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + goto fail; + + switch (cp_lexer_peek_token (parser->lexer)->type) + { + case CPP_PLUS: + reduc_code = PLUS_EXPR; + break; + case CPP_MULT: + reduc_code = MULT_EXPR; + break; + case CPP_MINUS: + reduc_code = MINUS_EXPR; + break; + case CPP_AND: + reduc_code = BIT_AND_EXPR; + break; + case CPP_XOR: + reduc_code = BIT_XOR_EXPR; + break; + case CPP_OR: + reduc_code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + reduc_code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + reduc_code = TRUTH_ORIF_EXPR; + break; + case CPP_NAME: + reduc_id = orig_reduc_id = cp_parser_identifier (parser); + break; + default: + cp_parser_error (parser, "expected %<+%>, %<*%>, %<-%>, %<&%>, %<^%>, " + "%<|%>, %<&&%>, %<||%> or identifier"); + goto fail; + } + + if (reduc_code != ERROR_MARK) + cp_lexer_consume_token (parser->lexer); + + reduc_id = omp_reduction_id (reduc_code, reduc_id, NULL_TREE); + if (reduc_id == error_mark_node) + goto fail; + + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto fail; + + /* Types may not be defined in declare reduction type list. */ + const char *saved_message; + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = G_("types may not be defined in declare reduction type list"); + bool saved_colon_corrects_to_scope_p; + saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + parser->colon_corrects_to_scope_p = false; + bool saved_colon_doesnt_start_class_def_p; + saved_colon_doesnt_start_class_def_p + = parser->colon_doesnt_start_class_def_p; + parser->colon_doesnt_start_class_def_p = true; + + while (true) + { + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + type = cp_parser_type_id (parser); + if (type == error_mark_node) + ; + else if (ARITHMETIC_TYPE_P (type) + && (orig_reduc_id == NULL_TREE + || (TREE_CODE (type) != COMPLEX_TYPE + && (strcmp (IDENTIFIER_POINTER (orig_reduc_id), + "min") == 0 + || strcmp (IDENTIFIER_POINTER (orig_reduc_id), + "max") == 0)))) + error_at (loc, "predeclared arithmetic type %qT in " + "%<#pragma omp declare reduction%>", type); + else if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE + || TREE_CODE (type) == ARRAY_TYPE) + error_at (loc, "function or array type %qT in " + "%<#pragma omp declare reduction%>", type); + else if (TREE_CODE (type) == REFERENCE_TYPE) + error_at (loc, "reference type %qT in " + "%<#pragma omp declare reduction%>", type); + else if (TYPE_QUALS_NO_ADDR_SPACE (type)) + error_at (loc, "const, volatile or __restrict qualified type %qT in " + "%<#pragma omp declare reduction%>", type); + else + types.safe_push (type); + + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + else + break; + } + + /* Restore the saved message. */ + parser->type_definition_forbidden_message = saved_message; + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + parser->colon_doesnt_start_class_def_p + = saved_colon_doesnt_start_class_def_p; + + if (!cp_parser_require (parser, CPP_COLON, RT_COLON) + || types.is_empty ()) + { + fail: + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + types.release (); + return; + } + + first_token = cp_lexer_peek_token (parser->lexer); + cp = NULL; + errs = errorcount; + FOR_EACH_VEC_ELT (types, i, type) + { + tree fntype + = build_function_type_list (void_type_node, + cp_build_reference_type (type, false), + NULL_TREE); + tree this_reduc_id = reduc_id; + if (!dependent_type_p (type)) + this_reduc_id = omp_reduction_id (ERROR_MARK, reduc_id, type); + tree fndecl = build_lang_decl (FUNCTION_DECL, this_reduc_id, fntype); + DECL_SOURCE_LOCATION (fndecl) = pragma_tok->location; + DECL_ARTIFICIAL (fndecl) = 1; + DECL_EXTERNAL (fndecl) = 1; + DECL_DECLARED_INLINE_P (fndecl) = 1; + DECL_IGNORED_P (fndecl) = 1; + DECL_OMP_DECLARE_REDUCTION_P (fndecl) = 1; + DECL_ATTRIBUTES (fndecl) + = tree_cons (get_identifier ("gnu_inline"), NULL_TREE, + DECL_ATTRIBUTES (fndecl)); + if (processing_template_decl) + fndecl = push_template_decl (fndecl); + bool block_scope = false; + tree block = NULL_TREE; + if (current_function_decl) + { + block_scope = true; + DECL_CONTEXT (fndecl) = global_namespace; + if (!processing_template_decl) + pushdecl (fndecl); + } + else if (current_class_type) + { + if (cp == NULL) + { + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) + && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + goto fail; + cp = cp_token_cache_new (first_token, + cp_lexer_peek_nth_token (parser->lexer, + 2)); + } + DECL_STATIC_FUNCTION_P (fndecl) = 1; + finish_member_declaration (fndecl); + DECL_PENDING_INLINE_INFO (fndecl) = cp; + DECL_PENDING_INLINE_P (fndecl) = 1; + vec_safe_push (unparsed_funs_with_definitions, fndecl); + continue; + } + else + { + DECL_CONTEXT (fndecl) = current_namespace; + pushdecl (fndecl); + } + if (!block_scope) + start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED); + else + block = begin_omp_structured_block (); + if (cp) + { + cp_parser_push_lexer_for_tokens (parser, cp); + parser->lexer->in_pragma = true; + } + if (!cp_parser_omp_declare_reduction_exprs (fndecl, parser)) + { + if (!block_scope) + finish_function (0); + else + DECL_CONTEXT (fndecl) = current_function_decl; + if (cp) + cp_parser_pop_lexer (parser); + goto fail; + } + if (cp) + cp_parser_pop_lexer (parser); + if (!block_scope) + finish_function (0); + else + { + DECL_CONTEXT (fndecl) = current_function_decl; + block = finish_omp_structured_block (block); + if (TREE_CODE (block) == BIND_EXPR) + DECL_SAVED_TREE (fndecl) = BIND_EXPR_BODY (block); + else if (TREE_CODE (block) == STATEMENT_LIST) + DECL_SAVED_TREE (fndecl) = block; + if (processing_template_decl) + add_decl_expr (fndecl); + } + cp_check_omp_declare_reduction (fndecl); + if (cp == NULL && types.length () > 1) + cp = cp_token_cache_new (first_token, + cp_lexer_peek_nth_token (parser->lexer, 2)); + if (errs != errorcount) + break; + } + + cp_parser_require_pragma_eol (parser, pragma_tok); + types.release (); +} + +/* OpenMP 4.0 + #pragma omp declare simd declare-simd-clauses[optseq] new-line + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + initializer-clause[opt] new-line + #pragma omp declare target new-line */ + +static void +cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "simd") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_simd (parser, pragma_tok, + context); + return; + } + cp_ensure_no_omp_declare_simd (parser); + if (strcmp (p, "reduction") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_reduction (parser, pragma_tok, + context); + return; + } + if (strcmp (p, "target") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_target (parser, pragma_tok); + return; + } + } + cp_parser_error (parser, "expected %<simd%> or %<reduction%> " + "or %<target%>"); + cp_parser_require_pragma_eol (parser, pragma_tok); +} + /* Main entry point to OpenMP statement pragmas. */ static void cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) { tree stmt; + char p_name[sizeof "#pragma omp teams distribute parallel for simd"]; + omp_clause_mask mask (0); switch (pragma_tok->pragma_kind) { @@ -28377,8 +30333,13 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_CRITICAL: stmt = cp_parser_omp_critical (parser, pragma_tok); break; + case PRAGMA_OMP_DISTRIBUTE: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, NULL); + break; case PRAGMA_OMP_FOR: - stmt = cp_parser_omp_for (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_for (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_MASTER: stmt = cp_parser_omp_master (parser, pragma_tok); @@ -28387,10 +30348,16 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) stmt = cp_parser_omp_ordered (parser, pragma_tok); break; case PRAGMA_OMP_PARALLEL: - stmt = cp_parser_omp_parallel (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_SECTIONS: - stmt = cp_parser_omp_sections (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_sections (parser, pragma_tok, p_name, mask, NULL); + break; + case PRAGMA_OMP_SIMD: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_SINGLE: stmt = cp_parser_omp_single (parser, pragma_tok); @@ -28398,6 +30365,13 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_TASK: stmt = cp_parser_omp_task (parser, pragma_tok); break; + case PRAGMA_OMP_TASKGROUP: + stmt = cp_parser_omp_taskgroup (parser, pragma_tok); + break; + case PRAGMA_OMP_TEAMS: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL); + break; default: gcc_unreachable (); } @@ -28754,6 +30728,8 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) parser->lexer->in_pragma = true; id = pragma_tok->pragma_kind; + if (id != PRAGMA_OMP_DECLARE_REDUCTION) + cp_ensure_no_omp_declare_simd (parser); switch (id) { case PRAGMA_GCC_PCH_PREPROCESS: @@ -28823,24 +30799,71 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) } break; + case PRAGMA_OMP_CANCEL: + switch (context) + { + case pragma_compound: + cp_parser_omp_cancel (parser, pragma_tok); + return false; + case pragma_stmt: + error_at (pragma_tok->location, + "%<#pragma omp cancel%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + + case PRAGMA_OMP_CANCELLATION_POINT: + switch (context) + { + case pragma_compound: + cp_parser_omp_cancellation_point (parser, pragma_tok); + return false; + case pragma_stmt: + error_at (pragma_tok->location, + "%<#pragma omp cancellation point%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + case PRAGMA_OMP_THREADPRIVATE: cp_parser_omp_threadprivate (parser, pragma_tok); return false; + case PRAGMA_OMP_DECLARE_REDUCTION: + cp_parser_omp_declare (parser, pragma_tok, context); + return false; + case PRAGMA_OMP_ATOMIC: case PRAGMA_OMP_CRITICAL: + case PRAGMA_OMP_DISTRIBUTE: case PRAGMA_OMP_FOR: case PRAGMA_OMP_MASTER: case PRAGMA_OMP_ORDERED: case PRAGMA_OMP_PARALLEL: case PRAGMA_OMP_SECTIONS: + case PRAGMA_OMP_SIMD: case PRAGMA_OMP_SINGLE: case PRAGMA_OMP_TASK: - if (context == pragma_external) + case PRAGMA_OMP_TASKGROUP: + case PRAGMA_OMP_TEAMS: + if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; cp_parser_omp_construct (parser, pragma_tok); return true; + case PRAGMA_OMP_TARGET: + return cp_parser_omp_target (parser, pragma_tok, context); + + case PRAGMA_OMP_END_DECLARE_TARGET: + cp_parser_omp_end_declare_target (parser, pragma_tok); + return false; + case PRAGMA_OMP_SECTION: error_at (pragma_tok->location, "%<#pragma omp section%> may only be used in " diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index ffdddaf..75f327b 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -196,6 +196,14 @@ typedef struct GTY (()) cp_parser_context { } cp_parser_context; +/* Control structure for #pragma omp declare simd parsing. */ +struct cp_omp_declare_simd_data { + bool error_seen; /* Set if error has been reported. */ + bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ + vec<cp_token_cache_ptr> tokens; +}; + + /* The cp_parser structure represents the C++ parser. */ typedef struct GTY(()) cp_parser { @@ -324,6 +332,12 @@ typedef struct GTY(()) cp_parser { /* TRUE if we can auto-correct a colon to a scope operator. */ bool colon_corrects_to_scope_p; + /* TRUE if : doesn't start a class definition. Should be only used + together with type_definition_forbidden_message non-NULL, in + contexts where new types may not be defined, and the type list + is terminated by colon. */ + bool colon_doesnt_start_class_def_p; + /* If non-NULL, then we are parsing a construct where new type definitions are not permitted. The string stored here will be issued as an error message if a type is defined. */ @@ -342,6 +356,10 @@ typedef struct GTY(()) cp_parser { current declaration. */ unsigned num_template_parameter_lists; + /* When parsing #pragma omp declare simd, this is a pointer to a + data structure with everything needed for parsing the clauses. */ + cp_omp_declare_simd_data * GTY((skip)) omp_declare_simd; + /* TRUE if the function being declared was made a template due to its parameter list containing generic type specifiers (`auto' or concept identifiers) rather than an explicit template parameter list. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a350007..5721a68 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8545,6 +8545,8 @@ can_complete_type_without_circularity (tree type) return 1; } +static tree tsubst_omp_clauses (tree, bool, tree, tsubst_flags_t, tree); + /* Apply any attributes which had to be deferred until instantiation time. DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes; ARGS, COMPLAIN, IN_DECL are as tsubst. */ @@ -8586,14 +8588,32 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, { *p = TREE_CHAIN (t); TREE_CHAIN (t) = NULL_TREE; + if (flag_openmp + && is_attribute_p ("omp declare simd", + get_attribute_name (t)) + && TREE_VALUE (t)) + { + tree clauses = TREE_VALUE (TREE_VALUE (t)); + clauses = tsubst_omp_clauses (clauses, true, args, + complain, in_decl); + c_omp_declare_simd_clauses_to_decls (*decl_p, clauses); + clauses = finish_omp_clauses (clauses); + tree parms = DECL_ARGUMENTS (*decl_p); + clauses + = c_omp_declare_simd_clauses_to_numbers (parms, clauses); + if (clauses) + TREE_VALUE (TREE_VALUE (t)) = clauses; + else + TREE_VALUE (t) = NULL_TREE; + } /* If the first attribute argument is an identifier, don't pass it through tsubst. Attributes like mode, format, cleanup and several target specific attributes expect it unmodified. */ - if (TREE_VALUE (t) - && TREE_CODE (TREE_VALUE (t)) == TREE_LIST - && TREE_VALUE (TREE_VALUE (t)) - && (identifier_p (TREE_VALUE (TREE_VALUE (t))))) + else if (TREE_VALUE (t) + && TREE_CODE (TREE_VALUE (t)) == TREE_LIST + && TREE_VALUE (TREE_VALUE (t)) + && identifier_p (TREE_VALUE (TREE_VALUE (t)))) { tree chain = tsubst_expr (TREE_CHAIN (TREE_VALUE (t)), args, complain, @@ -8915,6 +8935,9 @@ instantiate_class_template_1 (tree type) /* Instantiate members marked with attribute used. */ if (r != error_mark_node && DECL_PRESERVE_P (r)) mark_used (r); + if (TREE_CODE (r) == FUNCTION_DECL + && DECL_OMP_DECLARE_REDUCTION_P (r)) + cp_check_omp_declare_reduction (r); } else { @@ -10383,6 +10406,24 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_INITIAL (r) = NULL_TREE; DECL_CONTEXT (r) = ctx; + /* OpenMP UDRs have the only argument a reference to the declared + type. We want to diagnose if the declared type is a reference, + which is invalid, but as references to references are usually + quietly merged, diagnose it here. */ + if (DECL_OMP_DECLARE_REDUCTION_P (t)) + { + tree argtype + = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (t)))); + argtype = tsubst (argtype, args, complain, in_decl); + if (TREE_CODE (argtype) == REFERENCE_TYPE) + error_at (DECL_SOURCE_LOCATION (t), + "reference type %qT in " + "%<#pragma omp declare reduction%>", argtype); + if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL) + DECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t), + argtype); + } + if (member && DECL_CONV_FN_P (r)) /* Type-conversion operator. Reconstruct the name, in case it's the name of one of the template's parameters. */ @@ -12815,8 +12856,8 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* Like tsubst_copy, but specifically for OpenMP clauses. */ static tree -tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, - tree in_decl) +tsubst_omp_clauses (tree clauses, bool declare_simd, + tree args, tsubst_flags_t complain, tree in_decl) { tree new_clauses = NULL, nc, oc; @@ -12841,7 +12882,6 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_SHARED: case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_IF: @@ -12849,22 +12889,73 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: OMP_CLAUSE_OPERAND (nc, 0) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl, /*integral_constant_expression_p=*/false); break; + case OMP_CLAUSE_REDUCTION: + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (oc)) + { + tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (oc); + if (TREE_CODE (placeholder) == SCOPE_REF) + { + tree scope = tsubst (TREE_OPERAND (placeholder, 0), args, + complain, in_decl); + OMP_CLAUSE_REDUCTION_PLACEHOLDER (nc) + = build_qualified_name (NULL_TREE, scope, + TREE_OPERAND (placeholder, 1), + false); + } + else + gcc_assert (identifier_p (placeholder)); + } + OMP_CLAUSE_OPERAND (nc, 0) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + break; + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + OMP_CLAUSE_OPERAND (nc, 0) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + OMP_CLAUSE_OPERAND (nc, 1) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + break; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: break; default: gcc_unreachable (); } } - return finish_omp_clauses (nreverse (new_clauses)); + new_clauses = nreverse (new_clauses); + if (!declare_simd) + new_clauses = finish_omp_clauses (new_clauses); + return new_clauses; } /* Like tsubst_copy_and_build, but unshare TREE_LIST nodes. */ @@ -13169,6 +13260,15 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, } else if (DECL_IMPLICIT_TYPEDEF_P (t)) /* We already did a pushtag. */; + else if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_OMP_DECLARE_REDUCTION_P (decl) + && DECL_FUNCTION_SCOPE_P (pattern_decl)) + { + DECL_CONTEXT (decl) = NULL_TREE; + pushdecl (decl); + DECL_CONTEXT (decl) = current_function_decl; + cp_check_omp_declare_reduction (decl); + } else { int const_init = false; @@ -13440,7 +13540,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_PARALLEL: - tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), + tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, args, complain, in_decl); stmt = begin_omp_parallel (); RECUR (OMP_PARALLEL_BODY (t)); @@ -13449,7 +13549,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_TASK: - tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), + tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, args, complain, in_decl); stmt = begin_omp_task (); RECUR (OMP_TASK_BODY (t)); @@ -13457,17 +13557,23 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_FOR: + case OMP_SIMD: + case OMP_DISTRIBUTE: { tree clauses, body, pre_body; - tree declv, initv, condv, incrv; + tree declv = NULL_TREE, initv = NULL_TREE, condv = NULL_TREE; + tree incrv = NULL_TREE; int i; - clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), + clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, args, complain, in_decl); - declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); - initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); - condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); - incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + if (OMP_FOR_INIT (t) != NULL_TREE) + { + declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + } stmt = begin_omp_structured_block (); @@ -13475,17 +13581,29 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, RECUR (OMP_FOR_PRE_BODY (t)); pre_body = pop_stmt_list (pre_body); - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) - tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv, - &clauses, args, complain, in_decl, - integral_constant_expression_p); + if (OMP_FOR_INIT (t) != NULL_TREE) + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) + tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv, + &clauses, args, complain, in_decl, + integral_constant_expression_p); body = push_stmt_list (); RECUR (OMP_FOR_BODY (t)); body = pop_stmt_list (body); - t = finish_omp_for (EXPR_LOCATION (t), declv, initv, condv, incrv, - body, pre_body, clauses); + if (OMP_FOR_INIT (t) != NULL_TREE) + t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, initv, + condv, incrv, body, pre_body, clauses); + else + { + t = make_node (TREE_CODE (t)); + TREE_TYPE (t) = void_type_node; + OMP_FOR_BODY (t) = body; + OMP_FOR_PRE_BODY (t) = pre_body; + OMP_FOR_CLAUSES (t) = clauses; + SET_EXPR_LOCATION (t, EXPR_LOCATION (t)); + add_stmt (t); + } add_stmt (finish_omp_structured_block (stmt)); } @@ -13493,7 +13611,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OMP_SECTIONS: case OMP_SINGLE: - tmp = tsubst_omp_clauses (OMP_CLAUSES (t), args, complain, in_decl); + case OMP_TEAMS: + case OMP_TARGET_DATA: + case OMP_TARGET: + tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, + args, complain, in_decl); stmt = push_stmt_list (); RECUR (OMP_BODY (t)); stmt = pop_stmt_list (stmt); @@ -13504,9 +13626,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, add_stmt (t); break; + case OMP_TARGET_UPDATE: + tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false, + args, complain, in_decl); + t = copy_node (t); + OMP_CLAUSES (t) = tmp; + add_stmt (t); + break; + case OMP_SECTION: case OMP_CRITICAL: case OMP_MASTER: + case OMP_TASKGROUP: case OMP_ORDERED: stmt = push_stmt_list (); RECUR (OMP_BODY (t)); @@ -13532,7 +13663,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op1, 0)); rhs = RECUR (TREE_OPERAND (op1, 1)); finish_omp_atomic (OMP_ATOMIC, TREE_CODE (op1), lhs, rhs, - NULL_TREE, NULL_TREE, rhs1); + NULL_TREE, NULL_TREE, rhs1, + OMP_ATOMIC_SEQ_CST (t)); } else { @@ -13560,6 +13692,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op11, 0)); rhs = RECUR (TREE_OPERAND (op11, 1)); opcode = TREE_CODE (op11); + if (opcode == MODIFY_EXPR) + opcode = NOP_EXPR; } else { @@ -13567,7 +13701,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op1, 0)); rhs = RECUR (TREE_OPERAND (op1, 1)); } - finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1); + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, + OMP_ATOMIC_SEQ_CST (t)); } break; @@ -13639,6 +13774,73 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, #undef RETURN } +/* Instantiate the special body of the artificial DECL_OMP_DECLARE_REDUCTION + function. For description of the body see comment above + cp_parser_omp_declare_reduction_exprs. */ + +static void +tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl) +{ + if (t == NULL_TREE || t == error_mark_node) + return; + + gcc_assert (TREE_CODE (t) == STATEMENT_LIST); + + tree_stmt_iterator tsi; + int i; + tree stmts[7]; + memset (stmts, 0, sizeof stmts); + for (i = 0, tsi = tsi_start (t); + i < 7 && !tsi_end_p (tsi); + i++, tsi_next (&tsi)) + stmts[i] = tsi_stmt (tsi); + gcc_assert (tsi_end_p (tsi)); + + if (i >= 3) + { + gcc_assert (TREE_CODE (stmts[0]) == DECL_EXPR + && TREE_CODE (stmts[1]) == DECL_EXPR); + tree omp_out = tsubst (DECL_EXPR_DECL (stmts[0]), + args, complain, in_decl); + tree omp_in = tsubst (DECL_EXPR_DECL (stmts[1]), + args, complain, in_decl); + DECL_CONTEXT (omp_out) = current_function_decl; + DECL_CONTEXT (omp_in) = current_function_decl; + keep_next_level (true); + tree block = begin_omp_structured_block (); + tsubst_expr (stmts[2], args, complain, in_decl, false); + block = finish_omp_structured_block (block); + block = maybe_cleanup_point_expr_void (block); + add_decl_expr (omp_out); + if (TREE_NO_WARNING (DECL_EXPR_DECL (stmts[0]))) + TREE_NO_WARNING (omp_out) = 1; + add_decl_expr (omp_in); + finish_expr_stmt (block); + } + if (i >= 6) + { + gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR + && TREE_CODE (stmts[4]) == DECL_EXPR); + tree omp_priv = tsubst (DECL_EXPR_DECL (stmts[3]), + args, complain, in_decl); + tree omp_orig = tsubst (DECL_EXPR_DECL (stmts[4]), + args, complain, in_decl); + DECL_CONTEXT (omp_priv) = current_function_decl; + DECL_CONTEXT (omp_orig) = current_function_decl; + keep_next_level (true); + tree block = begin_omp_structured_block (); + tsubst_expr (stmts[5], args, complain, in_decl, false); + block = finish_omp_structured_block (block); + block = maybe_cleanup_point_expr_void (block); + cp_walk_tree (&block, cp_remove_omp_priv_cleanup_stmt, omp_priv, NULL); + add_decl_expr (omp_priv); + add_decl_expr (omp_orig); + finish_expr_stmt (block); + if (i == 7) + add_decl_expr (omp_orig); + } +} + /* T is a postfix-expression that is not being used in a function call. Return the substituted version of T. */ @@ -19340,6 +19542,7 @@ instantiate_decl (tree d, int defer_ok, tree subst_decl; tree tmpl_parm; tree spec_parm; + tree block = NULL_TREE; /* Save away the current list, in case we are instantiating one template from within the body of another. */ @@ -19349,7 +19552,11 @@ instantiate_decl (tree d, int defer_ok, local_specializations = pointer_map_create (); /* Set up context. */ - start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); + if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern) + && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL) + block = push_stmt_list (); + else + start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); /* Some typedefs referenced from within the template code need to be access checked at template instantiation time, i.e now. These @@ -19386,21 +19593,37 @@ instantiate_decl (tree d, int defer_ok, gcc_assert (!spec_parm); /* Substitute into the body of the function. */ - tsubst_expr (DECL_SAVED_TREE (code_pattern), args, - tf_warning_or_error, tmpl, - /*integral_constant_expression_p=*/false); - - /* Set the current input_location to the end of the function - so that finish_function knows where we are. */ - input_location = DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus; + if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) + tsubst_omp_udr (DECL_SAVED_TREE (code_pattern), args, + tf_warning_or_error, tmpl); + else + { + tsubst_expr (DECL_SAVED_TREE (code_pattern), args, + tf_warning_or_error, tmpl, + /*integral_constant_expression_p=*/false); + + /* Set the current input_location to the end of the function + so that finish_function knows where we are. */ + input_location + = DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus; + } /* We don't need the local specializations any more. */ pointer_map_destroy (local_specializations); local_specializations = saved_local_specializations; /* Finish the function. */ - d = finish_function (0); - expand_or_defer_fn (d); + if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern) + && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL) + DECL_SAVED_TREE (d) = pop_stmt_list (block); + else + { + d = finish_function (0); + expand_or_defer_fn (d); + } + + if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) + cp_check_omp_declare_reduction (d); } /* We're not deferring instantiation any more. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index aa0490e..9bfd263 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4047,7 +4047,8 @@ finalize_nrv (tree *tp, tree var, tree result) bool cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, - bool need_copy_ctor, bool need_copy_assignment) + bool need_copy_ctor, bool need_copy_assignment, + bool need_dtor) { int save_errorcount = errorcount; tree info, t; @@ -4071,8 +4072,7 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, TREE_VEC_ELT (info, 0) = t; } - if ((need_default_ctor || need_copy_ctor) - && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) + if (need_dtor && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) TREE_VEC_ELT (info, 1) = get_dtor (type, tf_warning_or_error); if (need_copy_assignment) @@ -4086,6 +4086,1037 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, return errorcount != save_errorcount; } +/* Helper function for handle_omp_array_sections. Called recursively + to handle multiple array-section-subscripts. C is the clause, + T current expression (initially OMP_CLAUSE_DECL), which is either + a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound + expression if specified, TREE_VALUE length expression if specified, + TREE_CHAIN is what it has been specified after, or some decl. + TYPES vector is populated with array section types, MAYBE_ZERO_LEN + set to true if any of the array-section-subscript could have length + of zero (explicit or implicit), FIRST_NON_ONE is the index of the + first array-section-subscript which is known not to have length + of one. Given say: + map(a[:b][2:1][:c][:2][:d][e:f][2:5]) + FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] + all are or may have length of 1, array-section-subscript [:2] is the + first one knonwn not to have length 1. For array-section-subscript + <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't + 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we + can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above + case though, as some lengths could be zero. */ + +static tree +handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, + bool &maybe_zero_len, unsigned int &first_non_one) +{ + tree ret, low_bound, length, type; + if (TREE_CODE (t) != TREE_LIST) + { + if (error_operand_p (t)) + return error_mark_node; + if (type_dependent_expression_p (t)) + return NULL_TREE; + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + return NULL_TREE; + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + t = convert_from_reference (t); + return t; + } + + ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, + maybe_zero_len, first_non_one); + if (ret == error_mark_node || ret == NULL_TREE) + return ret; + + type = TREE_TYPE (ret); + low_bound = TREE_PURPOSE (t); + length = TREE_VALUE (t); + if ((low_bound && type_dependent_expression_p (low_bound)) + || (length && type_dependent_expression_p (length))) + return NULL_TREE; + + if (low_bound == error_mark_node || length == error_mark_node) + return error_mark_node; + + if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE of array section does not have integral type", + low_bound); + return error_mark_node; + } + if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE of array section does not have integral type", + length); + return error_mark_node; + } + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + + if (length != NULL_TREE) + { + if (!integer_nonzerop (length)) + maybe_zero_len = true; + if (first_non_one == types.length () + && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) + first_non_one++; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (length == NULL_TREE + && (TYPE_DOMAIN (type) == NULL_TREE + || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for unknown bound array type length expression must " + "be specified"); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST + && tree_int_cst_sgn (low_bound) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative low bound in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TYPE_DOMAIN (type) + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + == INTEGER_CST) + { + tree size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + size_one_node); + if (TREE_CODE (low_bound) == INTEGER_CST) + { + if (tree_int_cst_lt (size, low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE above array section size " + "in %qs clause", low_bound, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (tree_int_cst_equal (size, low_bound)) + maybe_zero_len = true; + else if (length == NULL_TREE + && first_non_one == types.length () + && tree_int_cst_equal + (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + low_bound)) + first_non_one++; + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + if (length && TREE_CODE (length) == INTEGER_CST) + { + if (tree_int_cst_lt (size, length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE above array section size " + "in %qs clause", length, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST) + { + tree lbpluslen + = size_binop (PLUS_EXPR, + fold_convert (sizetype, low_bound), + fold_convert (sizetype, length)); + if (TREE_CODE (lbpluslen) == INTEGER_CST + && tree_int_cst_lt (size, lbpluslen)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "high bound %qE above array section size " + "in %qs clause", lbpluslen, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + } + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + + /* For [lb:] we will need to evaluate lb more than once. */ + if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + { + tree lb = cp_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + } + else if (TREE_CODE (type) == POINTER_TYPE) + { + if (length == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for pointer type length expression must be specified"); + return error_mark_node; + } + /* If there is a pointer type anywhere but in the very first + array-section-subscript, the array section can't be contiguous. */ + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have pointer or array type", ret); + return error_mark_node; + } + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + types.safe_push (TREE_TYPE (ret)); + /* We will need to evaluate lb more than once. */ + tree lb = cp_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false); + return ret; +} + +/* Handle array sections for clause C. */ + +static bool +handle_omp_array_sections (tree c) +{ + bool maybe_zero_len = false; + unsigned int first_non_one = 0; + vec<tree> types = vNULL; + tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, + maybe_zero_len, first_non_one); + if (first == error_mark_node) + { + types.release (); + return true; + } + if (first == NULL_TREE) + { + types.release (); + return false; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + tree t = OMP_CLAUSE_DECL (c); + tree tem = NULL_TREE; + types.release (); + if (processing_template_decl) + return false; + /* Need to evaluate side effects in the length expressions + if any. */ + while (TREE_CODE (t) == TREE_LIST) + { + if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t))) + { + if (tem == NULL_TREE) + tem = TREE_VALUE (t); + else + tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), + TREE_VALUE (t), tem); + } + t = TREE_CHAIN (t); + } + if (tem) + first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); + OMP_CLAUSE_DECL (c) = first; + } + else + { + unsigned int num = types.length (), i; + tree t, side_effects = NULL_TREE, size = NULL_TREE; + tree condition = NULL_TREE; + + if (int_size_in_bytes (TREE_TYPE (first)) <= 0) + maybe_zero_len = true; + if (processing_template_decl && maybe_zero_len) + { + types.release (); + return false; + } + + for (i = num, t = OMP_CLAUSE_DECL (c); i > 0; + t = TREE_CHAIN (t)) + { + tree low_bound = TREE_PURPOSE (t); + tree length = TREE_VALUE (t); + + i--; + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + if (!maybe_zero_len && i > first_non_one) + { + if (integer_nonzerop (low_bound)) + goto do_warn_noncontiguous; + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && TYPE_DOMAIN (types[i]) + && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))) + == INTEGER_CST) + { + tree size; + size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + if (!tree_int_cst_equal (length, size)) + { + do_warn_noncontiguous: + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs " + "clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + types.release (); + return true; + } + } + if (!processing_template_decl + && length != NULL_TREE + && TREE_SIDE_EFFECTS (length)) + { + if (side_effects == NULL_TREE) + side_effects = length; + else + side_effects = build2 (COMPOUND_EXPR, + TREE_TYPE (side_effects), + length, side_effects); + } + } + else if (processing_template_decl) + continue; + else + { + tree l; + + if (i > first_non_one && length && integer_nonzerop (length)) + continue; + if (length) + l = fold_convert (sizetype, length); + else + { + l = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + l = size_binop (MINUS_EXPR, l, + fold_convert (sizetype, low_bound)); + } + if (i > first_non_one) + { + l = fold_build2 (NE_EXPR, boolean_type_node, l, + size_zero_node); + if (condition == NULL_TREE) + condition = l; + else + condition = fold_build2 (BIT_AND_EXPR, boolean_type_node, + l, condition); + } + else if (size == NULL_TREE) + { + size = size_in_bytes (TREE_TYPE (types[i])); + size = size_binop (MULT_EXPR, size, l); + if (condition) + size = fold_build3 (COND_EXPR, sizetype, condition, + size, size_zero_node); + } + else + size = size_binop (MULT_EXPR, size, l); + } + } + types.release (); + if (!processing_template_decl) + { + if (side_effects) + size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + OMP_CLAUSE_DECL (c) = first; + OMP_CLAUSE_SIZE (c) = size; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + return false; + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER; + if (!cxx_mark_addressable (t)) + return false; + OMP_CLAUSE_DECL (c2) = t; + t = build_fold_addr_expr (first); + t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + ptrdiff_type_node, t); + tree ptr = OMP_CLAUSE_DECL (c2); + ptr = convert_from_reference (ptr); + if (!POINTER_TYPE_P (TREE_TYPE (ptr))) + ptr = build_fold_addr_expr (ptr); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + ptrdiff_type_node, t, + fold_convert_loc (OMP_CLAUSE_LOCATION (c), + ptrdiff_type_node, ptr)); + OMP_CLAUSE_SIZE (c2) = t; + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = c2; + ptr = OMP_CLAUSE_DECL (c2); + if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (ptr)))) + { + tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_MAP_KIND (c3) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_DECL (c3) = ptr; + OMP_CLAUSE_DECL (c2) = convert_from_reference (ptr); + OMP_CLAUSE_SIZE (c3) = size_zero_node; + OMP_CLAUSE_CHAIN (c3) = OMP_CLAUSE_CHAIN (c2); + OMP_CLAUSE_CHAIN (c2) = c3; + } + } + } + return false; +} + +/* Return identifier to look up for omp declare reduction. */ + +tree +omp_reduction_id (enum tree_code reduction_code, tree reduction_id, tree type) +{ + const char *p = NULL; + const char *m = NULL; + switch (reduction_code) + { + case PLUS_EXPR: + case MULT_EXPR: + case MINUS_EXPR: + case BIT_AND_EXPR: + case BIT_XOR_EXPR: + case BIT_IOR_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + reduction_id = ansi_opname (reduction_code); + break; + case MIN_EXPR: + p = "min"; + break; + case MAX_EXPR: + p = "max"; + break; + default: + break; + } + + if (p == NULL) + { + if (TREE_CODE (reduction_id) != IDENTIFIER_NODE) + return error_mark_node; + p = IDENTIFIER_POINTER (reduction_id); + } + + if (type != NULL_TREE) + m = mangle_type_string (TYPE_MAIN_VARIANT (type)); + + const char prefix[] = "omp declare reduction "; + size_t lenp = sizeof (prefix); + if (strncmp (p, prefix, lenp - 1) == 0) + lenp = 1; + size_t len = strlen (p); + size_t lenm = m ? strlen (m) + 1 : 0; + char *name = XALLOCAVEC (char, lenp + len + lenm); + if (lenp > 1) + memcpy (name, prefix, lenp - 1); + memcpy (name + lenp - 1, p, len + 1); + if (m) + { + name[lenp + len - 1] = '~'; + memcpy (name + lenp + len, m, lenm); + } + return get_identifier (name); +} + +/* Lookup OpenMP UDR ID for TYPE, return the corresponding artificial + FUNCTION_DECL or NULL_TREE if not found. */ + +static tree +omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp, + vec<tree> *ambiguousp) +{ + tree orig_id = id; + tree baselink = NULL_TREE; + if (identifier_p (id)) + { + cp_id_kind idk; + bool nonint_cst_expression_p; + const char *error_msg; + id = omp_reduction_id (ERROR_MARK, id, type); + tree decl = lookup_name (id); + if (decl == NULL_TREE) + decl = error_mark_node; + id = finish_id_expression (id, decl, NULL_TREE, &idk, false, true, + &nonint_cst_expression_p, false, true, false, + false, &error_msg, loc); + if (idk == CP_ID_KIND_UNQUALIFIED + && identifier_p (id)) + { + vec<tree, va_gc> *args = NULL; + vec_safe_push (args, build_reference_type (type)); + id = perform_koenig_lookup (id, args, false, tf_none); + } + } + else if (TREE_CODE (id) == SCOPE_REF) + id = lookup_qualified_name (TREE_OPERAND (id, 0), + omp_reduction_id (ERROR_MARK, + TREE_OPERAND (id, 1), + type), + false, false); + tree fns = id; + if (id && is_overloaded_fn (id)) + id = get_fns (id); + for (; id; id = OVL_NEXT (id)) + { + tree fndecl = OVL_CURRENT (id); + if (TREE_CODE (fndecl) == FUNCTION_DECL) + { + tree argtype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); + if (same_type_p (TREE_TYPE (argtype), type)) + break; + } + } + if (id && BASELINK_P (fns)) + { + if (baselinkp) + *baselinkp = fns; + else + baselink = fns; + } + if (id == NULL_TREE && CLASS_TYPE_P (type) && TYPE_BINFO (type)) + { + vec<tree> ambiguous = vNULL; + tree binfo = TYPE_BINFO (type), base_binfo, ret = NULL_TREE; + unsigned int ix; + if (ambiguousp == NULL) + ambiguousp = &ambiguous; + for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++) + { + id = omp_reduction_lookup (loc, orig_id, BINFO_TYPE (base_binfo), + baselinkp ? baselinkp : &baselink, + ambiguousp); + if (id == NULL_TREE) + continue; + if (!ambiguousp->is_empty ()) + ambiguousp->safe_push (id); + else if (ret != NULL_TREE) + { + ambiguousp->safe_push (ret); + ambiguousp->safe_push (id); + ret = NULL_TREE; + } + else + ret = id; + } + if (ambiguousp != &ambiguous) + return ret; + if (!ambiguous.is_empty ()) + { + const char *str = _("candidates are:"); + unsigned int idx; + tree udr; + error_at (loc, "user defined reduction lookup is ambiguous"); + FOR_EACH_VEC_ELT (ambiguous, idx, udr) + { + inform (DECL_SOURCE_LOCATION (udr), "%s %#D", str, udr); + if (idx == 0) + str = get_spaces (str); + } + ambiguous.release (); + ret = error_mark_node; + baselink = NULL_TREE; + } + id = ret; + } + if (id && baselink) + perform_or_defer_access_check (BASELINK_BINFO (baselink), + id, id, tf_warning_or_error); + return id; +} + +/* Helper function for cp_parser_omp_declare_reduction_exprs + and tsubst_omp_udr. + Remove CLEANUP_STMT for data (omp_priv variable). + Also append INIT_EXPR for DECL_INITIAL of omp_priv after its + DECL_EXPR. */ + +tree +cp_remove_omp_priv_cleanup_stmt (tree *tp, int *walk_subtrees, void *data) +{ + if (TYPE_P (*tp)) + *walk_subtrees = 0; + else if (TREE_CODE (*tp) == CLEANUP_STMT && CLEANUP_DECL (*tp) == (tree) data) + *tp = CLEANUP_BODY (*tp); + else if (TREE_CODE (*tp) == DECL_EXPR) + { + tree decl = DECL_EXPR_DECL (*tp); + if (!processing_template_decl + && decl == (tree) data + && DECL_INITIAL (decl) + && DECL_INITIAL (decl) != error_mark_node) + { + tree list = NULL_TREE; + append_to_statement_list_force (*tp, &list); + tree init_expr = build2 (INIT_EXPR, void_type_node, + decl, DECL_INITIAL (decl)); + DECL_INITIAL (decl) = NULL_TREE; + append_to_statement_list_force (init_expr, &list); + *tp = list; + } + } + return NULL_TREE; +} + +/* Data passed from cp_check_omp_declare_reduction to + cp_check_omp_declare_reduction_r. */ + +struct cp_check_omp_declare_reduction_data +{ + location_t loc; + tree stmts[7]; + bool combiner_p; +}; + +/* Helper function for cp_check_omp_declare_reduction, called via + cp_walk_tree. */ + +static tree +cp_check_omp_declare_reduction_r (tree *tp, int *, void *data) +{ + struct cp_check_omp_declare_reduction_data *udr_data + = (struct cp_check_omp_declare_reduction_data *) data; + if (SSA_VAR_P (*tp) + && !DECL_ARTIFICIAL (*tp) + && *tp != DECL_EXPR_DECL (udr_data->stmts[udr_data->combiner_p ? 0 : 3]) + && *tp != DECL_EXPR_DECL (udr_data->stmts[udr_data->combiner_p ? 1 : 4])) + { + location_t loc = udr_data->loc; + if (udr_data->combiner_p) + error_at (loc, "%<#pragma omp declare reduction%> combiner refers to " + "variable %qD which is not %<omp_out%> nor %<omp_in%>", + *tp); + else + error_at (loc, "%<#pragma omp declare reduction%> initializer refers " + "to variable %qD which is not %<omp_priv%> nor " + "%<omp_orig%>", + *tp); + return *tp; + } + return NULL_TREE; +} + +/* Diagnose violation of OpenMP #pragma omp declare reduction restrictions. */ + +void +cp_check_omp_declare_reduction (tree udr) +{ + tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (udr))); + gcc_assert (TREE_CODE (type) == REFERENCE_TYPE); + type = TREE_TYPE (type); + int i; + location_t loc = DECL_SOURCE_LOCATION (udr); + + if (type == error_mark_node) + return; + if (ARITHMETIC_TYPE_P (type)) + { + static enum tree_code predef_codes[] + = { PLUS_EXPR, MULT_EXPR, MINUS_EXPR, BIT_AND_EXPR, BIT_XOR_EXPR, + BIT_IOR_EXPR, TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR }; + for (i = 0; i < 8; i++) + { + tree id = omp_reduction_id (predef_codes[i], NULL_TREE, NULL_TREE); + const char *n1 = IDENTIFIER_POINTER (DECL_NAME (udr)); + const char *n2 = IDENTIFIER_POINTER (id); + if (strncmp (n1, n2, IDENTIFIER_LENGTH (id)) == 0 + && (n1[IDENTIFIER_LENGTH (id)] == '~' + || n1[IDENTIFIER_LENGTH (id)] == '\0')) + break; + } + + if (i == 8 + && TREE_CODE (type) != COMPLEX_EXPR) + { + const char prefix_minmax[] = "omp declare reduction m"; + size_t prefix_size = sizeof (prefix_minmax) - 1; + const char *n = IDENTIFIER_POINTER (DECL_NAME (udr)); + if (strncmp (IDENTIFIER_POINTER (DECL_NAME (udr)), + prefix_minmax, prefix_size) == 0 + && ((n[prefix_size] == 'i' && n[prefix_size + 1] == 'n') + || (n[prefix_size] == 'a' && n[prefix_size + 1] == 'x')) + && (n[prefix_size + 2] == '~' || n[prefix_size + 2] == '\0')) + i = 0; + } + if (i < 8) + { + error_at (loc, "predeclared arithmetic type %qT in " + "%<#pragma omp declare reduction%>", type); + return; + } + } + else if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE + || TREE_CODE (type) == ARRAY_TYPE) + { + error_at (loc, "function or array type %qT in " + "%<#pragma omp declare reduction%>", type); + return; + } + else if (TREE_CODE (type) == REFERENCE_TYPE) + { + error_at (loc, "reference type %qT in %<#pragma omp declare reduction%>", + type); + return; + } + else if (TYPE_QUALS_NO_ADDR_SPACE (type)) + { + error_at (loc, "const, volatile or __restrict qualified type %qT in " + "%<#pragma omp declare reduction%>", type); + return; + } + + tree body = DECL_SAVED_TREE (udr); + if (body == NULL_TREE || TREE_CODE (body) != STATEMENT_LIST) + return; + + tree_stmt_iterator tsi; + struct cp_check_omp_declare_reduction_data data; + memset (data.stmts, 0, sizeof data.stmts); + for (i = 0, tsi = tsi_start (body); + i < 7 && !tsi_end_p (tsi); + i++, tsi_next (&tsi)) + data.stmts[i] = tsi_stmt (tsi); + data.loc = loc; + gcc_assert (tsi_end_p (tsi)); + if (i >= 3) + { + gcc_assert (TREE_CODE (data.stmts[0]) == DECL_EXPR + && TREE_CODE (data.stmts[1]) == DECL_EXPR); + if (TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0]))) + return; + data.combiner_p = true; + if (cp_walk_tree (&data.stmts[2], cp_check_omp_declare_reduction_r, + &data, NULL)) + TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])) = 1; + } + if (i >= 6) + { + gcc_assert (TREE_CODE (data.stmts[3]) == DECL_EXPR + && TREE_CODE (data.stmts[4]) == DECL_EXPR); + data.combiner_p = false; + if (cp_walk_tree (&data.stmts[5], cp_check_omp_declare_reduction_r, + &data, NULL) + || cp_walk_tree (&DECL_INITIAL (DECL_EXPR_DECL (data.stmts[3])), + cp_check_omp_declare_reduction_r, &data, NULL)) + TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])) = 1; + if (i == 7) + gcc_assert (TREE_CODE (data.stmts[6]) == DECL_EXPR); + } +} + +/* Helper function of finish_omp_clauses. Clone STMT as if we were making + an inline call. But, remap + the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER + and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */ + +static tree +clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2, + tree decl, tree placeholder) +{ + copy_body_data id; + struct pointer_map_t *decl_map = pointer_map_create (); + + *pointer_map_insert (decl_map, omp_decl1) = placeholder; + *pointer_map_insert (decl_map, omp_decl2) = decl; + memset (&id, 0, sizeof (id)); + id.src_fn = DECL_CONTEXT (omp_decl1); + id.dst_fn = current_function_decl; + id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn); + id.decl_map = decl_map; + + id.copy_decl = copy_decl_no_change; + id.transform_call_graph_edges = CB_CGE_DUPLICATE; + id.transform_new_cfg = true; + id.transform_return_to_modify = false; + id.transform_lang_insert_block = NULL; + id.eh_lp_nr = 0; + walk_tree (&stmt, copy_tree_body_r, &id, NULL); + pointer_map_destroy (decl_map); + return stmt; +} + +/* Helper function of finish_omp_clauses, called via cp_walk_tree. + Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */ + +static tree +find_omp_placeholder_r (tree *tp, int *, void *data) +{ + if (*tp == (tree) data) + return *tp; + return NULL_TREE; +} + +/* Helper function of finish_omp_clauses. Handle OMP_CLAUSE_REDUCTION C. + Return true if there is some error and the clause should be removed. */ + +static bool +finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) +{ + tree t = OMP_CLAUSE_DECL (c); + bool predefined = false; + tree type = TREE_TYPE (t); + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + if (ARITHMETIC_TYPE_P (type)) + switch (OMP_CLAUSE_REDUCTION_CODE (c)) + { + case PLUS_EXPR: + case MULT_EXPR: + case MINUS_EXPR: + predefined = true; + break; + case MIN_EXPR: + case MAX_EXPR: + if (TREE_CODE (type) == COMPLEX_TYPE) + break; + predefined = true; + break; + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + if (FLOAT_TYPE_P (type)) + break; + predefined = true; + break; + default: + break; + } + else if (TREE_CODE (type) == ARRAY_TYPE || TYPE_READONLY (type)) + { + error ("%qE has invalid type for %<reduction%>", t); + return true; + } + else if (!processing_template_decl) + { + t = require_complete_type (t); + if (t == error_mark_node) + return true; + OMP_CLAUSE_DECL (c) = t; + } + + if (predefined) + { + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE; + return false; + } + else if (processing_template_decl) + return false; + + tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); + + type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE; + if (id == NULL_TREE) + id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c), + NULL_TREE, NULL_TREE); + id = omp_reduction_lookup (OMP_CLAUSE_LOCATION (c), id, type, NULL, NULL); + if (id) + { + if (id == error_mark_node) + return true; + id = OVL_CURRENT (id); + mark_used (id); + tree body = DECL_SAVED_TREE (id); + if (TREE_CODE (body) == STATEMENT_LIST) + { + tree_stmt_iterator tsi; + tree placeholder = NULL_TREE; + int i; + tree stmts[7]; + tree atype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id))); + atype = TREE_TYPE (atype); + bool need_static_cast = !same_type_p (type, atype); + memset (stmts, 0, sizeof stmts); + for (i = 0, tsi = tsi_start (body); + i < 7 && !tsi_end_p (tsi); + i++, tsi_next (&tsi)) + stmts[i] = tsi_stmt (tsi); + gcc_assert (tsi_end_p (tsi)); + + if (i >= 3) + { + gcc_assert (TREE_CODE (stmts[0]) == DECL_EXPR + && TREE_CODE (stmts[1]) == DECL_EXPR); + placeholder = build_lang_decl (VAR_DECL, NULL_TREE, type); + DECL_ARTIFICIAL (placeholder) = 1; + DECL_IGNORED_P (placeholder) = 1; + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; + if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0]))) + cxx_mark_addressable (placeholder); + if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1])) + && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) + != REFERENCE_TYPE) + cxx_mark_addressable (OMP_CLAUSE_DECL (c)); + tree omp_out = placeholder; + tree omp_in = convert_from_reference (OMP_CLAUSE_DECL (c)); + if (need_static_cast) + { + tree rtype = build_reference_type (atype); + omp_out = build_static_cast (rtype, omp_out, + tf_warning_or_error); + omp_in = build_static_cast (rtype, omp_in, + tf_warning_or_error); + if (omp_out == error_mark_node || omp_in == error_mark_node) + return true; + omp_out = convert_from_reference (omp_out); + omp_in = convert_from_reference (omp_in); + } + OMP_CLAUSE_REDUCTION_MERGE (c) + = clone_omp_udr (stmts[2], DECL_EXPR_DECL (stmts[0]), + DECL_EXPR_DECL (stmts[1]), omp_in, omp_out); + } + if (i >= 6) + { + gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR + && TREE_CODE (stmts[4]) == DECL_EXPR); + if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3]))) + cxx_mark_addressable (OMP_CLAUSE_DECL (c)); + if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4]))) + cxx_mark_addressable (placeholder); + tree omp_priv = convert_from_reference (OMP_CLAUSE_DECL (c)); + tree omp_orig = placeholder; + if (need_static_cast) + { + if (i == 7) + { + error_at (OMP_CLAUSE_LOCATION (c), + "user defined reduction with constructor " + "initializer for base class %qT", atype); + return true; + } + tree rtype = build_reference_type (atype); + omp_priv = build_static_cast (rtype, omp_priv, + tf_warning_or_error); + omp_orig = build_static_cast (rtype, omp_orig, + tf_warning_or_error); + if (omp_priv == error_mark_node + || omp_orig == error_mark_node) + return true; + omp_priv = convert_from_reference (omp_priv); + omp_orig = convert_from_reference (omp_orig); + } + if (i == 6) + *need_default_ctor = true; + OMP_CLAUSE_REDUCTION_INIT (c) + = clone_omp_udr (stmts[5], DECL_EXPR_DECL (stmts[4]), + DECL_EXPR_DECL (stmts[3]), + omp_priv, omp_orig); + if (cp_walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), + find_omp_placeholder_r, placeholder, NULL)) + OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1; + } + else if (i >= 3) + { + if (CLASS_TYPE_P (type) && !pod_type_p (type)) + *need_default_ctor = true; + else + { + tree init; + tree v = convert_from_reference (t); + if (AGGREGATE_TYPE_P (TREE_TYPE (v))) + init = build_constructor (TREE_TYPE (v), NULL); + else + init = fold_convert (TREE_TYPE (v), integer_zero_node); + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (v), v, init); + } + } + } + } + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + *need_dtor = true; + else + { + error ("user defined reduction not found for %qD", t); + return true; + } + return false; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -4093,13 +5124,16 @@ tree finish_omp_clauses (tree clauses) { bitmap_head generic_head, firstprivate_head, lastprivate_head; + bitmap_head aligned_head; tree c, t, *pc = &clauses; - const char *name; + bool branch_seen = false; + bool copyprivate_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); for (pc = &clauses, c = clauses; c ; c = *pc) { @@ -4108,19 +5142,58 @@ finish_omp_clauses (tree clauses) switch (OMP_CLAUSE_CODE (c)) { case OMP_CLAUSE_SHARED: - name = "shared"; goto check_dup_generic; case OMP_CLAUSE_PRIVATE: - name = "private"; goto check_dup_generic; case OMP_CLAUSE_REDUCTION: - name = "reduction"; goto check_dup_generic; case OMP_CLAUSE_COPYPRIVATE: - name = "copyprivate"; + copyprivate_seen = true; goto check_dup_generic; case OMP_CLAUSE_COPYIN: - name = "copyin"; + goto check_dup_generic; + case OMP_CLAUSE_LINEAR: + t = OMP_CLAUSE_DECL (c); + if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error ("linear clause applied to non-integral non-pointer " + "variable with %qT type", TREE_TYPE (t)); + remove = true; + break; + } + t = OMP_CLAUSE_LINEAR_STEP (c); + if (t == NULL_TREE) + t = integer_one_node; + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("linear step expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) + == POINTER_TYPE) + { + t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + OMP_CLAUSE_DECL (c), t); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), + MINUS_EXPR, sizetype, t, + OMP_CLAUSE_DECL (c)); + if (t == error_mark_node) + remove = true; + } + } + OMP_CLAUSE_LINEAR_STEP (c) = t; + } goto check_dup_generic; check_dup_generic: t = OMP_CLAUSE_DECL (c); @@ -4129,9 +5202,11 @@ finish_omp_clauses (tree clauses) if (processing_template_decl) break; if (DECL_P (t)) - error ("%qD is not a variable in clause %qs", t, name); + error ("%qD is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); else - error ("%qE is not a variable in clause %qs", t, name); + error ("%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } else if (bitmap_bit_p (&generic_head, DECL_UID (t)) @@ -4249,12 +5324,299 @@ finish_omp_clauses (tree clauses) } break; + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_SAFELEN: + t = OMP_CLAUSE_OPERAND (c, 0); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%qs length expression must be integral", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else + { + t = mark_rvalue_use (t); + t = maybe_constant_value (t); + if (!processing_template_decl) + { + if (TREE_CODE (t) != INTEGER_CST + || tree_int_cst_sgn (t) != 1) + { + error ("%qs length expression must be positive constant" + " integer expression", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + OMP_CLAUSE_OPERAND (c, 0) = t; + } + break; + + case OMP_CLAUSE_NUM_TEAMS: + t = OMP_CLAUSE_NUM_TEAMS_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<num_teams%> expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_THREAD_LIMIT: + t = OMP_CLAUSE_THREAD_LIMIT_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<thread_limit%> expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_DEVICE: + t = OMP_CLAUSE_DEVICE_ID (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<device%> id must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_DEVICE_ID (c) = t; + } + break; + + case OMP_CLAUSE_DIST_SCHEDULE: + t = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c); + if (t == NULL) + ; + else if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<dist_schedule%> chunk size expression must be " + "integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_ALIGNED: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in %<aligned%> clause", t); + else + error ("%qE is not a variable in %<aligned%> clause", t); + remove = true; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + error ("%qD appears more than once in %<aligned%> clauses", t); + remove = true; + } + else + bitmap_set_bit (&aligned_head, DECL_UID (t)); + t = OMP_CLAUSE_ALIGNED_ALIGNMENT (c); + if (t == error_mark_node) + remove = true; + else if (t == NULL_TREE) + break; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<aligned%> clause alignment expression must " + "be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + t = maybe_constant_value (t); + if (!processing_template_decl) + { + if (TREE_CODE (t) != INTEGER_CST + || tree_int_cst_sgn (t) != 1) + { + error ("%<aligned%> clause alignment expression must be " + "positive constant integer expression"); + remove = true; + } + } + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = t; + } + break; + + case OMP_CLAUSE_DEPEND: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in %<depend%> clause", t); + else + error ("%qE is not a variable in %<depend%> clause", t); + remove = true; + } + else if (!processing_template_decl + && !cxx_mark_addressable (t)) + remove = true; + break; + + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + else + { + t = OMP_CLAUSE_DECL (c); + if (!cp_omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section does not have mappable type " + "in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER) + break; + if (DECL_P (t)) + error ("%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error ("%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error ("%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!processing_template_decl + && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE + && !cxx_mark_addressable (t)) + remove = true; + else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER) + && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t)) + == REFERENCE_TYPE) + ? TREE_TYPE (TREE_TYPE (t)) + : TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t))) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + error ("%qD appears more than once in motion clauses", t); + else + error ("%qD appears more than once in map clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_UNIFORM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not an argument in %<uniform%> clause", t); + else + error ("%qE is not an argument in %<uniform%> clause", t); + remove = true; + } + break; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_PROC_BIND: + break; + + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + if (branch_seen) + { + error ("%<inbranch%> clause is incompatible with " + "%<notinbranch%>"); + remove = true; + } + branch_seen = true; break; default: @@ -4276,44 +5638,50 @@ finish_omp_clauses (tree clauses) bool need_copy_ctor = false; bool need_copy_assignment = false; bool need_implicitly_determined = false; + bool need_dtor = false; tree type, inner_type; switch (c_kind) { case OMP_CLAUSE_SHARED: - name = "shared"; need_implicitly_determined = true; break; case OMP_CLAUSE_PRIVATE: - name = "private"; need_complete_non_reference = true; need_default_ctor = true; + need_dtor = true; need_implicitly_determined = true; break; case OMP_CLAUSE_FIRSTPRIVATE: - name = "firstprivate"; need_complete_non_reference = true; need_copy_ctor = true; + need_dtor = true; need_implicitly_determined = true; break; case OMP_CLAUSE_LASTPRIVATE: - name = "lastprivate"; need_complete_non_reference = true; need_copy_assignment = true; need_implicitly_determined = true; break; case OMP_CLAUSE_REDUCTION: - name = "reduction"; need_implicitly_determined = true; break; case OMP_CLAUSE_COPYPRIVATE: - name = "copyprivate"; need_copy_assignment = true; break; case OMP_CLAUSE_COPYIN: - name = "copyin"; need_copy_assignment = true; break; + case OMP_CLAUSE_NOWAIT: + if (copyprivate_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<nowait%> clause must not be used together " + "with %<copyprivate%>"); + *pc = OMP_CLAUSE_CHAIN (c); + continue; + } + /* FALLTHRU */ default: pc = &OMP_CLAUSE_CHAIN (c); continue; @@ -4331,33 +5699,18 @@ finish_omp_clauses (tree clauses) { case OMP_CLAUSE_LASTPRIVATE: if (!bitmap_bit_p (&firstprivate_head, DECL_UID (t))) - need_default_ctor = true; + { + need_default_ctor = true; + need_dtor = true; + } break; case OMP_CLAUSE_REDUCTION: - if (AGGREGATE_TYPE_P (TREE_TYPE (t)) - || POINTER_TYPE_P (TREE_TYPE (t))) - { - error ("%qE has invalid type for %<reduction%>", t); - remove = true; - } - else if (FLOAT_TYPE_P (TREE_TYPE (t))) - { - enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); - switch (r_code) - { - case PLUS_EXPR: - case MULT_EXPR: - case MINUS_EXPR: - case MIN_EXPR: - case MAX_EXPR: - break; - default: - error ("%qE has invalid type for %<reduction(%s)%>", - t, operator_name_info[r_code].name); - remove = true; - } - } + if (finish_omp_reduction_clause (c, &need_default_ctor, + &need_dtor)) + remove = true; + else + t = OMP_CLAUSE_DECL (c); break; case OMP_CLAUSE_COPYIN: @@ -4380,7 +5733,8 @@ finish_omp_clauses (tree clauses) else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE && need_complete_non_reference) { - error ("%qE has reference type for %qs", t, name); + error ("%qE has reference type for %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } } @@ -4410,7 +5764,7 @@ finish_omp_clauses (tree clauses) if (share_name) { error ("%qE is predetermined %qs for %qs", - t, share_name, name); + t, share_name, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } } @@ -4420,15 +5774,21 @@ finish_omp_clauses (tree clauses) while (TREE_CODE (inner_type) == ARRAY_TYPE) inner_type = TREE_TYPE (inner_type); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && TREE_CODE (inner_type) == REFERENCE_TYPE) + inner_type = TREE_TYPE (inner_type); + /* Check for special function availability by building a call to one. Save the results, because later we won't be in the right context for making these queries. */ if (CLASS_TYPE_P (inner_type) && COMPLETE_TYPE_P (inner_type) - && (need_default_ctor || need_copy_ctor || need_copy_assignment) + && (need_default_ctor || need_copy_ctor + || need_copy_assignment || need_dtor) && !type_dependent_expression_p (t) && cxx_omp_create_clause_info (c, inner_type, need_default_ctor, - need_copy_ctor, need_copy_assignment)) + need_copy_ctor, need_copy_assignment, + need_dtor)) remove = true; if (remove) @@ -4809,8 +6169,8 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, sk_omp scope. */ tree -finish_omp_for (location_t locus, tree declv, tree initv, tree condv, - tree incrv, tree body, tree pre_body, tree clauses) +finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, + tree condv, tree incrv, tree body, tree pre_body, tree clauses) { tree omp_for = NULL, orig_incr = NULL; tree decl, init, cond, incr; @@ -4879,7 +6239,7 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, { tree stmt; - stmt = make_node (OMP_FOR); + stmt = make_node (code); for (i = 0; i < TREE_VEC_LENGTH (declv); i++) { @@ -4937,6 +6297,12 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, if (CLASS_TYPE_P (TREE_TYPE (decl))) { + if (code == OMP_SIMD) + { + error_at (elocus, "%<#pragma omp simd%> used with class " + "iteration variable %qE", decl); + return NULL; + } if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, incrv, &body, &pre_body, clauses)) return NULL; @@ -4991,7 +6357,7 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, if (IS_EMPTY_STMT (pre_body)) pre_body = NULL; - omp_for = c_finish_omp_for (locus, declv, initv, condv, incrv, + omp_for = c_finish_omp_for (locus, code, declv, initv, condv, incrv, body, pre_body); if (omp_for == NULL) @@ -5036,7 +6402,7 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, void finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, - tree rhs, tree v, tree lhs1, tree rhs1) + tree rhs, tree v, tree lhs1, tree rhs1, bool seq_cst) { tree orig_lhs; tree orig_rhs; @@ -5078,8 +6444,36 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, } if (!dependent_p) { + bool swapped = false; + if (rhs1 && cp_tree_equal (lhs, rhs)) + { + tree tem = rhs; + rhs = rhs1; + rhs1 = tem; + swapped = !commutative_tree_code (opcode); + } + if (rhs1 && !cp_tree_equal (lhs, rhs1)) + { + if (code == OMP_ATOMIC) + error ("%<#pragma omp atomic update%> uses two different " + "expressions for memory"); + else + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + return; + } + if (lhs1 && !cp_tree_equal (lhs, lhs1)) + { + if (code == OMP_ATOMIC) + error ("%<#pragma omp atomic update%> uses two different " + "expressions for memory"); + else + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + return; + } stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs, - v, lhs1, rhs1); + v, lhs1, rhs1, swapped, seq_cst); if (stmt == error_mark_node) return; } @@ -5089,6 +6483,7 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, { stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs), OMP_ATOMIC_READ, orig_lhs); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); } else @@ -5104,10 +6499,12 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, { stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs1), code, orig_lhs1, stmt); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); } } stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; } add_stmt (stmt); } @@ -5151,6 +6548,69 @@ finish_omp_taskyield (void) release_tree_vector (vec); finish_expr_stmt (stmt); } + +void +finish_omp_cancel (tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error ("%<#pragma omp cancel must specify one of " + "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> clauses"); + return; + } + vec<tree, va_gc> *vec = make_tree_vector (); + tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF); + if (ifc != NULL_TREE) + { + 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), + build_zero_cst (type)); + } + else + ifc = boolean_true_node; + vec->quick_push (build_int_cst (integer_type_node, mask)); + vec->quick_push (ifc); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + release_tree_vector (vec); + finish_expr_stmt (stmt); +} + +void +finish_omp_cancellation_point (tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error ("%<#pragma omp cancellation point must specify one of " + "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> clauses"); + return; + } + vec<tree, va_gc> *vec + = make_tree_vector_single (build_int_cst (integer_type_node, mask)); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + release_tree_vector (vec); + finish_expr_stmt (stmt); +} /* Begin a __transaction_atomic or __transaction_relaxed statement. If PCOMPOUND is non-null, this is for a function-transaction-block, and we |