aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog169
-rw-r--r--gcc/cp/cp-array-notation.c1
-rw-r--r--gcc/cp/cp-gimplify.c25
-rw-r--r--gcc/cp/cp-objcp-common.h2
-rw-r--r--gcc/cp/cp-tree.h34
-rw-r--r--gcc/cp/decl.c52
-rw-r--r--gcc/cp/decl2.c73
-rw-r--r--gcc/cp/parser.c2569
-rw-r--r--gcc/cp/parser.h18
-rw-r--r--gcc/cp/pt.c293
-rw-r--r--gcc/cp/semantics.c1564
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